11import Phaser from 'phaser' ;
22import { EVENTS , gameEvents } from '../config/Events' ;
33
4+ // 定义一个简单的接口,只需要对象有 x 坐标即可
5+ // 这样不需要导入具体的 Player 类,避免循环依赖
6+ export interface IControlTarget {
7+ x : number ;
8+ }
9+
410export default class InputZones {
511 private scene : Phaser . Scene ;
6- private leftDown = false ;
7- private rightDown = false ;
12+ private target : IControlTarget ; // 存储风筝/玩家的引用
13+
14+ private isDown : boolean = false ; // 是否正在按压
815 private cursors ?: Phaser . Types . Input . Keyboard . CursorKeys ;
916 private lastDir = 0 ;
10- private leftZone : Phaser . GameObjects . Zone ;
11- private rightZone : Phaser . GameObjects . Zone ;
17+ private inputZone : Phaser . GameObjects . Zone ;
1218
13- constructor ( scene : Phaser . Scene ) {
19+ // 灵敏度死区:防止手指正好按在风筝上时左右鬼畜抖动
20+ private readonly DEAD_ZONE = 10 ;
21+
22+ /**
23+ * @param scene 场景
24+ * @param target 被控制的对象(必须包含 x 属性),通常传入 this.player
25+ */
26+ constructor ( scene : Phaser . Scene , target : IControlTarget ) {
1427 this . scene = scene ;
28+ this . target = target ;
1529 const { width, height } = scene . scale ;
16- const halfWidth = width / 2 ;
17-
18- const leftDebug = scene . add . rectangle ( halfWidth / 2 , height / 2 , halfWidth , height , 0x00ff00 , 0.0 ) ;
19- const rightDebug = scene . add . rectangle ( halfWidth + halfWidth / 2 , height / 2 , halfWidth , height , 0xff0000 , 0.0 ) ;
20- leftDebug . setScrollFactor ( 0 ) . setDepth ( - 1000 ) ;
21- rightDebug . setScrollFactor ( 0 ) . setDepth ( - 1000 ) ;
2230
23- this . leftZone = scene . add . zone ( halfWidth / 2 , height / 2 , halfWidth , height ) ;
24- this . rightZone = scene . add . zone ( halfWidth + halfWidth / 2 , height / 2 , halfWidth , height ) ;
25- this . leftZone . setScrollFactor ( 0 ) . setDepth ( - 999 ) ;
26- this . rightZone . setScrollFactor ( 0 ) . setDepth ( - 999 ) ;
31+ // 1. 创建全屏触控区
32+ // 深度设为极低,确保作为背景层接收输入,不阻挡 UI 按钮
33+ this . inputZone = scene . add . zone ( width / 2 , height / 2 , width , height ) ;
34+ this . inputZone . setScrollFactor ( 0 ) . setDepth ( - 999 ) ;
35+ this . inputZone . setInteractive ( ) ;
2736
28- this . leftZone . setInteractive ( ) ;
29- this . rightZone . setInteractive ( ) ;
30-
31- this . leftZone . on ( 'pointerdown' , ( ) => {
32- this . leftDown = true ;
33- this . emitDirection ( ) ;
34- } ) ;
35- this . leftZone . on ( 'pointerup' , ( ) => {
36- this . leftDown = false ;
37- this . emitDirection ( ) ;
38- } ) ;
39- this . leftZone . on ( 'pointerout' , ( ) => {
40- this . leftDown = false ;
41- this . emitDirection ( ) ;
42- } ) ;
43- this . leftZone . on ( 'pointerupoutside' , ( ) => {
44- this . leftDown = false ;
37+ // 2. 绑定事件
38+ // 按下时标记状态,并立即触发一次方向检测
39+ this . inputZone . on ( 'pointerdown' , ( ) => {
40+ this . isDown = true ;
4541 this . emitDirection ( ) ;
4642 } ) ;
4743
48- this . rightZone . on ( 'pointerdown' , ( ) => {
49- this . rightDown = true ;
50- this . emitDirection ( ) ;
51- } ) ;
52- this . rightZone . on ( 'pointerup' , ( ) => {
53- this . rightDown = false ;
54- this . emitDirection ( ) ;
55- } ) ;
56- this . rightZone . on ( 'pointerout' , ( ) => {
57- this . rightDown = false ;
58- this . emitDirection ( ) ;
59- } ) ;
60- this . rightZone . on ( 'pointerupoutside' , ( ) => {
61- this . rightDown = false ;
62- this . emitDirection ( ) ;
63- } ) ;
44+ // 各种松开的情况
45+ this . inputZone . on ( 'pointerup' , this . handleUp , this ) ;
46+ this . inputZone . on ( 'pointerupoutside' , this . handleUp , this ) ;
47+
48+ // 全局松开作为保险
49+ scene . input . on ( 'pointerup' , this . handleUp , this ) ;
6450
51+ // 3. 键盘备用 (保持原有键盘逻辑)
6552 this . cursors = scene . input . keyboard ?. createCursorKeys ( ) ;
66-
67- scene . input . on ( 'pointerup' , this . handleGlobalPointerUp , this ) ;
6853 }
6954
70- private handleGlobalPointerUp ( ) {
71- if ( ! this . leftDown && ! this . rightDown ) return ;
72- this . leftDown = false ;
73- this . rightDown = false ;
55+ private handleUp ( ) {
56+ if ( ! this . isDown ) return ;
57+ this . isDown = false ;
7458 this . emitDirection ( ) ;
7559 }
7660
7761 private emitDirection ( ) {
7862 const dir = this . getDirection ( ) ;
63+ // 只有方向改变时才发送事件,优化性能
7964 if ( dir === this . lastDir ) return ;
8065 this . lastDir = dir ;
8166 gameEvents . emit ( EVENTS . INPUT_DIR , dir ) ;
8267 }
8368
8469 public update ( ) {
85- if ( ! this . cursors ) return ;
70+ // 每一帧都检测,确保如果风筝飞过了手指位置,方向会实时反转
8671 const dir = this . getDirection ( ) ;
8772 if ( dir === this . lastDir ) return ;
8873 this . lastDir = dir ;
8974 gameEvents . emit ( EVENTS . INPUT_DIR , dir ) ;
9075 }
9176
9277 private getDirection ( ) : number {
93- if ( this . leftDown ) return - 1 ;
94- if ( this . rightDown ) return 1 ;
78+ // A. 优先检测触摸/鼠标
79+ if ( this . isDown ) {
80+ const pointer = this . scene . input . activePointer ;
81+ // 使用 worldX 以兼容摄像机移动
82+ const targetX = pointer . worldX ;
83+ const currentX = this . target . x ;
84+
85+ const diff = targetX - currentX ;
86+
87+ // 如果距离非常近(死区内),则不移动,防止抖动
88+ if ( Math . abs ( diff ) < this . DEAD_ZONE ) {
89+ return 0 ;
90+ }
91+
92+ // 返回 1 (向右) 或 -1 (向左)
93+ return Math . sign ( diff ) ;
94+ }
95+
96+ // B. 如果没有触摸,检测键盘 (作为备用/PC端控制)
9597 if ( this . cursors ?. left ?. isDown ) return - 1 ;
9698 if ( this . cursors ?. right ?. isDown ) return 1 ;
99+
97100 return 0 ;
98101 }
99102
100103 destroy ( ) {
101- this . scene . input . off ( 'pointerup' , this . handleGlobalPointerUp , this ) ;
102- this . leftZone . destroy ( ) ;
103- this . rightZone . destroy ( ) ;
104+ this . scene . input . off ( 'pointerup' , this . handleUp , this ) ;
105+ this . inputZone . destroy ( ) ;
104106 }
105- }
107+ }
0 commit comments