|
|
|
|
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() {
|
|
|
|
|
void this._loadPlayerSkin();
|
|
|
|
|
|
|
|
|
|
// 缓存“角色”节点及初始朝向(只做左右翻转,不改大小)
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async _loadPlayerSkin(): Promise<void> {
|
|
|
|
|
const skin = this.playerNode?.find('skin');
|
|
|
|
|
if (!skin?.isValid) return;
|
|
|
|
|
const n = await gg.res.getNodeAsync(`skin/${gg.skin.CurrentSkin}/`, '主角', GBundle.Items);
|
|
|
|
|
if (!n?.isValid || !skin?.isValid) {
|
|
|
|
|
console.warn('[PlayerController] 主角皮肤加载失败');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
skin.addChild(n);
|
|
|
|
|
this.playerSpine = n.getComponent(sp.Skeleton);
|
|
|
|
|
this.playWait();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|