引言
Cocos中实现跳一跳游戏效果
大家好,2023年快要过去了,你们的游戏都做完了吗?
昨天和朋友们聊天的时候聊到,2个小时能不能做一个跳一跳游戏?
基于好奇和探索的心理,笔者尝试了一下,2个小时做个效果勉强可以,但是想要上线还得大大优化。
本文将介绍一下如何在Cocos中实现跳一跳游戏效果。
本文源工程可在文末阅读原文获取,小伙伴们自行前往。
1.什么是跳一跳
可能有很多小伙伴不知道跳一跳是什么游戏。简单介绍一下:
跳一跳是一款由微信推出的小游戏,最初是作为微信内置功能之一。
这款游戏的玩法相对简单,玩家需要通过点击屏幕控制一个小人跳跃,跳跃的目标是跳到不同的方块上,而方块的距离会有所变化。
跳一跳因其简单有趣的玩法而在一段时间内风靡一时。
我们分析一下里面具体的游戏效果
2.跳一跳需求分析
经过简单的分析,跳一跳涉及的游戏效果可能如下:
- 地块的生成,每次跳跃完成之后会自动生成一块地块,距离和方向随机。
- 长按屏幕蓄力跳跃,根据玩家按压屏幕的时间决定跳跃的距离。
- 得分,每次成功跳跃(跳到下一块地块,不掉落)可获得1分。
- 游戏失败的判断,没有跳到地块上,掉落在地板的判断。
下面一起在Cocos中实现跳一跳游戏效果
3.跳一跳游戏效果的实现
1.环境
引擎版本:Cocos Creator 3.8.1
编程语言:TypeScript
2.资源准备
本期节目效果继续由跳一跳鸡和笔者的技能范围指示器效果友情助攻。
3.编写代码
首先创建一个FloorCreator
组件,用来动态生成跳一跳的地块。其中关键的内容如下:
- 通过
instantiate
克隆生成地块。 - 通过
nextFloor
数组管理地块,循环使用。 - 通过
Math.random()
随机地块方向和距离。 - 通过
add3f(0, 1, 0)
给地块一个初始高度,做一个生成效果。
代码如下:
import { _decorator, Component, instantiate, Node, v3 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('FloorCreator')
export class FloorCreator extends Component {
@property(Node)
floorPfb: Node = null;
curFloor: Node;
nextFloor: Node[] = [];
start() {
this.curFloor = this.floorPfb;
}
public createFloor() {
var dir = Math.random() < 0.5 ? v3(-1, 0, 0) : v3(0, 0, -1);
var newFloor = this.nextFloor.length > 1 ? this.nextFloor.shift() : instantiate(this.curFloor);
newFloor.parent = this.curFloor.parent;
newFloor.position = this.curFloor.position;
newFloor.position.add(dir.multiplyScalar(Math.random() * 3 + 1.5)).add3f(0, 1, 0);
newFloor.active = false;
newFloor.active = true;
this.nextFloor.push(this.curFloor);
this.curFloor = newFloor;
return {
dir: dir.normalize(),
floor: newFloor
};
}
}
效果如下:
地块的生成做好之后,我们创建一个JumpAndJump
组件,用于控制整个游戏流程。其中包含一些属性:
player
,主角的引用。floorCreator
,地板生成器的引用。skillRangeIndicator
,技能范围指示器的引用。scoreLab
,分数标签的引用。- 其他一些
touchSpeed
跳跃距离增长速度、jumpTime
跳跃时间、jumpHeight
跳跃高度等一些配置。
@ccclass('JumpAndJump')
export class JumpAndJump extends Component {
@property(Node)
player: Node = null;
@property(FloorCreator)
floorCreator: FloorCreator = null;
@property(SkillRangeIndicator)
skillRangeIndicator: SkillRangeIndicator = null;
@property(Label)
scoreLab: Label = null;
@property(CCFloat)
touchSpeed: number = 0.1;
@property(CCFloat)
jumpTime: number = 1;
@property(CCFloat)
jumpHeight: number = 1;
}
在start
方法中监听一下触摸事件:
Input.EventType.TOUCH_START
触摸开始。Input.EventType.TOUCH_END
触摸结束。Input.EventType.TOUCH_CANCEL
触摸取消。
start() {
this.createFloor();
var node = find("Canvas/ui_joystick_panel");
node.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
node.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
node.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
触摸开始的处理:
- 重新计算跳跃距离
this.radius
。 - 标记触摸开始
this.touching
。 - 显示范围指示圈。
- 播放蓄力动画。
onTouchStart() {
if (this.gameover || this.jumping) return;
this.radius = 0;
this.touching = true;
if (this.showLine)
this.skillRangeIndicator.showSkillRangeIndicator(this.player.position);
this.player.getComponent(SkeletalAnimation).crossFade("anim_rig_sky_jump");
}
触摸过程的处理:
- 根据时间增加跳跃距离。
- 根据时间放大范围圈。
protected update(dt: number): void {
if (this.touching) {
this.radius += this.touchSpeed;
if (this.showLine)
this.skillRangeIndicator.setScale(this.radius);
}
}
效果如下:
触摸完成的处理:
- 隐藏范围圈。
- 通过
tween
动画实现主角跳跃位移。 - 跳跃过程中取消重力影响
useGravity = false
。 - 跳跃成功加分并生成下一个地块。
- 跳跃失败显示重新挑战按钮。
onTouchEnd() {
if (this.gameover || !this.touching) return;
this.player.getComponent(RigidBody).useGravity = false;
this.touching = false;
this.skillRangeIndicator.hideSkillRangeIndicator();
this.jumping = true;
this.player.getComponent(SkeletalAnimation).crossFade("anim_rig_fly");
tween(this.player).by(this.jumpTime / 2, { worldPosition: this.dir.clone().multiplyScalar(this.radius / 4).add3f(0, this.jumpHeight, 0) })
.by(this.jumpTime / 2, { worldPosition: this.dir.clone().multiplyScalar(this.radius / 4).subtract3f(0, this.jumpHeight, 0) }).call(() => {
this.player.getComponent(RigidBody).useGravity = true;
this.player.getComponent(SkeletalAnimation).crossFade("anim_rig_idle_2");
this.jumping = false;
if (!this.isGameOver()) {
this.setScore(this.score + 1);
this.createFloor();
}
else {
this.gameover = true;
find("Canvas/Button").active = true;
this.player.getComponent(SkeletalAnimation).crossFade("anim_rig_fall_into_water_die");
}
}).start();
}
其中跳跃失败的判断:
- 超出地块中心0.5即判断失败。
isGameOver() {
return Math.abs(this.player.worldPosition.x - this.floor.worldPosition.x) > 0.5 || Math.abs(this.player.worldPosition.z - this.floor.worldPosition.z) > 0.5;
}
效果如下:
4.效果演示
以上就是2个小时完成的游戏效果,你要来试试吗?
结语
本文源工程可通过私信JumpAndJump或者阅读原文付费获取。
在哪里可以看到如此清晰的思路,快跟上我的节奏!关注我,和我一起了解游戏行业最新动态,学习游戏开发技巧。
我是”亿元程序员”,一位有着8年游戏行业经验的主程。在游戏开发中,希望能给到您帮助, 也希望通过您能帮助到大家。
AD:笔者线上的小游戏《贪吃蛇掌机经典》《重力迷宫球》《填色之旅》大家可以自行点击搜索体验。
实不相瞒,想要个赞和在看!请把该文章分享给你觉得有需要的其他小伙伴。谢谢!
推荐专栏:
原文链接:https://juejin.cn/post/7317141855518572544 作者:亿元程序员