cocos 武器攻击敌人后 将碰撞node传给角色脚本 有角色脚本传递计算伤害 调用敌人脚本 敌人自己计算血量 如果超过最大血量 自己删除
武器碰撞后 将node传给角色
import { _decorator, Collider2D, Component, Contact2DType, IPhysics2DContact, Node } from 'cc';
import { juesedong } from './juesedong';
const { ccclass, property } = _decorator;@ccclass('wuqiya')
export class wuqiya extends Component {@property(Node)juese:Node=null;onLoad(){// 监听碰撞事件const collider = this.getComponent(Collider2D);if (collider) {collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);}}// 碰撞回调onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {if(otherCollider.node.name.includes("zoo")){this.juese.getComponent(juesedong).direnshouji(otherCollider.node);}console.log(otherCollider.node.name);}start() {}update(deltaTime: number) {}
}
角色计算伤害后 给敌人脚本计算当前血量
import { _decorator, Animation, Camera, CCFloat, Collider2D, Component, Contact2DType, EventKeyboard, input, Input, IPhysics2DContact, KeyCode, Node, RigidBody2D, Sprite, Vec2, Vec3 } from 'cc';
import { jiangshidong } from './jiangshidong';
import { enemyhit } from './enemyhit';
const { ccclass, property } = _decorator;@ccclass('juesedong')
export class juesedong extends Component {@property({ type: CCFloat })moveSpeed: number = 200;@property({ type: Node })spriteNode: Node = null; // 精灵节点(包含Sprite组件)private isMoving: boolean = false;private moveDirection: Vec2 = new Vec2(0, 0);private targetPosition: Vec3 = new Vec3();// 动画状态private lastDirection: string = "down";@property({ type: Camera })mainCamera: Camera = null;@property({ type: CCFloat })cameraFollowSpeed: number = 5;@property(CCFloat)shanghai:number=10;@property({ type: CCFloat })screenBoundary: number = 100; // 屏幕边界,角色到达边界时相机移动onLoad() {// 初始化位置Vec3.copy(this.targetPosition, this.node.position);// 监听键盘事件input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);input.on(Input.EventType.KEY_UP, this.onKeyUp, this);// 如果没有指定精灵节点,默认使用当前节点if (!this.spriteNode) {this.spriteNode = this.node;}const wuqiya=this.node.getChildByName("donghua").getChildByName("wuqiya");wuqiya.active=false;// 监听碰撞事件const collider = this.getComponent(Collider2D);if (collider) {collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);}}// 碰撞回调onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {console.log(otherCollider.node.name);}direnshouji(diren:Node,shanghai:number=this.shanghai){this.direnxianshishanghai(diren,shanghai);//return this.shanghai;}direnxianshishanghai(diren:Node,shanghai:number){diren.getComponent(enemyhit).zhixingshanghai(shanghai);}onKeyDown(event: EventKeyboard) {switch (event.keyCode) {case KeyCode.KEY_W:this.moveDirection.y = 1;// 相机跟随break;case KeyCode.KEY_S:this.moveDirection.y = -1;// 相机跟随break;case KeyCode.KEY_A:this.moveDirection.x = -1;// 相机跟随break;case KeyCode.KEY_D:this.moveDirection.x = 1;// 相机跟随break;case KeyCode.KEY_C:this.wuqiya();break;}this.isMoving = true;this.updateAnimation();}wuqiya(){this.node.getChildByNameconst wuqiya=this.node.getChildByName("donghua").getChildByName("wuqiya");wuqiya.active=true;const yadonghua=wuqiya.getComponent(Animation);yadonghua.play();if(yadonghua.getState("wuqiya").isPlaying){this.node.getChildByName("juese").getChildByName("wuqiyashengzi").active=false;this.node.getChildByName("juese").getChildByName("wuqiya").active=false;}else{this.node.getChildByName("juese").getChildByName("wuqiyashengzi").active=true;this.node.getChildByName("juese").getChildByName("wuqiya").active=true;}console.log("lunyazi");}private cameraFollow(deltaTime: number) {if (!this.mainCamera) return;const playerPos = this.node.position;const cameraPos = this.mainCamera.node.position;// 平滑跟随const targetCameraPos = new Vec3(playerPos.x, playerPos.y, cameraPos.z);const newCameraPos = new Vec3();Vec3.lerp(newCameraPos, cameraPos, targetCameraPos, this.cameraFollowSpeed * deltaTime);this.mainCamera.node.setPosition(newCameraPos);}private lerp(a: number, b: number, t: number): number {return a + (b - a) * t;}onKeyUp(event: EventKeyboard) {switch (event.keyCode) {case KeyCode.KEY_W:if (this.moveDirection.y > 0) this.moveDirection.y = 0;break;case KeyCode.KEY_S:if (this.moveDirection.y < 0) this.moveDirection.y = 0;break;case KeyCode.KEY_A:if (this.moveDirection.x < 0) this.moveDirection.x = 0;break;case KeyCode.KEY_D:if (this.moveDirection.x > 0) this.moveDirection.x = 0;break;}this.isMoving = !this.moveDirection.equals(Vec2.ZERO);this.updateAnimation();}updateAnimation() {if (!this.isMoving) {this.setIdleAnimation();return;}// 根据移动方向设置动画if (Math.abs(this.moveDirection.y) > Math.abs(this.moveDirection.x)) {this.lastDirection = this.moveDirection.y > 0 ? "up" : "down";} else {if (this.moveDirection.x !== 0) {this.lastDirection = this.moveDirection.x > 0 ? "right" : "left";// 翻转精灵实现左右转身this.spriteNode.scale = new Vec3(this.moveDirection.x > 0 ? -1 : 1, 1, 1);}}this.setWalkAnimation(this.lastDirection);}setIdleAnimation() {// 实现 idle 动画逻辑// 例如:this.animation.play(`idle_${this.lastDirection}`);console.log(`Idle: ${this.lastDirection}`);}setWalkAnimation(direction: string) {// 实现 walk 动画逻辑// 例如:this.animation.play(`walk_${direction}`);console.log(`Walk: ${direction}`);}update(deltaTime: number) {if (this.isMoving) {// 计算移动量const moveDelta = new Vec3(this.moveDirection.x * this.moveSpeed * deltaTime,this.moveDirection.y * this.moveSpeed * deltaTime,0);// 更新目标位置Vec3.add(this.targetPosition, this.node.position, moveDelta);// 应用移动this.node.setPosition(this.targetPosition);this.cameraFollow(deltaTime);}}onDestroy() {input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);input.off(Input.EventType.KEY_UP, this.onKeyUp, this);}
}
敌人脚本执行上海后计算当前血量
import { _decorator, Camera, Collider2D, Component, Contact2DType, director, instantiate, IPhysics2DContact, Label, Node, Prefab, ProgressBar, RigidBody2D, TERRAIN_HEIGHT_BASE, tween, UIOpacity, v2, v3, Vec2, Vec3 } from 'cc';
import { dong } from './dong';
import { fashefabao } from './fashefabao';
const { ccclass, property } = _decorator;@ccclass('enemyhit')
export class enemyhit extends Component {start() {}@property(ProgressBar)xt:ProgressBar=null;zongxueliang:number=100;dangqianxueliang:number=100;@property(Prefab)zdyuzhiti:Prefab=null;@property(Node)diren:Node;private lastDirection: string = "down";@property(Prefab)huoqudaoju:Prefab=null;// 敌人追踪玩家子弹@property(Node)wodezidan:Node=null; // 敌人自己的子弹juesezidan:Node=null; // 玩家的子弹@property(Prefab)lizi:Prefab=null;@property(Camera)maincamera:Camera=null;private zidanRigidBody: RigidBody2D | null = null;private zidanCollider: Collider2D | null = null;private shouldDestroyBullet: boolean = false;// 发射冷却时间private lastFasheTime: number = 0;private fasheInterval: number = 2; // 2秒发射一次onLoad(){// 监听碰撞事件const collider = this.getComponent(Collider2D);if (collider) {collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);}this.dangqianxueliang=this.zongxueliang;}// 碰撞回调onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {if(otherCollider.node.name.includes("wuqiya")){}}
show(damage: string,xianshishijian:number) {// 创建伤害数字节点const damageNode = instantiate(this.huoqudaoju);// 设置为角色的子节点(显示在角色上方)this.xt.node.addChild(damageNode);// 设置伤害值// 设置位置(角色头顶上方)const playerPos = this.xt.node.position.clone();console.log(playerPos);const o=damageNode.getComponent(Label);o.string = `${damage}`;damageNode.setPosition(new Vec3(Math.random() * 40 + 30,Math.random() * 170 + 30,0));let opacity = damageNode.getComponent(UIOpacity);if (!opacity) {opacity = damageNode.addComponent(UIOpacity);}opacity.opacity = 255; // 初始完全不透明// 上浮动画tween(damageNode).to(1, { position: new Vec3(0, 170, 0) }).start();// 渐隐效果tween(damageNode.getComponent(UIOpacity)).to(xianshishijian, { opacity: 0 }).call(() => damageNode.destroy()) // 动画结束销毁.start();
}update(deltaTime: number) {// 敌人子弹追踪玩家if( this.diren && this.diren.isValid){this.zhuizongjuese(deltaTime);}// 检查是否应该发射子弹(冷却时间)//this.lastFasheTime += deltaTime;//if(this.lastFasheTime >= this.fasheInterval){//this.tryFasheZidan();//}try {let ewordpos = this.node.getWorldPosition();let cha = v3(0, 70, 0);let tarwordpos = ewordpos.add(cha);let tarlopos = v3();this.xt.node.parent.inverseTransformPoint(tarlopos, tarwordpos);this.xt.node.position = tarlopos;} catch (error) {console.warn("更新血条位置时出错:", error);}}zhixingshanghai(hit: number) {if (!this.node.isValid) return;this.dangqianxueliang = this.dangqianxueliang - hit;this.upxueliang();this.showlizi(this.node.position);this.show(hit.toString(),4);let xue=this.dangqianxueliang;//this.shakeCamera(3);if(xue<=0&&this.node.isValid&&this.xt.node.isValid){console.log(this.node.name);this.scheduleOnce(()=>{this.safeDestroyEnemy();},0.7);}}getxue(){return this.dangqianxueliang;}getxuetiao(){return this.xt.node;}// 安全的敌人销毁方法
safeDestroyEnemy() {// 优化安全销毁方法// 0. 检查节点有效性try {// 先检查节点有效性if (!this.node || !this.node.isValid) return;// 直接销毁血条(如果存在且有效)if (this.xt && this.xt.node && this.xt.node.isValid) {this.xt.node.removeFromParent();this.xt.node.destroy();}// 直接销毁敌人节点if (this.node.isValid) {this.node.removeFromParent();this.node.destroy();}} catch (error) {console.warn("直接销毁敌人时出错:", error);// 如果出错,尝试最暴力的方式if (this.node && this.node.isValid) {try {this.node.destroy();} catch (e) {console.error("最终销毁也失败:", e);}}}
}// 摄像机晃动方法
shakeCamera(intensity: number = 0.5, duration: number = 0.3) {if (!this.maincamera) return;const cameraNode = this.maincamera.node;// 保存原始位置const startPos = cameraNode.position.clone();// 停止之前的动画tween(cameraNode).stop();// 创建晃动动画tween(cameraNode).to(duration / 4, { position: v3(startPos.x + intensity, startPos.y + intensity, startPos.z) }).to(duration / 4, { position: v3(startPos.x - intensity, startPos.y - intensity, startPos.z) }).to(duration / 4, { position: v3(startPos.x + intensity/2, startPos.y + intensity/2, startPos.z) }).to(duration / 4, { position: v3(startPos.x, startPos.y, startPos.z) }).start();
}upxueliang() {if (!this.xt || !this.xt.node || !this.xt.node.isValid) return;const progress = this.dangqianxueliang / this.zongxueliang;this.xt.progress = Math.max(0, Math.min(1, progress));}shanchujiangshi(){let xue=this.dangqianxueliang;if(xue<=0){console.log(this.node.name);this.node.removeFromParent();this.node.destroy();this.xt.node.removeFromParent();this.xt.node.destroy();}}// 敌人子弹追踪玩家 - 修改为世界坐标计算zhuizongjuese(deltaTime:number){if( !this.diren) return;// 获取世界坐标进行计算const zidanWorldPos = this.node.getWorldPosition();const jueseWorldPos = this.diren.getWorldPosition();let juli = Vec3.distance(zidanWorldPos, jueseWorldPos);if(juli < 10000){// 使用世界坐标计算方向let direction = v2(jueseWorldPos.x - zidanWorldPos.x,jueseWorldPos.y - zidanWorldPos.y);direction.normalize();let selfjiao = this.node.angle;let juesejiao = Math.atan2(direction.y, direction.x);let jiao = juesejiao * 180 / Math.PI;let newjiao = this.lerpAngle(selfjiao, jiao, 70 * deltaTime);//this.node.angle = newjiao;let r = newjiao * Math.PI / 180;let movex = Math.cos(r) * 70 * deltaTime;let movey = Math.sin(r) * 70 * deltaTime;// 使用相对位置移动(因为子弹在敌人节点下)const currentPos = this.node.position;this.node.setPosition(currentPos.x + movex, currentPos.y + movey);// 根据水平方向判断朝向(最简单的方法)if (direction.x > 0) {// 玩家在右边,朝右this.node.scale = new Vec3(1, 1, 1);} else {// 玩家在左边,朝左this.node.scale = new Vec3(-1, 1, 1);}}else{// 如果子弹距离太远,销毁并重新发射}}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);}showlizi(position:Vec3){const l = instantiate(this.lizi);// 添加到场景根节点if(this.node.parent && this.node.parent.parent){this.node.parent.parent.addChild(l);// 将本地坐标转换为世界坐标let worldPos = v3();this.node.getWorldPosition(worldPos);l.setWorldPosition(worldPos);}this.scheduleOnce(() => {if(l.isValid) l.destroy();}, 7);}zhuanshijiezuobiao(node:Node){// 将本地坐标转换为世界坐标let worldPos = v3();let position=node.getWorldPosition(worldPos);return position;}
}