引言
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)
给地块一个初始高度,做一个生成效果。
代码如下:
typescript
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
跳跃高度等一些配置。
typescript
@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
触摸取消。
typescript
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
。 - 显示范围指示圈。
- 播放蓄力动画。
typescript
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");
}
触摸过程的处理:
- 根据时间增加跳跃距离。
- 根据时间放大范围圈。
typescript
protected update(dt: number): void {
if (this.touching) {
this.radius += this.touchSpeed;
if (this.showLine)
this.skillRangeIndicator.setScale(this.radius);
}
}
效果如下:
触摸完成的处理:
- 隐藏范围圈。
- 通过
tween
动画实现主角跳跃位移。 - 跳跃过程中取消重力影响
useGravity = false
。 - 跳跃成功加分并生成下一个地块。
- 跳跃失败显示重新挑战按钮。
typescript
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即判断失败。
typescript
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:笔者线上的小游戏《贪吃蛇掌机经典》《重力迷宫球》《填色之旅》大家可以自行点击搜索体验。
实不相瞒,想要个赞 和在看 !请把该文章分享给你觉得有需要的其他小伙伴。谢谢!
推荐专栏: