|
|
@@ -1,4 +1,4 @@
|
|
|
-import { _decorator, Component, Node, Vec2, Vec3, UITransform, Collider2D, Contact2DType, IPhysics2DContact, RigidBody2D, Prefab, instantiate, find, CircleCollider2D } from 'cc';
|
|
|
+import { _decorator, Component, Node, Vec2, Vec3, UITransform, Collider2D, Contact2DType, IPhysics2DContact, RigidBody2D, Prefab, instantiate, find, CircleCollider2D, PhysicsSystem2D } from 'cc';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
@ccclass('BallController')
|
|
|
@@ -12,12 +12,8 @@ export class BallController extends Component {
|
|
|
|
|
|
// 球的移动速度
|
|
|
@property
|
|
|
- public speed: number = 150;
|
|
|
+ public speed: number = 10;
|
|
|
|
|
|
- // 子弹发射冷却时间(秒)
|
|
|
- @property
|
|
|
- public bulletCooldown: number = 0.5;
|
|
|
-
|
|
|
// 反弹随机偏移最大角度(弧度)
|
|
|
@property
|
|
|
public maxReflectionRandomness: number = 0.2;
|
|
|
@@ -42,12 +38,6 @@ export class BallController extends Component {
|
|
|
// 是否已初始化
|
|
|
private initialized: boolean = false;
|
|
|
|
|
|
- // 子弹冷却状态
|
|
|
- private canFireBullet: boolean = true;
|
|
|
-
|
|
|
- // 碰撞的方块ID记录,避免重复发射
|
|
|
- private collidedBlockIds: Set<string> = new Set();
|
|
|
-
|
|
|
// 子弹预制体
|
|
|
@property({
|
|
|
type: Prefab,
|
|
|
@@ -56,15 +46,30 @@ export class BallController extends Component {
|
|
|
public bulletPrefab: Prefab = null;
|
|
|
|
|
|
start() {
|
|
|
+ console.log('🎮 === BallController 开始初始化 ===');
|
|
|
+
|
|
|
// 计算游戏边界
|
|
|
this.calculateGameBounds();
|
|
|
|
|
|
// 检查子弹预制体是否已设置
|
|
|
if (this.bulletPrefab) {
|
|
|
- console.log('子弹预制体已设置:', this.bulletPrefab.name);
|
|
|
+ console.log('✅ 子弹预制体已设置:', this.bulletPrefab.name);
|
|
|
} else {
|
|
|
- console.error('子弹预制体未设置!请在编辑器中设置bulletPrefab属性');
|
|
|
+ console.error('❌ 子弹预制体未设置!请在编辑器中设置bulletPrefab属性');
|
|
|
+ console.error('⚠️ 这将导致小球碰撞方块时无法发射子弹');
|
|
|
}
|
|
|
+
|
|
|
+ // 检查小球预制体是否已设置
|
|
|
+ if (this.ballPrefab) {
|
|
|
+ console.log('✅ 小球预制体已设置:', this.ballPrefab.name);
|
|
|
+ } else {
|
|
|
+ console.error('❌ 小球预制体未设置!请在编辑器中设置ballPrefab属性');
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('🎮 === BallController 初始化完成 ===');
|
|
|
+
|
|
|
+ // 输出碰撞矩阵调试信息
|
|
|
+ this.logCollisionMatrix();
|
|
|
}
|
|
|
|
|
|
// 计算游戏边界(使用GameArea节点)
|
|
|
@@ -141,6 +146,9 @@ export class BallController extends Component {
|
|
|
// 初始化方向
|
|
|
this.initializeDirection();
|
|
|
|
|
|
+ // 检查方块碰撞体状态
|
|
|
+ this.checkBlockColliders();
|
|
|
+
|
|
|
this.initialized = true;
|
|
|
console.log('小球创建完成:', {
|
|
|
position: this.activeBall.position,
|
|
|
@@ -149,6 +157,97 @@ export class BallController extends Component {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ // 检查所有已放置方块的碰撞体组件
|
|
|
+ private checkBlockColliders() {
|
|
|
+ console.log('🔍 === 检查方块碰撞体组件 ===');
|
|
|
+
|
|
|
+ const placedBlocksContainer = find('Canvas/PlacedBlocks');
|
|
|
+ if (!placedBlocksContainer) {
|
|
|
+ console.log('❌ 找不到PlacedBlocks容器');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const blocks = [];
|
|
|
+ for (let i = 0; i < placedBlocksContainer.children.length; i++) {
|
|
|
+ const block = placedBlocksContainer.children[i];
|
|
|
+ if (block.name.includes('Block') || block.getChildByName('B1')) {
|
|
|
+ blocks.push(block);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(`找到 ${blocks.length} 个方块`);
|
|
|
+
|
|
|
+ let fixedCount = 0;
|
|
|
+
|
|
|
+ for (let i = 0; i < blocks.length; i++) {
|
|
|
+ const block = blocks[i];
|
|
|
+ console.log(`\n检查方块 ${i + 1}: ${block.name}`);
|
|
|
+ console.log('方块路径:', this.getNodePath(block));
|
|
|
+
|
|
|
+ // 检查方块本身的碰撞体
|
|
|
+ const blockCollider = block.getComponent(Collider2D);
|
|
|
+ console.log('方块有碰撞体:', !!blockCollider);
|
|
|
+ if (blockCollider) {
|
|
|
+ console.log('碰撞体类型:', blockCollider.constructor.name);
|
|
|
+ console.log('碰撞组:', blockCollider.group);
|
|
|
+ console.log('碰撞标签:', blockCollider.tag);
|
|
|
+ console.log('是否为传感器:', blockCollider.sensor);
|
|
|
+
|
|
|
+ // 🔧 自动修复碰撞组设置
|
|
|
+ if (blockCollider.group !== 2) {
|
|
|
+ console.log(`🔧 修复方块碰撞组: ${blockCollider.group} -> 2`);
|
|
|
+ blockCollider.group = 2; // 设置为Block组
|
|
|
+ fixedCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保不是传感器
|
|
|
+ if (blockCollider.sensor) {
|
|
|
+ console.log(`🔧 修复方块传感器设置: true -> false`);
|
|
|
+ blockCollider.sensor = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查B1子节点的碰撞体
|
|
|
+ const b1Node = block.getChildByName('B1');
|
|
|
+ if (b1Node) {
|
|
|
+ const b1Collider = b1Node.getComponent(Collider2D);
|
|
|
+ console.log('B1子节点有碰撞体:', !!b1Collider);
|
|
|
+ if (b1Collider) {
|
|
|
+ console.log('B1碰撞体类型:', b1Collider.constructor.name);
|
|
|
+ console.log('B1碰撞组:', b1Collider.group);
|
|
|
+ console.log('B1碰撞标签:', b1Collider.tag);
|
|
|
+ console.log('B1是否为传感器:', b1Collider.sensor);
|
|
|
+
|
|
|
+ // 🔧 修复B1子节点的碰撞设置
|
|
|
+ if (b1Collider.group !== 2) {
|
|
|
+ console.log(`🔧 修复B1碰撞组: ${b1Collider.group} -> 2`);
|
|
|
+ b1Collider.group = 2; // 设置为Block组
|
|
|
+ fixedCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保B1不是传感器(需要实际碰撞)
|
|
|
+ if (b1Collider.sensor) {
|
|
|
+ console.log(`🔧 修复B1传感器设置: true -> false`);
|
|
|
+ b1Collider.sensor = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查Weapon子节点
|
|
|
+ const weaponNode = this.findWeaponNode(block);
|
|
|
+ console.log('方块有Weapon节点:', !!weaponNode);
|
|
|
+ if (weaponNode) {
|
|
|
+ console.log('Weapon节点路径:', this.getNodePath(weaponNode));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fixedCount > 0) {
|
|
|
+ console.log(`✅ 已修复 ${fixedCount} 个碰撞组设置`);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('🔍 === 方块碰撞体检查完成 ===');
|
|
|
+ }
|
|
|
+
|
|
|
// 随机位置小球
|
|
|
positionBallRandomly() {
|
|
|
if (!this.activeBall) return;
|
|
|
@@ -169,21 +268,21 @@ export class BallController extends Component {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 查找GridContainer节点,它包含所有放置的方块
|
|
|
- const gridContainer = gameArea.getChildByName('GridContainer');
|
|
|
- if (!gridContainer) {
|
|
|
- console.log('找不到GridContainer节点,使用默认随机位置');
|
|
|
+ // 查找PlacedBlocks节点,它包含所有放置的方块
|
|
|
+ const placedBlocksContainer = find('Canvas/PlacedBlocks');
|
|
|
+ if (!placedBlocksContainer) {
|
|
|
+ console.log('找不到PlacedBlocks节点,使用默认随机位置');
|
|
|
this.setRandomPositionDefault(minX, maxX, minY, maxY);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 获取所有已放置的方块
|
|
|
const placedBlocks = [];
|
|
|
- for (let i = 0; i < gridContainer.children.length; i++) {
|
|
|
- const cell = gridContainer.children[i];
|
|
|
- // 检查单元格是否有子节点(放置的方块)
|
|
|
- if (cell.children.length > 0) {
|
|
|
- placedBlocks.push(cell);
|
|
|
+ for (let i = 0; i < placedBlocksContainer.children.length; i++) {
|
|
|
+ const block = placedBlocksContainer.children[i];
|
|
|
+ // 检查是否是方块节点(通常以Block命名或有特定标识)
|
|
|
+ if (block.name.includes('Block') || block.getChildByName('B1')) {
|
|
|
+ placedBlocks.push(block);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -285,9 +384,13 @@ export class BallController extends Component {
|
|
|
setupCollider() {
|
|
|
if (!this.activeBall) return;
|
|
|
|
|
|
+ console.log('⚙️ === 开始设置小球碰撞组件 ===');
|
|
|
+ console.log('小球节点:', this.activeBall.name);
|
|
|
+
|
|
|
// 确保小球有刚体组件
|
|
|
let rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
if (!rigidBody) {
|
|
|
+ console.log('🔧 添加RigidBody2D组件...');
|
|
|
rigidBody = this.activeBall.addComponent(RigidBody2D);
|
|
|
rigidBody.type = 2; // Dynamic
|
|
|
rigidBody.gravityScale = 0; // 不受重力影响
|
|
|
@@ -296,7 +399,9 @@ export class BallController extends Component {
|
|
|
rigidBody.allowSleep = false; // 不允许休眠
|
|
|
rigidBody.linearDamping = 0; // 无线性阻尼,保持速度不衰减
|
|
|
rigidBody.angularDamping = 0; // 无角阻尼
|
|
|
+ console.log('✅ RigidBody2D组件已添加');
|
|
|
} else {
|
|
|
+ console.log('✅ RigidBody2D组件已存在,更新设置...');
|
|
|
// 确保已有的刚体组件设置正确
|
|
|
rigidBody.enabledContactListener = true;
|
|
|
rigidBody.gravityScale = 0;
|
|
|
@@ -308,23 +413,31 @@ export class BallController extends Component {
|
|
|
// 确保小球有碰撞组件
|
|
|
let collider = this.activeBall.getComponent(CircleCollider2D);
|
|
|
if (!collider) {
|
|
|
+ console.log('🔧 添加CircleCollider2D组件...');
|
|
|
collider = this.activeBall.addComponent(CircleCollider2D);
|
|
|
collider.radius = this.radius || 25; // 使用已计算的半径或默认值
|
|
|
collider.tag = 1; // 小球标签
|
|
|
- collider.group = 1; // 碰撞组
|
|
|
+ collider.group = 1; // 碰撞组1 - Ball组
|
|
|
collider.sensor = false; // 非传感器(实际碰撞)
|
|
|
collider.friction = 0; // 无摩擦
|
|
|
collider.restitution = 1; // 完全弹性碰撞
|
|
|
+ console.log('✅ CircleCollider2D组件已添加');
|
|
|
} else {
|
|
|
+ console.log('✅ CircleCollider2D组件已存在,更新设置...');
|
|
|
// 确保已有的碰撞组件设置正确
|
|
|
collider.sensor = false;
|
|
|
collider.restitution = 1;
|
|
|
+ collider.group = 1; // 确保是Ball组
|
|
|
+ collider.tag = 1; // 确保标签正确
|
|
|
}
|
|
|
|
|
|
- console.log('小球碰撞组件设置完成:', {
|
|
|
+ console.log('🔧 小球碰撞组件设置完成:', {
|
|
|
hasRigidBody: !!rigidBody,
|
|
|
hasCollider: !!collider,
|
|
|
- radius: collider ? collider.radius : 'unknown'
|
|
|
+ radius: collider ? collider.radius : 'unknown',
|
|
|
+ contactListener: rigidBody ? rigidBody.enabledContactListener : false,
|
|
|
+ group: collider ? collider.group : 'unknown',
|
|
|
+ tag: collider ? collider.tag : 'unknown'
|
|
|
});
|
|
|
|
|
|
// 移除可能存在的事件监听
|
|
|
@@ -333,145 +446,101 @@ export class BallController extends Component {
|
|
|
this.activeBall.off(Contact2DType.PRE_SOLVE);
|
|
|
this.activeBall.off(Contact2DType.POST_SOLVE);
|
|
|
|
|
|
- // 注册所有类型的碰撞事件
|
|
|
+ // 注册单个碰撞体的回调函数
|
|
|
this.activeBall.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
this.activeBall.on(Contact2DType.END_CONTACT, this.onEndContact, this);
|
|
|
this.activeBall.on(Contact2DType.PRE_SOLVE, this.onPreSolve, this);
|
|
|
this.activeBall.on(Contact2DType.POST_SOLVE, this.onPostSolve, this);
|
|
|
|
|
|
- console.log('已注册所有碰撞事件监听器');
|
|
|
+ // 注册全局碰撞回调函数
|
|
|
+ if (PhysicsSystem2D.instance) {
|
|
|
+ // 移除可能存在的全局监听器
|
|
|
+ PhysicsSystem2D.instance.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
+ PhysicsSystem2D.instance.off(Contact2DType.END_CONTACT, this.onEndContact, this);
|
|
|
+
|
|
|
+ // 注册全局监听器
|
|
|
+ PhysicsSystem2D.instance.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
+ PhysicsSystem2D.instance.on(Contact2DType.END_CONTACT, this.onEndContact, this);
|
|
|
+ console.log('✅ 已注册全局碰撞监听器');
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('✅ 已注册所有碰撞事件监听器');
|
|
|
+ console.log('⚙️ === 碰撞组件设置完成 ===');
|
|
|
}
|
|
|
|
|
|
- // 碰撞回调中,只需要更新方向向量,物理引擎会处理实际的反弹
|
|
|
+ // 碰撞回调 - 简化版本用于测试
|
|
|
onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
- // 获取碰撞点和法线
|
|
|
- if (!contact) {
|
|
|
- console.warn('碰撞事件没有contact对象');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 记录碰撞对象信息
|
|
|
- console.log('碰撞发生:', {
|
|
|
- selfName: selfCollider.node.name,
|
|
|
- otherName: otherCollider.node.name,
|
|
|
- otherPath: this.getNodePath(otherCollider.node)
|
|
|
+ console.log('🎯 碰撞成功...');
|
|
|
+ console.log('碰撞对象:', {
|
|
|
+ self: selfCollider.node.name,
|
|
|
+ other: otherCollider.node.name,
|
|
|
+ otherGroup: otherCollider.group,
|
|
|
+ selfGroup: selfCollider.group
|
|
|
});
|
|
|
-
|
|
|
- // Debug: 检查节点名称是否包含Block
|
|
|
- console.log(`检查节点名称: "${otherCollider.node.name}",是否包含'Block': ${otherCollider.node.name.includes('Block')}`);
|
|
|
-
|
|
|
- // 获取碰撞点的世界坐标
|
|
|
- const worldManifold = contact.getWorldManifold();
|
|
|
- if (!worldManifold) {
|
|
|
- console.warn('无法获取worldManifold');
|
|
|
- return;
|
|
|
+
|
|
|
+ // 判断哪个是小球,哪个是方块
|
|
|
+ let ballNode: Node = null;
|
|
|
+ let blockNode: Node = null;
|
|
|
+
|
|
|
+ // 检查self是否为小球(组1)
|
|
|
+ if (selfCollider.group === 1) {
|
|
|
+ ballNode = selfCollider.node;
|
|
|
+ blockNode = otherCollider.node;
|
|
|
+ }
|
|
|
+ // 检查other是否为小球(组1)
|
|
|
+ else if (otherCollider.group === 1) {
|
|
|
+ ballNode = otherCollider.node;
|
|
|
+ blockNode = selfCollider.node;
|
|
|
}
|
|
|
-
|
|
|
- // 获取碰撞法线
|
|
|
- const normal = worldManifold.normal;
|
|
|
- console.log('碰撞法线:', normal);
|
|
|
-
|
|
|
- // 检查是否碰到墙体
|
|
|
- const nodeName = otherCollider.node.name;
|
|
|
- const nodePath = this.getNodePath(otherCollider.node);
|
|
|
- const nodeParent = otherCollider.node.parent ? otherCollider.node.parent.name : 'unknown';
|
|
|
-
|
|
|
- console.log(`检查墙体碰撞: ${nodeName}, 路径: ${nodePath}, 父节点: ${nodeParent}`);
|
|
|
-
|
|
|
- // 使用多种方式检测墙体碰撞
|
|
|
- const isWall =
|
|
|
- nodeName === 'TopFence' ||
|
|
|
- nodeName === 'BottomFence' ||
|
|
|
- nodeName === 'JiguangL' ||
|
|
|
- nodeName === 'JiguangR' ||
|
|
|
- nodeName.includes('Fence') ||
|
|
|
- nodeName.includes('Jiguang') ||
|
|
|
- nodePath.includes('GameArea/TopFence') ||
|
|
|
- nodePath.includes('GameArea/BottomFence') ||
|
|
|
- nodePath.includes('GameArea/JiguangL') ||
|
|
|
- nodePath.includes('GameArea/JiguangR');
|
|
|
-
|
|
|
- if (isWall) {
|
|
|
- console.log(`球碰到了墙体 ${nodeName},进行反弹,路径: ${nodePath}`);
|
|
|
-
|
|
|
- // 更新方向向量
|
|
|
- this.direction = this.calculateReflection(this.direction, normal);
|
|
|
-
|
|
|
- // 确保球有刚体组件
|
|
|
- const rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
- if (rigidBody) {
|
|
|
- // 立即更新速度方向,确保反弹效果
|
|
|
- rigidBody.linearVelocity = new Vec2(
|
|
|
- this.direction.x * this.speed,
|
|
|
- this.direction.y * this.speed
|
|
|
- );
|
|
|
- console.log('更新后的速度:', rigidBody.linearVelocity);
|
|
|
- }
|
|
|
+
|
|
|
+ // 如果没有找到小球,跳过处理
|
|
|
+ if (!ballNode || !blockNode) {
|
|
|
+ console.log('❌ 未检测到小球参与的碰撞');
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- // 如果碰撞的是方块,发射子弹
|
|
|
- // 修改检测逻辑,使用更宽松的条件
|
|
|
+ console.log('✅ 检测到小球与方块碰撞:', {
|
|
|
+ ball: ballNode.name,
|
|
|
+ block: blockNode.name
|
|
|
+ });
|
|
|
+
|
|
|
+ // 检查碰撞对象是否为方块
|
|
|
+ const nodeName = blockNode.name;
|
|
|
+ const nodePath = this.getNodePath(blockNode);
|
|
|
+
|
|
|
+ // 检查是否有Weapon子节点(判断是否为方块)
|
|
|
+ const hasWeaponChild = blockNode.getChildByName('Weapon') !== null;
|
|
|
const isBlock =
|
|
|
nodeName.includes('Block') ||
|
|
|
nodePath.includes('Block') ||
|
|
|
- (otherCollider.node.getChildByName('Weapon') !== null);
|
|
|
+ hasWeaponChild;
|
|
|
|
|
|
- if (isBlock) {
|
|
|
- console.log(`检测到方块碰撞: ${nodeName}, 路径: ${nodePath}`);
|
|
|
+ console.log('判定为方块:', isBlock);
|
|
|
|
|
|
- // 检查冷却状态和是否已经对这个方块发射过子弹
|
|
|
- const blockId = otherCollider.node.uuid;
|
|
|
- if (this.canFireBullet && !this.collidedBlockIds.has(blockId)) {
|
|
|
- this.fireBullet(otherCollider.node);
|
|
|
- } else {
|
|
|
- console.log('子弹冷却中或已对此方块发射过子弹');
|
|
|
- }
|
|
|
+ if (isBlock) {
|
|
|
+ console.log(`🎯 检测到方块碰撞: ${nodeName}, 路径: ${nodePath}`);
|
|
|
+ console.log('🚀 方块武器被激活,发射子弹攻击敌人...');
|
|
|
+ this.fireBullet(blockNode);
|
|
|
+ console.log('✅ 子弹发射完成');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 碰撞结束事件
|
|
|
+ // 碰撞结束事件 - 简化版本
|
|
|
onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
- console.log('碰撞结束:', otherCollider.node.name);
|
|
|
+ console.log('🔚 碰撞结束:', {
|
|
|
+ self: selfCollider.node.name,
|
|
|
+ other: otherCollider.node.name
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- // 碰撞预处理事件
|
|
|
+ // 碰撞预处理事件 - 简化版本
|
|
|
onPreSolve(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
- console.log('碰撞预处理:', otherCollider.node.name);
|
|
|
+ console.log('⚙️ 碰撞预处理:', otherCollider.node.name);
|
|
|
}
|
|
|
|
|
|
- // 碰撞后处理事件
|
|
|
+ // 碰撞后处理事件 - 简化版本
|
|
|
onPostSolve(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
- console.log('碰撞后处理:', otherCollider.node.name);
|
|
|
-
|
|
|
- // 检查是否碰到墙体
|
|
|
- const nodeName = otherCollider.node.name;
|
|
|
- if (nodeName === 'TopFence' || nodeName === 'BottomFence' ||
|
|
|
- nodeName === 'JiguangL' || nodeName === 'JiguangR' ||
|
|
|
- nodeName.includes('Fence') || nodeName.includes('Jiguang')) {
|
|
|
- console.log(`球碰到了墙体 ${nodeName},处理反弹`);
|
|
|
-
|
|
|
- // 获取碰撞点和法线
|
|
|
- if (!contact) return;
|
|
|
-
|
|
|
- const worldManifold = contact.getWorldManifold();
|
|
|
- if (!worldManifold) return;
|
|
|
-
|
|
|
- // 获取碰撞法线
|
|
|
- const normal = worldManifold.normal;
|
|
|
-
|
|
|
- // 更新方向向量
|
|
|
- this.direction = this.calculateReflection(this.direction, normal);
|
|
|
-
|
|
|
- // 确保球有刚体组件
|
|
|
- const rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
- if (rigidBody) {
|
|
|
- // 立即更新速度方向,确保反弹效果
|
|
|
- rigidBody.linearVelocity = new Vec2(
|
|
|
- this.direction.x * this.speed,
|
|
|
- this.direction.y * this.speed
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
+ console.log('✅ 碰撞后处理:', otherCollider.node.name);
|
|
|
}
|
|
|
|
|
|
// 计算反射向量
|
|
|
@@ -528,114 +597,114 @@ export class BallController extends Component {
|
|
|
return randomizedReflection;
|
|
|
}
|
|
|
|
|
|
- // 发射子弹
|
|
|
+ // 从方块武器发射子弹攻击敌人
|
|
|
fireBullet(blockNode: Node) {
|
|
|
- console.log('发射子弹!击中方块:', blockNode.name);
|
|
|
+ console.log('🔫 === 方块武器发射子弹流程 ===');
|
|
|
+ console.log('激活的方块:', blockNode.name);
|
|
|
+ console.log('方块路径:', this.getNodePath(blockNode));
|
|
|
|
|
|
- // 检查冷却状态
|
|
|
- if (!this.canFireBullet) {
|
|
|
- console.log('子弹冷却中,无法发射');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查是否已经对这个方块发射过子弹
|
|
|
- const blockId = blockNode.uuid;
|
|
|
- if (this.collidedBlockIds.has(blockId)) {
|
|
|
- console.log('已经对此方块发射过子弹');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 记录此方块ID
|
|
|
- this.collidedBlockIds.add(blockId);
|
|
|
-
|
|
|
- // 设置冷却
|
|
|
- this.canFireBullet = false;
|
|
|
- this.scheduleOnce(() => {
|
|
|
- this.canFireBullet = true;
|
|
|
- // 清理碰撞记录
|
|
|
- this.collidedBlockIds.clear();
|
|
|
- }, this.bulletCooldown);
|
|
|
-
|
|
|
- // 检查是否有子弹预制体
|
|
|
+ // 检查子弹预制体是否存在
|
|
|
if (!this.bulletPrefab) {
|
|
|
- console.error('未设置子弹预制体');
|
|
|
+ console.error('❌ 子弹预制体未设置');
|
|
|
return;
|
|
|
- } else {
|
|
|
- console.log('子弹预制体已设置:', this.bulletPrefab.name);
|
|
|
- }
|
|
|
-
|
|
|
- // 查找Weapon节点 - 递归查找,因为Weapon可能在B1子节点下
|
|
|
- let weaponNode = this.findWeaponNode(blockNode);
|
|
|
-
|
|
|
+ }
|
|
|
+ // 查找方块中的Weapon节点
|
|
|
+ console.log('🔍 开始查找方块中的Weapon节点...');
|
|
|
+ const weaponNode = this.findWeaponNode(blockNode);
|
|
|
if (!weaponNode) {
|
|
|
- console.warn(`方块 ${blockNode.name} 没有找到Weapon子节点,创建一个`);
|
|
|
- // 如果没有找到Weapon节点,在B1节点下创建一个
|
|
|
- const b1Node = blockNode.getChildByName('B1');
|
|
|
- if (b1Node) {
|
|
|
- weaponNode = new Node('Weapon');
|
|
|
- // 确保Weapon节点有UITransform组件
|
|
|
- if (!weaponNode.getComponent(UITransform)) {
|
|
|
- weaponNode.addComponent(UITransform);
|
|
|
- }
|
|
|
- // 将Weapon添加到B1节点中
|
|
|
- b1Node.addChild(weaponNode);
|
|
|
- // 放置在B1中心
|
|
|
- weaponNode.position = new Vec3(0, 0, 0);
|
|
|
- } else {
|
|
|
- // 如果连B1节点都没有,直接添加到方块根节点
|
|
|
- weaponNode = new Node('Weapon');
|
|
|
- // 确保Weapon节点有UITransform组件
|
|
|
- if (!weaponNode.getComponent(UITransform)) {
|
|
|
- weaponNode.addComponent(UITransform);
|
|
|
- }
|
|
|
- // 将Weapon添加到方块中
|
|
|
- blockNode.addChild(weaponNode);
|
|
|
- // 放置在方块中心
|
|
|
- weaponNode.position = new Vec3(0, 0, 0);
|
|
|
- }
|
|
|
- } else {
|
|
|
- console.log(`找到方块 ${blockNode.name} 的Weapon子节点:`, weaponNode.name);
|
|
|
+ console.error('❌ 在方块中找不到Weapon节点:', blockNode.name);
|
|
|
+ console.log('方块结构:');
|
|
|
+ this.logNodeStructure(blockNode, 0);
|
|
|
+ return;
|
|
|
}
|
|
|
+ console.log('✅ 找到Weapon节点:', weaponNode.name);
|
|
|
+ console.log('Weapon节点路径:', this.getNodePath(weaponNode));
|
|
|
|
|
|
// 实例化子弹
|
|
|
+ console.log('🏗️ 开始创建攻击敌人的子弹...');
|
|
|
const bullet = instantiate(this.bulletPrefab);
|
|
|
+ console.log('✅ 子弹创建成功:', bullet.name);
|
|
|
|
|
|
// 将子弹添加到GameArea中
|
|
|
const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
if (gameArea) {
|
|
|
gameArea.addChild(bullet);
|
|
|
+ console.log('✅ 子弹已添加到GameArea');
|
|
|
|
|
|
- // 设置子弹初始位置为Weapon节点的位置
|
|
|
- const weaponWorldPos = weaponNode.worldPosition;
|
|
|
- bullet.worldPosition = weaponWorldPos;
|
|
|
+ // 设置子弹初始位置 - 简化版本
|
|
|
+ try {
|
|
|
+ // 直接使用方块的位置作为发射起点
|
|
|
+ const blockWorldPos = blockNode.worldPosition;
|
|
|
+ console.log('方块世界坐标:', blockWorldPos);
|
|
|
+
|
|
|
+ // 延迟设置位置,确保节点已完全添加到场景树
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ try {
|
|
|
+ // 将世界坐标转换为GameArea的本地坐标
|
|
|
+ const gameAreaTransform = gameArea.getComponent(UITransform);
|
|
|
+ const localPos = gameAreaTransform.convertToNodeSpaceAR(blockWorldPos);
|
|
|
+ bullet.position = localPos;
|
|
|
+ console.log('✅ 子弹位置已设置:', {
|
|
|
+ blockWorldPos: blockWorldPos,
|
|
|
+ bulletLocalPos: localPos
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 设置子弹位置失败:', error);
|
|
|
+ // 备用方案:设置为GameArea中心
|
|
|
+ bullet.position = new Vec3(0, 0, 0);
|
|
|
+ console.log('✅ 使用默认位置设置子弹');
|
|
|
+ }
|
|
|
+ }, 0.02); // 延迟两帧
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 获取方块坐标失败:', error);
|
|
|
+ // 备用方案:设置为默认位置
|
|
|
+ bullet.position = new Vec3(0, 0, 0);
|
|
|
+ }
|
|
|
|
|
|
- // 子弹已经有BulletController组件,不需要再添加
|
|
|
- // 让子弹自己找到最近的敌人并攻击
|
|
|
- console.log('子弹已创建,将自动寻找并攻击最近的敌人');
|
|
|
+ console.log('🎯 子弹已创建,将自动寻找并攻击最近的敌人');
|
|
|
+ } else {
|
|
|
+ console.error('❌ 找不到GameArea节点');
|
|
|
}
|
|
|
+ console.log('🔫 === 方块武器发射子弹流程结束 ===');
|
|
|
}
|
|
|
|
|
|
// 递归查找Weapon节点
|
|
|
private findWeaponNode(node: Node): Node | null {
|
|
|
+ console.log(`🔍 在节点 ${node.name} 中查找Weapon...`);
|
|
|
+
|
|
|
// 先检查当前节点是否有Weapon子节点
|
|
|
const weaponNode = node.getChildByName('Weapon');
|
|
|
if (weaponNode) {
|
|
|
+ console.log(`✅ 在 ${node.name} 中找到Weapon节点`);
|
|
|
return weaponNode;
|
|
|
}
|
|
|
|
|
|
// 如果没有,递归检查所有子节点
|
|
|
for (let i = 0; i < node.children.length; i++) {
|
|
|
const child = node.children[i];
|
|
|
+ console.log(` 🔍 检查子节点: ${child.name}`);
|
|
|
const foundWeapon = this.findWeaponNode(child);
|
|
|
if (foundWeapon) {
|
|
|
+ console.log(`✅ 在 ${child.name} 的子节点中找到Weapon`);
|
|
|
return foundWeapon;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果都没找到,返回null
|
|
|
+ console.log(`❌ 在 ${node.name} 及其子节点中未找到Weapon`);
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ // 辅助方法:打印节点结构
|
|
|
+ private logNodeStructure(node: Node, depth: number) {
|
|
|
+ const indent = ' '.repeat(depth);
|
|
|
+ console.log(`${indent}${node.name}`);
|
|
|
+ for (let i = 0; i < node.children.length; i++) {
|
|
|
+ this.logNodeStructure(node.children[i], depth + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 获取节点的完整路径
|
|
|
private getNodePath(node: Node): string {
|
|
|
let path = node.name;
|
|
|
@@ -667,103 +736,132 @@ export class BallController extends Component {
|
|
|
this.direction.y = currentVelocity.y / speed;
|
|
|
}
|
|
|
|
|
|
- // 手动检测墙体碰撞
|
|
|
- this.checkWallCollisions();
|
|
|
- }
|
|
|
-
|
|
|
- // 手动检测方块碰撞
|
|
|
- this.checkBlockCollisions();
|
|
|
- }
|
|
|
-
|
|
|
- // 手动检测墙体碰撞
|
|
|
- checkWallCollisions() {
|
|
|
- if (!this.activeBall || !this.activeBall.isValid) return;
|
|
|
-
|
|
|
- // 获取小球的世界坐标
|
|
|
- const ballPos = this.activeBall.worldPosition;
|
|
|
- const ballRadius = this.radius;
|
|
|
-
|
|
|
- // 检查是否碰到上下左右边界
|
|
|
- let collided = false;
|
|
|
- let normal = new Vec2(0, 0);
|
|
|
-
|
|
|
- // 上边界碰撞
|
|
|
- if (ballPos.y + ballRadius >= this.gameBounds.top) {
|
|
|
- normal.y = -1;
|
|
|
- collided = true;
|
|
|
- console.log('手动检测到上边界碰撞');
|
|
|
- }
|
|
|
- // 下边界碰撞
|
|
|
- else if (ballPos.y - ballRadius <= this.gameBounds.bottom) {
|
|
|
- normal.y = 1;
|
|
|
- collided = true;
|
|
|
- console.log('手动检测到下边界碰撞');
|
|
|
- }
|
|
|
-
|
|
|
- // 左边界碰撞
|
|
|
- if (ballPos.x - ballRadius <= this.gameBounds.left) {
|
|
|
- normal.x = 1;
|
|
|
- collided = true;
|
|
|
- console.log('手动检测到左边界碰撞');
|
|
|
- }
|
|
|
- // 右边界碰撞
|
|
|
- else if (ballPos.x + ballRadius >= this.gameBounds.right) {
|
|
|
- normal.x = -1;
|
|
|
- collided = true;
|
|
|
- console.log('手动检测到右边界碰撞');
|
|
|
- }
|
|
|
-
|
|
|
- // 如果碰到边界,计算反弹
|
|
|
- if (collided) {
|
|
|
- // 标准化法向量
|
|
|
- if (normal.x !== 0 || normal.y !== 0) {
|
|
|
- normal.normalize();
|
|
|
- }
|
|
|
-
|
|
|
- // 计算反射方向
|
|
|
- this.direction = this.calculateReflection(this.direction, normal);
|
|
|
-
|
|
|
- // 更新速度
|
|
|
- const rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
- if (rigidBody) {
|
|
|
- // 立即更新速度方向,确保反弹效果
|
|
|
+ // 如果速度过低,重新设置速度以维持恒定运动
|
|
|
+ if (speed < this.speed * 0.9) {
|
|
|
rigidBody.linearVelocity = new Vec2(
|
|
|
this.direction.x * this.speed,
|
|
|
this.direction.y * this.speed
|
|
|
);
|
|
|
- console.log('手动更新速度方向:', this.direction);
|
|
|
}
|
|
|
+
|
|
|
+ // 定期检查小球是否接近方块但没有触发碰撞(调试用)
|
|
|
+ this.debugCheckNearBlocks();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // 手动检测方块碰撞
|
|
|
- checkBlockCollisions() {
|
|
|
- if (!this.activeBall) return;
|
|
|
-
|
|
|
- // 获取场景中所有方块
|
|
|
- const placedBlocks = find('Canvas/PlacedBlocks');
|
|
|
- if (!placedBlocks) return;
|
|
|
+
|
|
|
+ // 调试方法:检查小球是否接近方块但没有触发物理碰撞
|
|
|
+ private debugCheckCounter = 0;
|
|
|
+ private debugCheckNearBlocks() {
|
|
|
+ this.debugCheckCounter++;
|
|
|
+ // 每60帧(约1秒)检查一次
|
|
|
+ if (this.debugCheckCounter % 60 !== 0) return;
|
|
|
|
|
|
const ballPos = this.activeBall.worldPosition;
|
|
|
- const ballRadius = this.radius;
|
|
|
+ const placedBlocksContainer = find('Canvas/PlacedBlocks');
|
|
|
+ if (!placedBlocksContainer) return;
|
|
|
+
|
|
|
+ let nearestDistance = Infinity;
|
|
|
+ let nearestBlock = null;
|
|
|
|
|
|
- // 检查与每个方块的碰撞
|
|
|
- for (let i = 0; i < placedBlocks.children.length; i++) {
|
|
|
- const block = placedBlocks.children[i];
|
|
|
- if (!block.name.includes('Block')) continue;
|
|
|
+ for (let i = 0; i < placedBlocksContainer.children.length; i++) {
|
|
|
+ const block = placedBlocksContainer.children[i];
|
|
|
+ if (block.name.includes('Block') || block.getChildByName('B1')) {
|
|
|
+ const blockPos = block.worldPosition;
|
|
|
+ const distance = Math.sqrt(
|
|
|
+ Math.pow(ballPos.x - blockPos.x, 2) +
|
|
|
+ Math.pow(ballPos.y - blockPos.y, 2)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (distance < nearestDistance) {
|
|
|
+ nearestDistance = distance;
|
|
|
+ nearestBlock = block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nearestBlock && nearestDistance < 100) {
|
|
|
+ console.log(`⚠️ 小球接近方块但无物理碰撞: 距离=${nearestDistance.toFixed(1)}, 方块=${nearestBlock.name}`);
|
|
|
+ console.log('小球位置:', ballPos);
|
|
|
+ console.log('方块位置:', nearestBlock.worldPosition);
|
|
|
+
|
|
|
+ // 检查小球的碰撞体状态
|
|
|
+ console.log('=== 小球碰撞体详细检查 ===');
|
|
|
+ const ballCollider = this.activeBall.getComponent(Collider2D);
|
|
|
+ console.log('小球有碰撞体:', !!ballCollider);
|
|
|
+ if (ballCollider) {
|
|
|
+ console.log('小球碰撞体类型:', ballCollider.constructor.name);
|
|
|
+ console.log('小球碰撞组:', ballCollider.group);
|
|
|
+ console.log('小球碰撞标签:', ballCollider.tag);
|
|
|
+ console.log('小球是否为传感器:', ballCollider.sensor);
|
|
|
+ console.log('小球碰撞体是否启用:', ballCollider.enabled);
|
|
|
+ if (ballCollider instanceof CircleCollider2D) {
|
|
|
+ console.log('小球碰撞半径:', ballCollider.radius);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 简单距离检测(可以根据实际情况优化)
|
|
|
- const blockPos = block.worldPosition;
|
|
|
- const distance = Vec3.distance(ballPos, blockPos);
|
|
|
+ // 检查小球的刚体状态
|
|
|
+ const ballRigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
+ console.log('小球有刚体:', !!ballRigidBody);
|
|
|
+ if (ballRigidBody) {
|
|
|
+ console.log('小球刚体类型:', ballRigidBody.type);
|
|
|
+ console.log('小球刚体启用碰撞监听:', ballRigidBody.enabledContactListener);
|
|
|
+ console.log('小球刚体是否启用:', ballRigidBody.enabled);
|
|
|
+ }
|
|
|
|
|
|
- // 如果距离小于某个阈值,认为发生碰撞
|
|
|
- if (distance < ballRadius + 50) { // 50是一个估计值,根据方块大小调整
|
|
|
- console.log('手动检测到与方块碰撞:', block.name);
|
|
|
- this.fireBullet(block);
|
|
|
- break;
|
|
|
+ // 检查最近的方块碰撞体
|
|
|
+ console.log('=== 方块碰撞体详细检查 ===');
|
|
|
+ const blockCollider = nearestBlock.getComponent(Collider2D);
|
|
|
+ console.log('方块有碰撞体:', !!blockCollider);
|
|
|
+ if (blockCollider) {
|
|
|
+ console.log('方块碰撞体类型:', blockCollider.constructor.name);
|
|
|
+ console.log('方块碰撞组:', blockCollider.group);
|
|
|
+ console.log('方块碰撞标签:', blockCollider.tag);
|
|
|
+ console.log('方块是否为传感器:', blockCollider.sensor);
|
|
|
+ console.log('方块碰撞体是否启用:', blockCollider.enabled);
|
|
|
}
|
|
|
+
|
|
|
+ // 检查碰撞矩阵
|
|
|
+ console.log('=== 碰撞矩阵检查 ===');
|
|
|
+ if (ballCollider && blockCollider) {
|
|
|
+ console.log(`小球组${ballCollider.group} 是否能与方块组${blockCollider.group} 碰撞: ${this.checkCollisionMatrix(ballCollider.group, blockCollider.group)}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查物理引擎状态
|
|
|
+ console.log('=== 物理引擎状态检查 ===');
|
|
|
+ console.log('物理引擎是否启用:', PhysicsSystem2D.instance.enable);
|
|
|
+ console.log('物理引擎重力:', PhysicsSystem2D.instance.gravity);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 检查碰撞矩阵
|
|
|
+ private checkCollisionMatrix(group1: number, group2: number): boolean {
|
|
|
+ // 根据项目配置检查碰撞矩阵
|
|
|
+ // "collisionMatrix": { "0": 3, "1": 39, "2": 6, "3": 16, "4": 40, "5": 18 }
|
|
|
+ const collisionMatrix: { [key: string]: number } = {
|
|
|
+ "0": 3,
|
|
|
+ "1": 39,
|
|
|
+ "2": 6,
|
|
|
+ "3": 16,
|
|
|
+ "4": 40,
|
|
|
+ "5": 18
|
|
|
+ };
|
|
|
+
|
|
|
+ const mask1 = collisionMatrix[group1.toString()];
|
|
|
+ const mask2 = collisionMatrix[group2.toString()];
|
|
|
+
|
|
|
+ console.log(`组${group1}的碰撞掩码: ${mask1} (二进制: ${mask1?.toString(2)})`);
|
|
|
+ console.log(`组${group2}的碰撞掩码: ${mask2} (二进制: ${mask2?.toString(2)})`);
|
|
|
+
|
|
|
+ // 检查group1是否能与group2碰撞
|
|
|
+ const canCollide1to2 = mask1 && (mask1 & (1 << group2)) !== 0;
|
|
|
+ // 检查group2是否能与group1碰撞
|
|
|
+ const canCollide2to1 = mask2 && (mask2 & (1 << group1)) !== 0;
|
|
|
+
|
|
|
+ console.log(`组${group1}->组${group2}: ${canCollide1to2}`);
|
|
|
+ console.log(`组${group2}->组${group1}: ${canCollide2to1}`);
|
|
|
+
|
|
|
+ return canCollide1to2 && canCollide2to1;
|
|
|
+ }
|
|
|
|
|
|
// 初始化方向
|
|
|
initializeDirection() {
|
|
|
@@ -795,4 +893,37 @@ export class BallController extends Component {
|
|
|
this.calculateGameBounds();
|
|
|
this.createBall();
|
|
|
}
|
|
|
+
|
|
|
+ // 输出碰撞矩阵调试信息
|
|
|
+ private logCollisionMatrix() {
|
|
|
+ // 根据项目配置检查碰撞矩阵
|
|
|
+ // "collisionMatrix": { "0": 3, "1": 39, "2": 6, "3": 16, "4": 40, "5": 18 }
|
|
|
+ const collisionMatrix: { [key: string]: number } = {
|
|
|
+ "0": 3,
|
|
|
+ "1": 39,
|
|
|
+ "2": 6,
|
|
|
+ "3": 16,
|
|
|
+ "4": 40,
|
|
|
+ "5": 18
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('🔍 === 碰撞矩阵配置 ===');
|
|
|
+ for (const group in collisionMatrix) {
|
|
|
+ const mask = collisionMatrix[group];
|
|
|
+ console.log(`组 ${group}: 掩码 ${mask} (二进制: ${mask?.toString(2)})`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试Ball组(1)和Block组(2)是否能碰撞
|
|
|
+ const ballMask = collisionMatrix["1"]; // 39
|
|
|
+ const blockMask = collisionMatrix["2"]; // 6
|
|
|
+
|
|
|
+ const ballCanCollideWithBlock = (ballMask & (1 << 2)) !== 0; // 检查Ball能否与组2碰撞
|
|
|
+ const blockCanCollideWithBall = (blockMask & (1 << 1)) !== 0; // 检查Block能否与组1碰撞
|
|
|
+
|
|
|
+ console.log('🎯 碰撞测试结果:');
|
|
|
+ console.log(`Ball组(1) -> Block组(2): ${ballCanCollideWithBlock}`);
|
|
|
+ console.log(`Block组(2) -> Ball组(1): ${blockCanCollideWithBall}`);
|
|
|
+ console.log(`双向碰撞可用: ${ballCanCollideWithBlock && blockCanCollideWithBall}`);
|
|
|
+ console.log('🔍 === 碰撞矩阵分析完成 ===');
|
|
|
+ }
|
|
|
}
|