GameMaker 音乐游戏制作

将几何变成音乐 ——冰与火之舞

本文章参考《节奏医生》制作手记编写。

前言

节奏游戏(Rhythm Games)正如其名,是一种基于音乐节奏游玩的游戏类型。

此类型的游戏在如今变得非常常见,但我们不去讨论常见的原因,而是来讨论一下怎么去做。

“关于节奏游戏的一般架构的文档并不多”,这是很多人的共识。但也正因为如此,所以这篇文章才会出现。

此种游戏有许多关键机制。这些机制不局限于引擎或语言,甚至有些引擎已经内置了(例如Godot4引擎的音乐节奏系统)

内置是很幸运的,然而更多的是自己闭门造车的不幸。

第一章:分解

此章节用于分解一般节奏游戏架构中的各个部分,并且给出其在GameMaker中的解决方案。

节拍系统

系统本身

这一系统用于保持节拍。无论是使用物体(Object)还是脚本(Script)实现,该系统都有相类似的特性。

它应该有一个简单的函数/变量来给出歌曲的位置,供需要同步到节拍的所有内容使用。这意味着在同一时间内,背景音乐应该有且仅有一首正在播放

让我们创建一个叫'obj_clock'的物体,在其创造事件(Create Event)写入以下初始化代码:

bpm = [{time:0,value:120}] //这里是一个数组,包含了BPM节点
time_ms = 0 //音乐播放了多长时间?单位是毫秒(MS)
beat = 0 //当前是第几拍
pausing = false //是否暂停音乐
offset = 0.00 //延迟数:无论是什么音频系统,播放音频都带有延迟,因此需要这个。


// 以下所有函数都可以不用管理
function time_to_beat_bpm(time,bpm){
	var crotchet = bpm / 60.0
	return time*crotchet/1000000.0
}
function beat_to_time_bpm(beat,bpm){
	var crotchet = 60.0 / bpm
	return beat*crotchet*1000000.0
	
}
function time_get_bpm_by_time(time){
	for(var i=0;i<array_length(bpm);i++){
		var bpmtime = bpm[i].time
		if(bpmtime == time){
			return i
		}
	}
}
function time_to_beat(time){
	var bpmStu = time_get_previous_bpm(time)
	var beattime = bpmStu.time
	var vaule = bpmStu.value
	var willTime = time - beattime
	var beatcz = time_to_beat_bpm(willTime,vaule)
	if(time == 0){
		return 0
	}
	return time_to_beat(beattime) + beatcz
}
function beat_to_time(beat){
	var time = 0
	for(var i = 0;i<array_length(bpm);i++){
		var bpmtime = bpm[i].time
		time = bpmtime
		if(time_to_beat(time)>beat){
			break
		}
	}
	var prebpm = time_get_previous_bpm(time)
	return prebpm.time + beat_to_time_bpm(beat-time_to_beat(prebpm.time),prebpm.value)
}
function time_get_previous_bpm(time){
	var maxBPM = 0
	for(var i = 0;i<array_length(bpm);i++){
		var bpmtime = bpm[i].time
		if(bpmtime<time){
			maxBPM = maxBPM < bpmtime ? bpmtime : maxBPM
		}
	}
	var bpmListID = time_get_bpm_by_time(maxBPM)
	var bpmStu = bpm[bpmListID]
	
	return bpmStu
}
function reset_time(time){
	time_ms = time * 1000000 + offset
}

在步事件(Step Event)中输入以下代码:

time_ms += delta_time
beat = time_to_beat(time_ms)*4

现在,在该物体被创建那一刻起,所有物体都可以开始同步音乐:只要你判定obj_clock的beat就可以。

系统之外

一个好的节奏游戏应该处处遵循节奏:音符随着节奏而落下,人物随着节奏而摇摆。

看看《节奏医生》所搭建的场景吧,哪怕是一个不起眼的,正在移动的表带都是跟随节奏的。

这便是能够大幅度提高玩家体验感的一个操作。我知道你是GameMaker用户,在日常的编码中早已习惯了计算帧数,因为有计时器(alarm)的存在。但是在实际的游玩中,依凭帧数的游戏总是无法和音乐进行同步:因此,请尽最大可能的使用beat来代替原本的帧数计算。

如果你没有使用过协程(coroutines),那么你大概经常碰到这样的场景:在某个步事件中写入了这样的代码。

// 我们要实现一个动画
time++
if(time == 20){
//TODO
}
if(time == 30){
//TODO
}
if(time == 50){
//TODO
}
if(time == 60){
//TODO
}
if(time == 140){
//TODO
}
if(time == 150){
//TODO
}
if(time == 160){
//TODO
}
if(time == 250){
//TODO
}
if(time == 780){
//TODO
}
if(time == 1000){
//TODO
}

我非常推荐读者去学习一下协程,至少能让你的代码看起来没有这么杂乱。

话题说回节奏游戏,你最好将time都改成obj_clock.beat一类的东西来保证音乐同步。


文章未完工

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值