【掘金大冒险:Flappy-click】这游戏太上头了

534 阅读3分钟

我正在参加掘金社区游戏创意投稿大赛团队赛,详情请看:游戏创意投稿大赛

chrome-capture-2022-3-23.gif

经过不断的测试,调整游戏重力、速度、管道高度等参数,终于找到了游戏娱乐性和体验性的"啊哈时刻"。

我的最佳成绩是67,快来超越我吧,在线体验地址:biao-code.github.io/magic-game/

image.png

最近工作实在是太忙,各种事情不断。原本打算和小伙伴们搞个抬杠对话机器人,队名都起好了(杠出一片天),实在是精力不够,只能下次一定。

前几天挖矿的时候,看到yoyo,click,hawking,忽然来了灵感。于是以这三个小可爱有主题,我们一起完成了这个小游戏,掘金大冒险。

image.png

这次游戏主要基于kaboomJs,让我们省了大量的时间。对于做小游戏来说,这个库是在是太棒了,只要你有想法,提供的API和示例足够你完成一个超棒的游戏。

聊聊Click为什么这么上头。

这个游戏好玩的地方在于,它的操作太简单了,只需要click,点击鼠标左键,或者点击空格。死亡后,常常分数看不到,立马开始下一局,所以我对这个游戏的介绍是:Just keep click。

如何实现

首先需要在页面加载KaboomJs,我使用的在线加载的方式。

<script src="https://unpkg.com/kaboom/dist/kaboom.js"></script>

然后关键的JS来了。

初始化基本信息

画布,游戏引用的其他元素(需要注意文件路径)。

// 初始化画布
kaboom({
	scale: 0.7,
	background: [ 128, 180, 255 ],
})

// 引入基础元素
loadSprite("bean", "/assets/click.png")
loadSound("score", "/assets/score.mp3")
loadSound("wooosh", "/assets/wooosh.mp3")
loadSound("hit", "/assets/hit.mp3")

初始化游戏主场景

// 初始化游戏
scene("game", () => {

	const PIPE_OPEN = 240
	const PIPE_MIN = 60
	const JUMP_FORCE = 800
	// 经测试,速度定义为600时,更容易获取更高分数
	const SPEED = 600
	const CEILING = -60

	// 定义重力:3200是最合适的重力
	gravity(3200)

	// 游戏对象包含的组件和标签列表
	const bean = add([
		// sprite()表示它是用名为“bean”的精灵绘制的(在“loadSprite”中定义)
		sprite("bean"),
		// 默认位置
		pos(width() / 4, 0),
		// 对撞机
		area(),
		// body组件使它能够在重力世界中下落和跳跃
		body(),
	])

	// 检查是否有坠落死亡
	bean.onUpdate(() => {
		if (bean.pos.y >= height() || bean.pos.y <= CEILING) {
			// 切换到失败场景
			go("lose", score)
		}
	})

	// 绑定空格跳跃
	onKeyPress("space", () => {
		bean.jump(JUMP_FORCE)
		play("wooosh")
	})

	// 鼠标点击跳跃
	onClick(() => {
		const worldMousePos = toWorld(mousePos())
		addKaboom(worldMousePos)
		bean.jump(JUMP_FORCE)
		play("wooosh")
	})

	function spawnPipe() {

		// 计算管道位置
		const h1 = rand(PIPE_MIN, height() - PIPE_MIN - PIPE_OPEN)
		const h2 = height() - h1 - PIPE_OPEN

		add([
			pos(width(), 0),
			rect(64, h1),
			color(192, 192, 192),
			outline(4),
			area(),
			move(LEFT, SPEED),
			cleanup(),
			// 给它一个更容易定义的行为流
			"pipe",
		])

		add([
			pos(width(), h1 + PIPE_OPEN),
			rect(64, h2),
			color(192, 192, 192),
			outline(4),
			area(),
			move(LEFT, SPEED),
			cleanup(),
			"pipe",
			// 原始obj只是将每个字段分配给游戏obj的组件
			{ passed: false, },
		])

	}

	// bean与标记为“pipe”的对象关联时的回调
	bean.onCollide("pipe", () => {
		go("lose", score)
		play("hit")
		addKaboom(bean.pos)
	})

	// 标记为“pipe”的所有对象的每帧事件
	onUpdate("pipe", (p) => {
		// check if bean passed the pipe
		if (p.pos.x + p.width <= bean.pos.x && p.passed === false) {
			addScore()
			p.passed = true
		}
	})

	// 每1秒产生一根管子
	loop(1, () => {
		spawnPipe()
	})

	// 初始化分数
	let score = 0

	// 显示分数
	const scoreLabel = add([
		text(score),
		origin("center"),
		pos(width() / 2, 80),
		fixed(),
	])

	// 加分
	function addScore() {
		score++
		scoreLabel.text = score
		play("score")
	}

})

初始化失败场景

// 失败场景构建
scene("lose", (score) => {

	add([
		sprite("bean"),
		pos(width() / 2, height() / 2 - 108),
		scale(3),
		origin("center"),
	])

	// 显示分数
	add([
		text(score),
		pos(width() / 2, height() / 2 + 108),
		scale(3),
		origin("center"),
	])

	// 按下空格键返回游戏
	onKeyPress("space", () => go("game"))
	onClick(() => go("game"))

})