import { _decorator, Component, Node, Vec2, Vec3, find, RigidBody2D, Collider2D, Contact2DType, IPhysics2DContact, instantiate, Prefab, UITransform } from 'cc'; import { WeaponBlockExample } from './WeaponBlockExample'; const { ccclass, property } = _decorator; /** * 子弹控制器 - 安全版本 * * 设计原则: * 1. 在子弹添加到场景之前设置所有物理属性 * 2. 延迟启用物理组件,避免m_world为null错误 * 3. 确保物理组件在正确的时机激活 */ @ccclass('BulletController') export class BulletController extends Component { @property public speed: number = 300; @property public damage: number = 1; @property public lifetime: number = 5; private targetEnemy: Node = null; private rigidBody: RigidBody2D = null; private lifeTimer: number = 0; private direction: Vec3 = null; private firePosition: Vec3 = null; private isInitialized: boolean = false; private needsPhysicsSetup: boolean = false; /** * 设置子弹的发射位置 * @param position 发射位置(世界坐标) */ public setFirePosition(position: Vec3) { this.firePosition = position.clone(); this.needsPhysicsSetup = true; console.log('🎯 子弹发射位置已设置:', this.firePosition); } start() { console.log('🚀 子弹start()开始...'); // 设置生命周期 this.lifeTimer = this.lifetime; // 如果需要设置物理属性,延迟处理 if (this.needsPhysicsSetup) { // 使用更短的延迟,确保物理世界准备好 this.scheduleOnce(() => { this.setupPhysics(); }, 0.05); } console.log('✅ 子弹start()完成'); } /** * 设置物理属性 */ private setupPhysics() { console.log('🔧 开始设置子弹物理属性...'); // 获取物理组件 this.rigidBody = this.node.getComponent(RigidBody2D); const collider = this.node.getComponent(Collider2D); if (!this.rigidBody) { console.error('❌ 子弹预制体缺少RigidBody2D组件'); return; } if (!collider) { console.error('❌ 子弹预制体缺少Collider2D组件'); return; } console.log('✅ 物理组件获取成功'); // 确保物理组件设置正确 this.rigidBody.enabledContactListener = true; this.rigidBody.gravityScale = 0; // 不受重力影响 this.rigidBody.linearDamping = 0; // 无阻尼 this.rigidBody.angularDamping = 0; // 无角阻尼 // 绑定碰撞事件 collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); console.log('✅ 碰撞事件已绑定'); // 设置子弹位置 if (this.firePosition) { this.setPositionInGameArea(); } // 初始化方向和速度 this.initializeDirection(); this.isInitialized = true; console.log('✅ 子弹物理属性设置完成'); } /** * 在GameArea中设置子弹位置 */ private setPositionInGameArea() { const gameArea = find('Canvas/GameLevelUI/GameArea'); if (gameArea) { const gameAreaTransform = gameArea.getComponent(UITransform); if (gameAreaTransform) { const localPos = gameAreaTransform.convertToNodeSpaceAR(this.firePosition); this.node.position = localPos; console.log('✅ 子弹位置已设置:', localPos); } } } /** * 初始化子弹方向 */ private initializeDirection() { console.log('🎯 开始初始化子弹方向...'); // 寻找最近的敌人 this.findNearestEnemy(); // 设置方向 if (this.targetEnemy) { this.setDirectionToTarget(); } else { // 随机方向 const randomAngle = Math.random() * Math.PI * 2; this.direction = new Vec3(Math.cos(randomAngle), Math.sin(randomAngle), 0); console.log('🎲 使用随机方向'); } // 应用速度 this.applyVelocity(); } // 寻找最近的敌人 private findNearestEnemy() { const enemyContainer = find('Canvas/GameLevelUI/enemyContainer'); if (!enemyContainer) { console.log('❌ 未找到敌人容器'); return; } const enemies = enemyContainer.children.filter(child => child.active && (child.name.toLowerCase().includes('enemy') || child.getComponent('EnemyInstance') !== null) ); if (enemies.length === 0) { console.log('❌ 没有找到敌人'); return; } let nearestEnemy: Node = null; let nearestDistance = Infinity; const bulletPos = this.node.worldPosition; for (const enemy of enemies) { const distance = Vec3.distance(bulletPos, enemy.worldPosition); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } if (nearestEnemy) { this.targetEnemy = nearestEnemy; console.log(`🎯 锁定目标: ${nearestEnemy.name}`); } } // 设置朝向目标的方向 private setDirectionToTarget() { if (!this.targetEnemy) return; const targetPos = this.targetEnemy.worldPosition; const currentPos = this.node.worldPosition; this.direction = targetPos.clone().subtract(currentPos).normalize(); console.log('🎯 方向已设置,朝向目标敌人'); } // 应用速度 private applyVelocity() { if (!this.rigidBody || !this.direction) { console.error('❌ 无法应用速度:缺少刚体或方向'); return; } // 覆盖速度值(全局控制) const weaponGlobal = WeaponBlockExample.getInstance && WeaponBlockExample.getInstance(); if (weaponGlobal) { this.speed = weaponGlobal.getCurrentBulletSpeed(); } const velocity = new Vec2( this.direction.x * this.speed, this.direction.y * this.speed ); this.rigidBody.linearVelocity = velocity; console.log('✅ 子弹速度已应用:', velocity); } // 碰撞检测 onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { const otherNode = otherCollider.node; console.log('💥 子弹碰撞:', otherNode.name); // 检查是否击中敌人 if (this.isEnemyNode(otherNode)) { console.log('🎯 击中敌人:', otherNode.name); this.damageEnemy(otherNode); this.node.destroy(); } else if (otherNode.name.toLowerCase().includes('wall')) { console.log('🧱 击中墙体,销毁子弹'); this.node.destroy(); } } // 判断是否为敌人节点 private isEnemyNode(node: Node): boolean { const name = node.name.toLowerCase(); return name.includes('enemy') || name.includes('敌人') || node.getComponent('EnemyInstance') !== null || node.getComponent('EnemyComponent') !== null; } // 对敌人造成伤害 private damageEnemy(enemyNode: Node) { console.log('⚔️ 对敌人造成伤害:', this.damage); // 尝试调用敌人的受伤方法 const enemyInstance = enemyNode.getComponent('EnemyInstance') as any; if (enemyInstance) { if (typeof enemyInstance.takeDamage === 'function') { enemyInstance.takeDamage(this.damage); return; } if (typeof enemyInstance.health === 'number') { enemyInstance.health -= this.damage; if (enemyInstance.health <= 0) { enemyNode.destroy(); } return; } } // 备用方案:通过EnemyController const enemyController = find('Canvas/GameLevelUI/EnemyController')?.getComponent('EnemyController') as any; if (enemyController && typeof enemyController.damageEnemy === 'function') { enemyController.damageEnemy(enemyNode, this.damage); } } update(dt: number) { // 只有在初始化完成后才进行更新 if (!this.isInitialized) return; // 生命周期倒计时 this.lifeTimer -= dt; if (this.lifeTimer <= 0) { this.node.destroy(); } // 检查是否飞出游戏区域 this.checkOutOfBounds(); } /** * 如果子弹飞出 GameArea 边界(留有一定安全距离)则自动销毁 */ private checkOutOfBounds() { // 使用整个屏幕(Canvas)范围判定,而不是 GameArea const canvas = find('Canvas'); if (!canvas || !this.node || !this.node.isValid) return; const uiTransform = canvas.getComponent(UITransform); if (!uiTransform) return; const halfWidth = uiTransform.width / 2; const halfHeight = uiTransform.height / 2; const center = canvas.worldPosition; const left = center.x - halfWidth; const right = center.x + halfWidth; const bottom = center.y - halfHeight; const top = center.y + halfHeight; // 允许子弹稍微超出边界后再销毁,避免边缘误差 const margin = 100; const pos = this.node.worldPosition; if (pos.x < left - margin || pos.x > right + margin || pos.y < bottom - margin || pos.y > top + margin) { this.node.destroy(); } } }