Commit 24b4bd2f authored by haiyoucuv's avatar haiyoucuv

init

parent 8e3d82ba
...@@ -20,7 +20,8 @@ export class AISnake extends Snake { ...@@ -20,7 +20,8 @@ export class AISnake extends Snake {
range: [1, 5], range: [1, 5],
tooltip: "AI难度(1-5)" tooltip: "AI难度(1-5)"
}) })
private difficulty: number = 5; // private difficulty: number = 5;
private difficulty: number = 1 + Math.random() * 4;
private currentState: AIState = AIState.WANDERING; private currentState: AIState = AIState.WANDERING;
private behaviorTimer: number = 0; private behaviorTimer: number = 0;
...@@ -31,7 +32,7 @@ export class AISnake extends Snake { ...@@ -31,7 +32,7 @@ export class AISnake extends Snake {
private readonly BASE_VIEW_DISTANCE = 300; private readonly BASE_VIEW_DISTANCE = 300;
private readonly INTERCEPT_DISTANCE = 350; // 降低拦截距离 private readonly INTERCEPT_DISTANCE = 350; // 降低拦截距离
private readonly PREDICTION_TIME = 1.2; // 增加预测时间 private readonly PREDICTION_TIME = 1.2; // 增加预测时间
private readonly ESCAPE_BOUNDARY = 250; // 增加边界安全距离 private readonly ESCAPE_BOUNDARY = 150; // 增加边界安全距离
private readonly SAFE_MARGIN = 3.0; // 增加安全边际 private readonly SAFE_MARGIN = 3.0; // 增加安全边际
private readonly COLLISION_CHECK_DISTANCE = 500; // 增加碰撞检测距离 private readonly COLLISION_CHECK_DISTANCE = 500; // 增加碰撞检测距离
private readonly ASSIST_DISTANCE = 500; // 协助攻击的最大距离 private readonly ASSIST_DISTANCE = 500; // 协助攻击的最大距离
...@@ -49,12 +50,13 @@ export class AISnake extends Snake { ...@@ -49,12 +50,13 @@ export class AISnake extends Snake {
} }
onBeginEye(selfCollider: Collider2D, otherCollider: Collider2D){ onBeginEye(selfCollider: Collider2D, otherCollider: Collider2D) {
super.onBeginEye(selfCollider, otherCollider); super.onBeginEye(selfCollider, otherCollider);
if (otherCollider.group === PhysicsGroup["Body"] && otherCollider.tag != this.tag) { if (otherCollider.group === PhysicsGroup["Body"] && otherCollider.tag != this.tag) {
// 碰到其他蛇身 // 碰到其他蛇身
this.setAngle(this.head.angle + 180); // this.setAngle(this.head.angle + 180);
this.isFast = true; // this.isFast = true;
this.setState(AIState.ESCAPING, otherCollider.node.parent.getComponent(Snake));
} }
} }
...@@ -69,10 +71,10 @@ export class AISnake extends Snake { ...@@ -69,10 +71,10 @@ export class AISnake extends Snake {
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.15, (this.difficulty - 1) / 4),
viewDistance: this.BASE_VIEW_DISTANCE * (1 + (this.difficulty - 1) * 0.2), viewDistance: this.BASE_VIEW_DISTANCE * (1 + (this.difficulty - 1) * 0.2),
interceptDistance: this.INTERCEPT_DISTANCE * (1 + (this.difficulty - 1) * 0.2), interceptDistance: this.INTERCEPT_DISTANCE * (1 + (this.difficulty - 1) * 0.2),
aggressiveness: math.lerp(0.2, 0.7, (this.difficulty - 1) / 4), // 降低激进程度 aggressiveness: math.lerp(0.2, 0.7, (this.difficulty - 1) / 4), // 攻击性
predictionAccuracy: math.lerp(0.6, 0.9, (this.difficulty - 1) / 4), predictionAccuracy: math.lerp(0.6, 0.9, (this.difficulty - 1) / 4),
turnSpeed: math.lerp(2, 4.5, (this.difficulty - 1) / 4) // 略微降低最大转向速度 turnSpeed: math.lerp(2, 4.5, (this.difficulty - 1) / 4) // 略微降低最大转向速度
}; };
...@@ -129,10 +131,10 @@ export class AISnake extends Snake { ...@@ -129,10 +131,10 @@ export class AISnake extends Snake {
} }
// 默认追击玩家 // 默认追击玩家
if (player && player.isLife && if (player && player.isLife
Vec3.distance(myPos, player.head.getPosition()) < this.BASE_VIEW_DISTANCE && // 只在较近距离时考虑追击 && Vec3.distance(myPos, player.head.getPosition()) < this.BASE_VIEW_DISTANCE // 只在较近距离时考虑追击
this.getSnakeLen() > player.getSnakeLen() * 0.8 && // 保持一定实力优势 && this.getSnakeLen() > player.getSnakeLen() * 0.8 // 保持一定实力优势
math.random() < this.difficultyParams.aggressiveness * 0.6) { // 降低追击概率 && math.random() < this.difficultyParams.aggressiveness * 0.6) { // 追击概率
this.setState(AIState.INTERCEPTING, player); this.setState(AIState.INTERCEPTING, player);
} else { } else {
this.setState(AIState.WANDERING, null); this.setState(AIState.WANDERING, null);
...@@ -141,7 +143,7 @@ export class AISnake extends Snake { ...@@ -141,7 +143,7 @@ export class AISnake extends Snake {
// 判断是否在极度危险的位置(非常靠近边界) // 判断是否在极度危险的位置(非常靠近边界)
private isInDangerousPosition(position: Vec3): boolean { private isInDangerousPosition(position: Vec3): boolean {
const dangerBuffer = this.ESCAPE_BOUNDARY * 0.5; // 减小危险区域范围 const dangerBuffer = this.ESCAPE_BOUNDARY; // 减小危险区域范围
const mapWidth = Global.MAP_WIDTH; const mapWidth = Global.MAP_WIDTH;
const mapHeight = Global.MAP_HEIGHT; const mapHeight = Global.MAP_HEIGHT;
...@@ -281,11 +283,21 @@ export class AISnake extends Snake { ...@@ -281,11 +283,21 @@ export class AISnake extends Snake {
// 执行原有状态逻辑 // 执行原有状态逻辑
switch (this.currentState) { switch (this.currentState) {
case AIState.HUNTING: this.executeHunting(); break; case AIState.HUNTING:
case AIState.INTERCEPTING: this.executeIntercepting(); break; this.executeHunting();
case AIState.ESCAPING: this.executeEscaping(); break; break;
case AIState.WANDERING: this.executeWandering(); break; case AIState.INTERCEPTING:
case AIState.ASSISTING: this.executeAssisting(); break; this.executeIntercepting();
break;
case AIState.ESCAPING:
this.executeEscaping();
break;
case AIState.WANDERING:
this.executeWandering();
break;
case AIState.ASSISTING:
this.executeAssisting();
break;
} }
} }
...@@ -486,7 +498,7 @@ export class AISnake extends Snake { ...@@ -486,7 +498,7 @@ export class AISnake extends Snake {
} }
// 寻找需要躲避的附近AI // 寻找需要躲避的附近AI
private findNearbyAIToAvoid(): { snake: Snake, dangerLevel: number, canCounter: boolean } | null { private findNearbyAIToAvoid(): { snake: Snake, dangerLevel: number } | null {
const myPos = this.head.getPosition(); const myPos = this.head.getPosition();
const myFuturePos = this.predictFuturePosition(myPos, this.head.angle, this.speed * 2); const myFuturePos = this.predictFuturePosition(myPos, this.head.angle, this.speed * 2);
let maxDanger = 0; let maxDanger = 0;
...@@ -560,21 +572,10 @@ export class AISnake extends Snake { ...@@ -560,21 +572,10 @@ export class AISnake extends Snake {
} }
} }
// 评估是否可以反击
if (mostDangerousSnake) {
const threatLength = mostDangerousSnake.getSnakeLen();
const lengthAdvantage = myLength / threatLength;
const distance = Vec3.distance(myPos, mostDangerousSnake.head.getPosition());
const isSafeDistance = distance > this.COLLISION_CHECK_DISTANCE * this.SAFE_DISTANCE_MULTIPLIER;
canCounterAttack = lengthAdvantage > this.COUNTER_ATTACK_THRESHOLD && isSafeDistance;
}
// 降低触发避让的阈值,使AI更容易进入避让状态 // 降低触发避让的阈值,使AI更容易进入避让状态
return maxDanger > 15 ? { return maxDanger > 15 ? {
snake: mostDangerousSnake, snake: mostDangerousSnake,
dangerLevel: maxDanger, dangerLevel: maxDanger,
canCounter: canCounterAttack
} : null; } : null;
} }
...@@ -731,7 +732,7 @@ export class AISnake extends Snake { ...@@ -731,7 +732,7 @@ export class AISnake extends Snake {
private getDistanceToBoundary(position: Vec3): number { private getDistanceToBoundary(position: Vec3): number {
const mapWidth = Global.MAP_WIDTH; const mapWidth = Global.MAP_WIDTH;
const mapHeight = Global.MAP_HEIGHT; const mapHeight = Global.MAP_HEIGHT;
return Math.min( return Math.min(
mapWidth / 2 - Math.abs(position.x), mapWidth / 2 - Math.abs(position.x),
mapHeight / 2 - Math.abs(position.y) mapHeight / 2 - Math.abs(position.y)
...@@ -915,7 +916,7 @@ export class AISnake extends Snake { ...@@ -915,7 +916,7 @@ export class AISnake extends Snake {
// 判断是否能在竞争者之前到达食物 // 判断是否能在竞争者之前到达食物
private canReachFoodFirst(foodPos: Vec3, myDistance: number, competitors: Snake[]): boolean { private canReachFoodFirst(foodPos: Vec3, myDistance: number, competitors: Snake[]): boolean {
const mySpeed = this.speed * (this.isFast ? 2 : 1); const mySpeed = this.speed * this.moveScale;
const myTimeToReach = myDistance / mySpeed; const myTimeToReach = myDistance / mySpeed;
for (const competitor of competitors) { for (const competitor of competitors) {
......
import { _decorator } from "cc";
import { BuffType, BuffState } from "./BuffType";
import { Snake } from "../Snake";
const { ccclass, property } = _decorator;
@ccclass("BaseBuff")
export class BaseBuff {
protected type: BuffType = BuffType.NONE;
protected duration: number = 0;
protected remainTime: number = 0;
protected value: number = 0;
protected state: BuffState = BuffState.INACTIVE;
protected target: Snake = null;
constructor(type: BuffType, duration: number, value: number) {
this.type = type;
this.duration = duration;
this.remainTime = duration;
this.value = value;
}
// 激活Buff
activate(target: Snake): void {
this.target = target;
this.state = BuffState.ACTIVE;
this.onActivate();
}
// 更新Buff状态
update(dt: number): boolean {
if (this.state !== BuffState.ACTIVE) return false;
this.remainTime -= dt;
this.onUpdate(dt);
if (this.remainTime <= 0) {
this.deactivate();
return false;
}
return true;
}
// 停用Buff
deactivate(): void {
this.state = BuffState.FINISHED;
this.onDeactivate();
}
// 获取剩余时间
getRemainTime(): number {
return Math.max(0, this.remainTime);
}
// 获取Buff类型
getType(): BuffType {
return this.type;
}
// 获取Buff状态
getState(): BuffState {
return this.state;
}
// 获取Buff值
getValue(): number {
return this.value;
}
// 以下是子类需要实现的方法
protected onActivate(): void { }
protected onUpdate(dt: number): void { }
protected onDeactivate(): void { }
}
\ No newline at end of file
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "448e8ec0-47bb-488e-b80b-e52e93c7136f",
"files": [],
"subMetas": {},
"userData": {}
}
import { _decorator } from "cc";
import { BaseBuff } from "./BaseBuff";
import { BuffType } from "./BuffType";
import { Snake } from "../Snake";
import { ShieldBuff, SpeedUpBuff, MagnetBuff } from "./Buffs";
const { ccclass } = _decorator;
@ccclass("BuffManager")
export class BuffManager {
private buffs: Map<BuffType, BaseBuff> = new Map();
private target: Snake = null;
constructor(target: Snake) {
this.target = target;
}
// 添加Buff
addBuff(buff: BaseBuff): void {
const type = buff.getType();
// 如果已存在同类型Buff,先移除
if (this.buffs.has(type)) {
this.removeBuff(type);
}
this.buffs.set(type, buff);
buff.activate(this.target);
}
// 移除指定类型的Buff
removeBuff(type: BuffType): void {
const buff = this.buffs.get(type);
if (buff) {
buff.deactivate();
this.buffs.delete(type);
}
}
// 更新所有Buff
update(dt: number): void {
this.buffs.forEach((buff, type) => {
if (!buff.update(dt)) {
this.buffs.delete(type);
}
});
}
// 检查是否有某个Buff
hasBuff(type: BuffType): boolean {
return this.buffs.has(type);
}
// 获取Buff
getBuff(type: BuffType): BaseBuff | null {
return this.buffs.get(type) || null;
}
// 清除所有Buff
clearAll(): void {
this.buffs.forEach(buff => buff.deactivate());
this.buffs.clear();
}
// 获取所有激活的Buff
getActiveBuffs(): BaseBuff[] {
return Array.from(this.buffs.values());
}
// 创建Buff的便捷方法
createBuff(type: BuffType, duration?: number, value?: number): BaseBuff {
switch (type) {
case BuffType.SHIELD:
return new ShieldBuff(duration);
case BuffType.SPEED_UP:
return new SpeedUpBuff(duration, value);
case BuffType.MAGNET:
return new MagnetBuff(duration, value);
default:
return null;
}
}
}
\ No newline at end of file
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "1224d146-f247-4925-ba1c-eb35147e5b8f",
"files": [],
"subMetas": {},
"userData": {}
}
export enum BuffType {
NONE = 0,
SHIELD = 1, // 护盾
MAGNET = 2, // 磁铁
SPEED_UP = 3, // 加速
DOUBLE_SCORE = 4, // 双倍积分
INVINCIBLE = 5, // 无敌
FROZEN = 6, // 冰冻
// ... 可以继续添加更多类型
}
// Buff的一些通用状态
export enum BuffState {
INACTIVE = 0, // 未激活
ACTIVE = 1, // 激活中
FINISHED = 2 // 已结束
}
\ No newline at end of file
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "de21d110-11a6-4935-a4b4-1898a9fe6101",
"files": [],
"subMetas": {},
"userData": {}
}
import { BaseBuff } from "./BaseBuff";
import { BuffType } from "./BuffType";
// 护盾Buff
export class ShieldBuff extends BaseBuff {
constructor(duration: number = 10) {
super(BuffType.SHIELD, duration, 1);
}
protected onActivate(): void {
this.target.setInvincible(true);
}
protected onDeactivate(): void {
this.target.setInvincible(false);
}
}
// 加速Buff
export class SpeedUpBuff extends BaseBuff {
constructor(duration: number = 8, accPercent: number = 1.5) {
super(BuffType.SPEED_UP, duration, accPercent);
}
protected onActivate(): void {
this.target.setSpeedMultiplier(this.value);
}
protected onDeactivate(): void {
this.target.setSpeedMultiplier(1);
}
}
// 磁铁Buff
export class MagnetBuff extends BaseBuff {
constructor(duration: number = 15, range: number = 100) {
super(BuffType.MAGNET, duration, range);
}
protected onUpdate(dt: number): void {
// 在这里实现磁铁效果的逻辑
// 例如:吸引范围内的食物
}
}
\ No newline at end of file
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "aa216ae1-29cc-4cdc-bb17-86f9e1701160",
"files": [],
"subMetas": {},
"userData": {}
}
...@@ -4,33 +4,44 @@ const { ccclass, property } = _decorator; ...@@ -4,33 +4,44 @@ const { ccclass, property } = _decorator;
@ccclass("FastBtn") @ccclass("FastBtn")
export class FastBtn extends Component { export class FastBtn extends Component {
// 是否处于加速状态 // 是否处于加速状态
isFast: boolean = false; _isFast: boolean = false;
// 按钮精灵组件 // 是否处于加速状态
@property(Sprite) get isFast(): boolean {
sp: Sprite = null; return this._isFast;
}
// 按钮颜色状态
private c1 = new Color(255, 255, 255, 220); // 按下时的颜色 // 设置是否处于加速状态
private c2 = new Color(200, 200, 200, 200); // 松开时的颜色 set isFast(value: boolean) {
this._isFast = value;
onLoad() { this.node.emit("fast", value);
// 注册触摸事件 }
this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this); // 按钮精灵组件
this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this); @property(Sprite)
} sp: Sprite = null;
// 按下时的处理 // 按钮颜色状态
onTouchStart() { private c1 = new Color(255, 255, 255, 220); // 按下时的颜色
this.isFast = true; private c2 = new Color(200, 200, 200, 200); // 松开时的颜色
this.sp.color = this.c1;
} onLoad() {
// 注册触摸事件
// 松开时的处理 this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
onTouchEnd() { this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
this.isFast = false; this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
this.sp.color = this.c2; }
}
// 按下时的处理
onTouchStart() {
this.isFast = true;
this.sp.color = this.c2;
}
// 松开时的处理
onTouchEnd() {
this.isFast = false;
this.sp.color = this.c1;
}
} }
\ No newline at end of file
...@@ -22,11 +22,17 @@ export class Player extends Snake { ...@@ -22,11 +22,17 @@ export class Player extends Snake {
super.onLoad(); super.onLoad();
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this); input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.on(Input.EventType.KEY_UP, this.onKeyUp, this); input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
this.fastBtn.node.on("fast", this.onFast, this);
} }
onDestroy() { onDestroy() {
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this); input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.off(Input.EventType.KEY_UP, this.onKeyUp, this); input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
this.fastBtn.node.off("fast", this.onFast, this);
}
onFast(isFast: boolean) {
this.isFast = isFast;
} }
death() { death() {
...@@ -77,9 +83,6 @@ export class Player extends Snake { ...@@ -77,9 +83,6 @@ export class Player extends Snake {
onUpdate(dt: number) { onUpdate(dt: number) {
this.setAngle((360 - this.joystick.angle) % 360); this.setAngle((360 - this.joystick.angle) % 360);
this.isFast = this.fastBtn.isFast;
super.onUpdate(dt); super.onUpdate(dt);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"ver": "1.2.0", "ver": "1.2.0",
"importer": "directory", "importer": "directory",
"imported": true, "imported": true,
"uuid": "4fa63f7f-07d2-4949-b7aa-3f9827a3e8ce", "uuid": "37b804dc-24cb-428a-8adc-02385db11e69",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}
......
...@@ -20,8 +20,6 @@ import { PoolManager } from "./Manager/PoolManager"; ...@@ -20,8 +20,6 @@ import { PoolManager } from "./Manager/PoolManager";
import { isIntersect, loadSkin } from "./uitl"; import { isIntersect, loadSkin } from "./uitl";
import { MainGame } from "./MainGame"; import { MainGame } from "./MainGame";
import { executePreFrame, getItemGenerator } from "../../Utils/ExecutePreFrame"; import { executePreFrame, getItemGenerator } from "../../Utils/ExecutePreFrame";
import { BuffManager } from "./Buff/BuffManager";
import { BuffType } from "./Buff/BuffType";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
...@@ -212,17 +210,15 @@ export class Snake extends Component { ...@@ -212,17 +210,15 @@ export class Snake extends Component {
moveTime = 1 / 60; moveTime = 1 / 60;
totalTime = 0; totalTime = 0;
moveScale = 1;
onUpdate(dt: number) { onUpdate(dt: number) {
let moveScale = this.moveScale;
this.buffManager.update(dt);
let speedScale = 1;
if (this.isFast) { if (this.isFast) {
speedScale += 1; moveScale += 1;
} }
this.totalTime += dt * speedScale; this.totalTime += dt * moveScale;
while (this.totalTime >= this.moveTime) { while (this.totalTime >= this.moveTime) {
this.totalTime -= this.moveTime; this.totalTime -= this.moveTime;
this.move(this.moveTime); this.move(this.moveTime);
...@@ -268,7 +264,7 @@ export class Snake extends Component { ...@@ -268,7 +264,7 @@ export class Snake extends Component {
body.angle = Math.atan2( body.angle = Math.atan2(
targetPos.y - prevPos.y, targetPos.y - prevPos.y,
targetPos.x - prevPos.x targetPos.x - prevPos.x
) * 180 / Math.PI; ) * 180 / 3.1415927;
} }
body.setPosition(targetPos); body.setPosition(targetPos);
...@@ -340,30 +336,26 @@ export class Snake extends Component { ...@@ -340,30 +336,26 @@ export class Snake extends Component {
} }
private buffManager: BuffManager = new BuffManager(this); /**
private isInvincible: boolean = false; * 护盾时间
private speedMultiplier: number = 1; * 假如有两个护盾同时生效,则取时间大的,正是因为这样,才设计成数字
*/
onLoad() { _invincibleTime: number = 0;
// ... 其他初始化代码 ... get invincibleTime() {
this.buffManager = new BuffManager(this); return this._invincibleTime;
} }
// 添加Buff的便捷方法 set invincibleTime(value: number) {
addBuff(type: BuffType, duration?: number, value?: number) { this._invincibleTime = Math.max(this._invincibleTime, value);
const buff = this.buffManager.createBuff(type, duration, value);
if (buff) {
this.buffManager.addBuff(buff);
}
} }
// 提供给Buff使用的方法 clearInvincible() {
setInvincible(value: boolean) { this._invincibleTime = 0;
this.isInvincible = value;
} }
setSpeedMultiplier(value: number) { onLoad() {
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