Commit 3aaa6993 authored by haiyoucuv's avatar haiyoucuv

init

parent a0ce4989
......@@ -41,6 +41,15 @@ export class AISnake extends Snake {
private assistTarget: AISnake = null; // 正在协助的AI蛇
death() {
super.death();
this.node.removeFromParent();
this.destroy();
MainGame.ins.initAnimal(1);
}
private get difficultyParams() {
return {
reactionTime: math.lerp(0.8, 0.2, (this.difficulty - 1) / 4),
......@@ -560,7 +569,7 @@ export class AISnake extends Snake {
}
private executeEscaping() {
if (!this.escapeTarget) {
if (!this.escapeTarget?.isLife) {
// 如果没有特定的逃离目标,检查并避开所有潜在威胁
this.avoidAllThreats();
return;
......
import {
_decorator,
Collider2D,
Component,
Contact2DType,
math,
Node,
PhysicsGroup,
Prefab,
Sprite,
SpriteFrame,
tween,
v2,
v3,
Vec3,
_decorator,
Collider2D,
Component,
Contact2DType,
math,
Node,
PhysicsGroup,
Prefab,
Sprite,
SpriteFrame,
tween,
v2,
v3,
Vec3,
} from "cc";
import { FoodType } from "./Enums";
import { Global } from "./Global";
......@@ -26,341 +26,344 @@ import { BuffType } from "./Buff/BuffType";
const { ccclass, property } = _decorator;
export interface IInitConfig {
x?: number;
y?: number;
angle?: number;
skinName?: string;
scale?: number;
bodyCount?: number;
x?: number;
y?: number;
angle?: number;
skinName?: string;
scale?: number;
bodyCount?: number;
}
@ccclass("Snake")
export class Snake extends Component {
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);
}
static tag: number = 0;
this.isLife = true;
this.ready = true;
}
async setSkin(skinName: string) {
const skin = await loadSkin(skinName);
this.imgHead = skin.getSpriteFrame("head");
this.imgBody1 = skin.getSpriteFrame("body1");
this.imgBody2 = skin.getSpriteFrame("body2");
}
onEnable() {
const collider = this.head.getComponent(Collider2D);
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);
const eye = this.head.getChildByName("范围").getComponent(Collider2D);
eye.on(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
}
onDisable() {
const collider = this.head.getComponent(Collider2D);
collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);
const eye = this.head.getChildByName("范围").getComponent(Collider2D);
eye.off(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
}
// 碰撞检测
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();
// 属性装饰器
@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;
}
}
// 能量与成长
private addEnergy(value: number) {
this.energy += value;
const growthThreshold = Math.floor(10 * this.scale);
// 初始化方法
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);
if (this.energy >= growthThreshold) {
this.grow();
this.energy -= growthThreshold;
// 设置身体部分的贴图
body.getComponent(Sprite).spriteFrame = i % 2 == 0 ? this.imgBody1 : this.imgBody2;
if (this.scale < 0.8) {
this.scale += 0.005;
}
this.speed = 600 * this.scale;
body.active = false;
this.bodyArr.push(body);
}
this.isLife = true;
this.ready = true;
}
}
// 蛇身体生长
private grow() {
const len = this.bodyArr.length;
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);
async setSkin(skinName: string) {
const skin = await loadSkin(skinName);
this.imgHead = skin.getSpriteFrame("head");
this.imgBody1 = skin.getSpriteFrame("body1");
this.imgBody2 = skin.getSpriteFrame("body2");
}
newBody.getComponent(Sprite).spriteFrame = len % 2 == 0 ? this.imgBody1 : this.imgBody2;
newBody.getComponent(Collider2D).tag = this.tag;
onEnable() {
const collider = this.head.getComponent(Collider2D);
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);
newBody.active = isIntersect(
newBody.getPosition(),
this.head.getPosition(),
this.vw,
this.vh
);
const eye = this.head.getChildByName("范围").getComponent(Collider2D);
eye.on(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
}
this.bodyArr.splice(len, 0, newBody);
}
onDisable() {
const collider = this.head.getComponent(Collider2D);
collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);
setAngle(angle: number) {
this.isLife && (this.head.angle = angle);
}
const eye = this.head.getChildByName("范围").getComponent(Collider2D);
eye.off(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
}
isFast = false;
private positions: Vec3[] = []; // 存储历史位置点
private readonly HISTORY_LENGTH = 100; // 增加历史点数量
private readonly SEGMENT_SPACING = 5; // 增加节点间距
// 碰撞检测
private onBeginHead(selfCollider: Collider2D, otherCollider: Collider2D) {
if (otherCollider.group === PhysicsGroup["Body"] && otherCollider.tag != this.tag) {
this.death();
}
}
moveTime = 1 / 60;
totalTime = 0;
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 (!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.isFast) {
speedScale += 1;
if (this.scale < 0.8) {
this.scale += 0.005;
}
this.speed = 600 * this.scale;
}
}
this.totalTime += dt * speedScale;
while (this.totalTime >= this.moveTime) {
this.totalTime -= this.moveTime;
this.move(this.moveTime);
// 蛇身体生长
private grow() {
const len = this.bodyArr.length;
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) {
if (!this.ready || !this.isLife) {
return;
setAngle(angle: number) {
this.isLife && (this.head.angle = angle);
}
// 更新头部位置
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();
isFast = false;
private positions: Vec3[] = []; // 存储历史位置点
private readonly HISTORY_LENGTH = 100; // 增加历史点数量
private readonly SEGMENT_SPACING = 5; // 增加节点间距
moveTime = 1 / 60;
totalTime = 0;
onUpdate(dt: number) {
this.buffManager.update(dt);
let speedScale = 1;
if (this.isFast) {
speedScale += 1;
}
this.totalTime += dt * speedScale;
while (this.totalTime >= this.moveTime) {
this.totalTime -= this.moveTime;
this.move(this.moveTime);
}
}
// 更新身体节点位置
for (let i = 0; i < this.bodyArr.length; i++) {
const body = this.bodyArr[i];
protected move(dt: number) {
if (!this.ready || !this.isLife) {
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) {
const targetPos = this.positions[offset];
// 更新身体节点位置
for (let i = 0; i < this.bodyArr.length; i++) {
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 prevPos = this.positions[offset - 1];
body.angle = Math.atan2(
targetPos.y - prevPos.y,
targetPos.x - prevPos.x
) * 180 / Math.PI;
// 边界检查
const mapHalfWidth = Global.MAP_WIDTH / 2;
const mapHalfHeight = Global.MAP_HEIGHT / 2;
if (
newHeadPos.x <= -mapHalfWidth || newHeadPos.x >= mapHalfWidth ||
newHeadPos.y <= -mapHalfHeight || newHeadPos.y >= mapHalfHeight
) {
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(
targetPos,
this.head.getPosition(),
this.vw,
this.vh
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;
}
// 边界检查
const mapHalfWidth = Global.MAP_WIDTH / 2;
const mapHalfHeight = Global.MAP_HEIGHT / 2;
if (
newHeadPos.x <= -mapHalfWidth || newHeadPos.x >= mapHalfWidth ||
newHeadPos.y <= -mapHalfHeight || newHeadPos.y >= mapHalfHeight
) {
this.death();
private buffManager: BuffManager = new BuffManager(this);
private isInvincible: boolean = false;
private speedMultiplier: number = 1;
onLoad() {
// ... 其他初始化代码 ...
this.buffManager = new BuffManager(this);
}
}
getSnakeLen() {
return this.bodyArr.length;
}
// 死亡处理
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的便捷方法
addBuff(type: BuffType, duration?: number, value?: number) {
const buff = this.buffManager.createBuff(type, duration, value);
if (buff) {
this.buffManager.addBuff(buff);
}
}
}
// 提供给Buff使用的方法
setInvincible(value: boolean) {
this.isInvincible = value;
}
// 提供给Buff使用的方法
setInvincible(value: boolean) {
this.isInvincible = value;
}
setSpeedMultiplier(value: number) {
this.speedMultiplier = value;
}
setSpeedMultiplier(value: number) {
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