mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-29 20:41:29 +08:00
feat(SS) 添加地图
This commit is contained in:
1 parent
2616dc21f1
commit
d3669bd44e
13 files changed
+1358
-98
No files matched your search
@@ -0,0 +1,196 @@
|
|||||||
|
# InputPlugin 架构设计说明
|
||||||
|
|
||||||
|
## 问题分析
|
||||||
|
|
||||||
|
### 原始设计的问题
|
||||||
|
1. **紧耦合**:直接依赖 Phaser 的 Key 对象和事件系统
|
||||||
|
2. **无法跨引擎**:切换引擎需要重写整个插件
|
||||||
|
3. **违反开闭原则**:修改输入方式需要修改插件内部代码
|
||||||
|
4. **测试困难**:难以进行单元测试(依赖具体引擎)
|
||||||
|
|
||||||
|
## 解决方案:适配器模式
|
||||||
|
|
||||||
|
### 架构层次
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ 业务逻辑层 (GameScene) │
|
||||||
|
│ - 不关心底层实现 │
|
||||||
|
│ - 只调用统一接口 │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ InputPlugin (核心插件) │
|
||||||
|
│ - 提供统一接口 │
|
||||||
|
│ - 管理适配器生命周期 │
|
||||||
|
│ - registerKey(), isDown(), isUp() │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ IInputAdapter (接口定义) │
|
||||||
|
│ - 定义适配器必须实现的方法 │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ 具体适配器实现 │
|
||||||
|
│ - PhaserInputAdapter │
|
||||||
|
│ - PixiInputAdapter │
|
||||||
|
│ - CocosInputAdapter │
|
||||||
|
│ - GodotInputAdapter (可扩展) │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 核心优势
|
||||||
|
|
||||||
|
#### 1. **跨引擎复用**
|
||||||
|
```javascript
|
||||||
|
// Phaser 中使用
|
||||||
|
const phaserPlugin = new InputPlugin(scene);
|
||||||
|
phaserPlugin.registerKey('W', ['ArrowUp']);
|
||||||
|
if (phaserPlugin.isDown('W')) { /* 移动 */ }
|
||||||
|
|
||||||
|
// PixiJS 中使用(代码完全相同)
|
||||||
|
const pixiPlugin = new PixiInputPlugin(app);
|
||||||
|
pixiPlugin.registerKey('W', ['ArrowUp']);
|
||||||
|
if (pixiPlugin.isDown('W')) { /* 移动 */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. **易于扩展**
|
||||||
|
添加新引擎支持只需实现适配器接口:
|
||||||
|
```javascript
|
||||||
|
class GodotInputAdapter extends IInputAdapter {
|
||||||
|
initialize() { /* Godot 特定实现 */ }
|
||||||
|
registerKey(key, aliases) { /* ... */ }
|
||||||
|
isDown(key) { /* ... */ }
|
||||||
|
isUp(key) { /* ... */ }
|
||||||
|
destroy() { /* ... */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. **易于测试**
|
||||||
|
```javascript
|
||||||
|
class MockInputAdapter extends IInputAdapter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.mockKeys = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {}
|
||||||
|
|
||||||
|
registerKey(key, aliases) {
|
||||||
|
this.mockKeys.set(key, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
isDown(key) {
|
||||||
|
return this.mockKeys.get(key) || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isUp(key) {
|
||||||
|
return !this.isDown(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {}
|
||||||
|
|
||||||
|
// 测试辅助方法
|
||||||
|
setKeyDown(key) {
|
||||||
|
this.mockKeys.set(key, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setKeyUp(key) {
|
||||||
|
this.mockKeys.set(key, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单元测试示例
|
||||||
|
const mockAdapter = new MockInputAdapter();
|
||||||
|
const plugin = new InputPlugin(null, null);
|
||||||
|
plugin.inputAdapter = mockAdapter;
|
||||||
|
|
||||||
|
plugin.registerKey('W');
|
||||||
|
mockAdapter.setKeyDown('W');
|
||||||
|
assert(plugin.isDown('W') === true);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. **符合设计原则**
|
||||||
|
- **单一职责原则**:每个适配器只负责一个引擎的输入处理
|
||||||
|
- **开闭原则**:对扩展开放,对修改关闭
|
||||||
|
- **依赖倒置原则**:依赖抽象接口,不依赖具体实现
|
||||||
|
- **里氏替换原则**:所有适配器可以互相替换
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### Phaser 项目
|
||||||
|
```javascript
|
||||||
|
// main.js
|
||||||
|
import { InputPlugin } from './plugins/InputPlugin.js';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
scene: [GameScene],
|
||||||
|
plugins: {
|
||||||
|
scene: [
|
||||||
|
{
|
||||||
|
key: 'InputPlugin',
|
||||||
|
plugin: InputPlugin,
|
||||||
|
mapping: 'inputPlugin'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// GameScene.js
|
||||||
|
create() {
|
||||||
|
// 注册按键
|
||||||
|
this.inputPlugin.registerKey('W', ['ArrowUp']);
|
||||||
|
this.inputPlugin.registerKey('S', ['ArrowDown']);
|
||||||
|
this.inputPlugin.registerKey('A', ['ArrowLeft']);
|
||||||
|
this.inputPlugin.registerKey('D', ['ArrowRight']);
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
// 使用统一接口
|
||||||
|
if (this.inputPlugin.isDown('W')) {
|
||||||
|
this.player.setVelocityY(-200);
|
||||||
|
}
|
||||||
|
if (this.inputPlugin.isDown('S')) {
|
||||||
|
this.player.setVelocityY(200);
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PixiJS 项目
|
||||||
|
```javascript
|
||||||
|
// main.js
|
||||||
|
import { PixiInputPlugin } from './plugins/PixiInputPlugin.js';
|
||||||
|
|
||||||
|
const app = new PIXI.Application({ width: 800, height: 600 });
|
||||||
|
const inputPlugin = new PixiInputPlugin(app);
|
||||||
|
|
||||||
|
inputPlugin.registerKey('W', ['ArrowUp']);
|
||||||
|
inputPlugin.registerKey('S', ['ArrowDown']);
|
||||||
|
|
||||||
|
// 游戏循环
|
||||||
|
app.ticker.add(() => {
|
||||||
|
if (inputPlugin.isDown('W')) {
|
||||||
|
player.y -= 2;
|
||||||
|
}
|
||||||
|
if (inputPlugin.isDown('S')) {
|
||||||
|
player.y += 2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
**适配器模式的优势:**
|
||||||
|
- ✅ 解耦:业务逻辑与具体引擎实现分离
|
||||||
|
- ✅ 复用:同一套业务逻辑可在不同引擎中使用
|
||||||
|
- ✅ 扩展:添加新引擎支持无需修改现有代码
|
||||||
|
- ✅ 测试:可以轻松创建 Mock 对象进行单元测试
|
||||||
|
- ✅ 维护:每个适配器独立维护,降低复杂度
|
||||||
|
|
||||||
|
**何时使用适配器模式:**
|
||||||
|
- 需要集成第三方库或框架
|
||||||
|
- 需要支持多种实现方式
|
||||||
|
- 需要在不修改现有代码的情况下扩展功能
|
||||||
|
- 需要提高代码的可测试性
|
||||||
@@ -5,17 +5,34 @@
|
|||||||
* 当创建的角色超过3个时,点击已存在的角色会为其设置纹理
|
* 当创建的角色超过3个时,点击已存在的角色会为其设置纹理
|
||||||
* 当设置纹理的角色超过3个时,自动切换到 MenuScene 场景
|
* 当设置纹理的角色超过3个时,自动切换到 MenuScene 场景
|
||||||
*/
|
*/
|
||||||
export default class BreatheLife extends Phaser.Scene {
|
import WorldLand from './WorldLand.js'
|
||||||
|
export default class BreatheLife extends WorldLand {
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
* 初始化场景并设置场景键名为 'BreatheLife'
|
* 初始化场景并设置场景键名
|
||||||
|
* @param {string} sceneKey - 场景键名,默认值为 'BreatheLife'
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor(sceneKey = 'BreatheLife') {
|
||||||
super('BreatheLife')
|
super(sceneKey)
|
||||||
this.nextScene = 'MenuScene'
|
this.nextScene = 'MenuScene'
|
||||||
|
|
||||||
|
this.UIDepth = 100 // UI层级深度,确保在其他元素之上
|
||||||
|
this.maskDepth = 99 // 黑夜遮罩层级,低于UI层级
|
||||||
|
this.SpriteDepth = 98 // 角色层级,确保在地图层级之上
|
||||||
|
this.mapDepth = 97 // 地图层级,确保在UI层级之下
|
||||||
|
|
||||||
|
|
||||||
|
this.tileCount = 234 // 瓦片总数,从tile_0000到tile_0233
|
||||||
|
this.tileSize = 16 // 瓦片大小
|
||||||
|
this.mapWidth = 18; // 瓦片图行数
|
||||||
|
this.mapHeight = 13; // 瓦片图列数
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
|
// 加载草地瓦片图
|
||||||
|
this.load.image(`grass`, `assets/PNG/Tiles/Tiles/tile_0024.png`)
|
||||||
|
this.load.image(`smallGrass`, `assets/PNG/Tiles/Tiles/tile_0044.png`)
|
||||||
|
|
||||||
// 加载角色动画和图片资源
|
// 加载角色动画和图片资源
|
||||||
this.load.image(`player0-0`, `assets/PNG/Players/Tiles/tile_${String(0).padStart(4, '0')}.png`)
|
this.load.image(`player0-0`, `assets/PNG/Players/Tiles/tile_${String(0).padStart(4, '0')}.png`)
|
||||||
this.load.image(`player1-0`, `assets/PNG/Players/Tiles/tile_${String(8).padStart(4, '0')}.png`)
|
this.load.image(`player1-0`, `assets/PNG/Players/Tiles/tile_${String(8).padStart(4, '0')}.png`)
|
||||||
@@ -47,6 +64,10 @@ export default class BreatheLife extends Phaser.Scene {
|
|||||||
this.spriteAnimCount = 0
|
this.spriteAnimCount = 0
|
||||||
this.targetCount = 3 // 目标角色数量
|
this.targetCount = 3 // 目标角色数量
|
||||||
|
|
||||||
|
this.createTilemap() // 创建瓦片地图
|
||||||
|
this.initFrameRateText() // 初始化帧率显示文本
|
||||||
|
this.initDayNight(this.toGameTime('2000-01-01 12:00:00')) // 初始化时间,白天黑夜状态
|
||||||
|
|
||||||
// 监听鼠标点击事件,点击后创建一个新的角色
|
// 监听鼠标点击事件,点击后创建一个新的角色
|
||||||
this.input.on('pointerdown', () => {
|
this.input.on('pointerdown', () => {
|
||||||
// 获取点击位置的坐标
|
// 获取点击位置的坐标
|
||||||
@@ -84,6 +105,7 @@ export default class BreatheLife extends Phaser.Scene {
|
|||||||
}else if (this.spriteCount < 3) {
|
}else if (this.spriteCount < 3) {
|
||||||
// 创建一个新的角色 sprite,缩放为1倍,并设置原点为中心底部
|
// 创建一个新的角色 sprite,缩放为1倍,并设置原点为中心底部
|
||||||
const sprite = this.physics.add.sprite(x, y, 'player').setScale(1).setOrigin(0.5, 1)
|
const sprite = this.physics.add.sprite(x, y, 'player').setScale(1).setOrigin(0.5, 1)
|
||||||
|
sprite.setDepth(this.SpriteDepth) // 设置角色层级
|
||||||
|
|
||||||
// 设置角色碰撞世界边界
|
// 设置角色碰撞世界边界
|
||||||
sprite.setCollideWorldBounds(true)
|
sprite.setCollideWorldBounds(true)
|
||||||
|
|||||||
@@ -4,44 +4,71 @@
|
|||||||
* 初始引导场景,显示空白背景并在用户交互或自动延迟后
|
* 初始引导场景,显示空白背景并在用户交互或自动延迟后
|
||||||
* 执行过渡动画切换到下一个场景
|
* 执行过渡动画切换到下一个场景
|
||||||
*/
|
*/
|
||||||
import GameTimeManager from '../../systems/GameTimeManager.js'
|
import WorldTime from './WorldTime.js'
|
||||||
|
|
||||||
export default class WorldLand extends Phaser.Scene {
|
export default class WorldLand extends WorldTime {
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
* 初始化场景并设置场景键名为 'WorldLand'
|
* 初始化场景并设置场景键名
|
||||||
|
* @param {string} sceneKey - 场景键名
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor(sceneKey = 'WorldLand') {
|
||||||
super('WorldLand')
|
super(sceneKey)
|
||||||
this.nextScene = 'BreatheLife'
|
this.nextScene = 'BreatheLife'
|
||||||
|
|
||||||
this.timeManager = new GameTimeManager() // 创建游戏时间管理器实例
|
|
||||||
|
|
||||||
this.UIDepth = 100 // UI层级深度,确保在其他元素之上
|
this.UIDepth = 100 // UI层级深度,确保在其他元素之上
|
||||||
this.maskDepth = 99 // 黑夜遮罩层级,低于UI层级
|
this.maskDepth = 99 // 黑夜遮罩层级,低于UI层级
|
||||||
|
this.mapDepth = 98 // 地图层级,确保在UI层级之下
|
||||||
|
|
||||||
|
this.tileCount = 234 // 瓦片总数,从tile_0000到tile_0233
|
||||||
|
this.tileSize = 16 // 瓦片大小
|
||||||
|
this.mapWidth = 18; // 瓦片图行数
|
||||||
|
this.mapHeight = 13; // 瓦片图列数
|
||||||
|
}
|
||||||
|
preload() {
|
||||||
|
// 加载草地瓦片图
|
||||||
|
this.load.image(`grass`, `assets/PNG/Tiles/Tiles/tile_0024.png`)
|
||||||
|
this.load.image(`smallGrass`, `assets/PNG/Tiles/Tiles/tile_0044.png`)
|
||||||
}
|
}
|
||||||
create() {
|
create() {
|
||||||
// 设置场景背景颜色为深灰色
|
// 设置场景背景颜色为深灰色
|
||||||
this.cameras.main.setBackgroundColor('#999999')
|
this.cameras.main.setBackgroundColor('#999999')
|
||||||
|
// 初始化计数器,用于跟踪创建的小草数量
|
||||||
|
this.smallGrassCount = 0
|
||||||
|
|
||||||
// 监听鼠标点击事件,点击后执行场景过渡动画
|
this.initInput() // 初始化输入事件
|
||||||
this.input.on('pointerdown', () => {
|
this.initDayNight(this.toGameTime('2000-01-01 17:57:00')) // 初始化时间,白天黑夜状态
|
||||||
this.scene.start(this.nextScene);
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听键盘按键事件,按键后执行场景过渡动画
|
this.createTilemap() // 创建瓦片地图
|
||||||
this.input.keyboard.on('keydown', () => {
|
|
||||||
this.scene.start(this.nextScene);
|
|
||||||
})
|
|
||||||
|
|
||||||
this.initDayNight(this.toGameTime('1999-12-30 23:57:00')) // 初始化时间,白天黑夜状态
|
|
||||||
this.initFrameRateText() // 初始化帧率显示文本
|
this.initFrameRateText() // 初始化帧率显示文本
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 更新游戏时间
|
createTilemap() {
|
||||||
* 每帧调用,刷新游戏时间
|
// 获取当前屏幕大小
|
||||||
*/
|
const screenWidth = this.cameras.main.width;
|
||||||
|
const screenHeight = this.cameras.main.height;
|
||||||
|
|
||||||
|
// 计算需要的瓦片数量
|
||||||
|
const tilesX = Math.ceil(screenWidth / this.tileSize);
|
||||||
|
const tilesY = Math.ceil(screenHeight / this.tileSize);
|
||||||
|
|
||||||
|
// 草地铺满屏幕
|
||||||
|
for (let y = 0; y < tilesY; y++) {
|
||||||
|
for (let x = 0; x < tilesX; x++) {
|
||||||
|
// 使用草地瓦片
|
||||||
|
const tile = this.add.image(
|
||||||
|
x * this.tileSize + this.tileSize / 2,
|
||||||
|
y * this.tileSize + this.tileSize / 2,
|
||||||
|
'grass'
|
||||||
|
);
|
||||||
|
tile.setDepth(this.mapDepth); // 设置深度,确保在UI层级之下
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`草地铺满屏幕完成,使用了 ${tilesX}x${tilesY} 个瓦片`)
|
||||||
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
this.showFrameRate() // 显示当前帧率
|
this.showFrameRate() // 显示当前帧率
|
||||||
this.updateGameTime() // 更新游戏时间
|
this.updateGameTime() // 更新游戏时间
|
||||||
@@ -49,7 +76,31 @@ export default class WorldLand extends Phaser.Scene {
|
|||||||
this.updateDayNight() // 更新昼夜状态
|
this.updateDayNight() // 更新昼夜状态
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initInput() {
|
||||||
|
// 监听鼠标点击事件,点击后创建一个新的小草
|
||||||
|
this.input.on('pointerdown', () => {
|
||||||
|
// 获取点击位置的坐标
|
||||||
|
const { x, y } = this.input.activePointer
|
||||||
|
this.createTile(x, y)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听键盘按键事件,按键后执行场景过渡动画
|
||||||
|
this.input.keyboard.on('keydown', () => {
|
||||||
|
this.scene.start(this.nextScene);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
createTile(x, y) {
|
||||||
|
if (this.smallGrassCount >= 10) {
|
||||||
|
this.scene.start(this.nextScene);
|
||||||
|
}
|
||||||
|
// 创建瓦片图实例
|
||||||
|
const tile = this.add.image(x, y, 'smallGrass');
|
||||||
|
tile.setDepth(this.mapDepth); // 设置深度,确保在UI层级之下
|
||||||
|
tile.setScrollFactor(0); // 固定瓦片,不随相机移动
|
||||||
|
// 增加小草计数器
|
||||||
|
this.smallGrassCount++;
|
||||||
|
}
|
||||||
initFrameRateText() {
|
initFrameRateText() {
|
||||||
// 创建帧率显示文本
|
// 创建帧率显示文本
|
||||||
this.frameRateText = this.add.text(
|
this.frameRateText = this.add.text(
|
||||||
@@ -61,74 +112,7 @@ export default class WorldLand extends Phaser.Scene {
|
|||||||
).setScrollFactor(0).setDepth(this.UIDepth) // 固定文本,不随相机移动,UI层级
|
).setScrollFactor(0).setDepth(this.UIDepth) // 固定文本,不随相机移动,UI层级
|
||||||
}
|
}
|
||||||
showFrameRate() {
|
showFrameRate() {
|
||||||
// 获取当前帧率
|
const frameRate = this.game.loop.actualFps // 获取当前帧率
|
||||||
const frameRate = this.game.loop.actualFps
|
this.frameRateText.setText(`Frame Rate: ${frameRate.toFixed(2)}`) // 更新帧率显示文本
|
||||||
// 更新帧率显示文本
|
|
||||||
this.frameRateText.setText(`Frame Rate: ${frameRate.toFixed(2)}`)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 初始化昼夜状态
|
|
||||||
* 设置初始为白天,添加事件监听切换状态
|
|
||||||
*/
|
|
||||||
initDayNight(gameTime) {
|
|
||||||
this.timeManager.init(gameTime) // 初始化时间管理器
|
|
||||||
// 创建时间显示文本
|
|
||||||
this.timeText = this.add.text(
|
|
||||||
20, 20, '', {
|
|
||||||
fontSize: '20px',
|
|
||||||
fill: '#ffffff',
|
|
||||||
fontFamily: 'Arial'
|
|
||||||
}
|
|
||||||
).setScrollFactor(0).setDepth(this.UIDepth) // 固定文本,不随相机移动,UI层级
|
|
||||||
// 添加黑夜遮罩
|
|
||||||
this.nightMask = this.add.rectangle(
|
|
||||||
0, 0,
|
|
||||||
this.cameras.main.width,
|
|
||||||
this.cameras.main.height,
|
|
||||||
0x000000
|
|
||||||
).setOrigin(0, 0).setScrollFactor(0).setDepth(this.maskDepth) // 固定遮罩,不随相机移动,遮罩层级
|
|
||||||
this.nightMask.alpha = 0 // 初始设置为透明
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 更新游戏时间
|
|
||||||
* 每帧调用,基于现实时间流逝更新游戏时间
|
|
||||||
*/
|
|
||||||
updateGameTime() {
|
|
||||||
this.timeManager.updateGameTime() // 使用时间管理器更新游戏时间
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获取游戏中的日期
|
|
||||||
* 根据游戏时间戳计算游戏年月日时分秒,格式为YYYY-MM-DD HH:mm:ss
|
|
||||||
*/
|
|
||||||
getGameDate() {
|
|
||||||
return this.timeManager.getGameDate() // 使用时间管理器获取游戏日期
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 转换游戏时间字符串为游戏时间戳
|
|
||||||
* 接收时间字符串,格式为YYYY-MM-DD HH:mm:ss,返回游戏时间戳(单位:秒)
|
|
||||||
*/
|
|
||||||
toGameTime(gameTimeString) {
|
|
||||||
return this.timeManager.toGameTime(gameTimeString) // 使用时间管理器转换游戏时间
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 显示当前时间
|
|
||||||
* 每帧调用,更新显示时间
|
|
||||||
*/
|
|
||||||
displayTime() {
|
|
||||||
const timeString = this.getGameDate().dateString
|
|
||||||
const day = this.timeManager.getDayNightState() ? '白天' : '黑夜'
|
|
||||||
// 更新显示时间
|
|
||||||
this.timeText.setText(`${day} ${timeString}`)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 更新昼夜状态
|
|
||||||
* 每帧调用,根据游戏时间切换白天黑夜状态
|
|
||||||
*/
|
|
||||||
updateDayNight() {
|
|
||||||
const isDay = this.timeManager.updateDayNight()
|
|
||||||
// 根据昼夜状态更新遮罩
|
|
||||||
if (this.nightMask) {
|
|
||||||
this.nightMask.alpha = isDay ? 0 : 0.5
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,11 @@
|
|||||||
export default class WorldTime extends Phaser.Scene {
|
export default class WorldTime extends Phaser.Scene {
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
* 初始化场景并设置场景键名为 'WorldTime'
|
* 初始化场景并设置场景键名
|
||||||
|
* @param {string} sceneKey - 场景键名
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor(sceneKey = 'WorldTime') {
|
||||||
super('WorldTime')
|
super(sceneKey)
|
||||||
this.nextScene = 'WorldLand'
|
this.nextScene = 'WorldLand'
|
||||||
|
|
||||||
this.gameTime = 0 // 游戏中的时间戳(单位:秒)
|
this.gameTime = 0 // 游戏中的时间戳(单位:秒)
|
||||||
@@ -34,6 +35,15 @@ export default class WorldTime extends Phaser.Scene {
|
|||||||
// 设置场景背景颜色为深灰色
|
// 设置场景背景颜色为深灰色
|
||||||
this.cameras.main.setBackgroundColor('#999999')
|
this.cameras.main.setBackgroundColor('#999999')
|
||||||
|
|
||||||
|
this.initInput() // 初始化输入事件
|
||||||
|
|
||||||
|
this.initDayNight(this.toGameTime('1999-12-30 23:57:00')) // 初始化时间,白天黑夜状态
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 初始化输入事件
|
||||||
|
* 监听鼠标点击和键盘按键,触发场景过渡
|
||||||
|
*/
|
||||||
|
initInput() {
|
||||||
// 监听鼠标点击事件,点击后执行场景过渡动画
|
// 监听鼠标点击事件,点击后执行场景过渡动画
|
||||||
this.input.on('pointerdown', () => {
|
this.input.on('pointerdown', () => {
|
||||||
this.scene.start(this.nextScene);
|
this.scene.start(this.nextScene);
|
||||||
@@ -43,8 +53,6 @@ export default class WorldTime extends Phaser.Scene {
|
|||||||
this.input.keyboard.on('keydown', () => {
|
this.input.keyboard.on('keydown', () => {
|
||||||
this.scene.start(this.nextScene);
|
this.scene.start(this.nextScene);
|
||||||
})
|
})
|
||||||
|
|
||||||
this.initDayNight(this.toGameTime('2000-01-01 17:57:00')) // 初始化时间,白天黑夜状态
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 更新游戏时间
|
* 更新游戏时间
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
<title>Phaser</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #000;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
display: block;
|
||||||
|
max-width: 100vw;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="../phaser.min.js"></script>
|
||||||
|
<script type="module" src="main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
// main.js
|
||||||
|
|
||||||
|
import { GameScene } from './scenes/GameScene.js';
|
||||||
|
import { JoystickTestScene } from './scenes/JoystickTestScene.js';
|
||||||
|
import { InputPlugin } from './plugins/InputPlugin.js';
|
||||||
|
|
||||||
|
console.log('InputPlugin 导入:', InputPlugin);
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
type: Phaser.AUTO,
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
backgroundColor: '#000000',
|
||||||
|
physics: {
|
||||||
|
default: 'arcade',
|
||||||
|
arcade: {
|
||||||
|
debug: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scene: [JoystickTestScene, GameScene],
|
||||||
|
plugins: {
|
||||||
|
scene: [
|
||||||
|
{
|
||||||
|
key: 'InputPlugin',
|
||||||
|
plugin: InputPlugin,
|
||||||
|
mapping: 'inputPlugin'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 添加缩放配置,解决拉伸问题
|
||||||
|
scale: {
|
||||||
|
mode: Phaser.Scale.FIT,
|
||||||
|
autoCenter: Phaser.Scale.CENTER_BOTH,
|
||||||
|
min: {
|
||||||
|
width: 400,
|
||||||
|
height: 300
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
width: 1600,
|
||||||
|
height: 1200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('游戏配置:', config);
|
||||||
|
window.game = new Phaser.Game(config);
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
// plugins/InputPlugin.js
|
||||||
|
|
||||||
|
import { InputSystem } from './core/InputSystem.js';
|
||||||
|
import { PhaserInputAdapter } from './adapters/PhaserInputAdapter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InputPlugin 场景插件
|
||||||
|
* 作为 Phaser 场景插件的包装器,使用适配器架构
|
||||||
|
*/
|
||||||
|
export class InputPlugin extends Phaser.Plugins.ScenePlugin {
|
||||||
|
constructor(scene, pluginManager) {
|
||||||
|
super(scene, pluginManager);
|
||||||
|
console.log('InputPlugin 场景插件初始化');
|
||||||
|
|
||||||
|
// 创建 Phaser 适配器
|
||||||
|
this.adapter = new PhaserInputAdapter(scene);
|
||||||
|
|
||||||
|
// 创建核心输入系统
|
||||||
|
this.inputSystem = new InputSystem(this.adapter);
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
this.inputSystem.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动插件
|
||||||
|
*/
|
||||||
|
boot() {
|
||||||
|
console.log('InputPlugin 场景插件启动');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试方法
|
||||||
|
* @returns {string} 测试结果
|
||||||
|
*/
|
||||||
|
testMethod() {
|
||||||
|
return 'InputPlugin 测试方法';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建触摸轮盘
|
||||||
|
* @param {Object} config 轮盘配置
|
||||||
|
* @returns {string} 轮盘ID
|
||||||
|
*/
|
||||||
|
createJoystick(config) {
|
||||||
|
return this.inputSystem.createJoystick(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建屏幕按钮
|
||||||
|
* @param {Object} config 按钮配置
|
||||||
|
* @returns {string} 按钮ID
|
||||||
|
*/
|
||||||
|
createButton(config) {
|
||||||
|
return this.inputSystem.createButton(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘方向向量
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 方向向量 {x, y}
|
||||||
|
*/
|
||||||
|
getJoystickDirection(joystickId) {
|
||||||
|
return this.inputSystem.getJoystickDirection(joystickId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘力度
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {number} 力度值 (0-1)
|
||||||
|
*/
|
||||||
|
getJoystickMagnitude(joystickId) {
|
||||||
|
return this.inputSystem.getJoystickMagnitude(joystickId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取归一化的轮盘方向
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 归一化向量 {x, y} (-1 到 1)
|
||||||
|
*/
|
||||||
|
getJoystickNormalized(joystickId) {
|
||||||
|
return this.inputSystem.getJoystickNormalized(joystickId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否按下
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否按下
|
||||||
|
*/
|
||||||
|
isButtonDown(buttonId) {
|
||||||
|
return this.inputSystem.isButtonDown(buttonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否释放
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否释放
|
||||||
|
*/
|
||||||
|
isButtonUp(buttonId) {
|
||||||
|
return this.inputSystem.isButtonUp(buttonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁插件
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
console.log('InputPlugin 场景插件销毁');
|
||||||
|
if (this.inputSystem) {
|
||||||
|
this.inputSystem.destroy();
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
// plugins/adapters/CocosInputAdapter.js
|
||||||
|
|
||||||
|
export class CocosInputAdapter {
|
||||||
|
constructor(director) {
|
||||||
|
this.director = director;
|
||||||
|
this.keyMap = new Map();
|
||||||
|
this.isInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
if (this.isInitialized) return;
|
||||||
|
|
||||||
|
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, (event) => {
|
||||||
|
this.handleKeyDown(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, (event) => {
|
||||||
|
this.handleKeyUp(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.isInitialized = true;
|
||||||
|
console.log('CocosInputAdapter 已初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown(event) {
|
||||||
|
const keyCode = event.keyCode;
|
||||||
|
this.keyState.set(keyCode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyUp(event) {
|
||||||
|
const keyCode = event.keyCode;
|
||||||
|
this.keyState.set(keyCode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerKey(key, aliases = []) {
|
||||||
|
const keyCode = this.getKeyCode(key);
|
||||||
|
this.keyMap.set(key, keyCode);
|
||||||
|
|
||||||
|
aliases.forEach(alias => {
|
||||||
|
const aliasKeyCode = this.getKeyCode(alias);
|
||||||
|
this.keyMap.set(alias, keyCode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getKeyCode(key) {
|
||||||
|
const keyMap = {
|
||||||
|
'W': cc.macro.KEY.w,
|
||||||
|
'A': cc.macro.KEY.a,
|
||||||
|
'S': cc.macro.KEY.s,
|
||||||
|
'D': cc.macro.KEY.d,
|
||||||
|
'UP': cc.macro.KEY.up,
|
||||||
|
'DOWN': cc.macro.KEY.down,
|
||||||
|
'LEFT': cc.macro.KEY.left,
|
||||||
|
'RIGHT': cc.macro.KEY.right
|
||||||
|
};
|
||||||
|
return keyMap[key] || key;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDown(key) {
|
||||||
|
const keyCode = this.keyMap.get(key);
|
||||||
|
return this.keyState.get(keyCode) || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isUp(key) {
|
||||||
|
return !this.isDown(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN);
|
||||||
|
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP);
|
||||||
|
this.keyMap.clear();
|
||||||
|
this.keyState.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
// plugins/adapters/IInputAdapter.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入适配器接口
|
||||||
|
* 所有引擎适配器必须实现这些方法
|
||||||
|
*/
|
||||||
|
export class IInputAdapter {
|
||||||
|
constructor() {
|
||||||
|
if (this.constructor === IInputAdapter) {
|
||||||
|
throw new Error('IInputAdapter 是抽象类,不能直接实例化');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化适配器
|
||||||
|
*/
|
||||||
|
initialize() {
|
||||||
|
throw new Error('initialize() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建触摸轮盘
|
||||||
|
* @param {Object} config 轮盘配置
|
||||||
|
* @returns {Object} 轮盘实例
|
||||||
|
*/
|
||||||
|
createJoystick(config) {
|
||||||
|
throw new Error('createJoystick() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建屏幕按钮
|
||||||
|
* @param {Object} config 按钮配置
|
||||||
|
* @returns {Object} 按钮实例
|
||||||
|
*/
|
||||||
|
createButton(config) {
|
||||||
|
throw new Error('createButton() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘方向向量
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 方向向量 {x, y}
|
||||||
|
*/
|
||||||
|
getJoystickDirection(joystickId) {
|
||||||
|
throw new Error('getJoystickDirection() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘力度
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {number} 力度值 (0-1)
|
||||||
|
*/
|
||||||
|
getJoystickMagnitude(joystickId) {
|
||||||
|
throw new Error('getJoystickMagnitude() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取归一化的轮盘方向
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 归一化向量 {x, y} (-1 到 1)
|
||||||
|
*/
|
||||||
|
getJoystickNormalized(joystickId) {
|
||||||
|
throw new Error('getJoystickNormalized() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否按下
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否按下
|
||||||
|
*/
|
||||||
|
isButtonDown(buttonId) {
|
||||||
|
throw new Error('isButtonDown() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否释放
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否释放
|
||||||
|
*/
|
||||||
|
isButtonUp(buttonId) {
|
||||||
|
throw new Error('isButtonUp() 必须由子类实现');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁适配器
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
throw new Error('destroy() 必须由子类实现');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
// plugins/adapters/PhaserInputAdapter.js
|
||||||
|
|
||||||
|
import { IInputAdapter } from './IInputAdapter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Phaser 输入适配器
|
||||||
|
* 实现 IInputAdapter 接口,使用 Phaser API
|
||||||
|
*/
|
||||||
|
export class PhaserInputAdapter extends IInputAdapter {
|
||||||
|
constructor(scene) {
|
||||||
|
super();
|
||||||
|
this.scene = scene;
|
||||||
|
this.joysticks = new Map();
|
||||||
|
this.buttons = new Map();
|
||||||
|
console.log('PhaserInputAdapter 初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化适配器
|
||||||
|
*/
|
||||||
|
initialize() {
|
||||||
|
if (!this.scene.input) {
|
||||||
|
console.warn('Phaser 输入系统不可用');
|
||||||
|
}
|
||||||
|
console.log('PhaserInputAdapter 已初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建触摸轮盘
|
||||||
|
* @param {Object} config 轮盘配置
|
||||||
|
* @returns {Object} 轮盘实例
|
||||||
|
*/
|
||||||
|
createJoystick(config) {
|
||||||
|
try {
|
||||||
|
const joystick = {
|
||||||
|
id: config.id,
|
||||||
|
base: null,
|
||||||
|
thumb: null,
|
||||||
|
isActive: false,
|
||||||
|
startX: config.x || 100,
|
||||||
|
startY: config.y || this.scene.sys.game.config.height - 100,
|
||||||
|
radius: config.radius || 60,
|
||||||
|
maxDistance: config.maxDistance || 40,
|
||||||
|
currentX: 0,
|
||||||
|
currentY: 0,
|
||||||
|
normalizedX: 0,
|
||||||
|
normalizedY: 0,
|
||||||
|
magnitude: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建轮盘底座
|
||||||
|
joystick.base = this.scene.add.circle(joystick.startX, joystick.startY, joystick.radius, 0x444444, 0.5);
|
||||||
|
joystick.base.setScrollFactor(0);
|
||||||
|
|
||||||
|
// 创建轮盘拇指
|
||||||
|
joystick.thumb = this.scene.add.circle(joystick.startX, joystick.startY, joystick.radius * 0.5, 0x888888, 0.8);
|
||||||
|
joystick.thumb.setScrollFactor(0);
|
||||||
|
|
||||||
|
// 监听触摸事件
|
||||||
|
const self = this;
|
||||||
|
this.scene.input.on('pointerdown', function(pointer) {
|
||||||
|
if (self.calculateDistance(pointer.x, pointer.y, joystick.startX, joystick.startY) < joystick.radius) {
|
||||||
|
joystick.isActive = true;
|
||||||
|
joystick.thumb.setPosition(pointer.x, pointer.y);
|
||||||
|
self.updateJoystick(joystick, pointer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scene.input.on('pointermove', function(pointer) {
|
||||||
|
if (joystick.isActive) {
|
||||||
|
self.updateJoystick(joystick, pointer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scene.input.on('pointerup', function() {
|
||||||
|
if (joystick.isActive) {
|
||||||
|
joystick.isActive = false;
|
||||||
|
joystick.thumb.setPosition(joystick.startX, joystick.startY);
|
||||||
|
joystick.currentX = 0;
|
||||||
|
joystick.currentY = 0;
|
||||||
|
joystick.normalizedX = 0;
|
||||||
|
joystick.normalizedY = 0;
|
||||||
|
joystick.magnitude = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.joysticks.set(config.id, joystick);
|
||||||
|
return joystick;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建轮盘失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建屏幕按钮
|
||||||
|
* @param {Object} config 按钮配置
|
||||||
|
* @returns {Object} 按钮实例
|
||||||
|
*/
|
||||||
|
createButton(config) {
|
||||||
|
try {
|
||||||
|
const button = {
|
||||||
|
id: config.id,
|
||||||
|
sprite: null,
|
||||||
|
text: null,
|
||||||
|
isDown: false,
|
||||||
|
x: config.x || this.scene.sys.game.config.width - 100,
|
||||||
|
y: config.y || this.scene.sys.game.config.height - 100,
|
||||||
|
width: config.width || 80,
|
||||||
|
height: config.height || 80,
|
||||||
|
label: config.label || 'Button',
|
||||||
|
onDown: config.onDown || null,
|
||||||
|
onUp: config.onUp || null
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建按钮背景
|
||||||
|
button.sprite = this.scene.add.rectangle(button.x, button.y, button.width, button.height, 0x444444, 0.5);
|
||||||
|
button.sprite.setScrollFactor(0);
|
||||||
|
button.sprite.setInteractive();
|
||||||
|
|
||||||
|
// 创建按钮文字
|
||||||
|
button.text = this.scene.add.text(button.x, button.y, button.label, {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
button.text.setScrollFactor(0);
|
||||||
|
button.text.setOrigin(0.5, 0.5);
|
||||||
|
|
||||||
|
// 监听触摸事件
|
||||||
|
button.sprite.on('pointerdown', function() {
|
||||||
|
button.isDown = true;
|
||||||
|
button.sprite.setFillStyle(0x666666, 0.8);
|
||||||
|
if (button.onDown) {
|
||||||
|
button.onDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
button.sprite.on('pointerup', function() {
|
||||||
|
button.isDown = false;
|
||||||
|
button.sprite.setFillStyle(0x444444, 0.5);
|
||||||
|
if (button.onUp) {
|
||||||
|
button.onUp();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
button.sprite.on('pointerout', function() {
|
||||||
|
if (button.isDown) {
|
||||||
|
button.isDown = false;
|
||||||
|
button.sprite.setFillStyle(0x444444, 0.5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.set(config.id, button);
|
||||||
|
return button;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建按钮失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两点之间的距离
|
||||||
|
* @param {number} x1
|
||||||
|
* @param {number} y1
|
||||||
|
* @param {number} x2
|
||||||
|
* @param {number} y2
|
||||||
|
* @returns {number} 距离
|
||||||
|
*/
|
||||||
|
calculateDistance(x1, y1, x2, y2) {
|
||||||
|
const dx = x2 - x1;
|
||||||
|
const dy = y2 - y1;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两点之间的角度
|
||||||
|
* @param {number} x1
|
||||||
|
* @param {number} y1
|
||||||
|
* @param {number} x2
|
||||||
|
* @param {number} y2
|
||||||
|
* @returns {number} 角度
|
||||||
|
*/
|
||||||
|
calculateAngle(x1, y1, x2, y2) {
|
||||||
|
return Math.atan2(y2 - y1, x2 - x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新轮盘状态
|
||||||
|
* @param {Object} joystick 轮盘实例
|
||||||
|
* @param {Object} pointer 指针事件
|
||||||
|
*/
|
||||||
|
updateJoystick(joystick, pointer) {
|
||||||
|
const distance = this.calculateDistance(joystick.startX, joystick.startY, pointer.x, pointer.y);
|
||||||
|
const angle = this.calculateAngle(joystick.startX, joystick.startY, pointer.x, pointer.y);
|
||||||
|
|
||||||
|
// 限制最大距离
|
||||||
|
const limitedDistance = Math.min(distance, joystick.maxDistance);
|
||||||
|
joystick.magnitude = limitedDistance / joystick.maxDistance;
|
||||||
|
|
||||||
|
// 计算位置
|
||||||
|
joystick.currentX = Math.cos(angle) * limitedDistance;
|
||||||
|
joystick.currentY = Math.sin(angle) * limitedDistance;
|
||||||
|
|
||||||
|
// 归一化(-1 到 1 之间)
|
||||||
|
joystick.normalizedX = joystick.currentX / joystick.maxDistance;
|
||||||
|
joystick.normalizedY = joystick.currentY / joystick.maxDistance;
|
||||||
|
|
||||||
|
// 更新拇指位置
|
||||||
|
joystick.thumb.setPosition(
|
||||||
|
joystick.startX + joystick.currentX,
|
||||||
|
joystick.startY + joystick.currentY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘方向向量
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 方向向量 {x, y}
|
||||||
|
*/
|
||||||
|
getJoystickDirection(joystickId) {
|
||||||
|
const joystick = this.joysticks.get(joystickId);
|
||||||
|
if (!joystick) return { x: 0, y: 0 };
|
||||||
|
return { x: joystick.currentX, y: joystick.currentY };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘力度
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {number} 力度值 (0-1)
|
||||||
|
*/
|
||||||
|
getJoystickMagnitude(joystickId) {
|
||||||
|
const joystick = this.joysticks.get(joystickId);
|
||||||
|
if (!joystick) return 0;
|
||||||
|
return joystick.magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取归一化的轮盘方向
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 归一化向量 {x, y} (-1 到 1)
|
||||||
|
*/
|
||||||
|
getJoystickNormalized(joystickId) {
|
||||||
|
const joystick = this.joysticks.get(joystickId);
|
||||||
|
if (!joystick) return { x: 0, y: 0 };
|
||||||
|
return { x: joystick.normalizedX, y: joystick.normalizedY };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否按下
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否按下
|
||||||
|
*/
|
||||||
|
isButtonDown(buttonId) {
|
||||||
|
const button = this.buttons.get(buttonId);
|
||||||
|
return button ? button.isDown : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否释放
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否释放
|
||||||
|
*/
|
||||||
|
isButtonUp(buttonId) {
|
||||||
|
return !this.isButtonDown(buttonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁适配器
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
// 清理轮盘
|
||||||
|
this.joysticks.forEach(joystick => {
|
||||||
|
if (joystick.base) joystick.base.destroy();
|
||||||
|
if (joystick.thumb) joystick.thumb.destroy();
|
||||||
|
});
|
||||||
|
this.joysticks.clear();
|
||||||
|
|
||||||
|
// 清理按钮
|
||||||
|
this.buttons.forEach(button => {
|
||||||
|
if (button.sprite) button.sprite.destroy();
|
||||||
|
if (button.text) button.text.destroy();
|
||||||
|
});
|
||||||
|
this.buttons.clear();
|
||||||
|
|
||||||
|
console.log('PhaserInputAdapter 已销毁');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
// plugins/core/InputSystem.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心输入系统 - 引擎无关
|
||||||
|
* 使用适配器模式实现跨引擎兼容
|
||||||
|
*/
|
||||||
|
export class InputSystem {
|
||||||
|
constructor(adapter) {
|
||||||
|
if (!adapter) {
|
||||||
|
throw new Error('InputSystem 需要一个适配器实例');
|
||||||
|
}
|
||||||
|
this.adapter = adapter;
|
||||||
|
this.joysticks = new Map();
|
||||||
|
this.buttons = new Map();
|
||||||
|
console.log('InputSystem 初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化输入系统
|
||||||
|
*/
|
||||||
|
initialize() {
|
||||||
|
this.adapter.initialize();
|
||||||
|
console.log('InputSystem 已初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建触摸轮盘
|
||||||
|
* @param {Object} config 轮盘配置
|
||||||
|
* @returns {string} 轮盘ID
|
||||||
|
*/
|
||||||
|
createJoystick(config) {
|
||||||
|
const joystickId = config.id || `joystick_${this.joysticks.size}`;
|
||||||
|
const createdJoystick = this.adapter.createJoystick({
|
||||||
|
...config,
|
||||||
|
id: joystickId
|
||||||
|
});
|
||||||
|
if (createdJoystick) {
|
||||||
|
this.joysticks.set(joystickId, createdJoystick);
|
||||||
|
console.log('创建轮盘:', joystickId);
|
||||||
|
}
|
||||||
|
return joystickId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建屏幕按钮
|
||||||
|
* @param {Object} config 按钮配置
|
||||||
|
* @returns {string} 按钮ID
|
||||||
|
*/
|
||||||
|
createButton(config) {
|
||||||
|
const buttonId = config.id || `button_${this.buttons.size}`;
|
||||||
|
const createdButton = this.adapter.createButton({
|
||||||
|
...config,
|
||||||
|
id: buttonId
|
||||||
|
});
|
||||||
|
if (createdButton) {
|
||||||
|
this.buttons.set(buttonId, createdButton);
|
||||||
|
console.log('创建按钮:', buttonId);
|
||||||
|
}
|
||||||
|
return buttonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘方向向量
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 方向向量 {x, y}
|
||||||
|
*/
|
||||||
|
getJoystickDirection(joystickId) {
|
||||||
|
return this.adapter.getJoystickDirection(joystickId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮盘力度
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {number} 力度值 (0-1)
|
||||||
|
*/
|
||||||
|
getJoystickMagnitude(joystickId) {
|
||||||
|
return this.adapter.getJoystickMagnitude(joystickId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取归一化的轮盘方向
|
||||||
|
* @param {string} joystickId 轮盘ID
|
||||||
|
* @returns {Object} 归一化向量 {x, y} (-1 到 1)
|
||||||
|
*/
|
||||||
|
getJoystickNormalized(joystickId) {
|
||||||
|
return this.adapter.getJoystickNormalized(joystickId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否按下
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否按下
|
||||||
|
*/
|
||||||
|
isButtonDown(buttonId) {
|
||||||
|
return this.adapter.isButtonDown(buttonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查按钮是否释放
|
||||||
|
* @param {string} buttonId 按钮ID
|
||||||
|
* @returns {boolean} 是否释放
|
||||||
|
*/
|
||||||
|
isButtonUp(buttonId) {
|
||||||
|
return this.adapter.isButtonUp(buttonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁输入系统
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
this.adapter.destroy();
|
||||||
|
this.joysticks.clear();
|
||||||
|
this.buttons.clear();
|
||||||
|
console.log('InputSystem 已销毁');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
// scenes/GameScene.js
|
||||||
|
|
||||||
|
export class GameScene extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super('GameScene');
|
||||||
|
this.moveSpeed = 200;
|
||||||
|
this.joystickId = null;
|
||||||
|
this.inputPlugin = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
const graphics = this.make.graphics();
|
||||||
|
graphics.fillStyle(0xffffff, 1);
|
||||||
|
graphics.fillRect(0, 0, 32, 32);
|
||||||
|
graphics.generateTexture('player', 32, 32);
|
||||||
|
graphics.destroy();
|
||||||
|
|
||||||
|
this.player = this.physics.add.sprite(400, 300, 'player');
|
||||||
|
this.player.setCollideWorldBounds(true);
|
||||||
|
|
||||||
|
// 获取插件实例(更可靠的方式)
|
||||||
|
this.inputPlugin = this.plugins.get('InputPlugin');
|
||||||
|
|
||||||
|
if (this.inputPlugin) {
|
||||||
|
// 添加触摸轮盘
|
||||||
|
this.joystickId = this.inputPlugin.createJoystick({
|
||||||
|
id: 'movement',
|
||||||
|
x: 100,
|
||||||
|
y: this.sys.game.config.height - 100,
|
||||||
|
radius: 60,
|
||||||
|
maxDistance: 40
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('InputPlugin 未找到!');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加提示文字
|
||||||
|
this.add.text(10, 10, '使用 WASD/方向键 或 触摸轮盘移动', { fill: '#ffffff', fontSize: '16px' });
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
// 重置速度
|
||||||
|
this.player.setVelocity(0);
|
||||||
|
|
||||||
|
// 键盘输入
|
||||||
|
const cursors = this.input.keyboard.createCursorKeys();
|
||||||
|
const keys = this.input.keyboard.addKeys('W,A,S,D');
|
||||||
|
|
||||||
|
if (cursors.up.isDown || keys.W.isDown) {
|
||||||
|
this.player.setVelocityY(-this.moveSpeed);
|
||||||
|
}
|
||||||
|
if (cursors.down.isDown || keys.S.isDown) {
|
||||||
|
this.player.setVelocityY(this.moveSpeed);
|
||||||
|
}
|
||||||
|
if (cursors.left.isDown || keys.A.isDown) {
|
||||||
|
this.player.setVelocityX(-this.moveSpeed);
|
||||||
|
}
|
||||||
|
if (cursors.right.isDown || keys.D.isDown) {
|
||||||
|
this.player.setVelocityX(this.moveSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸轮盘输入(带归一化)
|
||||||
|
if (this.inputPlugin && this.joystickId) {
|
||||||
|
const joystickNormalized = this.inputPlugin.getJoystickNormalized(this.joystickId);
|
||||||
|
if (joystickNormalized.x !== 0 || joystickNormalized.y !== 0) {
|
||||||
|
this.player.setVelocityX(joystickNormalized.x * this.moveSpeed);
|
||||||
|
this.player.setVelocityY(joystickNormalized.y * this.moveSpeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
// scenes/JoystickTestScene.js
|
||||||
|
|
||||||
|
import { InputPlugin } from '../plugins/InputPlugin.js';
|
||||||
|
|
||||||
|
export class JoystickTestScene extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super('JoystickTestScene');
|
||||||
|
this.moveSpeed = 200;
|
||||||
|
this.sprintSpeed = 400; // 冲刺速度
|
||||||
|
this.inputPlugin = null;
|
||||||
|
this.joystickId = null;
|
||||||
|
this.sprintButtonId = null;
|
||||||
|
this.isSprinting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
// 创建背景
|
||||||
|
this.cameras.main.setBackgroundColor('#2c3e50');
|
||||||
|
|
||||||
|
// 创建玩家
|
||||||
|
const graphics = this.make.graphics();
|
||||||
|
graphics.fillStyle(0x3498db, 1);
|
||||||
|
graphics.fillRect(0, 0, 40, 40);
|
||||||
|
graphics.generateTexture('player', 40, 40);
|
||||||
|
graphics.destroy();
|
||||||
|
|
||||||
|
this.player = this.physics.add.sprite(400, 300, 'player');
|
||||||
|
this.player.setCollideWorldBounds(true);
|
||||||
|
|
||||||
|
// 直接创建 InputPlugin 实例(绕过插件系统)
|
||||||
|
try {
|
||||||
|
this.inputPlugin = new InputPlugin(this, this.plugins);
|
||||||
|
console.log('直接创建 InputPlugin:', this.inputPlugin);
|
||||||
|
|
||||||
|
// 手动启动插件
|
||||||
|
this.inputPlugin.boot();
|
||||||
|
|
||||||
|
// 测试插件方法
|
||||||
|
const testResult = this.inputPlugin.testMethod();
|
||||||
|
console.log('插件测试结果:', testResult);
|
||||||
|
|
||||||
|
// 添加移动轮盘
|
||||||
|
this.joystickId = this.inputPlugin.createJoystick({
|
||||||
|
id: 'movement',
|
||||||
|
x: 150,
|
||||||
|
y: this.sys.game.config.height - 150,
|
||||||
|
radius: 80,
|
||||||
|
maxDistance: 60
|
||||||
|
});
|
||||||
|
console.log('创建轮盘:', this.joystickId);
|
||||||
|
|
||||||
|
// 添加冲刺按钮
|
||||||
|
this.sprintButtonId = this.inputPlugin.createButton({
|
||||||
|
id: 'sprint',
|
||||||
|
x: this.sys.game.config.width - 150,
|
||||||
|
y: this.sys.game.config.height - 150,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
label: '冲刺',
|
||||||
|
onDown: () => {
|
||||||
|
this.isSprinting = true;
|
||||||
|
console.log('开始冲刺');
|
||||||
|
},
|
||||||
|
onUp: () => {
|
||||||
|
this.isSprinting = false;
|
||||||
|
console.log('结束冲刺');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('创建冲刺按钮:', this.sprintButtonId);
|
||||||
|
|
||||||
|
// 添加提示文字
|
||||||
|
this.add.text(10, 10, '触摸轮盘测试场景', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '24px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add.text(10, 50, '使用左侧轮盘移动', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add.text(10, 80, '使用右侧按钮冲刺', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add.text(10, 110, '使用 WASD 或方向键也可以移动', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示轮盘状态
|
||||||
|
this.statusText = this.add.text(10, 150, '轮盘状态: 未激活', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加适配器架构信息
|
||||||
|
this.add.text(10, 300, '适配器架构信息:', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add.text(10, 330, '- 核心: InputSystem (引擎无关)', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add.text(10, 360, '- 适配器: PhaserInputAdapter', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.add.text(10, 390, '- 插件: InputPlugin (场景插件)', {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建 InputPlugin 失败:', error);
|
||||||
|
this.add.text(10, 10, 'InputPlugin 初始化失败!', {
|
||||||
|
fill: '#ff0000',
|
||||||
|
fontSize: '24px'
|
||||||
|
});
|
||||||
|
this.add.text(10, 50, '错误: ' + error.message, {
|
||||||
|
fill: '#ffffff',
|
||||||
|
fontSize: '16px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
// 重置速度
|
||||||
|
this.player.setVelocity(0);
|
||||||
|
|
||||||
|
// 确定当前速度(根据是否冲刺)
|
||||||
|
const currentSpeed = this.isSprinting ? this.sprintSpeed : this.moveSpeed;
|
||||||
|
|
||||||
|
// 键盘输入
|
||||||
|
const cursors = this.input.keyboard.createCursorKeys();
|
||||||
|
const keys = this.input.keyboard.addKeys('W,A,S,D,SHIFT');
|
||||||
|
|
||||||
|
let hasKeyboardInput = false;
|
||||||
|
|
||||||
|
// 检查冲刺键(Shift)
|
||||||
|
if (keys.SHIFT.isDown) {
|
||||||
|
this.isSprinting = true;
|
||||||
|
} else if (!this.inputPlugin || this.inputPlugin.isButtonUp(this.sprintButtonId)) {
|
||||||
|
this.isSprinting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursors.up.isDown || keys.W.isDown) {
|
||||||
|
this.player.setVelocityY(-currentSpeed);
|
||||||
|
hasKeyboardInput = true;
|
||||||
|
}
|
||||||
|
if (cursors.down.isDown || keys.S.isDown) {
|
||||||
|
this.player.setVelocityY(currentSpeed);
|
||||||
|
hasKeyboardInput = true;
|
||||||
|
}
|
||||||
|
if (cursors.left.isDown || keys.A.isDown) {
|
||||||
|
this.player.setVelocityX(-currentSpeed);
|
||||||
|
hasKeyboardInput = true;
|
||||||
|
}
|
||||||
|
if (cursors.right.isDown || keys.D.isDown) {
|
||||||
|
this.player.setVelocityX(currentSpeed);
|
||||||
|
hasKeyboardInput = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸轮盘输入
|
||||||
|
if (this.inputPlugin && this.joystickId) {
|
||||||
|
try {
|
||||||
|
const joystickNormalized = this.inputPlugin.getJoystickNormalized(this.joystickId);
|
||||||
|
const joystickMagnitude = this.inputPlugin.getJoystickMagnitude(this.joystickId);
|
||||||
|
|
||||||
|
if (joystickNormalized.x !== 0 || joystickNormalized.y !== 0) {
|
||||||
|
this.player.setVelocityX(joystickNormalized.x * currentSpeed);
|
||||||
|
this.player.setVelocityY(joystickNormalized.y * currentSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新状态文字
|
||||||
|
if (this.statusText) {
|
||||||
|
const sprintStatus = this.isSprinting ? '(冲刺中)' : '';
|
||||||
|
if (joystickMagnitude > 0) {
|
||||||
|
this.statusText.setText(`轮盘状态: 激活${sprintStatus}\n力度: ${joystickMagnitude.toFixed(2)}\n方向: X=${joystickNormalized.x.toFixed(2)}, Y=${joystickNormalized.y.toFixed(2)}\n速度: ${currentSpeed}`);
|
||||||
|
} else if (hasKeyboardInput) {
|
||||||
|
this.statusText.setText(`轮盘状态: 未激活${sprintStatus} (使用键盘)\n速度: ${currentSpeed}`);
|
||||||
|
} else {
|
||||||
|
this.statusText.setText(`轮盘状态: 未激活${sprintStatus}\n速度: ${currentSpeed}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('轮盘更新失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (this.inputPlugin) {
|
||||||
|
this.inputPlugin.destroy();
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user