|
|
@@ -12,7 +12,7 @@ export class BallController extends Component {
|
|
|
|
|
|
// 球的移动速度
|
|
|
@property
|
|
|
- public speed: number = 10;
|
|
|
+ public speed: number = 50;
|
|
|
|
|
|
// 当前活动的球
|
|
|
private activeBall: Node = null;
|
|
|
@@ -41,10 +41,6 @@ export class BallController extends Component {
|
|
|
})
|
|
|
public bulletPrefab: Prefab = null;
|
|
|
|
|
|
- // 子弹速度
|
|
|
- @property
|
|
|
- public bulletSpeed: number = 50;
|
|
|
-
|
|
|
start() {
|
|
|
// 计算游戏边界
|
|
|
this.calculateGameBounds();
|
|
|
@@ -53,7 +49,7 @@ export class BallController extends Component {
|
|
|
// 计算游戏边界(使用GameArea节点)
|
|
|
calculateGameBounds() {
|
|
|
// 获取GameArea节点
|
|
|
- const gameArea = find('Canvas/GameArea');
|
|
|
+ const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
if (!gameArea) {
|
|
|
console.error('找不到GameArea节点');
|
|
|
return;
|
|
|
@@ -79,6 +75,33 @@ export class BallController extends Component {
|
|
|
this.gameBounds.top = worldPos.y + areaHeight / 2;
|
|
|
|
|
|
console.log('GameArea Bounds:', this.gameBounds);
|
|
|
+
|
|
|
+ // 查找并输出墙体节点信息
|
|
|
+ this.logWallInfo();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 输出墙体节点信息
|
|
|
+ logWallInfo() {
|
|
|
+ const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
+ if (!gameArea) return;
|
|
|
+
|
|
|
+ // 查找墙体节点
|
|
|
+ const walls = ['TopFence', 'BottomFence', 'JiguangL', 'JiguangR'];
|
|
|
+ walls.forEach(wallName => {
|
|
|
+ const wall = gameArea.getChildByName(wallName);
|
|
|
+ if (wall) {
|
|
|
+ const transform = wall.getComponent(UITransform);
|
|
|
+ const collider = wall.getComponent(Collider2D);
|
|
|
+ console.log(`墙体节点 ${wallName} 信息:`, {
|
|
|
+ position: wall.worldPosition,
|
|
|
+ size: transform ? { width: transform.width, height: transform.height } : 'unknown',
|
|
|
+ hasCollider: !!collider,
|
|
|
+ colliderType: collider ? collider.constructor.name : 'none'
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.warn(`找不到墙体节点 ${wallName}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
// 创建小球
|
|
|
@@ -97,7 +120,7 @@ export class BallController extends Component {
|
|
|
this.activeBall = instantiate(this.ballPrefab);
|
|
|
|
|
|
// 将小球添加到GameArea中
|
|
|
- const gameArea = find('Canvas/GameArea');
|
|
|
+ const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
if (gameArea) {
|
|
|
gameArea.addChild(this.activeBall);
|
|
|
} else {
|
|
|
@@ -111,6 +134,10 @@ export class BallController extends Component {
|
|
|
const transform = this.activeBall.getComponent(UITransform);
|
|
|
if (transform) {
|
|
|
this.radius = transform.width / 2;
|
|
|
+ console.log('小球半径设置为:', this.radius);
|
|
|
+ } else {
|
|
|
+ this.radius = 25; // 默认半径
|
|
|
+ console.warn('无法获取小球UITransform组件,使用默认半径:', this.radius);
|
|
|
}
|
|
|
|
|
|
// 确保有碰撞组件
|
|
|
@@ -120,6 +147,11 @@ export class BallController extends Component {
|
|
|
this.initializeDirection();
|
|
|
|
|
|
this.initialized = true;
|
|
|
+ console.log('小球创建完成:', {
|
|
|
+ position: this.activeBall.position,
|
|
|
+ radius: this.radius,
|
|
|
+ initialized: this.initialized
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
// 随机位置小球
|
|
|
@@ -140,7 +172,7 @@ export class BallController extends Component {
|
|
|
const randomY = Math.random() * (maxY - minY) + minY;
|
|
|
|
|
|
// 将世界坐标转换为相对于GameArea的本地坐标
|
|
|
- const gameArea = find('Canvas/GameArea');
|
|
|
+ const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
if (gameArea) {
|
|
|
const localPos = gameArea.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(randomX, randomY, 0));
|
|
|
this.activeBall.position = localPos;
|
|
|
@@ -161,61 +193,157 @@ export class BallController extends Component {
|
|
|
rigidBody.type = 2; // Dynamic
|
|
|
rigidBody.gravityScale = 0; // 不受重力影响
|
|
|
rigidBody.enabledContactListener = true; // 启用碰撞监听
|
|
|
- rigidBody.bullet = true; // 高精度碰撞检测
|
|
|
- rigidBody.fixedRotation = false; // 允许旋转
|
|
|
- rigidBody.allowSleep = true;
|
|
|
+ rigidBody.fixedRotation = true; // 固定旋转
|
|
|
+ rigidBody.allowSleep = false; // 不允许休眠
|
|
|
+ rigidBody.linearDamping = 0; // 无阻尼
|
|
|
+ rigidBody.angularDamping = 0; // 无角阻尼
|
|
|
+ } else {
|
|
|
+ // 确保已有的刚体组件设置正确
|
|
|
+ rigidBody.enabledContactListener = true;
|
|
|
+ rigidBody.gravityScale = 0;
|
|
|
}
|
|
|
|
|
|
- // 注册碰撞事件
|
|
|
- this.activeBall.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
- }
|
|
|
-
|
|
|
- // 初始化方向
|
|
|
- initializeDirection() {
|
|
|
- // 随机初始方向
|
|
|
- const angle = Math.random() * Math.PI * 2; // 0-2π之间的随机角度
|
|
|
- this.direction.x = Math.cos(angle);
|
|
|
- this.direction.y = Math.sin(angle);
|
|
|
- this.direction.normalize();
|
|
|
-
|
|
|
- console.log('Ball initialized with direction:', this.direction);
|
|
|
- }
|
|
|
-
|
|
|
- // 初始化球的参数 - 公开方法,供GameManager调用
|
|
|
- initialize() {
|
|
|
- this.calculateGameBounds();
|
|
|
- this.createBall();
|
|
|
- }
|
|
|
+ // 确保小球有碰撞组件
|
|
|
+ let collider = this.activeBall.getComponent(CircleCollider2D);
|
|
|
+ if (!collider) {
|
|
|
+ collider = this.activeBall.addComponent(CircleCollider2D);
|
|
|
+ collider.radius = this.radius || 25; // 使用已计算的半径或默认值
|
|
|
+ collider.tag = 1; // 小球标签
|
|
|
+ collider.group = 1; // 碰撞组
|
|
|
+ collider.sensor = false; // 非传感器(实际碰撞)
|
|
|
+ collider.friction = 0; // 无摩擦
|
|
|
+ collider.restitution = 1; // 完全弹性碰撞
|
|
|
+ } else {
|
|
|
+ // 确保已有的碰撞组件设置正确
|
|
|
+ collider.sensor = false;
|
|
|
+ collider.restitution = 1;
|
|
|
+ }
|
|
|
|
|
|
- update(dt: number) {
|
|
|
- // 如果使用物理引擎,不要手动更新位置
|
|
|
- if (!this.initialized || !this.activeBall || !this.activeBall.isValid) return;
|
|
|
+ console.log('小球碰撞组件设置完成:', {
|
|
|
+ hasRigidBody: !!rigidBody,
|
|
|
+ hasCollider: !!collider,
|
|
|
+ radius: collider ? collider.radius : 'unknown'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 移除可能存在的事件监听
|
|
|
+ this.activeBall.off(Contact2DType.BEGIN_CONTACT);
|
|
|
+ this.activeBall.off(Contact2DType.END_CONTACT);
|
|
|
+ this.activeBall.off(Contact2DType.PRE_SOLVE);
|
|
|
+ this.activeBall.off(Contact2DType.POST_SOLVE);
|
|
|
|
|
|
- // 使用刚体组件控制小球移动,而不是直接设置位置
|
|
|
- const rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
- if (rigidBody) {
|
|
|
- // 设置线性速度而不是位置
|
|
|
- rigidBody.linearVelocity = new Vec2(
|
|
|
- this.direction.x * this.speed,
|
|
|
- this.direction.y * this.speed
|
|
|
- );
|
|
|
- }
|
|
|
+ // 注册所有类型的碰撞事件
|
|
|
+ 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('已注册所有碰撞事件监听器');
|
|
|
}
|
|
|
|
|
|
// 碰撞回调中,只需要更新方向向量,物理引擎会处理实际的反弹
|
|
|
onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
// 获取碰撞点和法线
|
|
|
- if (!contact) return;
|
|
|
+ if (!contact) {
|
|
|
+ console.warn('碰撞事件没有contact对象');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录碰撞对象信息
|
|
|
+ console.log('碰撞发生:', {
|
|
|
+ selfName: selfCollider.node.name,
|
|
|
+ otherName: otherCollider.node.name,
|
|
|
+ otherPath: this.getNodePath(otherCollider.node)
|
|
|
+ });
|
|
|
|
|
|
// 获取碰撞点的世界坐标
|
|
|
const worldManifold = contact.getWorldManifold();
|
|
|
- if (!worldManifold) return;
|
|
|
+ if (!worldManifold) {
|
|
|
+ console.warn('无法获取worldManifold');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
// 获取碰撞法线
|
|
|
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';
|
|
|
|
|
|
- // 更新方向向量,但让物理引擎处理实际的反弹
|
|
|
- this.direction = this.calculateReflection(this.direction, normal);
|
|
|
+ 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);
|
|
|
+
|
|
|
+ // 强制设置位置,避免卡在墙内
|
|
|
+ const ballPos = this.activeBall.worldPosition;
|
|
|
+ const ballRadius = this.radius;
|
|
|
+
|
|
|
+ // 根据碰撞法线调整位置
|
|
|
+ if (Math.abs(normal.y) > Math.abs(normal.x)) {
|
|
|
+ // 上下墙体碰撞
|
|
|
+ if (normal.y > 0) {
|
|
|
+ // 下墙
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ ballPos.x,
|
|
|
+ ballPos.y + ballRadius * 0.5,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ } else {
|
|
|
+ // 上墙
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ ballPos.x,
|
|
|
+ ballPos.y - ballRadius * 0.5,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 左右墙体碰撞
|
|
|
+ if (normal.x > 0) {
|
|
|
+ // 左墙
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ ballPos.x + ballRadius * 0.5,
|
|
|
+ ballPos.y,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ } else {
|
|
|
+ // 右墙
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ ballPos.x - ballRadius * 0.5,
|
|
|
+ ballPos.y,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// 如果碰撞的是方块,发射子弹
|
|
|
if (otherCollider.node.name.includes('Block')) {
|
|
|
@@ -223,6 +351,51 @@ export class BallController extends Component {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 碰撞结束事件
|
|
|
+ onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
+ console.log('碰撞结束:', otherCollider.node.name);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 碰撞预处理事件
|
|
|
+ onPreSolve(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
+ 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
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 计算反射向量
|
|
|
calculateReflection(direction: Vec2, normal: Vec2): Vec2 {
|
|
|
// 使用反射公式: R = V - 2(V·N)N
|
|
|
@@ -232,7 +405,27 @@ export class BallController extends Component {
|
|
|
direction.y - 2 * dot * normal.y
|
|
|
);
|
|
|
reflection.normalize();
|
|
|
- return reflection;
|
|
|
+
|
|
|
+ // 添加一些随机性,避免重复的反弹路径
|
|
|
+ const randomAngle = (Math.random() - 0.5) * 0.2; // -0.1到0.1弧度的随机角度
|
|
|
+ const cos = Math.cos(randomAngle);
|
|
|
+ const sin = Math.sin(randomAngle);
|
|
|
+
|
|
|
+ // 应用随机旋转
|
|
|
+ const randomizedReflection = new Vec2(
|
|
|
+ reflection.x * cos - reflection.y * sin,
|
|
|
+ reflection.x * sin + reflection.y * cos
|
|
|
+ );
|
|
|
+
|
|
|
+ randomizedReflection.normalize();
|
|
|
+ console.log('反射方向:', {
|
|
|
+ original: direction,
|
|
|
+ normal: normal,
|
|
|
+ reflection: reflection,
|
|
|
+ randomized: randomizedReflection
|
|
|
+ });
|
|
|
+
|
|
|
+ return randomizedReflection;
|
|
|
}
|
|
|
|
|
|
// 发射子弹
|
|
|
@@ -256,7 +449,7 @@ export class BallController extends Component {
|
|
|
const bullet = instantiate(this.bulletPrefab);
|
|
|
|
|
|
// 将子弹添加到GameArea中
|
|
|
- const gameArea = find('Canvas/GameArea');
|
|
|
+ const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
if (gameArea) {
|
|
|
gameArea.addChild(bullet);
|
|
|
|
|
|
@@ -272,33 +465,6 @@ export class BallController extends Component {
|
|
|
);
|
|
|
direction.normalize();
|
|
|
|
|
|
- // 添加刚体组件控制子弹移动
|
|
|
- let rigidBody = bullet.getComponent(RigidBody2D);
|
|
|
- if (!rigidBody) {
|
|
|
- rigidBody = bullet.addComponent(RigidBody2D);
|
|
|
- rigidBody.type = 2; // Dynamic
|
|
|
- rigidBody.gravityScale = 0; // 不受重力影响
|
|
|
- rigidBody.fixedRotation = true; // 固定旋转
|
|
|
- rigidBody.allowSleep = false; // 不允许休眠
|
|
|
- }
|
|
|
-
|
|
|
- // 设置子弹速度
|
|
|
- rigidBody.linearVelocity = new Vec2(
|
|
|
- direction.x * this.bulletSpeed,
|
|
|
- direction.y * this.bulletSpeed
|
|
|
- );
|
|
|
-
|
|
|
- // 确保子弹有碰撞体
|
|
|
- let collider = bullet.getComponent(CircleCollider2D);
|
|
|
- if (!collider) {
|
|
|
- collider = bullet.addComponent(CircleCollider2D);
|
|
|
- collider.radius = 5; // 设置适当的半径
|
|
|
- collider.tag = 3; // 子弹标签
|
|
|
- collider.group = 1; // 与其他物体同组
|
|
|
- collider.sensor = false;
|
|
|
- collider.friction = 0;
|
|
|
- collider.restitution = 1;
|
|
|
- }
|
|
|
|
|
|
// 添加自动销毁逻辑
|
|
|
this.scheduleOnce(() => {
|
|
|
@@ -308,4 +474,161 @@ export class BallController extends Component {
|
|
|
}, 5); // 5秒后销毁子弹
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 获取节点的完整路径
|
|
|
+ private getNodePath(node: Node): string {
|
|
|
+ let path = node.name;
|
|
|
+ let current = node;
|
|
|
+
|
|
|
+ while (current.parent) {
|
|
|
+ current = current.parent;
|
|
|
+ path = current.name + '/' + path;
|
|
|
+ }
|
|
|
+
|
|
|
+ return path;
|
|
|
+ }
|
|
|
+
|
|
|
+ update(dt: number) {
|
|
|
+ // 如果使用物理引擎,不要手动更新位置
|
|
|
+ if (!this.initialized || !this.activeBall || !this.activeBall.isValid) return;
|
|
|
+
|
|
|
+ // 使用刚体组件控制小球移动,而不是直接设置位置
|
|
|
+ const rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
+ if (rigidBody) {
|
|
|
+ // 检查速度是否过小或为零,如果是则恢复速度
|
|
|
+ const currentVelocity = rigidBody.linearVelocity;
|
|
|
+ const speed = Math.sqrt(currentVelocity.x * currentVelocity.x + currentVelocity.y * currentVelocity.y);
|
|
|
+
|
|
|
+ if (speed < 1.0) {
|
|
|
+ console.log('检测到速度过小,恢复速度:', speed);
|
|
|
+ // 如果速度太小,恢复到正常速度
|
|
|
+ this.direction.normalize();
|
|
|
+ rigidBody.linearVelocity = new Vec2(
|
|
|
+ this.direction.x * this.speed,
|
|
|
+ this.direction.y * this.speed
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保方向向量与实际速度方向一致
|
|
|
+ if (speed > 1.0) {
|
|
|
+ this.direction.x = currentVelocity.x / speed;
|
|
|
+ this.direction.y = currentVelocity.y / speed;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 手动检测墙体碰撞
|
|
|
+ this.checkWallCollisions();
|
|
|
+
|
|
|
+ // 每隔一段时间输出小球状态信息
|
|
|
+ if (Math.random() < 0.01) { // 约每100帧输出一次
|
|
|
+ console.log('小球状态:', {
|
|
|
+ position: this.activeBall.worldPosition,
|
|
|
+ velocity: rigidBody.linearVelocity,
|
|
|
+ speed: speed,
|
|
|
+ direction: this.direction
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 手动检测墙体碰撞
|
|
|
+ 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('手动检测到上边界碰撞');
|
|
|
+ // 修正位置,避免卡在边界
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ ballPos.x,
|
|
|
+ this.gameBounds.top - ballRadius - 0.1,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ // 下边界碰撞
|
|
|
+ else if (ballPos.y - ballRadius <= this.gameBounds.bottom) {
|
|
|
+ normal.y = 1;
|
|
|
+ collided = true;
|
|
|
+ console.log('手动检测到下边界碰撞');
|
|
|
+ // 修正位置,避免卡在边界
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ ballPos.x,
|
|
|
+ this.gameBounds.bottom + ballRadius + 0.1,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 左边界碰撞
|
|
|
+ if (ballPos.x - ballRadius <= this.gameBounds.left) {
|
|
|
+ normal.x = 1;
|
|
|
+ collided = true;
|
|
|
+ console.log('手动检测到左边界碰撞');
|
|
|
+ // 修正位置,避免卡在边界
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ this.gameBounds.left + ballRadius + 0.1,
|
|
|
+ ballPos.y,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ // 右边界碰撞
|
|
|
+ else if (ballPos.x + ballRadius >= this.gameBounds.right) {
|
|
|
+ normal.x = -1;
|
|
|
+ collided = true;
|
|
|
+ console.log('手动检测到右边界碰撞');
|
|
|
+ // 修正位置,避免卡在边界
|
|
|
+ this.activeBall.setWorldPosition(new Vec3(
|
|
|
+ this.gameBounds.right - ballRadius - 0.1,
|
|
|
+ ballPos.y,
|
|
|
+ ballPos.z
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果碰到边界,计算反弹
|
|
|
+ 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) {
|
|
|
+ // 立即更新速度方向,确保反弹效果
|
|
|
+ rigidBody.linearVelocity = new Vec2(
|
|
|
+ this.direction.x * this.speed,
|
|
|
+ this.direction.y * this.speed
|
|
|
+ );
|
|
|
+ console.log('手动更新速度方向:', this.direction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化方向
|
|
|
+ initializeDirection() {
|
|
|
+ // 随机初始方向
|
|
|
+ const angle = Math.random() * Math.PI * 2; // 0-2π之间的随机角度
|
|
|
+ this.direction.x = Math.cos(angle);
|
|
|
+ this.direction.y = Math.sin(angle);
|
|
|
+ this.direction.normalize();
|
|
|
+
|
|
|
+ console.log('Ball initialized with direction:', this.direction);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化球的参数 - 公开方法,供GameManager调用
|
|
|
+ initialize() {
|
|
|
+ this.calculateGameBounds();
|
|
|
+ this.createBall();
|
|
|
+ }
|
|
|
}
|