主题
12 · Cocos 对照:同玩法最小迁移
目标:在 Creator 3.x 里复刻 Phaser 街机射击核心(移动、射击、刷敌、碰撞得分、Game Over)。
前置:11 · 编辑器与 TS · 玩法对齐 10
碰撞默认方案:Physics2DBoxCollider2D+ 接触回调(对照 Phaser Arcadeoverlap)。
1. 编辑器操作:场景搭法
在 480×640 场景中建议层级:
text
Canvas (或 2D 根)
├── GameRoot ← 挂 GameController.ts(刷怪、分数、胜负)
├── Player ← Sprite 色块 + RigidBody2D(Kinematic) + BoxCollider2D
│ └── (脚本 PlayerController.ts)
├── BulletLayer ← 空节点,运行时挂子弹
├── EnemyLayer ← 空节点,运行时挂敌人
└── UI
└── ScoreLabel ← Label:「Score: 0」1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
预制体:
- 建
Bullet节点:小竖条 Sprite +RigidBody2D(Kinematic)+BoxCollider2D(勾选 Sensor,更像 overlap)+ 可选Bullet.ts。 - 拖到资源成 Prefab。
- 同理做
EnemyPrefab(红色方块,速度向下在脚本里写)。
GameRoot 的 GameController 上拖入:Bullet/Enemy 预制体引用、Player 节点、Score Label、BulletLayer、EnemyLayer。
2. 对应 TS:输入与玩家
PlayerController.ts(要点):
ts
import { _decorator, Component, input, Input, EventKeyboard, KeyCode, Vec3 } from 'cc'
const { ccclass, property } = _decorator
@ccclass('PlayerController')
export class PlayerController extends Component {
@property speed = 260
private axis = 0
private _pos = new Vec3()
onEnable() {
input.on(Input.EventType.KEY_DOWN, this.onDown, this)
input.on(Input.EventType.KEY_UP, this.onUp, this)
}
onDisable() {
input.off(Input.EventType.KEY_DOWN, this.onDown, this)
input.off(Input.EventType.KEY_UP, this.onUp, this)
}
private onDown(e: EventKeyboard) {
if (e.keyCode === KeyCode.KEY_A || e.keyCode === KeyCode.ARROW_LEFT) this.axis = -1
if (e.keyCode === KeyCode.KEY_D || e.keyCode === KeyCode.ARROW_RIGHT) this.axis = 1
}
private onUp(e: EventKeyboard) {
if (
e.keyCode === KeyCode.KEY_A ||
e.keyCode === KeyCode.ARROW_LEFT ||
e.keyCode === KeyCode.KEY_D ||
e.keyCode === KeyCode.ARROW_RIGHT
) {
this.axis = 0
}
}
update(dt: number) {
this.node.getPosition(this._pos)
this._pos.x += this.axis * this.speed * dt
const half = 20
const maxX = 240 - half // 设计宽 480、原点在中心时按你的坐标系改
if (this._pos.x < -maxX) this._pos.x = -maxX
if (this._pos.x > maxX) this._pos.x = maxX
this.node.setPosition(this._pos)
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
坐标系:Creator 常以设计分辨率中心为原点;Phaser 默认左上。改边界数字时以预览为准,不要求与 Phaser 像素级一致。
空格射击可放在 GameController:读 KEY_SPACE + fireCd,instantiate(bulletPrefab) 到 BulletLayer,设初始位置在玩家上方。
3. 对应 TS:刷怪与子弹运动
ts
// GameController 内示意
spawnEnemy() {
const node = instantiate(this.enemyPrefab)
node.parent = this.enemyLayer
node.setPosition(Math.random() * 400 - 200, 300)
// EnemyMotor:update 里 position.y -= speed * dt
}
spawnBullet() {
const node = instantiate(this.bulletPrefab)
node.parent = this.bulletLayer
node.setPosition(this.player.position.x, this.player.position.y + 30)
// BulletMotor:position.y += 420 * dt;出屏 destroy
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
对照 Phaser:Group.get ↔ instantiate + destroy;对象池仍留阶段三。
4. Physics2D 碰撞(默认方案)
编辑器:
- 项目设置启用 2D 物理(若模板未开)。
- Player / Bullet / Enemy:
RigidBody2D类型建议 Kinematic(位置由脚本驱),BoxCollider2D勾选 Sensor(触发而不产生推力,对齐 overlap)。 - 在子弹或敌人脚本里监听接触:
ts
import { _decorator, Component, Contact2DType, Collider2D, IPhysics2DContact } from 'cc'
@ccclass('BulletHit')
export class BulletHit extends Component {
onEnable() {
const col = this.getComponent(Collider2D)!
col.on(Contact2DType.BEGIN_CONTACT, this.onBegin, this)
}
onBegin(_s: Collider2D, o: Collider2D, _c: IPhysics2DContact | null) {
if (o.node.name.startsWith('Enemy') || o.node.name.includes('enemy')) {
// 通知 GameController +1 分,然后 destroy 双方
this.node.destroy()
o.node.destroy()
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
玩家与敌人同理:BEGIN_CONTACT → gameOver,停刷怪、显示 Label「Game Over — press R」,KEY_R 时 director.loadScene(当前场景名) 重载。
若物理调试成本过高(备选): 在 GameController.update 里对子弹/敌人做 AABB(复用 05 的 hit),先保证玩法,再换回 Physics2D——文档默认仍以物理接触为准。
5. 验收(对齐 10,不要求像素一致)
- [ ] 左右移动 + 大致不出屏
- [ ] 空格射击 + 冷却,子弹向上,出屏销毁
- [ ] 定时刷敌下落
- [ ] 子弹碰敌得分,双方消失
- [ ] 敌碰玩家 Game Over,R 重开场景
- [ ] 可玩约 30s
6. 迁移时心里要有数
| 已在 Phaser 会的 | Cocos 里换皮 |
|---|---|
| Scene.create 里 new 一切 | 编辑器摆 + Prefab + 少量代码 |
| overlap 回调 | Contact2D BEGIN_CONTACT |
scene.restart | director.loadScene |
| 纹理 key | SpriteFrame / 色块材质 |
下一篇用表把整张地图钉死。
