cocos creator 3.8 打飞机Demo 9

news/2024/11/25 14:21:05/

简单的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));}
  1. 创建敌方小飞机,挂上脚本,配置预制体

//小飞机的移动速度_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();}}
  1. 创建己方子弹,挂上脚本,配置预制体
//自方的移动速度_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();}}
  1. 创建敌方子弹,挂上脚本,配置预制体
//敌方的移动速度_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();}}
  1. 创建一个空节点,放置生成的子弹的容器

  1. 由于敌机上也要生成子弹,而且还是预制体,这个容器节点就没法挂载了,那就来一个控制类。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;}
  1. 该分组了,需要的地方加上碰撞器与刚体,这里我勾选了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();}}
  1. 简单的一个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 :valueinterface IDicPrefab {[name: string]: Prefab;}

在定义两个对象

//两个容器对象 节点与预制
_dicPool: IDicPool = {};
//定义这个对象,根据名字来取对应的prefab
_dicPrefab: IDicPrefab = {};

然后一个 get 一个put的实现

  1. 替换
   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一会儿上传,新手可以看看

    //获取节点 //替换游戏中的instantiategetNode(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.destroyputNode(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);}}


http://www.ppmy.cn/news/1549839.html

相关文章

RHCE——DNS域名解析服务器

1、DNS简介 DNS是互联网上的一项服务&#xff0c;它作为将域名和IP地址相互映射的一个分布式 数据库&#xff0c;能够使人更方便的访问互联网。 &#xff08;1&#xff09;因特网的域名结构 因特网在命名时采用的是层次树状结构的命名方法。任何一个连接在 因特网上的主机或路…

Python MySQL通过Binlog 获取变更记录 恢复数据

通过MySQL的二进制日志&#xff08;Binlog&#xff09;获取数据库的变更记录&#xff0c;并用于恢复数据&#xff0c;是一个相对高级的操作。这通常涉及读取Binlog中的事件&#xff0c;解析这些事件以了解数据变更的详细信息&#xff0c;然后基于这些信息来恢复或回滚数据。 在…

设计模式之 命令模式

命令模式&#xff08;Command Pattern&#xff09;是行为型设计模式之一&#xff0c;它将请求&#xff08;或命令&#xff09;封装成一个对象&#xff0c;从而使用户能够将请求发送者与请求接收者解耦。通过命令模式&#xff0c;调用操作的对象与执行操作的对象不直接关联&…

前端工程化-node/npm/babel/polyfill/webpack 一文速通

文章主要介绍了前端工程化的相关内容&#xff0c;包括 Node 环境、npm 包管理器及其命令、配置和镜像&#xff0c;package.json 文件&#xff0c;babel 和 polyfill 用于解决 JavaScript 兼容性问题&#xff0c;以及 webpack 这一前端构建工具的作用、核心概念、构建流程、安装…

BEV:显示相机视角转换-----FastBEV/IPM与LSS

一、背景 BEV方案中&#xff0c;将图像视角转换到BEV视角的方法对模型性能影响较大&#xff0c;FastBEV的速度较快&#xff0c;但投影效果上限不高&#xff0c;LSS投影上限较高&#xff0c;但速度较慢 &#xff08;耗时相对较高&#xff09;。是否有折中的方案&#xff0c;在耗…

AI 在软件开发流程中的优势、挑战及应对策略

AI 在软件开发流程中的优势、挑战及应对策略 随着人工智能技术的飞速发展&#xff0c;AI大模型正在逐步渗透到软件开发的各个环节&#xff0c;从代码自动生成到智能测试&#xff0c;AI的应用正在重塑传统的软件开发流程。本篇文章将分析AI在软件开发流程中带来的优势&#xff0…

【Anaconda】Pycharm如何配置conda虚拟环境

一、前置准备 电脑已安装 Anaconda、Pycharm 软件&#xff1b;已创建需要集成到 Pycharm conda 环境&#xff1b; 推荐参考&#xff1a; Anaconda快速上手&#xff1a;如何下载安装与配置Anaconda 二、环境配置 1&#xff09;Pycharm 打开 Settings > Project: > Pytho…

Spring模块详解Ⅴ(Spring ORM Spring Transaction)

目录 小程随笔Spring ORM 作用主要组件示例 HibernateTemplateJpaTemplate 总结优缺点 优点缺点 总结 Spring Transaction 1. 概述2. 传播行为&#xff08;Propagation&#xff09;3. 隔离级别 4. 回滚规则 5. 事务配置方式6. 事务管理器7. 常见的事务问题与最佳实践总结 小程…