|
|
@@ -1,4 +1,4 @@
|
|
|
-import { _decorator, Component, Node, Vec2, Vec3, UITransform, Collider2D, Contact2DType, IPhysics2DContact, director, CircleCollider2D, RigidBody2D, Prefab, instantiate, find, js } from 'cc';
|
|
|
+import { _decorator, Component, Node, Vec2, Vec3, UITransform, Collider2D, Contact2DType, IPhysics2DContact, RigidBody2D, Prefab, instantiate, find, CircleCollider2D } from 'cc';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
@ccclass('BallController')
|
|
|
@@ -20,7 +20,7 @@ export class BallController extends Component {
|
|
|
// 球的方向向量
|
|
|
private direction: Vec2 = new Vec2();
|
|
|
|
|
|
- // 游戏区域边界
|
|
|
+ // GameArea区域边界
|
|
|
private gameBounds = {
|
|
|
left: 0,
|
|
|
right: 0,
|
|
|
@@ -34,40 +34,51 @@ export class BallController extends Component {
|
|
|
// 是否已初始化
|
|
|
private initialized: boolean = false;
|
|
|
|
|
|
+ // 子弹预制体
|
|
|
+ @property({
|
|
|
+ type: Prefab,
|
|
|
+ tooltip: '拖拽子弹预制体到这里'
|
|
|
+ })
|
|
|
+ public bulletPrefab: Prefab = null;
|
|
|
+
|
|
|
+ // 子弹速度
|
|
|
+ @property
|
|
|
+ public bulletSpeed: number = 50;
|
|
|
+
|
|
|
start() {
|
|
|
// 计算游戏边界
|
|
|
this.calculateGameBounds();
|
|
|
}
|
|
|
|
|
|
- // 计算游戏边界(使用整个屏幕)
|
|
|
+ // 计算游戏边界(使用GameArea节点)
|
|
|
calculateGameBounds() {
|
|
|
- // 获取屏幕尺寸
|
|
|
- const canvas = find('Canvas');
|
|
|
- if (!canvas) {
|
|
|
- console.error('找不到Canvas节点');
|
|
|
+ // 获取GameArea节点
|
|
|
+ const gameArea = find('Canvas/GameArea');
|
|
|
+ if (!gameArea) {
|
|
|
+ console.error('找不到GameArea节点');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const canvasUI = canvas.getComponent(UITransform);
|
|
|
- if (!canvasUI) {
|
|
|
- console.error('Canvas节点没有UITransform组件');
|
|
|
+ const gameAreaUI = gameArea.getComponent(UITransform);
|
|
|
+ if (!gameAreaUI) {
|
|
|
+ console.error('GameArea节点没有UITransform组件');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 获取屏幕的尺寸
|
|
|
- const screenWidth = canvasUI.width;
|
|
|
- const screenHeight = canvasUI.height;
|
|
|
+ // 获取GameArea的尺寸
|
|
|
+ const areaWidth = gameAreaUI.width;
|
|
|
+ const areaHeight = gameAreaUI.height;
|
|
|
|
|
|
- // 获取屏幕的世界坐标位置
|
|
|
- const worldPos = canvas.worldPosition;
|
|
|
+ // 获取GameArea的世界坐标位置
|
|
|
+ const worldPos = gameArea.worldPosition;
|
|
|
|
|
|
- // 计算屏幕的世界坐标边界
|
|
|
- this.gameBounds.left = worldPos.x - screenWidth / 2;
|
|
|
- this.gameBounds.right = worldPos.x + screenWidth / 2;
|
|
|
- this.gameBounds.bottom = worldPos.y - screenHeight / 2;
|
|
|
- this.gameBounds.top = worldPos.y + screenHeight / 2;
|
|
|
+ // 计算GameArea的世界坐标边界
|
|
|
+ this.gameBounds.left = worldPos.x - areaWidth / 2;
|
|
|
+ this.gameBounds.right = worldPos.x + areaWidth / 2;
|
|
|
+ this.gameBounds.bottom = worldPos.y - areaHeight / 2;
|
|
|
+ this.gameBounds.top = worldPos.y + areaHeight / 2;
|
|
|
|
|
|
- console.log('Screen Bounds:', this.gameBounds);
|
|
|
+ console.log('GameArea Bounds:', this.gameBounds);
|
|
|
}
|
|
|
|
|
|
// 创建小球
|
|
|
@@ -84,10 +95,16 @@ export class BallController extends Component {
|
|
|
|
|
|
// 实例化小球
|
|
|
this.activeBall = instantiate(this.ballPrefab);
|
|
|
- this.node.addChild(this.activeBall);
|
|
|
-
|
|
|
+
|
|
|
+ // 将小球添加到GameArea中
|
|
|
+ const gameArea = find('Canvas/GameArea');
|
|
|
+ if (gameArea) {
|
|
|
+ gameArea.addChild(this.activeBall);
|
|
|
+ } else {
|
|
|
+ this.node.addChild(this.activeBall);
|
|
|
+ }
|
|
|
|
|
|
- // 随机位置(在屏幕范围内)
|
|
|
+ // 随机位置(在GameArea范围内)
|
|
|
this.positionBallRandomly();
|
|
|
|
|
|
// 设置球的半径
|
|
|
@@ -105,7 +122,6 @@ export class BallController extends Component {
|
|
|
this.initialized = true;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 随机位置小球
|
|
|
positionBallRandomly() {
|
|
|
if (!this.activeBall) return;
|
|
|
@@ -114,19 +130,19 @@ export class BallController extends Component {
|
|
|
const ballRadius = transform ? transform.width / 2 : 25;
|
|
|
|
|
|
// 计算可生成的范围(考虑小球半径,避免生成在边缘)
|
|
|
- const minX = this.gameBounds.left + ballRadius;
|
|
|
- const maxX = this.gameBounds.right - ballRadius;
|
|
|
- const minY = this.gameBounds.bottom + ballRadius;
|
|
|
- const maxY = this.gameBounds.top - ballRadius;
|
|
|
+ const minX = this.gameBounds.left + ballRadius + 20; // 额外偏移,避免生成在边缘
|
|
|
+ const maxX = this.gameBounds.right - ballRadius - 20;
|
|
|
+ const minY = this.gameBounds.bottom + ballRadius + 20;
|
|
|
+ const maxY = this.gameBounds.top - ballRadius - 20;
|
|
|
|
|
|
// 随机生成位置
|
|
|
const randomX = Math.random() * (maxX - minX) + minX;
|
|
|
const randomY = Math.random() * (maxY - minY) + minY;
|
|
|
|
|
|
- // 将世界坐标转换为相对于节点的本地坐标
|
|
|
- const canvas = find('Canvas');
|
|
|
- if (canvas) {
|
|
|
- const localPos = canvas.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(randomX, randomY, 0));
|
|
|
+ // 将世界坐标转换为相对于GameArea的本地坐标
|
|
|
+ const gameArea = find('Canvas/GameArea');
|
|
|
+ if (gameArea) {
|
|
|
+ const localPos = gameArea.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(randomX, randomY, 0));
|
|
|
this.activeBall.position = localPos;
|
|
|
} else {
|
|
|
// 直接设置位置(不太准确,但作为后备)
|
|
|
@@ -138,22 +154,20 @@ export class BallController extends Component {
|
|
|
setupCollider() {
|
|
|
if (!this.activeBall) return;
|
|
|
|
|
|
- let collider = this.activeBall.getComponent(CircleCollider2D);
|
|
|
- if (!collider) {
|
|
|
- collider = this.activeBall.addComponent(CircleCollider2D);
|
|
|
- collider.radius = this.radius;
|
|
|
- collider.tag = 0;
|
|
|
- collider.group = 1;
|
|
|
- collider.sensor = false;
|
|
|
- collider.friction = 0;
|
|
|
- collider.restitution = 1; // 完全弹性碰撞
|
|
|
- } else {
|
|
|
- // 设置碰撞组件的属性
|
|
|
- collider.restitution = 1; // 确保完全弹性碰撞
|
|
|
+ // 确保小球有刚体组件
|
|
|
+ let rigidBody = this.activeBall.getComponent(RigidBody2D);
|
|
|
+ if (!rigidBody) {
|
|
|
+ rigidBody = this.activeBall.addComponent(RigidBody2D);
|
|
|
+ rigidBody.type = 2; // Dynamic
|
|
|
+ rigidBody.gravityScale = 0; // 不受重力影响
|
|
|
+ rigidBody.enabledContactListener = true; // 启用碰撞监听
|
|
|
+ rigidBody.bullet = true; // 高精度碰撞检测
|
|
|
+ rigidBody.fixedRotation = false; // 允许旋转
|
|
|
+ rigidBody.allowSleep = true;
|
|
|
}
|
|
|
|
|
|
// 注册碰撞事件
|
|
|
- collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
+ this.activeBall.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
}
|
|
|
|
|
|
// 初始化方向
|
|
|
@@ -186,11 +200,6 @@ export class BallController extends Component {
|
|
|
this.direction.y * this.speed
|
|
|
);
|
|
|
}
|
|
|
-
|
|
|
- // 不再需要这些代码,因为物理引擎会处理碰撞和位置更新
|
|
|
- // const newPos = new Vec3(...);
|
|
|
- // this.checkBoundaryCollision(newPos);
|
|
|
- // this.activeBall.position = newPos;
|
|
|
}
|
|
|
|
|
|
// 碰撞回调中,只需要更新方向向量,物理引擎会处理实际的反弹
|
|
|
@@ -229,7 +238,74 @@ export class BallController extends Component {
|
|
|
// 发射子弹
|
|
|
fireBullet(blockNode: Node) {
|
|
|
console.log('发射子弹!击中方块:', blockNode.name);
|
|
|
- // 这里只是模拟发射子弹,实际的子弹逻辑和动画将在后续添加
|
|
|
+
|
|
|
+ // 检查是否有子弹预制体
|
|
|
+ if (!this.bulletPrefab) {
|
|
|
+ console.error('未设置子弹预制体');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查找Weapon节点
|
|
|
+ const weaponNode = blockNode.getChildByName('Weapon');
|
|
|
+ if (!weaponNode) {
|
|
|
+ console.warn(`方块 ${blockNode.name} 没有Weapon子节点`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 实例化子弹
|
|
|
+ const bullet = instantiate(this.bulletPrefab);
|
|
|
+
|
|
|
+ // 将子弹添加到GameArea中
|
|
|
+ const gameArea = find('Canvas/GameArea');
|
|
|
+ if (gameArea) {
|
|
|
+ gameArea.addChild(bullet);
|
|
|
+
|
|
|
+ // 设置子弹初始位置为Weapon节点的位置
|
|
|
+ const weaponWorldPos = weaponNode.worldPosition;
|
|
|
+ bullet.worldPosition = weaponWorldPos;
|
|
|
+
|
|
|
+ // 计算子弹方向 - 从Weapon指向小球
|
|
|
+ const ballPos = this.activeBall.worldPosition;
|
|
|
+ const direction = new Vec2(
|
|
|
+ ballPos.x - weaponWorldPos.x,
|
|
|
+ ballPos.y - weaponWorldPos.y
|
|
|
+ );
|
|
|
+ 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(() => {
|
|
|
+ if (bullet && bullet.isValid) {
|
|
|
+ bullet.destroy();
|
|
|
+ }
|
|
|
+ }, 5); // 5秒后销毁子弹
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
}
|