简单的demo实现,没优化以及加上音频文件,没有开始结束暂停等逻辑。
首先2D状态下,接受的素材
1、首先实现背景的移动
基本逻辑如下 关于fixUpdate,可以写一个基类,然后继承它
//固定帧计时
private _now_time = 0;
//固定帧时间
private frameTime = 0.016;
start() {
this.gameBg1.setPosition(0, 0, 0);
this.gameBg2.setPosition(0, this._maxRange, 0);
}
update(deltaTime: number) {
this._now_time += deltaTime;
while (this._now_time >= this.frameTime) {
//迭代逻辑
this.childUpdate(this.frameTime);
this._now_time -= this.frameTime;
}
}
childUpdate(deltaTime: number) {
this.gameBg1.setPosition(0, this.gameBg1.position.y - this._moveSpeed * deltaTime, 0);
this.gameBg2.setPosition(0, this.gameBg2.position.y - this._moveSpeed * deltaTime, 0);
if (this.gameBg1.position.y <= -this._maxRange) {
this.gameBg1.setPosition(0, this.gameBg2.position.y + this._maxRange, 0);
} else if (this.gameBg2.position.y <= -this._maxRange) {
this.gameBg2.setPosition(0, this.gameBg1.position.z + this._maxRange, 0);
}
}
2、创建角色小飞机,来一个脚本控制小飞机的移动
3.x上
Input该输入类管理所有的输入事件,包括:触摸、鼠标、加速计、游戏手柄、6DOF手柄、头戴显示器 和 键盘。
所以Node与Input的这连个监听事件,都可以使用
//玩家飞机
@property(Node)
userPlane: Node = null;
protected onLoad(): void {
this.userPlane.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
this.userPlane.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
this.userPlane.on(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
this.userPlane.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
// input.on(Input.EventType.TOUCH_START, this.onTouchEventStart, this);
// input.on(Input.EventType.TOUCH_MOVE, this.onTouchEventMove, this);
// input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEventCanel, this);
// input.on(Input.EventType.TOUCH_END, this.onTouchEventEnd, this);
this.userPlane.setPosition(v3(0, -300, 0));
}
onTouchMove(event: EventTouch) {
// 获取触点距离上一次事件移动的距离对象,对象包含 x 和 y 属性。
const delta = event.getDelta();
const position = this.userPlane.position;
this.userPlane.setPosition(v3(position.x + delta.x, position.y + delta.y, position.z));
}
- 创建敌方小飞机,挂上脚本,配置预制体
//小飞机的移动速度
_moveSpeed: number = 10;
//背景移动的上线距离
_maxRange: number = 740;//大于1/2的界面高度
update(deltaTime: number) {
const postion = this.node.position;
//移动的距离
const moveLength = postion.y - this._moveSpeed;
this.node.setPosition(postion.x, moveLength, postion.z);
if (moveLength <= -this._maxRange) {
this.node.destroy();
}
}
- 创建己方子弹,挂上脚本,配置预制体
//自方的移动速度
_moveSpeed: number = 15;
//子弹移动的上线距离
_maxRange: number = 1344;
update(deltaTime: number) {
let position = this.node.position;
this.node.setPosition(position.x, position.y + this._moveSpeed, position.z);
position = this.node.position;
if (position.y > this._maxRange) {
this.node.destroy();
}
}
- 创建敌方子弹,挂上脚本,配置预制体
//敌方的移动速度
_moveSpeed: number = 15;
//子弹移动的上线距离
_maxRange: number = 1344/2;
update(deltaTime: number) {
let position = this.node.position;
this.node.setPosition(position.x, position.y - this._moveSpeed, position.z);
position = this.node.position;
if (position.y < -this._maxRange) {
this.node.destroy();
}
}
- 创建一个空节点,放置生成的子弹的容器
- 由于敌机上也要生成子弹,而且还是预制体,这个容器节点就没法挂载了,那就来一个控制类。GameCtrl或者GameManager名字自己好记就弄那个名字呗。
在这个类上写方法创建子弹,并引入,这样就会暴露个问题,引入的GameCtrl为空或者null,
两种方法
1>在GameCtrl 的onLoad中让它赋值this,window[“GameCtrl”] = this,然后在其他的脚本中调用它下面的方法。
2>找到这里节点上挂载的这个脚本,用一个方法在onLoad中,不一定是onLoad,总之就是提前传入:让这个类指向this,让脚本能够找到这个类。
createPlayer() {
// const playerBullet: Node = instantiate(this.playerBullet);
// const position = rootNode.position;
// playerBullet.setParent(rootNode);
// playerBullet.setPosition(position.x, position.y, position.z);
let playerComp = this.userPlane.getComponent(PlayerCtrl);
playerComp.showBullet(this);
}
showBullet(gameCtrl: GameCtrl, needShoot: boolean = false) {
this.gameCtrl = gameCtrl;
this.needShoot = needShoot;
}
- 该分组了,需要的地方加上碰撞器与刚体,这里我勾选了Is Trigger,没有用2D的Collider,创建的是3D项目,就这样吧。
碰撞判断
protected onEnable(): void {
const collider = this.node.getComponent(Collider);
collider.on("onTriggerEnter", this.onTriggerEnter, this);
}
protected onDisable(): void {
const collider = this.node.getComponent(Collider);
collider.off("onTriggerEnter", this.onTriggerEnter, this);
}
onTriggerEnter(event: ITriggerEvent) {
const collisionGroup = event.otherCollider.getGroup();
//己方小飞机
if (collisionGroup == 1 << 1) {
this.node.destroy();
}
}
- 简单的一个demo写的差不多了,再来一个节点池NodePool
@ccclass('NodePoolManger')
export class NodePoolManger extends Component {
//没有继承Component 需要静态的
//在实际应用中需要实例化,走单例模式
static _instance: NodePoolManger;
static instance() {
//没有就new一个,有就直接返回这个实例
if (!this._instance) {
this._instance = new NodePoolManger();
}
return this._instance;
}
}
定义两个数据结构的接口
//定义一个数据结构map集合 字典
interface IDicPool {
[name: string]: NodePool;
}
//数据结构接口 key :value
interface IDicPrefab {
[name: string]: Prefab;
}
在定义两个对象
//两个容器对象 节点与预制
_dicPool: IDicPool = {};
//定义这个对象,根据名字来取对应的prefab
_dicPrefab: IDicPrefab = {};
然后一个 get 一个put的实现
- 替换
createPlayerbullte(rootNode: any) {
const playerBullet: Node = NodePoolManger.instance().getNode(this.playerBullet, this.bulletRoot);
// const playerBullet: Node = instantiate(this.playerBullet);
// playerBullet.setParent(this.bulletRoot);
playerBullet.setPosition(rootNode.position.x, rootNode.position.y + 80, rootNode.position.z);
}
onTriggerEnter(event: ITriggerEvent) {
const collisionGroup = event.otherCollider.getGroup();
//己方小飞机
if (collisionGroup == 1 << 1) {
NodePoolManger.instance().putNode(this.node);
// this.node.destroy();
}
}
demo一会儿上传,新手可以看看
//获取节点 //替换游戏中的instantiate
getNode(prefab: Prefab, parent: Node) {
// let name = prefab.name;
let name = prefab.data.name;
// console.log("get pool " + name);
let node: Node = null;
//先判断这种池子存在否
this._dicPrefab[name] = prefab;
let pool = this._dicPool[name];
//检查有没有这个池子
if (pool) {
//检查池子中有没有这个预制体
if (pool.size() > 0) {
node = pool.get();
} else {
//没有就实例化一个
node = instantiate(prefab);
}
} else {
//没有这种池子,就新建一个
this._dicPool[name] = new NodePool();
node = instantiate(prefab);
}
node.parent = parent;
//激活这个节点
node.active = true;
return node;
}
//缓存节点 //替换游戏中的node.destroy
putNode(node: Node) {
let name = node.name;
// console.log("put pool " + name);
//节点被回收,不能再作为场景里面的对象存在与场景中
node.parent = null;
//池子中有这种类型的
if (this._dicPool[name]) {
this._dicPool[name].put(node);
} else {
//没有就创建再放进去
this._dicPool[name] = new NodePool();
this._dicPool[name].put(node);
}
}