Files
tankwar_proj/js/scenes/SettingsScene.js
T
jakciehan c4bd390478 commit
2026-05-12 08:03:21 +08:00

220 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* SettingsScene.js
* Settings screen with sound, music, and vibration toggles.
*/
const {
SCREEN_WIDTH,
SCREEN_HEIGHT,
COLORS,
SCENE,
} = require('../base/GameGlobal');
const { t } = require('../i18n/I18n');
const SettingsScene = {
_settings: {
soundEnabled: true,
musicEnabled: true,
vibrationEnabled: true,
},
_buttons: {},
enter() {
// Load settings from storage
try {
const saved = wx.getStorageSync('game_settings');
if (saved) {
this._settings = { ...this._settings, ...JSON.parse(saved) };
}
} catch (e) {
console.warn('[Settings] Failed to load settings:', e);
}
this._buttons = {};
},
exit() {
// Save settings
try {
wx.setStorageSync('game_settings', JSON.stringify(this._settings));
} catch (e) {
console.warn('[Settings] Failed to save settings:', e);
}
},
update(dt) {},
render(ctx) {
// Background
ctx.fillStyle = COLORS.MENU_BG;
ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
const cx = SCREEN_WIDTH / 2;
// Reset button map each frame so layout changes don't keep stale rects.
this._buttons = {};
// Title
const titleY = Math.max(48, SCREEN_HEIGHT * 0.08);
ctx.fillStyle = COLORS.MENU_TITLE;
ctx.font = 'bold 28px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(t('settings.title'), cx, titleY);
// Back button (reserved at bottom so we can layout rows above it).
const backH = 42;
const backMarginBottom = 28;
const backCenterY = SCREEN_HEIGHT - backMarginBottom - backH / 2;
// Rows: nickname + 3 toggles. Distribute evenly between title and back btn.
const rows = [
{ type: 'toggle', key: 'soundEnabled', label: t('settings.sound'), icon: '🔊' },
{ type: 'toggle', key: 'musicEnabled', label: t('settings.music'), icon: '🎵' },
{ type: 'toggle', key: 'vibrationEnabled', label: t('settings.vibration'), icon: '📳' },
];
const rowH = 50;
const topPad = titleY + 36;
const bottomPad = backCenterY - backH / 2 - 20;
const availH = Math.max(rowH * rows.length, bottomPad - topPad);
const step = Math.max(rowH + 8, availH / rows.length);
const firstCenterY = topPad + step / 2;
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
const cy = firstCenterY + i * step;
this._renderToggle(ctx, cx, cy, row);
}
// Profile entry button (below the last toggle row)
const profileY = firstCenterY + rows.length * step;
this._renderProfileButton(ctx, cx, profileY);
// Back button
this._renderBackButton(ctx, cx, backCenterY);
},
_renderToggle(ctx, cx, y, toggle) {
const w = SCREEN_WIDTH * 0.7;
const h = 50;
const x = cx - w / 2;
const isOn = this._settings[toggle.key];
// Store button rect
this._buttons[toggle.key] = { x, y: y - h / 2, w, h };
// Background
ctx.fillStyle = '#1e1e3a';
ctx.fillRect(x, y - h / 2, w, h);
ctx.strokeStyle = '#333366';
ctx.lineWidth = 1;
ctx.strokeRect(x, y - h / 2, w, h);
// Icon and label
ctx.fillStyle = COLORS.HUD_TEXT;
ctx.font = '16px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(`${toggle.icon} ${toggle.label}`, x + 15, y);
// Toggle switch
const switchW = 50;
const switchH = 26;
const switchX = x + w - switchW - 15;
const switchY = y - switchH / 2;
// Switch track
ctx.fillStyle = isOn ? '#4CAF50' : '#555555';
ctx.beginPath();
ctx.arc(switchX + switchH / 2, y, switchH / 2, Math.PI / 2, Math.PI * 3 / 2);
ctx.arc(switchX + switchW - switchH / 2, y, switchH / 2, -Math.PI / 2, Math.PI / 2);
ctx.closePath();
ctx.fill();
// Switch knob
ctx.fillStyle = '#FFFFFF';
ctx.beginPath();
const knobX = isOn ? switchX + switchW - switchH / 2 : switchX + switchH / 2;
ctx.arc(knobX, y, switchH / 2 - 3, 0, Math.PI * 2);
ctx.fill();
},
_renderProfileButton(ctx, cx, y) {
const w = SCREEN_WIDTH * 0.7;
const h = 50;
const x = cx - w / 2;
this._buttons['profile'] = { x, y: y - h / 2, w, h };
// Background
ctx.fillStyle = '#1e1e3a';
ctx.fillRect(x, y - h / 2, w, h);
ctx.strokeStyle = '#333366';
ctx.lineWidth = 1;
ctx.strokeRect(x, y - h / 2, w, h);
// Icon and label
ctx.fillStyle = COLORS.HUD_TEXT;
ctx.font = '16px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(`👤 ${t('settings.profile')}`, x + 15, y);
// Arrow indicator
ctx.fillStyle = '#888888';
ctx.font = '14px Arial';
ctx.textAlign = 'right';
ctx.fillText('', x + w - 15, y);
},
_renderBackButton(ctx, cx, y) {
const w = SCREEN_WIDTH * 0.4;
const h = 42;
const x = cx - w / 2;
this._buttons['back'] = { x, y: y - h / 2, w, h };
ctx.fillStyle = COLORS.MENU_BTN;
ctx.strokeStyle = COLORS.MENU_BTN_BORDER;
ctx.lineWidth = 2;
ctx.fillRect(x, y - h / 2, w, h);
ctx.strokeRect(x, y - h / 2, w, h);
ctx.fillStyle = COLORS.MENU_BTN_TEXT;
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(t('common.back'), cx, y);
},
handleTouch(eventType, e) {
if (eventType !== 'touchstart') return;
const touch = e.touches[0];
const tx = touch.clientX;
const ty = touch.clientY;
for (const [key, rect] of Object.entries(this._buttons)) {
if (tx >= rect.x && tx <= rect.x + rect.w && ty >= rect.y && ty <= rect.y + rect.h) {
if (key === 'back') {
GameGlobal.sceneManager.switchTo(SCENE.MENU);
} else if (key === 'profile') {
const sm = GameGlobal.sceneManager;
if (!sm._scenes.has(SCENE.PROFILE)) {
const ProfileScene = require('./ProfileScene');
sm.register(SCENE.PROFILE, ProfileScene);
}
sm.switchTo(SCENE.PROFILE);
} else if (this._settings.hasOwnProperty(key)) {
this._settings[key] = !this._settings[key];
// Notify audio system
GameGlobal.eventBus.emit('settings:changed', this._settings);
}
break;
}
}
},
};
module.exports = SettingsScene;