import { _decorator, Component, input, EventTouch, Node, Input, Vec3, Collider2D, Contact2DType, SpriteFrame, Sprite, tween, Prefab, instantiate, director, } from "cc"; import { NoteControl } from "./NoteControl"; import { BombEffect } from "../effects/BombEffectControl"; import { EventDispatcher } from "../libs/EventDispatcher"; import { GlobalData } from "../config/GlobalData"; import { GameState } from "../config/Config"; const { ccclass, property } = _decorator; @ccclass("DinoControl") export class DinoControl extends Component { // 小恐龙脖子图片 @property(SpriteFrame) neckSpriteFrame: SpriteFrame = null; // 小恐龙脖子的高度 private neckHeight: number = 62; // x 轴的边界 private xMaxDistance: number = 180; // 爆炸特效预制体 @property(Prefab) bombEffectPrefab: Prefab = null; // 获取线节点 @property(Node) lineNode: Node = null; onLoad() { // 监听继续游戏事件 EventDispatcher.getTarget().on( EventDispatcher.GAME_RESUME, this.continueGame, this, ); // 监听小恐龙移动到线的位置 EventDispatcher.getTarget().on( EventDispatcher.MOVE_DINO_TO_LINE, this.moveDinoToLine, this, ); } start() { // 监听手指滑动事件 input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this); // 监听碰撞事件 this.node .getComponent(Collider2D) .on(Contact2DType.BEGIN_CONTACT, this.onCollisionEnter, this); } // 滑动事件 onTouchMove(event: EventTouch) { // 获取小恐龙的位置 const dinoPos = this.node.position; // 获取手指x移动距离 const deltaX = event.getDeltaX(); // 更新小恐龙的位置 // 目标位置 const targetPos = new Vec3(dinoPos.x + deltaX, dinoPos.y, dinoPos.z); if (targetPos.x < -this.xMaxDistance) { targetPos.x = -this.xMaxDistance; } else if (targetPos.x > this.xMaxDistance) { targetPos.x = this.xMaxDistance; } this.node.setPosition(targetPos); // 移动距离大于0时,小恐龙向右移动,否则向左移动 if (deltaX > 0) { this.node.scale = new Vec3(-1, 1, 1); } else { this.node.scale = new Vec3(1, 1, 1); } } onCollisionEnter(selfCollider: Collider2D, otherCollider: Collider2D) { // 如果游戏状态不是进行中,直接返回 if (GlobalData.gameState != GameState.PLAYING) { return; } if (otherCollider.tag == 2) { // 得分操作 GlobalData.curRoundTotalScore += GlobalData.addScore; // 触发小恐龙吃到音符事件 EventDispatcher.getTarget().emit(EventDispatcher.DINO_EAT_NOTE); // 小恐龙碰到了音符 otherCollider.node.getComponent(NoteControl).noteBeEaten(); // 增加脖子长度 this.addDinoNeckLength(); // 执行吃掉音符动画 this.playEatNoteAnimation(); // 播放爆炸特效 this.playBombEffect(); // 检测是否闯关成功 const isPassLevel = this.checkIsPassLevel(); if (isPassLevel) { EventDispatcher.getTarget().emit(EventDispatcher.PASS_LEVLE); } } } // 增加脖子长度 addDinoNeckLength() { // 添加脖子空节点 let neckChild = new Node(); // 给这个节点添加精灵组件 neckChild.addComponent(Sprite).spriteFrame = this.neckSpriteFrame; // 设置这个空节点的父节点 neckChild.parent = this.node.getChildByName("dino_neck_box"); // 获取小恐龙身体 const bodyNode = this.node.getChildByName("dino_body"); // 获取小恐龙位置 const bodyPos = bodyNode.getPosition(); // 设置小恐龙新的位置(往下移动一个脖子的距离) bodyNode.setPosition(bodyPos.x, bodyPos.y - this.neckHeight, 0); } // 执行吃掉音符动画 playEatNoteAnimation() { // 获取当前所有脖子列表 const neckList: Node[] = this.node .getChildByName("dino_neck_box") .children.slice(0, 16) as Node[]; // 定义存储动画的 promise let animationPromises = Promise.resolve(); // 遍历所有脖子 for (let i = 0; i < neckList.length; i++) { let neckNode = neckList[i]; // 播放吃掉音符动画 animationPromises = animationPromises.then(() => { return new Promise((resolve) => { tween(neckNode) .to(0.1, { scale: new Vec3(1.2, 1, 1) }) .to(0.1, { scale: new Vec3(1, 1, 1) }) .call(() => resolve()) .start(); }); }); } } // 播放爆炸特效 playBombEffect() { // 实例化爆炸特效 let bombEffectNode = instantiate(this.bombEffectPrefab); // 设置爆炸特效节点的位置 let bombPos = new Vec3( this.node.position.x, this.node.position.y + 100, this.node.position.z, ); // 设置位置 bombEffectNode.setPosition(bombPos); // 设置爆炸特效节点的父节点 bombEffectNode.setParent(this.node.parent); // 播放爆炸特效 bombEffectNode.getComponent(BombEffect).playBombEffect(); } // 移动小恐龙到线的位置 moveDinoToLine() { // 获取线的世界坐标 const linePos = this.lineNode.getWorldPosition(); // 获取小恐龙身体的世界坐标位置 const bodyPos = this.node.getChildByName("dino_body").getWorldPosition(); // 计算两个坐标 y 轴的差值 const deltaY = linePos.y - bodyPos.y; // 移动小恐龙到线的位置动画 tween(this.node) .by(1, { position: new Vec3(0, deltaY - 44, 0) }) .start(); } // 检测是否通过本关 checkIsPassLevel(): boolean { // 获取 note_manager 节点 const noteManager = director .getScene() .getChildByName("Canvas") .getChildByName("note_manager"); if (noteManager?.children?.length === 0) return true; return false; } // 继续游戏 continueGame() { const isPassLevel = this.checkIsPassLevel(); if (isPassLevel) { // 发送闯关成功事件 EventDispatcher.getTarget().emit(EventDispatcher.PASS_LEVLE); } } update(deltaTime: number) {} }