本文作者:BigBear

多年游戏行业研发经验

精通Unreal、CocosCreator游戏引擎

参与过多款手游、端游项目的研发

Cocos Creator入门实战:桌球小游戏

本篇主要是希望能够通过Cocos Creator实现一个桌球小游戏,从而能够让大家更好的了解以及运用Creator的物理系统

由于游戏比较简单,同时代码量也极少,因此就集中在一篇文章里面了。因此会长一些,有兴趣的同学麻烦耐心食用

开始之前

在开始桌球小游戏之前,我们需要对creator有一定了解以及熟悉,对js语法有一定的了解。在开始同样还是希望大家能够仔细的阅读一遍官方文档,以便理解。

所涉及到的知识点参考:

  • 物理系统

  • UI系统

  • 监听和发射事件

  • 动作列表

  • 预制体Prefab

  • 图集资源

ps:本项目所使用的Cocos Creator版本为v2.0.9

开启物理系统

为了尽量达到真实的效果,我们对于桌球的运动均采用物理模拟来实现。在Cocos Creator中物理系统是默认关闭的,我们可以通过下面的代码来开启物理系统

let 

同时我们也可以通过设置debugDrawFlags来开启一些调试信息的显示,方便我们开发预览

cc.director.getPhysicsManager().debugDrawFlags = 

这里我建议将物理系统的开启以及各个属性的设置统一开发为一个组件,这样可以方便我们在属性面板中管理物理系统的属性以及各个调试开关,同时这样的一个物理系统组件比较独立,在日后其他需要使用到物理系统的场景或者是其他项目中,都可以很方便的进行复用。

创建一个叫做"PhysicsManager.js"的脚本,代码如下:

/** * 物理引擎管理组件 */

cc.Class({    extends: cc.Component,

    properties: {       active: {default: true,           tooltip: '是否启用物理引擎',       },       aabb:{default: true,           tooltip: '是否显示包围盒',       },       pair: {default: true,       },       centerOfMass: {default: true,           tooltip: '是否显示中心点'       },       joint: {default: true,           tooltip: '是否显示关节连接线'       },       shape: {default: true,           tooltip: '是否填充形状'       },       gravity: {default: cc.v2(0,-960),           tooltip: '重力'       }    },

    onEnable() {//开启或关闭物理系统        let physicsManager = cc.director.getPhysicsManager();if (physicsManager.enabled && this.active) {            cc.warn('The physical system is enabled!');        }        physicsManager.enabled = this.active;

if (!this.active) {return;        }//设置物理系统的重力属性        physicsManager.gravity = this.gravity;

//设置调试标志        let drawBits = cc.PhysicsManager.DrawBits;if (CC_PREVIEW) {            physicsManager.debugDrawFlags =            (this.aabb && drawBits.e_aabbBit) |            (this.pair && drawBits.e_pairBit) |            (this.centerOfMass && drawBits.e_centerOfMassBit) |            (this.joint && drawBits.e_jointBit) |            (this.shape && drawBits.e_shapeBit);        } else {            physicsManager.debugDrawFlags = 0;        }    },

    onDisable() {        let physicsManager = cc.director.getPhysicsManager();        physicsManager.debugDrawFlags = 0;        physicsManager.enabled = false;    }});

编写完脚本后,我们将这个组件挂载到Canvas节点下。在属性面板中我们可以看到:

可视化的编辑,非常的方便。勾上Active开启物理系统,这里调试开关我们开启Shape即可,由于我们这个桌游游戏demo是一个俯视的视角,因此Gravity重力我们设置为(0,0),让小球不会受到重力的影响向下坠去。

桌面节点

在Canvas下面创建一个子节点作为我们的桌面节点。

  • 给它添加一个cc.Sprite组件并且给予它显示的spriteFrame

  • 添加RighdBody组件

  1. 由于桌面是静止不动的,因此我们将Type设置为Static

  2. 去掉AwakeOnLoad,因为我们并不需要它处于唤醒状态

  • 添加四个边的碰撞组件

  1. 注意不是使用碰撞组件,而是物理组件中的Collider组件

  2. 勾选Editing选项可在场景编辑器中改变碰撞体的大小和位置

  • 添加六个袋口的碰撞组件

  1. 这里用的碰撞体为CircleCollider

  2. 袋口碰撞体的tag我们设置为1

  3. 这里是为了在碰撞回调中与四周的边区分开来,便于判断

最终的节点碰撞体应调整为这样的效果: 

小球

搞定完桌面我们来制作小球。同样,小球也是需要使用到物理系统的

  • 红球

    摆放好后我们可以将这10个小球节点都放到一个空节点下,这样我们就可以将这个10个小球做成一个prefab。方便我们动态生成。 

    • 创建一个带Sprite组件的节点,给予红球的图片显示

    • 添加一个球形碰撞组件(CircleCollider)并调整大小

    • 勾选Bullet属性,由于小球是有可能进行高速移动的,因此勾选上这个属性可以禁止它穿过其他同样正在进行高速移动的其他物体(其他的的小球)

    • 由于小球是需要移动的,并非静止不动,因此刚体的Type选择为Dynamic 

    • AllowSleep一定要勾选上

    • Linear Damping设置为1.2,Angular Damping设置为0.8,通过这两个值我们可以让小球在没有其他外力或者碰撞时从运动中慢慢的停止下来

ok,到这里我们的红球就做好了。我们可以将红球节点在场景中复制10个出来,摆放为金字塔的形状,注意摆放时红球与红球之间不要发生碰撞,否则游戏一开始红球就会散开。

白球与红球基本是一样的,只需要将spriteframe更换为白球的纹理即可。

球杆

在白球节点下创建一个子节点“Cue”,“Cue”节点为一个空节点。

在这个空节点下再创建一个子节点,并添加Sprite组件,使用球杆的问题。调整节点的x坐标,使得球杆与白球的位置如下

这样设计节点的层级关系是为了方便进行球杆的角度计算,当然会有其他不同的做法,这里只是其中的一种。

同样的,我们将白球和球杆做成一个预制体,方便我们后面的动态创建


做到这里整个节点树应该是如下的一个结构


接下来我们就要在这个基础上开发我们的游戏逻辑的脚本组件了

球杆脚本Cue.js

球杆脚本我们挂到“Cue”节点下,它的功能我们主要需要实现这几个:

  • 监听鼠标事件,通过鼠标的移动控制球杆的方向

  • 监听鼠标左键的按下以及抬起事件,通过按下的时间控制球杆的力度

  • 鼠标左键按下时,球杆做向后的移动,松开鼠标左键,球杆做向前击打白球的动作

  • 球杆击打时,向白球发送自定义事件,使得白球进行运动

  • 接受白球发送过来的自定义事件,使得白球运动过程中,球杆不能操作并隐藏显示

明确了需求,并对需求进行功能拆分后,我们可以开始做手编码了。

  • 首先要做的就是在start方法中对上面提到的一些事件进行监听的注册

    start () {//鼠标移动系统事件        cc.Canvas.instance.node.on(cc.Node.EventType.MOUSE_MOVE, this.onMouseMove, this);//鼠标左键按下系统事件        cc.Canvas.instance.node.on(cc.Node.EventType.MOUSE_DOWN, this.onMouseDown, this);//鼠标左键抬起系统事件        cc.Canvas.instance.node.on(cc.Node.EventType.MOUSE_UP, this.onMouseUp, this);//白球停止的自定义事件        cc.Canvas.instance.node.on("wball-sleep", this.onwballSleep, this);    },

注册完事件后,我们定一个cc.Node类型的属性,将cue的子节点,也就是显示球杆纹理的那个节点引用进来

properties: {

接下来我们挨个实现这些事件的回调。

  • 鼠标移动的事件回调

    onMouseMove (event) {//按下鼠标时,球杆方向不再移动。球杆隐藏时操作无效if (this._mouseDown || this.node.opacity != 255) {return;        }//获取鼠标的当前位置坐标var loc = event.getLocation();this._mousePosition = loc;//将坐标转换到父节点的坐标系下        loc = this.node.parent.convertToNodeSpaceAR(loc);//计算与(-1,0)向量的夹脚,改夹脚即为球杆需要转动的角度var angle = loc.signAngle(cc.v2(-1,0));        angle = cc.misc.radiansToDegrees(angle);//设置球杆的角度this.node.rotation = angle;    },

通过这段代码,我们即可让球杆跟随鼠标进行转动,从而控制击球的方向

  • 鼠标左键按下的事件回调

    onMouseDown (event) {//球杆隐藏时操作无效if (this.node.opacity != 255) {return;        }//将按下鼠标的标记设置为truethis._mouseDown = true;

//使球杆向后移动,每秒向后移动50个像素//这里可以将-50这个值提升为组件属性,暴露到属性面板中方便配置调试this.cue.runAction(cc.repeatForever(cc.moveBy(1, cc.v2(-50, 0))));    },

这里的速度属性值可以提取出来,在属性面板中进行配置。这样做会好一些,我这里完全是偷懒写死了

  • 鼠标左键抬起的事件回调

    onMouseUp (event) {//球杆隐藏时操作无效if (this.node.opacity != 255) {return;        }//计算球杆向后移动的像素,通过这个值来计算击球的力度var force = this.cue.x - 182;//停止球杆向后移动的动作this.cue.stopAllActions();//使用序列动作,先执行this.cue.runAction(cc.sequence(            cc.moveTo(0.1, cc.v2(-182,0)).easing(cc.easeSineOut()),            cc.callFunc(() => {//将按下鼠标的标记设置为falsethis._mouseDown = false;//创建自定义事件"cue",并派发出去//事件有两个参数,一个是force,通过这个值,白球可以计算击球力度//另一个值为cue,是一个cc.vec2坐标,记录按下时的鼠标位置,这是提供给白球进行角度计算的var customEvent = new cc.Event.EventCustom("cue", true);                customEvent.force = force;                customEvent.cue = this._mousePositionthis.node.dispatchEvent(customEvent);//隐藏球杆this.node.opacity = 0;            })        ));    },

这里force计算中的- 182也是可以提取为参数进行配置的,这里再次偷懒写死

  • 白球停止的自定义事件回调

    onwballSleep () {//白球停止时,显示球杆this.node.opacity = 255;    },

ok,这样子我们就完成了球杆Cue.js脚本的代码编写

白球脚本 wball.js

白球需要做的事情就相对比较简单了:

  • 监听击球事件“cue”,通过击球力度和坐标计算出白球被击打后的线速度

  • 当白球停止运动时,也就是刚体的awake状态为false时,发送事件,告知球杆节点显示并可以击球了

因为要监听击球事件,因此首先是在start中对事件进行注册

    start () {//监听击球事件“cue”this.node.on("cue", this.onCue, this);//白球是否停止的标记,主要是用于使停止事件只发送一次//白球的初始状态是停止的,因此设置为truethis._sleep = true;    },

接下来是击球事件的回调实现

    onCue (event) {if (this && this.node.parent) {//白球没有停止,因此_sleep为falsethis._sleep = false;//计算白球运动的方向向量var direction = this.node.parent.convertToNodeSpaceAR(event.cue);            direction = direction.sub(this.node.position);            direction = direction.normalize();//根据方向和力度,计算并给予白球线速度this.node.getComponent(cc.RigidBody).linearVelocity = direction.mul(-Math.pow(1.016, Math.abs(event.force)));        }    },

最后是白球停止时的事件派发

    update (dt) {if (!this.node.getComponent(cc.RigidBody).awake && !this._sleep) {//白球从运动到停止,状态切换时,标记设置为true,并发送白球停止的事件this._sleep = true;            cc.Canvas.instance.node.emit("wball-sleep");        }    },

ok,搞定。基本上到这里,你已经可以控制白球去撞击其他的红球了。

这里有一个小技巧,可以看到白球停止的事件在球杆中我们是注册到了Canvas节点上。由于Cocos Creator目前的事件传递的机制是冒泡传递,因此会有一些情况下我们的事件不太好进行派发。而这样通过Canvas节点,我们就可以实现在场景中很方便的进行事件的监听处理以及派发。

需要注意的是,通过Canvas节点的话,意味着如果有场景切换的话,事件监听就会被注销掉,因此如果这个事件监听需要跨场景存在的话,可以自定义一个全局的cc.EventTarget对象用于事件的监听以及派发

球桌脚本 table.js

最后的脚本是我们的球桌脚本,这个脚本主要负责几个事情:

  • 球入袋的逻辑,红球入袋的记分以及胜负判定;白球入袋的重置白球位置逻辑

  • 开始游戏或是重新开始的游戏逻辑:重置记分以及重置白球红球的数量位置

最主要的代码是实现入袋的逻辑,这一部分需要我们实现onBeginContact方法 onBeginContact在组件所属节点的碰撞体发生碰撞时会进行调用 这个方法有三个参数 contact, selfCollider, otherCollider 第一个参数contact,是碰撞的信息 第二个参数selfCollider,是当前组件所属节点被碰撞到的Collider组件 第三个参数otherCollider,是非this节点,也就是发生碰撞另一个节点的Collider组件 代码如下:

    onBeginContact(contact, selfCollider, otherCollider) {//如果Collider的组件tag为1时,也就是小球碰撞到代表袋口的碰撞体时if (selfCollider.tag === 1) {//如果是与白球发生碰撞if (otherCollider.node.name === "wball") {//发送通知重新生成白球,重置位置this.node.emit("wball", otherCollider.node);            }else {//红球数减1this._ballNum--;this.ballLabel.string = "剩余" + this._ballNum + "球";//红球数小于等于0时,获得胜利if (this._ballNum <= 0) {this.gameUI.active = false;this.winUI.active = true;                }            }//将小球节点从场景树上移除            otherCollider.node.removeFromParent(true);        }    },

至于重新生成白球和红球的逻辑就更简单了,这里就不详细说了,届时你会利用上之前我们所做的白球,红球的prefab

至此,我们的桌球demo基本上算是完成了核心的部分了,剩下的就是一些UI上的逻辑了。比较简单就不一一叙述了。

希望通过这个小游戏的制作,可以帮助大家了解Creator以及了解Creator物理系统的应用

小游戏的完整代码以及工程,请在公众号回复【桌球】获取!

  1. CreatorPrimer 30篇教程汇总

  2. 我的B站视频开通啦!

  3. 从“新手引导”到“自动化测试”

  4. KUOKUO的趣味教程 | 进击的小怪诞生(1)

  5. KUOKUO的趣味教程 | 小怪物的视野(2)

  6. KUOKUO的趣味教程 | 小怪物也思考(3)

  7. 大神驾到 |「大掌教」Cocos3D组件详解

  8. CreatorPrimer|组件编码心得(上)

  9. CreatorPrimer|组件编码心得(中)

  10. CreatorPrimer|组件编码心得(下)

Cocos Creator游戏引擎可以支持鼠标吗_Cocos Creator入门实战:桌球小游戏相关推荐

  1. 【Java入门】桌球小游戏

    运行效果 没有小球进洞功能,只是碰壁回弹 目录结构 images里面的两个图片 可以下载保存 代码 package playballgame;import java.awt.*; import jav ...

  2. Cocos Creator入门实战:桌球小游戏

    Cocos Creator入门实战:桌球小游戏 转载请保留原文链接:https://blog.csdn.net/zzx023/article/details/90035153 本篇主要是希望能够通过C ...

  3. ​Cocos Creator入门实战:桌球小游戏

    本文作者:BigBear 多年游戏行业研发经验 精通Unreal.CocosCreator游戏引擎 参与过多款手游.端游项目的研发 Cocos Creator入门实战:桌球小游戏 本篇主要是希望能够通 ...

  4. xnawindowsphCocos2d-x for XNA游戏引擎全面支持WP7

    近日,开源社区cocos2d-x.org针对微软移动操作系统WindowsPhone7平台发布了一款新的游戏引擎,并正式命名为cocos2d-xforXNA.从此,开发者无需学习XNA绘图接口就可采用 ...

  5. 白鹭引擎助力《迷你世界》研发团队开发3D小游戏版

    <迷你世界>作为国内第一的放置类3D沙盒游戏,依靠三四线城市的游戏市场及垂直媒体的传播途径,研发团队用了短短3年时间就创造出了8000万活跃玩家.5000万玩家原创作品,仅2020年上半年 ...

  6. CocosCreator像素鸟小游戏实现(有源码)超详细教程 TS实现小游戏 零基础开发

    CocosCreator像素鸟小游戏实现(有源码)超详细教程 TS实现小游戏 大家中秋国庆快乐哈 前言 老规矩先看效果 源码的获取方式在最下面 对于本游戏来说canvas这样设置最佳哦 游戏实现思路: ...

  7. Python【小游戏合集】之重温童年最爱的扫雷小游戏

    导语: 哈喽吖!有许多铁汁们私信小编说用Python自行制作小游戏 ‍ ‍ 之后简直就是上头了~让wo多出一点小游戏合集(看来铁汁们跟小编一样都酷爱游戏) 有求必应~小游戏立刻安排上啦~~(扫雷真的是 ...

  8. 【中英双语教程】桌球小游戏(1)

    How to make a simple snooker game with Cocos Creator (1) 桌球小游戏是 BigBear 老师设计.撰写的中英双语的 Cocos Creator ...

  9. python3小游戏源代码_Python入门塔防小游戏,开发步骤和源码,带你轻松学python...

    在上一篇文章中,我介绍了有关python入门塔防小游戏的一些功能,下面我继续讲解有关这个小游戏的大致开发步骤. 开发工具还是: Python版本:3.6.4 相关的模块有:pygame模块,以及一些p ...

最新文章

  1. javafx 调用java_Java验证(javafx)
  2. Axure RP9 的元件库
  3. IntelliJ IDEA开发工具插件GsonFormat插件安装使用
  4. 液压减振器 matlab,摩托车液压减振器内泄漏对阻尼力影响计算及其对策
  5. opengl 4.5离线文档下载
  6. python抢购软件/插件/脚本附完整源码
  7. 新连接、新生意、新生态,专访快手商业生态开放平台
  8. 深度完美 Ghost XP_SP3 软件选择版_2011.09
  9. CFA一级学习笔记--固定收益(三)--估值
  10. 做硬件好还是软件好,千万别选错了路!
  11. AT24C01/AT24C02系列EEPROM芯片单片机读写驱动程序
  12. 数据可视化——Davinci
  13. 详解Java反射机制------入门篇
  14. 数字化时代需要迎接新技术
  15. Spring MVC 中的 Controller 是多例还是单列
  16. Spring Boot + Mybatis 实现简单的实验室预约微信小程序
  17. [GXYCTF2019]佛系青年
  18. 树莓派连接电视显示器或电脑显示器,显示无信号
  19. 戴尔4012管理地址
  20. 学习笔记5-梯度爆炸和梯度消失(K折交叉验证)

热门文章

  1. 《Master Opencv...读书笔记》非刚性人脸跟踪 II
  2. 怎样和程序猿谈一场不散场的爱情
  3. 微型计算机也称为个人计算机由,微型计算机概述计算机概述微型电脑组装系统台式电脑...
  4. “信号声源定位实验”
  5. 戴尔G15-5520蓝屏解决方法
  6. 数组some和every的区别
  7. 服务器环境(插件)搭建
  8. 递归算法-Java实现简单的递归操作
  9. Corral the Cows赶牛入圈(二维离散化)
  10. 常用的外贸英语口语汇总