| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- 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();
- }
- }
- }
|