Files
dino/assets/seripts/components/DinoControl.ts
2026-05-12 06:46:31 +08:00

242 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
_decorator,
Component,
input,
EventTouch,
Node,
Input,
Vec3,
Collider2D,
Contact2DType,
SpriteFrame,
Sprite,
tween,
Prefab,
instantiate,
director,
Color,
} 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() {
// 设置小恐龙颜色
this.setDinoColor();
// 监听继续游戏事件
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");
// 设置脖子的颜色
neckChild.getComponent(Sprite).color = new Color(
GlobalData.currentDinoInfo.dinoColor,
);
// 获取小恐龙身体
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);
}
}
// 设置小恐龙颜色
setDinoColor() {
// 获取当前小恐龙信息
const dinoInfo = GlobalData.currentDinoInfo;
// 获取小恐龙颜色
const dinoColor = new Color(dinoInfo.dinoColor);
// 设置小恐龙身体颜色
this.node.getChildByName("dino_body").getComponent(Sprite).color =
dinoColor;
// 设置小恐龙头部颜色
this.node.getChildByName("dino_head").getComponent(Sprite).color =
dinoColor;
}
update(deltaTime: number) {}
}