cocos做简单自动发射追踪子弹 切换敌人
先是获取敌人
this.huoqudiren();this.schedule(()=>{this.huoqudiren();},1);
如果敌人血量伪0 将敌人parent node下的血量伪0的敌人移除
const di=this.diren.children;
const index = di.indexOf(this.guai);if(index!==-1){//console.log(di.splice(index,1));di.splice(index,1)console.log('....');//this.guai=di.pop();}
然后重新获取敌人
huoqudiren(){this.guai=this.findzuijindiren();//console.log(this.guai);if(this.guai==null){return;}let xue=this.guai.getComponent(enemyhit).getxue();if(xue<=0){console.log(this.guai.name);if(this.guai==null){return;}const di=this.diren.children;const index = di.indexOf(this.guai);if(index!==-1){//console.log(di.splice(index,1));di.splice(index,1)console.log('....');//this.guai=di.pop();}this.guai=this.findzuijindiren();console.log('huan',this.guai.name);}}
find最近敌人
findzuijindiren(){const di=this.diren.children;let zuijindiren=null;let zuijinjuli=Number.MAX_VALUE;for(let i=0;i<di.length;i++){//console.log(di[i].name);// 计算子弹与怪物之间的距离(正确的计算)let juli = Vec2.distance(this.node.position, di[i].position);if(juli<zuijinjuli){zuijinjuli=juli;zuijindiren=di[i];}}return zuijindiren;
}
计算脚本挂载node 角色位置
然后遍历敌人node下所有敌人node距离
返回这个敌人node
每秒发射子弹
this.schedule(()=>{
this.onezidan();
},1);
计算子弹 敌人距离然后实例化预制体子弹
将子弹添加到角色node的parent 如果添加到角色node 子弹会跟着角色动 不会追踪敌人
然后在fashezidan数组添加进实例化的子弹
给子弹开启碰撞检测
在update执行this.fashe(deltaTime);
在fashe 计算子弹 敌人方向向量然后归一
import { _decorator, Collider2D, Component, Contact2DType, director, instantiate, IPhysics2DContact, Node, NodePool, ParticleSystem2D, Prefab, RigidBody2D, Script, Sprite, TypeScript, v2, v3, Vec2, Vec3 } from 'cc';
import { enemyhit } from './enemyhit';
const { ccclass, property } = _decorator;@ccclass('fashe')
export class fashe extends Component {@property(Prefab)zdyuzhiti:Prefab=null;@property(Node)guai0:Node;zdsz:Node[]=[];@property(Node)diren:Node;fashezidansz:Node[]=[];guai=null;guaimap=new Map();guaisz=[];@property(Prefab)lizi:Prefab=null;// 标记需要延迟销毁的子弹bulletsToRemove: Node[] = [];danfahit:number=10;onLoad(){this.huoqudiren();this.schedule(()=>{this.huoqudiren();},1);for(let i=0;i<10;i++){const zd=instantiate(this.zdyuzhiti);//zd.setPosition(this.node.position);//this.node.parent.parent.addChild(zd);this.zdsz.push(zd);const fashe=this.node.getChildByName('gongji');fashe.active=false;}this.schedule(()=>{//this.sanzidan();},3);this.schedule(()=>{this.onezidan();},1);}update(deltaTime: number) {this.fashe(deltaTime);//console.log(this.zdsz.size());// 在update中处理子弹销毁,避免在物理回调中直接操作this.cleanInvalidBullets();// 新增:在处理完物理逻辑后,安全地销毁子弹this.processBulletRemoval();}// 清理无效的子弹cleanInvalidBullets() {for (let i = this.fashezidansz.length - 1; i >= 0; i--) {if (!this.fashezidansz[i].isValid) {this.fashezidansz.splice(i, 1);}}}//想象你在排队数人,数到谁没资格就让他出列。//如果从前往后数(正着数)://你数到第2个人,他没资格,你让他出列。
//他走了,后面所有人就都往前挪了一位。刚才的第3个人变成了第2个人。
//但你接下来会去数第3个人,就把刚刚挪上来的这个“新第2个人”给漏掉了,没检查他。
//如果从后往前数(倒着数)://你先数最后一个人。让他出列不影响你前面人的位置。
//接着你数倒数第二个,让他出列也不影响你还没数的、更前面的人。
//这样你数的每一个人,都是你还没检查过的,一个都不会漏。
//所以,代码里从后往前循环 (i--),就是为了在删除数组里的子弹时,不会把没检查的子弹给漏掉。 这是一种安全又省事的编程技巧。// 新增:处理待销毁的子弹processBulletRemoval() {// 处理所有待销毁的子弹while (this.bulletsToRemove.length > 0) {const bullet = this.bulletsToRemove.pop();if (bullet && bullet.isValid) {const index = this.fashezidansz.indexOf(bullet);if (index !== -1) {this.fashezidansz.splice(index, 1);}bullet.destroy(); // 在主循环中安全销毁}}}// 角度线性插值方法lerpAngle(from: number, to: number, speed: number): number {let difference = to - from;// 确保选择最短旋转方向while (difference > 180) difference -= 360;while (difference < -180) difference += 360;return from + difference * Math.min(speed, 1);}hqzd(){let zd:Node;if(this.zdsz.length>0){zd=this.zdsz.pop();}else{zd=instantiate(this.zdyuzhiti);}return zd;}onezidan(){if (!this.guai) return;// 计算与敌人的距离let juli = Vec2.distance(this.node.position, this.guai.position);if(juli<1000){
// 直接实例化新子弹
const zd = instantiate(this.zdyuzhiti);zd.name="danfa";
zd.setPosition(this.node.position.x+70,this.node.position.y-174);zd.active = true;
// 确保子弹有父节点if(!zd.parent){this.node.parent.parent.addChild(zd);
}this.fashezidansz.push(zd);
director.emit('fashezidan');
director.emit("danfa",10);
const collider = zd.getComponent(Collider2D);if (collider) {collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);}}} huoqudiren(){this.guai=this.findzuijindiren();//console.log(this.guai);if(this.guai==null){return;}let xue=this.guai.getComponent(enemyhit).getxue();if(xue<=0){console.log(this.guai.name);if(this.guai==null){return;}const di=this.diren.children;const index = di.indexOf(this.guai);if(index!==-1){//console.log(di.splice(index,1));di.splice(index,1)console.log('....');//this.guai=di.pop();}this.guai=this.findzuijindiren();console.log('huan',this.guai.name);}}findzuijindiren(){const di=this.diren.children;let zuijindiren=null;let zuijinjuli=Number.MAX_VALUE;for(let i=0;i<di.length;i++){//console.log(di[i].name);// 计算子弹与怪物之间的距离(正确的计算)let juli = Vec2.distance(this.node.position, di[i].position);if(juli<zuijinjuli){zuijinjuli=juli;zuijindiren=di[i];}}return zuijindiren;
}fashe(deltaTime:number){if(this.guai==null){return;}for(let i=0;i<this.fashezidansz.length;i++){
// 计算子弹与怪物之间的距离(正确的计算)
let juli = Vec2.distance(this.fashezidansz[i].position, this.guai.position);// 只有在追踪距离内才进行追踪
if (juli < 1000) {this.fashezidansz[i].active=true;let direction = v2(this.guai.position.x - this.fashezidansz[i].position.x,this.guai.position.y - this.fashezidansz[i].position.y);direction.normalize();// 计算当前角度和目标角度let selfjiao = this.fashezidansz[i].angle;let guaijiao = Math.atan2(direction.y, direction.x);let jiao = guaijiao * 180 / Math.PI;// 平滑旋转角度let newjiao = this.lerpAngle(selfjiao, jiao, 70 * deltaTime);this.fashezidansz[i].angle = newjiao;// 根据新角度计算移动方向let r = newjiao * Math.PI / 180;let movex = Math.cos(r) * 700 * deltaTime;let movey = Math.sin(r) * 700 * deltaTime;// 应用移动this.fashezidansz[i].position = this.fashezidansz[i].position.add(v3(movex, movey, 0));
} else {// 如果不在追踪距离内,直线前进let r = this.fashezidansz[i].angle * Math.PI / 180;let movex = 700 ;let movey = 0;this.fashezidansz[i].active=false;//this.fashezidansz[i].position = this.fashezidansz[i].position.add(v3(movex, movey, 0));
}}}onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact |null){//console.log("ziji",selfCollider.node.name);//console.log("zhuang",otherCollider.node.name);const guaiwu=otherCollider.node;this.showlizi(selfCollider.node.position);guaiwu.getComponent(enemyhit).shoushang(this.danfahit);const bullet=selfCollider.node;if (bullet && bullet.isValid) {// 先从数组中移除const index = this.fashezidansz.indexOf(bullet);if (this.bulletsToRemove.indexOf(bullet) === -1) {this.bulletsToRemove.push(bullet);}let xue=otherCollider.node.getComponent(enemyhit).getxue();if(xue<=0){//console.log('huan',this.guai.name);}// 标记需要销毁的子弹,而不是立即销毁// 然后回收子弹}
}
showlizi(position:Vec3){const l=instantiate(this.lizi);l.setPosition(position);this.node.parent.parent.addChild(l);this.scheduleOnce(()=>{if(l.isValid){l.destroy();}},7);}}