Cocos合成大西瓜案例-下
我披上坚甲,挡在你身前,万千的关心只化为一句:小心。
本文约7.2千字,新手阅读需要16分钟,复习需要7分钟 【收藏随时查阅不再迷路】
👉关于作者
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣 !!!
专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎私我,交流群让学习不再孤单。
👉前提
【为了便于快速的理解,小空特意能用中文的用了中文,方便广大群众】
【友情提示:还是尽量使用中文哦】
👉实践过程
😜游戏主界面
经过前面两节的学习,到此开始页面我们就搞定了,接着就是进入开始游戏内容啦。
我们先来分析下具体玩法:
- 1.页面右上角可以提前预览下一个小球内容样式
- 2.在当前小球下落未完成之前不得再次释放新的小球,防止过快
- 3.左侧右侧底侧都不允许超界,有格挡物(碰撞肩擦)
- 4.小球具有自由落体属性以及适当的回弹效果
- 5.在小球合并过程中播放适当的音频以及合并效果
- 6.当超过上侧边界的时候要有输的判定和分数的显示
- 7.可以重新开始游戏和返回首页
所以我们先给其增加背景,左墙,右墙,以及底部地面,位置刚刚好包裹住背面。
为了里面的物体掉落后不出界,需要给墙体增加碰撞器(BoxCollider2D)以及刚体组件(RigidBody2D)
😜实现返回和重玩
在进行场景变换前,他俩都需要判断下当前所得分是不是大于历史最高分,大于的话则将当前的分保存替换,否则的话就可以不用管。然后利用【**director.loadScene】加载场景即可。
对了,别忘记给场景中的按钮指定点击事件。
//重玩游戏
GameRePlay() {
//也要判断看是否保存数据
let MaxScore = localStorage.getItem(ScriptStatic.MaxScore);
if (MaxScore != null) {
//当前分数和保存的分数做比较如果大 则保存 如果不大不保存
//parseInt 第二个参数代表的是进制
if (parseInt(MaxScore.toString(), 10) < ScriptStatic.CurrentScore) {
localStorage.setItem(ScriptStatic.MaxScore, ScriptStatic.CurrentScore + "");
}
}
//上面先将分数保存
ScriptStatic.CurrentScore=0;
director.loadScene("scene_game");
}
//返回上一场景
ClickBack() {
let MaxScore = localStorage.getItem(ScriptStatic.MaxScore);
if (MaxScore != null) {
//当前分数和保存的分数做比较如果大 则保存 如果不大不保存
//parseInt 第二个参数代表的是进制
if (parseInt(MaxScore.toString(), 10) < ScriptStatic.CurrentScore) {
localStorage.setItem(ScriptStatic.MaxScore, ScriptStatic.CurrentScore + "");
}
}
director.loadScene("scene_start");
}
😜小球预制体
要知道每次都要创建一个小球,且右上角有预览,所以我们需要一个预制体,后续通过实例化预制体来实现,并且该预制体初始化的时候能够自动随机不同的小球。
右键创建一个2D的Sprite,添加【CirleCollider2D】和【RigidBody2D】组件,刚体组件默认即可,碰撞组件需要修改下摩擦系数【Friction】和弹性系数【Restitution】,一个【0.2】一个【0.3】吧。【Radius】半径需要注意哦,不同的瓜半径不同,再加上碰撞的时候回来贴合的很合适,这个半径就需要和图片很重合最好,不能大也不能小。
对了我们顺便增加个弹性系数吧,这样有回弹效果就更Q啦。
然后增加个脚本,我们想想改脚本应该有啥功能
- 1.自动变化不同的球体
- 2.更改当前球体的Collider半径,这样能实现良好的碰撞检测
- 3.西瓜的碰撞事件以及碰撞后合并
- 4.死亡线的检测判定
//获取到精灵
let thisSprite = this.node.getComponent(Sprite);
if (thisSprite != null) {
thisSprite.spriteFrame = this.spriteFrames[index];
} else {
console.log("changeBall的thisSprite为空")
}
//动态改变创建的预制体的半径
let PrefabCollider = this.node.getComponent(CircleCollider2D);
if (PrefabCollider != null) {
if (index == 0) {
PrefabCollider.radius = (54 / 2 -1);
}
//……省略部分逻辑
ScriptStatic.CurrentBallRadius=PrefabCollider.radius;
} else {
console.log("changeBall的PrefabCollider为空")
}
碰撞的检测
我们使用的是2D的且直接针对Collider注册的监听
TempCollider.on(Contact2DType.BEGIN_CONTACT, this.MethodColliderEnter, this);
【MethodColliderEnter】方法是我们的逻辑处理,里面包含三个参数【selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null】,官方文档有介绍,在这小空就不自嗨啦。逻辑详情请参考源码,注释很详细。
注意哦:
要想碰撞事件生效,必须在物体的刚体组件中打开监听【EnabledContactListener】, 离谱。
在碰撞事件中进行销毁或者更新某个组件使用【setTimeout】来实现下一帧修改,因为当前帧修改会报异常的。
碰撞检测里面的逻辑函数我们用到了标签【TAG】,并且利用【TAG】做了某些操作的话,所以就要特别注意了,在场景中有些节点的【TAG】默认就是0,很容易造成误操作对象。所以我们修改场景中【背景_左墙】和【背景_右墙】以及【背景_地面】的碰撞组件【TAG】为100。
接着我们的主脚本就用到他了。
😜游戏主脚本
该脚本挂载在了背景黄图上,在开始和结束我们需要注册和解除注册点击事件。点击事件里面逻辑:
- 1.初始化预制体
- 2.设置位置
- 3.随机生成球体
- 4.右上角预览生成
具体详情可看源码中的【onClickStart】方法
注意:
UI上的脚本要想响应点击事件,必须挂载的物体上有【UITransform】,且在Canvas下
😜更新分数
【分数】节点上挂载【ScriptScore】脚本,脚本内直接开一个每秒更新一次的定时,取之前保存的分数变量即可。
但这并不满足我们,我们的显示一定要优雅,没错,优雅。
所以我们就需要用到艺术数字,这个开头我们的启动页面最大分数是先沟通的技术。
找到我们的【number.fnt】文件赋值给【Label】的【Font】,然后在代码中增加
this.schedule(()=> {
//设置分数艺术字
let LabelScore = this.node.getComponent(Label);
if (LabelScore != null) {
LabelScore.string = ScriptStatic.CurrentScore + "".toString();
} else {
console.log("获取文本节点为空")
}
}, 1);
😜死亡判定
当触碰到顶部线条的时候触发。所以UI要有碰撞检测,并且需要根据事件回调进行响应处理。
我们添加【RigidBody2D】和【BoxCollider2D】,注意:要想系统能调用回调,需要激活【EnabledContactListener】,之后在脚本的【onLoad】中注册事件。代码如下:
protected onLoad() {
let TempCollider = this.node.getComponent(BoxCollider2D);
if (TempCollider != null) {
console.log("死亡线注册了碰撞事件")
TempCollider.on(Contact2DType.BEGIN_CONTACT, this.MethodColliderEnterDeath, this);
} else {
console.log("死亡线Collider为空")
}
}
start() {
// [3]
}
/**
* 注意了 要想以上来不响应需要RigiBody2D的 Type 为静态类型 不能是默认的
* @param selfCollider
* @param otherCollider
* @param contact
* @constructor
* @private
*/
private MethodColliderEnterDeath(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
console.log("执行了死亡线的碰撞")
//判断是否为最大值保存分数
let MaxScore = localStorage.getItem(ScriptStatic.MaxScore);
if (MaxScore != null) {
//利用Number() 将字符串转为 number 可以对比大小
if (Number(MaxScore) < ScriptStatic.CurrentScore) {
localStorage.setItem(ScriptStatic.MaxScore, ScriptStatic.CurrentScore + "");
}
}
//展示死亡界面
if (this.NodeDeath != null) {
this.NodeDeath.setPosition(0, 0, 0);
} else {
console.log("死亡界面为空")
}
//禁止背景再有点击响应
if (this.NodeBg != null) {
let TempScript = this.NodeBg.getComponent(ScriptGame);
if (TempScript != null) {
console.log("取消了点击事件");
// this.NodeBg.off(Node.EventType.TOUCH_START, TempScript.onClickStart, this);
TempScript.IsDeath=false;
} else {
console.log("获取的脚本为空")
}
} else {
console.log("死亡界面为空")
}
}
至此,我们的整个开发流程结束。
下一篇文章小空分享在不同平台【微信QQ,字节抖音系,,百度等】发布成品并上架。
下下一篇小空带你利用广告系统增强游戏玩法,并且用广告来获取收益。
👉其他
📢作者:小空和小芝中的小空
📢转载说明-务必注明来源:https://zhima.blog.csdn.net/
📢欢迎点赞👍收藏🌟留言📝
- 点赞
- 收藏
- 关注作者
评论(0)