import { _decorator, Component, Input, input, KeyCode, Vec2, Node, EventKeyboard, Vec3, EventTouch, v3, sp, UITransform, Prefab, instantiate, Label, tween } from 'cc'; import { GEvent } from 'db://assets/mx/module/event/GEvent'; import { GBundle } from '../../game/ConfigRes'; import { BattleType, ChapterDifficulty } from '../../manager/ChapterDataManager'; const { ccclass, property } = _decorator; @ccclass('PlayerController') export class PlayerController extends Component { // 滑动控制区域节点 @property({ type: Node, tooltip: "指定的滑动控制区域" }) controlArea: Node = null; @property({ type: Node, tooltip: "可移动区域" }) moveArea: Node = null; // 玩家节点 @property({ type: Node, tooltip: "需要控制的玩家节点" }) playerNode: Node = null; @property(sp.Skeleton) playerSpine: sp.Skeleton = null; @property(sp.Skeleton) levelSpine: sp.Skeleton = null; // 移动灵敏度 sensitivity: number = 1.1; private gameModel: string = '' // 记录触摸起点(勿用 Vec3.ZERO:引擎内为只读,引导未放开移动时 onTouchStart 可能未赋值,onTouchMove 里不能改 .x) private startTouchPos: Vec3 = v3(0, 0, 0); // 记录玩家初始X位置(用于锁定X轴) private initialY: number = 0; _dt: number = 0 private rightX: number = 150 private leftX: number = -150 private isStart: boolean = false private isCanMove: boolean = false private isTouchStart: boolean = false private roleVisual: Node | null = null; private roleBaseScaleX: number = 1; private roleFacing: number = 0; // -1 left, +1 right, 0 unknown protected onEnable(): void { // 注册触摸事件 this.controlArea.on(Node.EventType.TOUCH_START, this.onTouchStart, this); this.controlArea.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.controlArea.on(Node.EventType.TOUCH_END, this.onTouchEnd, this); GEvent.Ins.on(GEvent.ShowLevelSpine, this.showLevelSpine, this); } protected onDisable(): void { // 移除输入事件监听 this.controlArea.off(Node.EventType.TOUCH_START, this.onTouchStart, this); this.controlArea.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.controlArea.off(Node.EventType.TOUCH_END, this.onTouchEnd, this); GEvent.Ins.off(GEvent.ShowLevelSpine, this.showLevelSpine, this); } onLoad() { let n = gg.res.getNode(`skin/${gg.skin.CurrentSkin}/`, `主角`, GBundle.Items); this.playerNode.find("skin").addChild(n); this.playerSpine = n.getComponent(sp.Skeleton); // 缓存“角色”节点及初始朝向(只做左右翻转,不改大小) this.roleVisual = this.playerNode.getChildByName('角色') || this.node.getChildByName('角色') || null; if (this.roleVisual) { const sx = this.roleVisual.scale.x; this.roleBaseScaleX = Math.abs(sx) > 1e-6 ? Math.abs(sx) : 1; this.roleFacing = sx >= 0 ? 1 : -1; } // 初始化玩家位置到屏幕左侧 this.setInitialPosition(); } protected start(): void { this.gameModel = gg.game.CurentSelectBattleType == BattleType.BoxMode ? 'baoxiang' : '不是宝箱副本' // if (this.gameModel == 'baoxiang') { // this.moveArea.getComponent(UITransform).height = 840 // this.moveArea.setPosition(0, -45) // } else { // this.moveArea.getComponent(UITransform).height = 742 // this.moveArea.setPosition(0, 15) // } // 记录玩家初始X位置,用于锁定X轴 this.initialY = this.playerNode.position.y; this.rightX = this.moveArea.x + this.moveArea.getComponent(UITransform).width / 2 this.leftX = this.moveArea.x - this.moveArea.getComponent(UITransform).width / 2 this.playWait(); } setIsReady(isStart: boolean) { this.isStart = isStart } setPlayerIsCanMove(isCanMove: boolean) { this.isCanMove = isCanMove } update(deltaTime: number) { if (!gg.game.isBattleContextActive()) return; if (!this.isStart) { return } this._dt += deltaTime * gg.game.CurentBattle.TimeScale //this._dt <= 1.6 || !this.isCanMove || // if (this._dt <= 1.6 || gg.game.CurentBattle.IsGamePause) { // this.playWait() // } else { // this.playAtk() // } } public setInitialPosition() { // 将玩家设置在屏幕左侧中间位置 // const canvas = this.node.parent!; // const canvasSize = canvas.getContentSize(); //this.playerNode.setPosition(0, -430); } /** * 触摸开始事件处理 * @param event 触摸事件 */ private onTouchStart(event: EventTouch) { if (!gg.game.CurentBattle.canUpdateFrame()) return if(!this.isCanMove && (gg.game.CurentBattle.ChapterId == 1 && gg.game.CurentBattle.Difficulty == ChapterDifficulty.Normal)){ return } // 获取触摸开始位置 event.preventSwallow = true; event.propagationStopped = true; const touchPos = event.getUILocation(); this.startTouchPos = v3(touchPos.x, touchPos.y, 0); this.isTouchStart = true } /** * 触摸移动事件处理 * @param event 触摸事件 */ private onTouchMove(event: EventTouch) { if (!gg.game.CurentBattle.canUpdateFrame()) return; if(!this.isCanMove && (gg.game.CurentBattle.ChapterId == 1 && gg.game.CurentBattle.Difficulty == ChapterDifficulty.Normal)){ return } //BattleManager.Instance.hideMovePlayerGuide() GEvent.Ins.emit(GEvent.onMovePlayer); // 获取当前触摸位置 const currentPos = event.getUILocation(); // 计算Y方向的移动距离 const deltaX = currentPos.x - this.startTouchPos.x; // 更新触摸起始参考点(整向量赋值,避免误改只读 Vec3) this.startTouchPos.set(currentPos.x, currentPos.y, 0); let posX = this.playerNode.position.x + deltaX * this.sensitivity if (posX < this.leftX) posX = this.leftX if (posX > this.rightX) posX = this.rightX // 左右转向:根据手指滑动方向翻转“角色”节点 if (this.roleVisual && Math.abs(deltaX) > 0.01) { const newFacing = deltaX > 0 ? 1 : -1; if (newFacing !== this.roleFacing) { this.roleFacing = newFacing; const s = this.roleVisual.scale; this.roleVisual.setScale(this.roleBaseScaleX * this.roleFacing, s.y, s.z); } } // 计算新位置(只改变Y坐标,X坐标保持初始值不变) // 应用新位置到玩家 this.playerNode.position = v3(posX, this.initialY, 0); } onTouchEnd(event: EventTouch) { //穿透 event.preventSwallow = true; event.propagationStopped = true; this.isTouchStart = false } /**攻击动效 */ public playAtk() { if (!this.playerSpine) return; //if (this.playerSpine.animation == '攻击') return this.playerSpine.setAnimation(0, '攻击', false); this.playerSpine.setCompleteListener(() => { this.playerSpine.setCompleteListener(null); this.playWait(); }) } /**待机动效 */ public playWait() { if (!this.playerSpine) return; if (this.playerSpine.animation == '待机') return this.playerSpine.setAnimation(0, '待机', true); } /**显示升级特效 */ showLevelSpine(labstr: string) { this.scheduleOnce(() => { this.levelSpine.node.active = true //播放音效 gg.audio.playEffect({ name: "强化" }); this.levelSpine.setAnimation(0, '升级', false); this.levelSpine.setCompleteListener(() => { this.levelSpine.node.active = false }) if (labstr) { let piaoLab = this.playerNode.find("piaoLab") piaoLab.setPosition(0, 65) if (piaoLab) { piaoLab.active = true piaoLab.getComponent(Label).string = labstr tween(piaoLab) .to(0.4, { position: v3(0, 120) }) .call(() => { piaoLab.active = false }) .start() } } }, 0.2) } /**播放挥刀动画 */ public playFruitKnifeAtk(callback: Function) { let n = this.node.find("水果刀"); if (n) { n.active = true; let anim = n.getComponent(sp.Skeleton); anim.setAnimation(0, '挥刀', false); anim.setCompleteListener(() => { n.active = false; anim.setCompleteListener(null); if (callback) { callback() } }) } } }