Commit 3aaa6993 authored by haiyoucuv's avatar haiyoucuv

init

parent a0ce4989
...@@ -41,6 +41,15 @@ export class AISnake extends Snake { ...@@ -41,6 +41,15 @@ export class AISnake extends Snake {
private assistTarget: AISnake = null; // 正在协助的AI蛇 private assistTarget: AISnake = null; // 正在协助的AI蛇
death() {
super.death();
this.node.removeFromParent();
this.destroy();
MainGame.ins.initAnimal(1);
}
private get difficultyParams() { private get difficultyParams() {
return { return {
reactionTime: math.lerp(0.8, 0.2, (this.difficulty - 1) / 4), reactionTime: math.lerp(0.8, 0.2, (this.difficulty - 1) / 4),
...@@ -560,7 +569,7 @@ export class AISnake extends Snake { ...@@ -560,7 +569,7 @@ export class AISnake extends Snake {
} }
private executeEscaping() { private executeEscaping() {
if (!this.escapeTarget) { if (!this.escapeTarget?.isLife) {
// 如果没有特定的逃离目标,检查并避开所有潜在威胁 // 如果没有特定的逃离目标,检查并避开所有潜在威胁
this.avoidAllThreats(); this.avoidAllThreats();
return; return;
......
import { import {
_decorator, _decorator,
Collider2D, Collider2D,
Component, Component,
Contact2DType, Contact2DType,
math, math,
Node, Node,
PhysicsGroup, PhysicsGroup,
Prefab, Prefab,
Sprite, Sprite,
SpriteFrame, SpriteFrame,
tween, tween,
v2, v2,
v3, v3,
Vec3, Vec3,
} from "cc"; } from "cc";
import { FoodType } from "./Enums"; import { FoodType } from "./Enums";
import { Global } from "./Global"; import { Global } from "./Global";
...@@ -26,341 +26,344 @@ import { BuffType } from "./Buff/BuffType"; ...@@ -26,341 +26,344 @@ import { BuffType } from "./Buff/BuffType";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
export interface IInitConfig { export interface IInitConfig {
x?: number; x?: number;
y?: number; y?: number;
angle?: number; angle?: number;
skinName?: string; skinName?: string;
scale?: number; scale?: number;
bodyCount?: number; bodyCount?: number;
} }
@ccclass("Snake") @ccclass("Snake")
export class Snake extends Component { export class Snake extends Component {
static tag: number = 0; static tag: number = 0;
// 属性装饰器
@property({ type: Node, displayName: "头部" }) head: Node = null;
@property(Prefab) bodyPrefab: Prefab = null;
// 私有成员变量
bodyArr: Node[] = [];
private imgHead: SpriteFrame = null;
private imgBody1: SpriteFrame = null;
private imgBody2: SpriteFrame = null;
// 蛇的状态
isLife: boolean = false;
private scale: number = 0.2;
speed: number = 600;
private energy: number = 0;
private tag: number = 0;
// 位置相关
private vw: number = Global.visibleSize.width / 2 + 100;
private vh: number = Global.visibleSize.height / 2 + 100;
private ready: boolean = false;
get radius() {
return this.scale * 50;
}
// 初始化方法
public async init(config: IInitConfig = {}) {
const {
x = 0, y = 0, angle = 0, scale = 0.2,
skinName = "default", bodyCount = 5,
} = config;
await this.setSkin(skinName);
this.ready = false;
this.energy = 0;
this.bodyArr = [];
this.scale = scale;
this.speed = this.speed * scale;
this.tag = Snake.tag++;
// 设置头部
this.head.angle = angle;
this.head.setPosition(x, y);
this.head.setScale(scale, scale);
this.head.getComponent(Sprite).spriteFrame = this.imgHead;
// 创建身体节点
for (let i = 0; i < bodyCount; i++) {
const body = PoolManager.instance.getNode(this.bodyPrefab, this.node);
const collider = body.getComponent(Collider2D);
collider.tag = this.tag;
body.angle = angle;
body.setPosition(-99999, -99999);
body.setScale(scale, scale);
// 设置身体部分的贴图
body.getComponent(Sprite).spriteFrame = i % 2 == 0 ? this.imgBody1 : this.imgBody2;
body.active = false;
this.bodyArr.push(body);
}
this.isLife = true; // 属性装饰器
this.ready = true; @property({ type: Node, displayName: "头部" }) head: Node = null;
}
@property(Prefab) bodyPrefab: Prefab = null;
async setSkin(skinName: string) {
const skin = await loadSkin(skinName); // 私有成员变量
this.imgHead = skin.getSpriteFrame("head"); bodyArr: Node[] = [];
this.imgBody1 = skin.getSpriteFrame("body1"); private imgHead: SpriteFrame = null;
this.imgBody2 = skin.getSpriteFrame("body2"); private imgBody1: SpriteFrame = null;
} private imgBody2: SpriteFrame = null;
onEnable() { // 蛇的状态
const collider = this.head.getComponent(Collider2D); isLife: boolean = false;
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this); private scale: number = 0.2;
speed: number = 600;
const eye = this.head.getChildByName("范围").getComponent(Collider2D); private energy: number = 0;
eye.on(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this); private tag: number = 0;
}
// 位置相关
onDisable() { private vw: number = Global.visibleSize.width / 2 + 100;
const collider = this.head.getComponent(Collider2D); private vh: number = Global.visibleSize.height / 2 + 100;
collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this); private ready: boolean = false;
const eye = this.head.getChildByName("范围").getComponent(Collider2D); get radius() {
eye.off(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this); return this.scale * 50;
}
// 碰撞检测
private onBeginHead(selfCollider: Collider2D, otherCollider: Collider2D) {
if (otherCollider.group === PhysicsGroup["Body"] && otherCollider.tag != this.tag) {
this.death();
}
}
private onBeginEye(selfCollider: Collider2D, otherCollider: Collider2D) {
if (otherCollider.group === PhysicsGroup["Prop"]) {
const foodType = otherCollider.tag;
// 食物吃掉的动画
tween(otherCollider.node)
.to(0.3, {
position: this.head.getPosition(),
scale: v3(0, 0)
})
.call(() => {
PoolManager.instance.putNode(otherCollider.node);
if (foodType == FoodType.FOOD) {
this.addEnergy(1);
}
})
.start();
} }
}
// 能量与成长 // 初始化方法
private addEnergy(value: number) { public async init(config: IInitConfig = {}) {
this.energy += value;
const growthThreshold = Math.floor(10 * this.scale); const {
x = 0, y = 0, angle = 0, scale = 0.2,
skinName = "default", bodyCount = 5,
} = config;
await this.setSkin(skinName);
this.ready = false;
this.energy = 0;
this.bodyArr = [];
this.scale = scale;
this.speed = this.speed * scale;
this.tag = Snake.tag++;
// 设置头部
this.head.angle = angle;
this.head.setPosition(x, y);
this.head.setScale(scale, scale);
this.head.getComponent(Sprite).spriteFrame = this.imgHead;
// 创建身体节点
for (let i = 0; i < bodyCount; i++) {
const body = PoolManager.instance.getNode(this.bodyPrefab, this.node);
const collider = body.getComponent(Collider2D);
collider.tag = this.tag;
body.angle = angle;
body.setPosition(-99999, -99999);
body.setScale(scale, scale);
if (this.energy >= growthThreshold) { // 设置身体部分的贴图
this.grow(); body.getComponent(Sprite).spriteFrame = i % 2 == 0 ? this.imgBody1 : this.imgBody2;
this.energy -= growthThreshold;
if (this.scale < 0.8) { body.active = false;
this.scale += 0.005; this.bodyArr.push(body);
} }
this.speed = 600 * this.scale;
this.isLife = true;
this.ready = true;
} }
}
// 蛇身体生长 async setSkin(skinName: string) {
private grow() { const skin = await loadSkin(skinName);
const len = this.bodyArr.length; this.imgHead = skin.getSpriteFrame("head");
const newBody = PoolManager.instance.getNode(this.bodyPrefab, this.node); this.imgBody1 = skin.getSpriteFrame("body1");
newBody.angle = this.bodyArr[len - 1].angle; this.imgBody2 = skin.getSpriteFrame("body2");
newBody.setPosition(this.bodyArr[len - 1].getPosition()); }
newBody.setScale(this.scale, this.scale);
newBody.getComponent(Sprite).spriteFrame = len % 2 == 0 ? this.imgBody1 : this.imgBody2; onEnable() {
newBody.getComponent(Collider2D).tag = this.tag; const collider = this.head.getComponent(Collider2D);
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);
newBody.active = isIntersect( const eye = this.head.getChildByName("范围").getComponent(Collider2D);
newBody.getPosition(), eye.on(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
this.head.getPosition(), }
this.vw,
this.vh
);
this.bodyArr.splice(len, 0, newBody); onDisable() {
} const collider = this.head.getComponent(Collider2D);
collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);
setAngle(angle: number) { const eye = this.head.getChildByName("范围").getComponent(Collider2D);
this.isLife && (this.head.angle = angle); eye.off(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
} }
isFast = false; // 碰撞检测
private positions: Vec3[] = []; // 存储历史位置点 private onBeginHead(selfCollider: Collider2D, otherCollider: Collider2D) {
private readonly HISTORY_LENGTH = 100; // 增加历史点数量 if (otherCollider.group === PhysicsGroup["Body"] && otherCollider.tag != this.tag) {
private readonly SEGMENT_SPACING = 5; // 增加节点间距 this.death();
}
}
moveTime = 1 / 60; private onBeginEye(selfCollider: Collider2D, otherCollider: Collider2D) {
totalTime = 0; if (otherCollider.group === PhysicsGroup["Prop"]) {
const foodType = otherCollider.tag;
// 食物吃掉的动画
tween(otherCollider.node)
.to(0.3, {
position: this.head.getPosition(),
scale: v3(0, 0)
})
.call(() => {
PoolManager.instance.putNode(otherCollider.node);
if (!this.isLife) return;
if (foodType == FoodType.FOOD) {
this.addEnergy(1);
}
})
.start();
}
}
onUpdate(dt: number) { // 能量与成长
private addEnergy(value: number) {
this.energy += value;
const growthThreshold = Math.floor(10 * this.scale);
this.buffManager.update(dt); if (this.energy >= growthThreshold) {
this.grow();
this.energy -= growthThreshold;
let speedScale = 1; if (this.scale < 0.8) {
if (this.isFast) { this.scale += 0.005;
speedScale += 1; }
this.speed = 600 * this.scale;
}
} }
this.totalTime += dt * speedScale; // 蛇身体生长
while (this.totalTime >= this.moveTime) { private grow() {
this.totalTime -= this.moveTime; const len = this.bodyArr.length;
this.move(this.moveTime); const newBody = PoolManager.instance.getNode(this.bodyPrefab, this.node);
newBody.angle = this.bodyArr[len - 1].angle;
newBody.setPosition(this.bodyArr[len - 1].getPosition());
newBody.setScale(this.scale, this.scale);
newBody.getComponent(Sprite).spriteFrame = len % 2 == 0 ? this.imgBody1 : this.imgBody2;
newBody.getComponent(Collider2D).tag = this.tag;
newBody.active = isIntersect(
newBody.getPosition(),
this.head.getPosition(),
this.vw,
this.vh
);
this.bodyArr.splice(len, 0, newBody);
} }
}
protected move(dt: number) { setAngle(angle: number) {
if (!this.ready || !this.isLife) { this.isLife && (this.head.angle = angle);
return;
} }
// 更新头部位置 isFast = false;
const newHeadPos = this.getNewPos( private positions: Vec3[] = []; // 存储历史位置点
this.head.angle, private readonly HISTORY_LENGTH = 100; // 增加历史点数量
dt, private readonly SEGMENT_SPACING = 5; // 增加节点间距
this.head.getPosition()
); moveTime = 1 / 60;
this.head.setPosition(newHeadPos); totalTime = 0;
this.head.setScale(this.scale, this.scale);
onUpdate(dt: number) {
// 存储历史位置
this.positions.unshift(newHeadPos.clone()); this.buffManager.update(dt);
// 确保历史位置点足够多,以容纳所有身体节点
const requiredLength = this.bodyArr.length * this.SEGMENT_SPACING + 1; let speedScale = 1;
if (this.positions.length > Math.max(requiredLength, this.HISTORY_LENGTH)) { if (this.isFast) {
this.positions.pop(); speedScale += 1;
}
this.totalTime += dt * speedScale;
while (this.totalTime >= this.moveTime) {
this.totalTime -= this.moveTime;
this.move(this.moveTime);
}
} }
// 更新身体节点位置 protected move(dt: number) {
for (let i = 0; i < this.bodyArr.length; i++) { if (!this.ready || !this.isLife) {
const body = this.bodyArr[i]; return;
}
// 为每个节点计算一个固定的偏移量 // 更新头部位置
const offset = (i + 1) * this.SEGMENT_SPACING; const newHeadPos = this.getNewPos(
this.head.angle,
dt,
this.head.getPosition()
);
this.head.setPosition(newHeadPos);
this.head.setScale(this.scale, this.scale);
// 存储历史位置
this.positions.unshift(newHeadPos.clone());
// 确保历史位置点足够多,以容纳所有身体节点
const requiredLength = this.bodyArr.length * this.SEGMENT_SPACING + 1;
if (this.positions.length > Math.max(requiredLength, this.HISTORY_LENGTH)) {
this.positions.pop();
}
// 确保不会超出历史位置数组范围 // 更新身体节点位置
if (offset < this.positions.length) { for (let i = 0; i < this.bodyArr.length; i++) {
const targetPos = this.positions[offset]; const body = this.bodyArr[i];
// 为每个节点计算一个固定的偏移量
const offset = (i + 1) * this.SEGMENT_SPACING;
// 确保不会超出历史位置数组范围
if (offset < this.positions.length) {
const targetPos = this.positions[offset];
// 计算角度
if (offset > 0) {
const prevPos = this.positions[offset - 1];
body.angle = Math.atan2(
targetPos.y - prevPos.y,
targetPos.x - prevPos.x
) * 180 / Math.PI;
}
body.setPosition(targetPos);
body.setScale(this.scale, this.scale);
body.setSiblingIndex(this.bodyArr.length - i);
body.active = isIntersect(
targetPos,
this.head.getPosition(),
this.vw,
this.vh
);
}
}
// 计算角度 // 边界检查
if (offset > 0) { const mapHalfWidth = Global.MAP_WIDTH / 2;
const prevPos = this.positions[offset - 1]; const mapHalfHeight = Global.MAP_HEIGHT / 2;
body.angle = Math.atan2( if (
targetPos.y - prevPos.y, newHeadPos.x <= -mapHalfWidth || newHeadPos.x >= mapHalfWidth ||
targetPos.x - prevPos.x newHeadPos.y <= -mapHalfHeight || newHeadPos.y >= mapHalfHeight
) * 180 / Math.PI; ) {
this.death();
} }
body.setPosition(targetPos); }
body.setScale(this.scale, this.scale);
body.setSiblingIndex(this.bodyArr.length - i); getSnakeLen() {
return this.bodyArr.length;
}
// 死亡处理
public death() {
if (!this.isLife) return;
this.isLife = false;
this.node.active = false;
body.active = isIntersect( this.initFond(this.bodyArr.length);
targetPos,
this.head.getPosition(), }
this.vw,
this.vh protected getNewPos(angle: number, dt: number, currentPos: Vec3, speed: number = this.speed): Vec3 {
const radian = angle / 180 * Math.PI;
const direction = v2(Math.cos(radian), Math.sin(radian));
return v3(currentPos.x + dt * direction.x * speed, currentPos.y + dt * direction.y * speed, 0);
}
/**
* 初始化食物
*/
initItem = (index: number) => {
const bp = this.bodyArr[index].getPosition();
MainGame.ins.fondManger.addFood(
math.randomRangeInt(bp.x - 10, bp.x + 11),
math.randomRangeInt(bp.y - 20, bp.y + 21)
); );
} this.bodyArr[index].setPosition(9999, 9999);
this.bodyArr[index].active = false;
};
/**
* 初始化食物
*/
async initFond(count: number) {
await executePreFrame(getItemGenerator(count, this.initItem), 1, this);
this.ready = true;
} }
// 边界检查
const mapHalfWidth = Global.MAP_WIDTH / 2; private buffManager: BuffManager = new BuffManager(this);
const mapHalfHeight = Global.MAP_HEIGHT / 2; private isInvincible: boolean = false;
if ( private speedMultiplier: number = 1;
newHeadPos.x <= -mapHalfWidth || newHeadPos.x >= mapHalfWidth ||
newHeadPos.y <= -mapHalfHeight || newHeadPos.y >= mapHalfHeight onLoad() {
) { // ... 其他初始化代码 ...
this.death(); this.buffManager = new BuffManager(this);
} }
} // 添加Buff的便捷方法
addBuff(type: BuffType, duration?: number, value?: number) {
getSnakeLen() { const buff = this.buffManager.createBuff(type, duration, value);
return this.bodyArr.length; if (buff) {
} this.buffManager.addBuff(buff);
}
// 死亡处理
public death() {
if (!this.isLife) return;
this.isLife = false;
this.node.active = false;
this.initFond(this.bodyArr.length);
}
protected getNewPos(angle: number, dt: number, currentPos: Vec3, speed: number = this.speed): Vec3 {
const radian = angle / 180 * Math.PI;
const direction = v2(Math.cos(radian), Math.sin(radian));
return v3(currentPos.x + dt * direction.x * speed, currentPos.y + dt * direction.y * speed, 0);
}
/**
* 初始化食物
*/
initItem = (index: number) => {
const bp = this.bodyArr[index].getPosition();
MainGame.ins.fondManger.addFood(
math.randomRangeInt(bp.x - 10, bp.x + 11),
math.randomRangeInt(bp.y - 20, bp.y + 21)
);
this.bodyArr[index].setPosition(9999, 9999);
this.bodyArr[index].active = false;
};
/**
* 初始化食物
*/
async initFond(count: number) {
await executePreFrame(getItemGenerator(count, this.initItem), 1, this);
this.ready = true;
}
private buffManager: BuffManager = new BuffManager(this);
private isInvincible: boolean = false;
private speedMultiplier: number = 1;
onLoad() {
// ... 其他初始化代码 ...
this.buffManager = new BuffManager(this);
}
// 添加Buff的便捷方法
addBuff(type: BuffType, duration?: number, value?: number) {
const buff = this.buffManager.createBuff(type, duration, value);
if (buff) {
this.buffManager.addBuff(buff);
} }
}
// 提供给Buff使用的方法 // 提供给Buff使用的方法
setInvincible(value: boolean) { setInvincible(value: boolean) {
this.isInvincible = value; this.isInvincible = value;
} }
setSpeedMultiplier(value: number) { setSpeedMultiplier(value: number) {
this.speedMultiplier = value; this.speedMultiplier = value;
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment