feat(map): add hero move animation component
新增了英雄移动组件,实现多个英雄的周期性往复移动和动画速度同步匹配 同时更新了预制件配置以适配新的组件和节点命名调整
This commit is contained in:
@@ -38,10 +38,13 @@
|
|||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 102
|
"__id__": 102
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 104
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": {
|
"_prefab": {
|
||||||
"__id__": 104
|
"__id__": 106
|
||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
@@ -240,7 +243,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "m7",
|
"_name": "h",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -618,7 +621,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "a1",
|
"_name": "h",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -996,7 +999,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "k1",
|
"_name": "h",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -1208,7 +1211,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "hero2",
|
"_name": "hero4",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -1374,7 +1377,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "m1",
|
"_name": "h",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -1586,7 +1589,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "hero4",
|
"_name": "hero5",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -1752,7 +1755,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "h1",
|
"_name": "h",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"__editorExtras__": {},
|
"__editorExtras__": {},
|
||||||
"_parent": {
|
"_parent": {
|
||||||
@@ -1990,6 +1993,39 @@
|
|||||||
"__type__": "cc.CompPrefabInfo",
|
"__type__": "cc.CompPrefabInfo",
|
||||||
"fileId": "f2zvSV135PlYuUfadiV2hO"
|
"fileId": "f2zvSV135PlYuUfadiV2hO"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "46ae531x0VGib728jAKeNFe",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 105
|
||||||
|
},
|
||||||
|
"hero1": {
|
||||||
|
"__id__": 42
|
||||||
|
},
|
||||||
|
"hero2": {
|
||||||
|
"__id__": 62
|
||||||
|
},
|
||||||
|
"hero3": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"hero4": {
|
||||||
|
"__id__": 62
|
||||||
|
},
|
||||||
|
"hero5": {
|
||||||
|
"__id__": 82
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "86bacQ+jZMOokmXQGUf5Ed"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.PrefabInfo",
|
"__type__": "cc.PrefabInfo",
|
||||||
"root": {
|
"root": {
|
||||||
|
|||||||
90
assets/script/game/map/HeroMoveComp.ts
Normal file
90
assets/script/game/map/HeroMoveComp.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { _decorator, Component, Node, Animation, Vec3 } from "cc";
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
@ccclass('HeroMoveComp')
|
||||||
|
export class HeroMoveComp extends Component {
|
||||||
|
|
||||||
|
@property({ type: Node })
|
||||||
|
hero1: Node = null!;
|
||||||
|
@property({ type: Node })
|
||||||
|
hero2: Node = null!;
|
||||||
|
@property({ type: Node })
|
||||||
|
hero3: Node = null!;
|
||||||
|
@property({ type: Node })
|
||||||
|
hero4: Node = null!;
|
||||||
|
@property({ type: Node })
|
||||||
|
hero5: Node = null!;
|
||||||
|
|
||||||
|
// 控制移动速度的基础参数
|
||||||
|
private baseSpeed: number = 20; // 每秒向右移动的基础像素速度
|
||||||
|
private timer: number = 0;
|
||||||
|
// 为每个英雄保存其对应的 Animation 和随机参数
|
||||||
|
private heroDatas: { node: Node, anim: Animation | null, startX: number, phase: number }[] = [];
|
||||||
|
|
||||||
|
onLoad() {
|
||||||
|
const heroes = [this.hero1, this.hero2, this.hero3, this.hero4, this.hero5];
|
||||||
|
|
||||||
|
heroes.forEach(heroNode => {
|
||||||
|
if (heroNode) {
|
||||||
|
// 查找名为 "h" 的子节点
|
||||||
|
const hNode = heroNode.getChildByName("h");
|
||||||
|
let anim: Animation | null = null;
|
||||||
|
if (hNode) {
|
||||||
|
anim = hNode.getComponent(Animation);
|
||||||
|
// 确保有动画组件才尝试播放
|
||||||
|
if (anim && anim.clips && anim.clips.length > 0) {
|
||||||
|
anim.play("move");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.heroDatas.push({
|
||||||
|
node: heroNode,
|
||||||
|
anim: anim,
|
||||||
|
startX: heroNode.position.x, // 记录初始X位置
|
||||||
|
phase: Math.random() * Math.PI * 2 // 随机初始相位
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update(dt: number) {
|
||||||
|
this.timer += dt;
|
||||||
|
|
||||||
|
this.heroDatas.forEach(data => {
|
||||||
|
if (!data.node) return;
|
||||||
|
|
||||||
|
// 设置周期为 4 秒 (例如:1秒加速向右,1秒减速回原点,1秒减速向左,1秒加速回原点)
|
||||||
|
// 使用正弦波控制速度,余弦波控制位移(因为速度是位移的导数)
|
||||||
|
const cycleDuration = 4;
|
||||||
|
const frequency = (Math.PI * 2) / cycleDuration;
|
||||||
|
|
||||||
|
// 速度倍率,范围在 0.9 ~ 1.1 之间波动
|
||||||
|
// sin 波形在 4秒周期内,正负各占 2秒
|
||||||
|
const speedMultiplier = 1.0 + Math.sin(this.timer * frequency + data.phase) * 0.1;
|
||||||
|
|
||||||
|
// 调整动画的播放速度
|
||||||
|
if (data.anim) {
|
||||||
|
// 检查状态是否存在,以避免没有播放动画时的错误
|
||||||
|
const state = data.anim.getState("move");
|
||||||
|
if (state && state.isPlaying) {
|
||||||
|
state.speed = speedMultiplier;
|
||||||
|
} else if (data.anim.clips && data.anim.clips.length > 0) {
|
||||||
|
// 如果停止了,尝试重新播放
|
||||||
|
data.anim.play("move");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据时间计算位置偏移量
|
||||||
|
// 使用 -cos 函数,使得当速度(sin)为最大时,位置在原点,
|
||||||
|
// 积分关系:速度 v = A * sin(wt),位移 s = - (A/w) * cos(wt)
|
||||||
|
// 这样能保证在一个周期内它始终围绕原点往复运动,最终回到原始点
|
||||||
|
const maxOffset = 30; // 左右偏离原点的最大像素距离
|
||||||
|
const currentOffset = -Math.cos(this.timer * frequency + data.phase) * maxOffset;
|
||||||
|
|
||||||
|
const pos = data.node.position;
|
||||||
|
// 相对于初始点进行位置设置,确保周期性回到原始点
|
||||||
|
data.node.setPosition(new Vec3(data.startX + currentOffset, pos.y, pos.z));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
9
assets/script/game/map/HeroMoveComp.ts.meta
Normal file
9
assets/script/game/map/HeroMoveComp.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "46ae5df5-c745-4689-bef6-f2300a78d15e",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user