GameMaker Studio 2小组导航 :介绍、愿景、内容
我最近半年开始学习GameMaker Studio 2(以下简称GMS2),向往着变成一名独立开发者,同时也在了解GMS2的引擎操作,阅读F1帮助文档,趴教程。可以说 GMS2 的中文用户很少,百度贴吧关注人数也未破万,资料很不成体系,很多前人的资料和文章都未被人整理,压在不知名的角落,我希望能够帮助其他的中文用户了解GMS2,所以建立一个快速导航,帮助大家快速开始GameMaker Studio 2的学习。
愿景和管理工作
希望大家不要在公开的帖子中留下联系方法或询问他人的联系方式,而是将有关一个话题的讨论都公开在帖子中,如果真的是要私下联系,可以使用私信的功能。我不希望看到的是一个人提出一个问题后通过私下的沟通解决了问题,而关于解决问题的过程并没有留在帖子中,无法给搜索到这个帖子的人提供帮助。
- 希望大家不要重复发帖,将与同一话题的讨论集中到一个帖子中
- 希望大家在发表帖子和回复之前先考虑一下措辞,事后发现错误也及时订正
- 希望大家不要发表无价值的回复,当你只是觉得某一个帖子好的时候,请使用「点赞」功能
管理员的工作主要是维护秩序,维护的主要目标是方便他人检索和阅读信息,希望大家不要感到不满。
- 修改帖子标题以符合帖子内容,通常会修改几乎所有帖子标题
- 修改正文和回复中明显的错别字、将代码编辑代码块
- 将重复的帖子导向讨论更多的帖子,并移除新的重复的帖子
- 删除重复或无意义的回复,删除不当内容
导航模块
- 快速索引社区:国内比较大的GameMaker中文社区和推荐的QQ群
- 求助:提出你在使用过程中遇到的问题,寻找需要的功能和插件,管理员会不定期整理QA内容,防止日经QA
- 开发:讨论与游戏开发有关的话题,或发布你自己开发的游戏
- 分享:原创文章、资料汇总、翻译自官网的文章和文档
快速索引社区
- Yoyogames官网
- GMS2官方文档
- GMS2文档红色激情汉化版
- GameMaker开发者之家(维护中)
- GameMaker百度贴吧
- GameMakerStudio2 Wiki(正在创建中)
- GameMaker开发者之家QQ群:235271204
- GameMaker:Studio2 菜鸟群:102797189
- GameMaker:Studio2入门小站
求助整合
- 官网如何购买,如何注册?
- 国内更新太慢,怎么办?
入门教程
开发
待续
[ 分享:入门 ] Make an RPG:开始我们的RPG之旅
文档说明
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。
由于原教程是基于GMS1版本的,我这里是用GMS2版本进行制作的,界面和部分函数都有变化,有错漏的地方,请参考原视频和官方帮助文档。接触GameMaker时,苦于国内没有完整的一个RPG教程,诺娃上的青铜的幻想的GameMaker: Studio 中文教程可惜因为作者的工作,没有持续更新下去。而红激的教程也是以FC上的小游戏为切入点,只好上油管,HeartBeast的教程很丰富,有平台跳跃、射击、也有角色扮演。
面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
主要包括以下内容(蓝色标识已完成,目前进度 :18/30):
- 1.BASIC MOVEMENT AND COLLISIONS(基础移动和碰撞)
- 2.STEP EVENT + VIEWS(步事件和视图)
- 3.VARIABLES AND CHARACTER SPRITES(变量和人物精灵)
- 4.DRAW EVENT, BACKGROUNDS, SCRIPTS, AND STATES(绘制事件,背景,脚本,状态)
- 5.SMOOTH VIEW MOVEMENT(平滑的移动视图)
- 6.BETTER PLAYER MOVEMENT(优化角色移动)
- 7.GAMEPAD INPUT(手柄输入)
- 8.DASH STATE(冲锋状态)
- 9.ADDING ENEMIES, DEPTH, AND INHERITANCE(增加敌人,理解深度和继承)
- 10.PLAYER ATTACK STATE(攻击状态)
- 11.HITBOXES AND KNOCKBACK(受击盒和击退)
- 12.BETTER CHARACTER SPRITE CONTROL(角色精灵控制优化)
- 13.ADDING ENEMY STATES(怪物状态机)
- 14.ENEMIES THAT ATTACK(怪物攻击)
- 15.ADDING STATS FOR THE PLAYER(人物状态)
- 16.LEVEL UP!(升级)
- 17.LIMIT DASH AND FIX A BUG(冲锋限制、修复BUG)
- 18.FIXED ENEMY MOVEMENT(修复怪物移动)
- 19.MOVING BETWEEN ROOMS(场景切换)
- 20.ENEMY LOOT DROP(怪物掉落)
- 21.FIXED ENEMY MOVEMENT(修复怪物移动)
- 22.DIALOG(对话)
- 23.IMPROVED DIALOG(对话优化)
- 24.PAUSE MENU(暂停)
- 25.储存游戏的简单方式
- 26.读取存档的简单方式
- 27.发射炮弹Projectiles
- 28.优化人物控制
- 29.优化AI
- 30.简单的音效
相关参考资料:
[ 分享 ]15.Adding Stats for the Player
我们本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节的主要内容为:
修复冲锋朝向错误
在之前的代码中,人物冲锋时,没有根据朝向来冲锋。
为了修复这个问题,需要在冲锋之前获取当前人物正在面对的方向参数。
在scr_dash_state脚本的执行冲锋代码之前,加入获取方向的代码。
玩家数据永久化
创建新的对象obj_player_stats,在create事件中初始化属性,hp,stamina等
[ 分享 ]14.Enemies that Attack(怪物攻击)
我们本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节的主要内容为:
创建alarm[1]来用作怪物攻击时的停顿时间
创建脚本scr_enemy_stall_state
在该脚本中,如果计时器alarm【1】归0时就调用,怪物待机脚本
创建与玩家角色的碰撞事件
在碰撞事件中,如果发生碰撞时,怪物没有处于stall状态,就在怪物和玩家的方向上创建一个damage对象,对玩家造成伤害.
创建完damage后,将怪物置于Stall状态,并开始计时,等待计时归0,进入idle状态.
这里的stall状态可以理解成Dota的“后摇”,也可以理解为RPG的“公共技能CD时间”,总之在这段时间内不能再创建damage对象。
但到这里还有一个问题未解决,就是damage对象可能会碰撞人物多次,造成的结果就是人物被伤害了多次,因为在damage实例被销毁之前,人物每帧都可能与damage发生碰撞。
[ 分享 ]13.Adding Enemy States(怪物状态)--待机、闲逛、追击
我们本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节的主要内容为:
- 创建怪物的闲逛、追击状态
- 闲逛:在没有发现玩家时,随机选取地图上的一个点作为目标点进行移动
- 追击:在发现玩家角色时,以玩家角色的坐标作为目标点进行移动
初始化怪物的属性
在obj_enemy_slime对象中创建alarm事件
然后在create事件中,创建怪物的属性:视野、目标点x坐标、目标点y坐标,速度、默认状态
创建脚本组
创建3个脚本组,依次为Helper Scripts、Player States、Enemy States。然后将对应的脚本移动到对应的组内。
创建闲逛和追击脚本
修改追击脚本
移除obj_enemy_slime的step事件中的移动代码,添加执行脚本状态。
这是因为我们需要将负责追击玩家角色的代码转移到scr_enemy_chase_state脚本中单独负责,保持模块的独立性。
在cr_enemy_chase_state脚本加入追击代码
创建怪物状态切换脚本
利用choose语句,在wander(闲逛)和idle(保持不动)之间的状态选择一个。在选择了状态后,马上将alarm[0]初始化,以便下一次触发选择脚本
即一旦alarm[0]减少到0,则在wander和idle两个状态中,选取一个,在选取后,直接重置alarm[0]的值。
创建检测玩家脚本来执行追击逻辑
创建脚本scr_check_for_player脚本来检测怪物的视野内是否有玩家角色
在idle状态中添加检测玩家执行代码
优化scr_check_for_player脚本
在找到玩家时,设定targetx和targety,对应在scr_enemy_chase_state中移除obj_player.x的引用。改为引用targetx.
创建wander代码
同样的,targetx在check检测脚本中已经完成,这里只是执行移动即可
总结一下:
[ 分享 ]12.Better Character Sprite Control(角色精灵控制优化)
我们本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节的主要内容为:
- 修复当朝向上,在向左冲锋时,精灵的图片不会发生变化的问题。
- 修正人物停下总是调用朝右精灵的错误
创建朝向
为了修正人物的朝向问题,当你朝向上,在向左冲锋时,精灵的图片不会发生变化,仍然会是向上的。
在obj_player中创建face变量,来储存人物的朝向,根据face的值来设置人物的精灵。
创建宏常量
创建宏常量的语法格式为 #macro 宏常量名称 宏的值
简单来说,宏常量可以理解为一个全局变量。
在object_player的create事件,创建宏常量并初始化。
创建新脚本scr_get_face()
注意round函数的一个小细节,它不是简单的四舍五入,而是约成离自己最近的一个偶数。
我们会用这个脚本和对象实例的dir变量来判断对象实例的朝向。
添加根据朝向改变obj_player精灵的代码
先将原有的根据速度进行对象精灵索引修改的代码注释
然后添加switch语句,在scr_move_state脚本中,使用人物对象实例的face变量的值来设置人物精灵
这样不论人物朝向是上下左右,它的精灵都会一一对应了。
修正人物停下总是朝右的错误
因为dir变量是根据xaxis和yaxis来获得的,所以在人物没有移动时。
再次根据dir去获取face,必然是因为dir = 0。
然后得到的face总是RIGHT,所以这里将scr_get_face脚本的调用放到只有xaxis或yaxis都不等于0的代码中去。
这样当没有按键按下时,人物的朝向就不会重置为0(右边),而是保持停下来的朝向了。
然后后续的根据face来改动obj_player的动画的代码不用改动。
但是至此,冲锋时,根据dir来冲锋的错误仍未被修复。
[ 分享 ]11.HITBOXES AND KNOCKBACK(受击盒和击退)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
在上一节当中已经做到了攻击状态和移动状态的切换,但实际上攻击的效果, 并没有得到实现,在这一节当中,将实现以下效果:
- 将攻击到的敌人击退
- 并扣除敌人的HP1点
创建精灵spr_damage,设置大小为24*24
然后使用笔刷工具,绘制一个黑色圆形,来示意攻击的范围,实际上可以将其称为“技能特效”。
设置原点中心在middle center的位置。(12*12)
创建obj_damage,并选中spr_damage作为它的精灵
实现击退的效果,是利用创建一个Obj对象,obj会对碰撞的其他对象施加一个力的作用,使其“被击退”,所以在此先创建一个对象
回到obj_life_parent的事件中,初始化生命体的HP属性
在“生命体”对象的create事件中,创建hp变量并赋值为3
注意玩家对象obj_player和obj_enemy_slime对象同样继承了该属性(在create事件中使用了event_inherited()),如果想要更改玩家的对象的血量为20,只需要在obj_player的create事件中,对变量hp重新赋值即可,但必须在event_inherited()语句后面,否则继承的父物体的赋值将会覆盖你前面的赋值,所以一般继承函数会放置在整段代码的最上方。
生命值归0,销毁生命体实例
常见的,HP归0,生物死亡需要进行销毁,节省内存。在destroy事件中实现。
对碰撞的物体“实施伤害”
创建obj_damage与生命体的碰撞事件
在攻击时,创建“实施伤害”的obj_damage
现在obj_player的create事件中,初始化attacked变量来标记攻击状态。
为什么要创建这个attacked变量呢,是因为碰撞事件是每帧都会进行检测的,如果不使用这个状态变量来控制,就会每帧都扣除碰撞到的对象1点HP,这显然不是我们的想要的效果,我们想要的效果,是“1次攻击只造成1次伤害”。
然后在scr_attack_state脚本中,来创建obj_damage。
同样的在从攻击动作切换回movestate时,需要重新将attacked变为false来准备下一次的创建damage对象。
修复玩家实例不存在的BUG
一般的,在引用任何对象的属性前,都必须判断对象实例是否存在,因为一旦GMS2进行索引的对象实例不存在,将会导致游戏崩溃,不存在就不索引,并且报出Debug信息。
在引用obj_view里引用obj_player的变量属性前,先对obj_player的实例判断是否存在
同样的,修正在obj_enemy_slime里的代码
由于这时obj_damage是对lifeform的碰撞,所以也会对玩家对象obj_player造成伤害
初始化obj_damage变量属性
这里将obj_damage造成的伤害和击退距离以变量的形式储存起来,方便以后的修改。
在step事件中引用伤害变量
添加obj_damage销毁代码
创建计时器变量
在计时器事件中进行实例销毁
修复damage实例对玩家player实例的伤害
在scr_attack_state创建damage对象的代码中,排除攻击者自身。(即obj_damage不是对所有对象实例造成伤害,这里要筛选掉自己。)
在创建damage对象后,马上对damage对象进行赋值。
创建击退效果
在damage的碰撞事件中,对碰到的物体实施击退,应用的是物理引擎的“冲击力”效果,physics_apply_impulse.
通过设置史莱姆的物理属性,来优化调整击退效果(击退距离)
将史莱姆的Linear Damping线性阻尼由0.1改为5,该阻尼值越高,移动时,需要的力就越大
修正obj_damage的创建位置
现在的代码是把obj_damage对象创建在自己的位置上,而正确的需求是将其创建在打击特效上,但是需要根据人物的打击的方向,将其放置在不同的位置上,所以针对四个不同的方向,使用switch语句来修正创建对象的x,y坐标
修正方向错误的问题
在施加击退冲击力时,方向应该是调用攻击脚本的实例位置和碰撞位置两点的矢量方向,而不是damage和碰撞到实例连线矢量方向
最后将obj_damage设置为隐藏
将visible设置勾选掉,当然如果有动画资源,而可以在创建obj_damage后设置它的精灵动画,作为打击特效或者受击特效处理
[ 分享 ]10.PLAYER ATTACK STATE(攻击状态)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- 13.10.10.1.创建带有特效的精灵SPR_PLAYER_ATTACK_DOWN
- 13.10.10.2.创建一个组PLAYER,将角色相关的精灵放入在内
- 13.10.10.3.在INPUT脚本中,书写释放攻击的按键检测
- 13.10.10.4.创建攻击脚本SCR_ATTACK_STATE
- 13.10.10.5.在SCR_MOVE_STATE脚本,进行切换状态
- 13.10.10.6.使用ANIMATIONEND事件来再次切换状态回到MOVESTATE
创建带有特效的精灵spr_player_attack_down
宽高为28*42,一共7帧,同样采用strip的方式进行多个导入精灵图片
设置原点和碰撞盒,这里需要将原点设置为对应的待机动作的匹配原点,即根据待机时的精灵图片的原点,来设置攻击的精灵图片,原点(也是因为这里攻击的精灵图片和待机的精灵图片不一样大小的缘故),这样在播放攻击的精灵动画时就不会发生跳帧。
和原有的向上行走动画spr_player_down的y轴点保持一致
同样的,创建其他3个精灵
spr_player_attack_right(7,10)
spr_player_attack_left(28,10)
spr_player_attack_up(14,31)
创建一个组Player,将角色相关的精灵放入在内
在Input脚本中,书写释放攻击的按键检测
创建攻击脚本scr_attack_state
设置攻击时播放精灵动画的速度
根据sprite_index的变量值来改变动画精灵图片。
在scr_move_state脚本,进行切换状态
检测到攻击按键按下时,将状态切换成攻击状态
使用AnimationEnd事件来再次切换状态回到movestate
即当攻击动画被播放完后,状态切换回移动状态
在obj_player的Add Event---other---Animation End事件中添加如下代码
到了攻击动作就做好了,但是关于攻击的效果(伤害和击退呢都还需要后续添加)
[ 分享 ] 9.ADDING ENEMIES, DEPTH, AND INHERITANCE(增加敌人,理解深度和继承)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
实现效果为,让地图出现一些怪物,并且这些怪物是会追着角色跑的(即向着角色的坐标进行移动)
- 创建史莱姆的精灵
- 创建史莱姆对象
- 将怪物设置在房间中
- 创建史莱姆的移动代码
- 史莱姆碰撞事件
- 父物体和继承
- 深度控制
首先要在游戏里放物体,自然是要遵循通用的规则:先创建精灵,创建对象,拖到对象到房间里。
创建史莱姆的精灵
命名为spr_enemey_slime,并导入精灵图片
创建史莱姆对象
创建对象obj_enemy_slime,然后选择精灵,并且设置对象的碰撞盒形状
选择形状的类型为Convex Shape自由设置顶点形状,然后将形状拉成三角形
注意在这个过程中,碰撞盒的形状不可以是内凹的,这是GMs进行顶点计算所要求
将怪物设置在房间中
并设置obj_enemy_slime的create事件:控制动画播放速度
创建史莱姆的移动代码
史莱姆碰撞事件
依次创建obj_enemy_slime与人物,墙体,史莱姆本身的碰撞事件,在碰撞事件内不用添加代码,只需要添加一行描述即可,表示需要调用碰撞事件
同样的我们需要修正旋转的问题
父物体和继承
创建一个对象,命名为obj_lifeform_parent,设置它与墙体的碰撞(同样的碰撞事件内不需要书写代码, 只需要添加注释说明即可)
然后回到obj_player中来,设置它的父物体为obj_lifeform_parent,这样就可以删除掉它本身的与obj_wall的碰撞了,因为它继承了父物体obj_lifeform_parent的属性(包含了与obj_wall的碰撞)
//继承是指子物体继承父物体的变量属性和事件
将修正旋转的代码也移动至父物体的create事件中,因为会将obj_player和obj_enemy_slime的父物体都设置为lifeform,所以可以移除两个对象的互相碰撞事件了,只需要添加与obj_lifeform_parent的碰撞事件即可。
对应在lifeform对象的create事件中,添加修正旋转代码,移除obj_player和obj_enemy_slime的旋转代码,设置它们的父物体为obj_lifeform_parent
注意这里有个问题,如果父物体和子物体都存在相同的事件时(如create事件),如果想要在子物体中含有父物体的属性,就需要在子物体中使用函数event_inherited(),不然就只会执行子物体事件中的内容
深度控制
在lifeform事件中,添加深度控制的代码
同样的,要在子物体(obj_enemy_slime)的对应的step事件中添加事件继承代码
[ 分享 ] 8.DASH STATE(冲锋状态)
然后回到scr_move_state脚本内,设定计时器的值本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
这一节需要达成的效果是,角色朝着当前的朝向,位移一小段距离,简称“冲锋”。
并且在冲锋过程中,遇到阻碍物(墙体,怪物)会停下来。
- 冲锋按键检测
- 创建DIR属性
- 创建SCR_DASH_STATE脚本
- 使用计时器
- 创建冲锋特效
冲锋按键检测
这里设置响应角色冲锋的按键为键盘上的C键和手柄上的X键
所以继续向负责按键检测脚本scr_get_input中,增加按键检测
创建储存角色朝向的变量dir
在obj_player中的create事件中,对dir进行初始化dir = 0;
以便在脚本中访问该变量属性
创建scr_dash_state脚本
(复制原来的scr_ move_state脚本代码),成为一个新脚本,命名为scr_dash_state
在scr_dash_state脚本内将获取dir和len的代码移除,再将动画控制代码也移除掉
将以下代码都移除掉
然后设置冲锋时,进行位移的固定冲锋距离:len = spd * 4;
只留下以下代码
然后回到scr_move_state脚本中来,检测是否按下了冲锋键,如果按下该键,则dash_key会在scr_get_input被更新为true.
这时会将状态变量state设置为scr_dash_state的脚本索引,那么在obj_player的step事件中,执行的脚本就变为冲锋
到此人物的冲锋就完成了,但是有一个问题是:“冲锋的结束我们没有做”,这会导致人物不受控制的固定朝一个方向冲锋,并且没有动画。
这是因为我们的只在obj_player的create事件中,对dir进行了初始化,而没有根据玩家输入来获取dir的值,所以讲scr_move_state脚本内的dir改成脚本变量(不使用var)
使用计时器
现在obj_player的计时器事件,里面不用写代码,只是代表创建了alarm[0]事件然后回到scr_move_state脚本内,设定初始化计时器变量alarm[0]的值然后回到计时器内,在触发计时器归0时,切换state状态变量:state = scr_move_state,这会结束冲锋状态,使角色回到响应移动的状态。
创建冲锋特效
这里说创建冲锋特效,实际指的是在角色原地创建一个和角色精灵图片相同的精灵图片,然后渐变透明并移除,这会在视觉上形成“残影”的效果。
先创建obj_dash_effect对象,然后在create事件中,初始化图片透明度
再在step事件,进行逐渐消失的处理(逐帧减少透明度)
然后回到scr_dash_state脚本中,在每调用一次scr_dash_state脚本,就创建一个在原地会自动消失的残影
通过计时器归0切换状态变量为scr_move_state脚本,来停止瞬移
[ 分享 ] 简单的对话框体(下)
该教程由油管上的妹子FriendlyCosmonaut原创,能翻墙的尽量看原版吧:Textbox Tutorial。
代码托管在Github。实现的效果为:
其实基本的逻辑已经在简单的对话框体(上)实现了,这一节主要是
- 将代码重构成可以复用,并且更加抽象模块化
- 多页文本对话和跳过对话的功能
- 打字效果(逐字出现的效果)
- 然后美化下对话框的表现:外边框,字体变色
多页对话文本和跳过某页对话的功能
将obj_susan的step事件的对话文本,直接改成变量myText
然后在create事件使用list结构对该变量声明和赋值,这样我们不必直接去step事件一一修改对话文本,可以直接在create对myText变量直接修改,其他地方引用变量。
注意这里的声明方式,list[index] = strings。同样的index的值将作为我们对话框的页码来使用:第一段对话,第二段对话...
既然有了多段对话,那么在obj_textbox的draw事件内,也要分别连续绘制不同的页码的文本。
将Draw事件内的引用的text变量,改为text[page]
同样的,由于使用page变量,在create也对page变量进行声明和赋值
然后为obj_textbox添加step事件,并且进行按键检测,检测到了则跳过当前页的对话(即page变量增加1)。
运行游戏,按下空格键能看到如下效果
修正对话框对象的创建条件为,按下space时,并且与NPC对象(如obj_susan)发生碰撞.
在obj_susan的step事件内,添加if语句
修正page变量的大小会超过文本text(list)的“长度”,即你一直按下空格,当对话框显示完最后一句话后,就销毁该对话框对象。
然后设置creator.myTextbox变量为空。
为什么这么做?
因为在NPC对象创建实例时,会判断自己的myTextBox存不存在,一旦存在它就不会创建第二个了,这个必须将已经被销毁的myTextBox变量设置为空,这样当再次触发创建NPC对象的TextBox时,TextBox才会被创建出来。
首先在obj_Textbox中声明creator变量为noone。然后在创建obj_Textbox时,将obj_Textbox的text变量换成NPC自己的对话文本,并且设置该obj_Textbox的creator(创建者)为自己。
这样在最后,就可以通过creator索引,在obj_Textbox的step事件中,设置NPC对象的myTextBox变量为空了(是不是很魔法,这个骚操作,真是给跪了,这个油管妹子。)
这里有一个优化的操作,作者不希望,当出现最后一句话后,再次按下空格不是销毁文本对话框(obj_Textbox),然后又马上创建新一个文本对话框(obj_Textbox)出现第一句话,而是这一次的空格仅仅只是起到销毁文本框的作用,这里有个细节操作,就是我们不知道GameMakerStudio2的代码运行顺序
所以我们不在运行检测到space空格按下的这一帧中立即将myTextbox变量设置为空,而是使用计时器alarm(并且是NPC对象的alarm变量)来移除myTextbox,就会使得这一次空格按下仅仅只是销毁文本对话框,而不会立即创建新的文本对话框了。
打字效果(逐字出现的效果)
为了实现逐字出现的文本对话框的效果,这里的方式是对展现的文本的内容进行处理。
在obj_Textbox的step事件中,创建一个临时变量textPart,并使用string_copy()函数来从指定的位置,复制指定个数的字符成为新的文本。
先在obj_Textbox的create事件中创建charCount变量(charCount每帧增加的数量可以作为逐字出现的速度来调节)
为了方便调试,查看结果,我们可以为obj_textbox对象添加draw_GUI事件,用显示当前绘制了多少个字符
运行游戏,即可触发对话,即可看到逐字出现的效果,但是可以看到左上的charCount数量在不断增加,没有达到本页对话的最大字符数时停下,这时比较消耗性能的。
为了修正这个问题
字体变色效果
在NPC对象(obj_susan)的create事件创建myname变量
再在对话框中,创建name变量
在创建对话框时,将NPC的名字变量赋值给对话框
然后修改绘制文本的代码
为了美观缘故,这里设置了水平边距和垂直边距,并且使姓名居中显示
运行游戏,即可看到效果。、
NPC对话模块化。
即创建一个可以对话的NPC父物体,其他NPC对象都从该对象继承。
在资源树上选中obj_susan,拿下<crtrl+d>快捷键复制一个对象,重命名为obj_parent_talking。
然后将其精灵设置为空。
接着将其create事件中的myName和myText变量都设置为空(这些内容将交给继承它的NPC对象来填充,毕竟不同的NPC有不同的名称,有不同的姓名)
然后对原来的NPC对象(obj_susan)进行处理
如果我们需要在继承obj_parent_talker的NPC对象另外表现出不同的属性,那么可以继续添加step事件,并在书写自己的属性代码前,添加继承函数event_inherited()
如此以来,我们就可以自由的创建更多的NPC了,只需要添加NPC自己的对话和姓名,而对话的逻辑和功能,都交给obj_parent_talker对象了。例如我们可以创建一个obj_bob对象,设置精灵,对话,姓名。
同时为了方便没有耐心看剧情的玩家,我们再添加一个小功能,在播放文字未完成时,再次按下空格,则将当前页的所有的文字全部显示出来。
运行游戏,则可以看到效果。
美化对话框
先获得对话框高度
再绘制一个包裹对话框外边缘的矩形边框
运行游戏,则可看到文章前贴出的效果图
到此,FriendlyCosmonaut妹子的对话系统教程完结了。
[ 分享 ]7.GAMEPAD INPUT(手柄输入)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- 检测手柄的输入。
- 剥离其他模块的输入检测,集成到scr_get_input中
检测手柄输入
作者是以Xbox360手柄为例,首先在scr_get_input脚本里面添加手柄输入代码
检测手柄是否连接成功(0是指槽位,或者说某个手柄),在连接成功的条件下
访问手柄十字方向轴的按下情况(正负),来为四个Key赋值
注:有关手柄输入的具体函数用法,可以参考官网文档Reference--Mouse、Keyboard and Other Control一节中的内容
剥离obj_player和scr_move_state脚本中的输入检测代码
将关于移动变量的xaxis和yaxis的处理都放到scr_get_input里面去,在obj_player中只访问它们
首先先在obj_player对象的create事件中,初始化变量xaxis和yaxis
然后将原来在scr_move_state脚本中根据四个key值来为xaxis和yaxis赋值的语句删除掉,移动至scr_get_input脚本中
并且在scr_get_input中将检测手柄输入来为四个key进行赋值的语句,修改为直接为xaxis和yaxis变量赋值。
到此。在scr_move_state纯粹是根据xaxis和yaxis的值来进行移动,不再负责按键检测和输入,处理。
RPG_Basic(6):BETTER PLAYER MOVEMENT(优化角色移动)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- 创建移动轴变量,来优化角色移动
- 为什么要优化角色移动,因为之前的移动时垂直速度和水平速度是完全独立,它们仅受各自的按键输入影响,这就导致,斜线运动时,水平和垂直方向都有速度,斜线合速度显然快于这两个速度,而我们需要的是人物朝任意方向移动,速度 都是一致的,这才会让玩家得心应手的控制和移动。
在obj_player的create事件中,创建新变量
- hspd水平速度分量
- vspd垂直速度分量
- len位移
然后将原来在scr_move_state脚本中的移动代码批量注释掉(四个if语句和stop动画语句),然后使用轴向变量yaxis和xasix来进行移动
- xaxis为正,往右移动,xaxis为负,往左移动,并且xaxis的值大小决定水平速度的大小
- xaxis为正,往右移动,xaxis为负,往左移动,并且yaxis的值大小决定垂直速度的大小
- spd作为系数来调整速度大小··
到这里,人物是可以移动了,但是人物没有动画的
需要重新进行动画处理(在scr_move_state进行如下处理)
- 根据yaxis和xaxis的值,来计算移动方向dir
- 根据yaxis和xaxis的值,来判断是否需要进行移动
- 通过lengthdir_x获取在x轴上的分量速度
- 然后根据len的值来设置是否进行播放动画(image_speed是否等于0),image_speed_player作为系数调整
- 如果len为0,就需要设置image_speed=0,停止动画,因为角色在停止时,是静止的(除非需要播放原地待机动作,不然就是如此处理image_speed=0,image_index = 0)
- 接下来是根据vspd和hspd的正负值,来设置角色的精灵图像
注意顺序对精灵动画的影响,这里hspd的代码在后面,也就是说当你按下斜向上的按键时,
会是水平方向的精灵动画(因为一旦有水平速度,在代码的最后,精灵动画最后就会被设置为spr_playe_right或者spr_player_left)
到此角色移动就优化完了
RPG_Basic(5):SMOOTH VIEW MOVEMENT(平滑的移动视图)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- 创建镜头控制器对象,来控制摄像机视图移动。
- 为什么要优化镜头移动,因为默认的镜头是跟随人物移动的,所以当人物停下来时,镜头就马上静止了,这会给你一种不平滑的体验,就像播放或者停止音乐时的音量淡出淡入效果,所以这里为镜头的移动做同样的处理。
创建一个控制摄像机视图移动的控制器 obj_view,在该对象的step事件中,
在每step内,摄像机视图的位置缩短与人物之间的距离的10%
将该对象拖入房间,然后在房间的视图设定中,把摄像机视图的跟随对象改为obj_view
这样一来,摄像机的移动就具有缓动的效果了。
RPG_Basic(4):DRAW EVENT, BACKGROUNDS, SCRIPTS, AND STATES(绘制事件,背景,脚本,状态)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- 导入背景图片,设置平铺
- 绘制角色脚下阴影
- 创建脚本,检测键盘输入
- 使用状态机来储存角色行为
设置房间背景图片
注:在GMS2版本中,资源树已经去除了Background类型,所以在GMS2设置背图片的方式时:
先创建精灵,命名为“spr_grass”,然后导入外部文件作为精灵图像
,然后在房间属性中,设置并平铺(Horizontal Tile水平平铺,Vertical Tile垂直平铺)
设置角色脚底阴影
创建一个精灵,命名"spr_player_shadow"
并导入外部文件作为精灵图像(文件下载地),设置中心为center(x:7,y10)
然后使用obj_player的draw事件来绘制人物的脚底阴影
注:在创建draw事件后,GMS就会不再调用默认的绘制自身的事件,所以需要在代码中额外增加一行“draw_self”
draw_sprite(精灵名称或者索引,图片编号,x坐标,y坐标)
创建脚本检测输入
创建脚本scr_get_input(),并且将检测输入的代码,全部移动至该脚本内
然后移除在obj_player对象内的检测输入代码,换成调用该脚本,主要在create和Step都要调用1次,create调用是因为要创建变量,step是需要每步进行检测
create事件:
step事件:
使用状态机
创建脚本,scr_move_state,然后将原本obj_player内的所有移动相关代码放置到该脚本内
在obj_player的Create事件中,声明状态变量state = scr_move_state
注:所谓状态机,简单而言就是同一时间只执行一个(种)动作或者行为,用变量state存储这个唯一的行为,在GMS2中的方式就是把脚本的名称赋值给变量,该变量就会成为脚本的索引。
在step事件中只要调用script_execute()函数执行该脚本即可保证同一时间只调用1个脚本(状态)
运行游戏,就能看到角色仍旧可以上下左右移动。
RPG_Basic(3):VARIABLES AND CHARACTER SPRITES(变量和人物精灵)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
基本概念
- instance variable 实例变量
- local variable 局部变量
- depth深度
在Create事件创建变量并在Step事件中使用
双击资源树上的obj_player对象,点击event,点击Create,在Create事件中的代码,添加实例变量spd,
注:GameMaker Studio 2 对大小写是敏感的,spd和SPD不是同一个变量
将原来的Step事件中的"4"替换成变量"spd",来代表角色移动的速度
尽量使用变量来控制参数,这样方便修改,如果想要改变角色移动的速度,只要在create事件中修改spd的数值即可,而不是挨个修改step事件中的数值。
使用局部变量来代替复杂的表达式
创建4个local variable(局部变量)来代表复杂的表达式,这样有助于保持代码的可读性。
注:索引按键A可以使用单引号,但在GMS2版本中,必须使用双引号来进行标识。
导入外部图片作为精灵子图像
创建的精灵,双击呼出编辑面板,点击EditImage
在弹出的界面,点击最上方的彩蛋的EDIT,选中需要导入的外部图片文件
然后设置参数即可
依次创建以下几个精灵并导入外部图片(外部图片资源在此下载,若链接失败,请科学上网,或者留言索要)
- spr_player_left
- spr_player_right
- spr_player_up
- spr_player_down
都是14*21大小,总帧数为6。
设置各个精灵的中心为middle centre
设置obj_player的碰撞盒至合适的位置
去除自动补齐颜色
点击游戏上方的按钮的设置按钮,将windows里面图像设置的红框条目,设置为空,这将禁止GMS引擎在游戏运行时,自动补齐精灵图片的动画,从而避免图像模糊。
手动设置精灵运行速度
在obj_player的create事件,令image_speed = 0;
这意味着obj_player的不会自动播放精灵动画,如果不设置为0,该精灵的动画将以精灵的参数speed为动画播放速度。
当你运行游戏,角色就会不停的循环的播放动画,就比如下图,角色没移动,但也在原地播放一个原地跑步的动画。
理解深度的概念
在obj_player还有一个参数,叫做depth,你可以简单理解成画面中的人离屏幕的距离,离得越远数字就越大。
负数离屏幕近,整数离屏幕远,当然这只是一个比喻的说法,正确的来说应该是渲染上的术语,你可以查看帮助文档帮助了解,或者查看青铜的幻想的GMS中文教程,这一点说的很清晰。
注:和GMS1不同,GMS2取消了直接在对象创建时设置depth,而是在脚本使用instance_create_depth()要求必须输入深度,如果你想要在不同的深度创建同一个对象,那么就不必像GMS1一样,创建两个对象啦。
运行游戏发现,在角色移动时,角色是“静止”,所静止其实是指obj_player没有精灵动画,它的精灵子图像永远固定不变。
如果想要在角色移动时,根据他移动的方向,播放不同的动画就需要改变obj_player的精灵子图像索引和动画速度了。
在if事件中添加索引更改,设置动画播放速度为0.2;
在step事件监测按键输入,每帧都会更新按键的情况,从而会导致其中某一个KEY被按下后,松开后,精灵子图像不会复原,就是在最后添加一个复原精灵子图像的代码,注意当设置image_speed = 0,精灵子图像索引会自动回到第一帧。
RPG_Basic(2):STEP EVENT + VIEWS(步事件和视图)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- Step事件
- 脚本基本函数:if、or、ord、keyboard_check()
- 摄像机和视图
- 摄像机跟随人物移动
基本概念
- if()函数
- or()函数
- keyboard_check()函数
- ord()函数
理解Step事件
在设置里面设置的帧数就是指的帧,step.
目前已经在第1节中将游戏运行速度改为1秒=30帧。
也就是说在Step事件里面的代码,(理想状态下)每秒会运行30次。
删除按键事件,添加STEP事件
将第1节,添加的键盘按键检测事件删除(右键点击,在弹出的窗口中点击Delete Event)
然后依次添加如下代码,即不通过GMS2提供的事件来检测键盘按键,而是通过内部函数来检测。
内部函数Keyboard_check():在这一帧,键盘的某个按钮是否被按下,按下返回true,没有返回false.
注意ord()的字符串引用需要使用双引号。
这样WASD和方向四键的检测事件就完成了。
创建房间视图
左键双击资源树上的房间名称
即可在GMS2界面的左下该房间对应的房间属性。
首先我们需要点击Enable Viewport为勾选状态,同时它的visible为勾选状态,否则游戏运行时就是一片漆黑,你可以把viewport理解为一个视频端口,有点类似于电视机里面的视频,AV,HDMI接口。
Cemera和View
Cemera(红色部分)是指在游戏世界能看到多大:指代在游戏具体的像素大小
View(黄色部分)是指游戏窗口有多大:指代游戏运行时,显示的游戏窗口大小
将Cemera和View的属性设置如下,然后点击Object Following(绿色部分)设置为obj_player,这样镜头视图将会跟着角色一起移动。
触发摄像机移动的范围、
在视图属性的下方,有一个设置视图跟随移动的条件
指代跟随的物体走到离屏幕边缘多近时,视图就开始根据人物移动,移动的速度为speed
设置完,运行游戏就能看到人物移动和镜头跟随移动的效果了
RPG_Basic(1):BASIC MOVEMENT AND COLLISIONS(基础移动和碰撞)
本系列是油管上的HeartBeast的[Beginner] Make an RPG课程的中文笔记,主要形式是截图的方式进行步骤上的说明。面向对象:GameMaker新手,以学习一门脚本编程语言,制作一个RPG游戏为目标的爱好者。
本节主要内容:
- 创建项目
- 创建精灵
- 创建对象
- 创建房间
- 开启物理引擎效果
- 将对象设置在房间某个位置
- 设置碰撞盒
- 使用键盘按键检测事件控制角色移动
基本概念
以下内容在官方帮助文档中,有更明晰和合理的解释,有疑问和错漏请参考帮助文档进行理解。
- 精灵Sprite:它们可以有独立的屏幕坐标、帧率、周期等等,在最终渲染时,它们会与背景等一起被合成为你看到的每一帧画面,它之所以被称为精灵,是因为Sprite单词含义为“精灵,鬼怪”,简单而言,可以理解成有动画的图片(和GIF动图的效果类似),更详细的内容请参考知乎。
- 对象Object:可以简单的理解成模版,学术化的语言,将其称为“现实事物的抽象,类”,但针对具体的游戏开发而言,举例如怪物模版,角色对象都是对象。
- 实例Instance:对象的一个现实例子,例如狗是对象,那么一只叫做Ryne的狗就是实例,通常在GMS2中对象是指在资源树上创建的Object对象,而实例是指在游戏运行时,以Object为模版,在游戏中实际的实例,这些实例具有一部分在Object定义的属性,如血量,速度等,但它是动态变化的,会受到其他的影响
- 房间Room:一般指的是游戏场景,游戏中角色所处的环境,分为多个种类层级(Layer),在表现上分为背景层,前景层,实例层。
创建项目:
命名项目名称为RPG Basics
选择储存文件的路径
设置项目参数
设置游戏运行帧数为30.
创建精灵
右键点击位于界面最左边的资源树,然后在呼出的二级面板,点击CreateSprite(创建精灵)即可创建新的
创建人物精灵,命名为spr_player
设置大小为32*32
点击Edit进入编辑图片
当我们临时没有美术资源时,可以利用Fill tool填充工具,将图片全部填充成蓝色,暂时替代一个美术资源来用
使用同样的方法,创建墙体精灵,命名为spr_wall,填充其颜色为黑色。
当我们有外部的美术资源,就在先在资源树创建精灵,不编辑和填充颜色,然后双击精灵,在弹出的界面点击import输入外部的图片为精灵
创建对象
同样的操作,在资源树里Create Object,创建玩家对象
双击对象,在弹出的界面,将其对象的Sprite精灵设置为spr_player
以同样的操作,创建墙体对象,obj_wall
创建房间
创建房间,命名为rm_one
在属性设置里面(双击房间,在默认视图的左下角),设置房间大小为640(width)*360(Height)
拖入房间对象
双击房间,在弹出的视图中,选中实例层(instance)
按住对象,拖动鼠标,单个拖入对象,像下图一样。
- 黑色方块:墙体
- 绿色小人:角色
这里有两个快捷操作
- 批量拖入(按住alt,可以单击房间连续拖入)
- 删除(选中,按住键盘Delete键,或者右键,在弹出的界面上点击delete )
- 批量删除(按住shift选取对象,可以进行批量选中)
运行游戏
点击左上的类似播放的按钮,可以运行游戏
可以看到如下效果,黑色墙体中间,有一个蓝色的小人
修改房间物理属性
点击资源树上的房间(一般创建项目后,会默认创建一个room),然后选中这个房间的物理属性,勾选enable Physics
将其Gravity_y修改为0,即Y方向没有力的影响,这样开启物理引擎影响的对象就会往下坠了。因为我们实际需求的是一个2D平面俯视图的效果。
设置对象的物理属性
在资源树上,选中对象obj_player,然后依次开启物理效果,然后修改碰撞盒形状为BOX,再匹配碰撞盒和精灵图片的位置。
实际上很多碰撞盒,不会和精灵图片完全吻合,比如上图中的碰撞盒只设置在下半身,想象在实际生活中,地面障碍可能与人发生碰撞的部位,就是脚部而已,所以类似的,在设置碰撞盒,从实际需求出发来设置碰撞盒的大小和形状。
按照同样的方法,设置obj_wall的物理属性和碰撞盒(这里要全覆盖)
需要注意的一点是,我们需要将墙体设置的密度(Density)设置为0,这意味着墙体是无限重的,能达到任意物体都无法移动它的效果(在房间开启物理效果的前提下)
创建移动代码
在资源树双击obj_player对象,在弹出的面板,点击Add Event,添加键盘输入检测事。这个事件能检测到键盘的左方向键被按下,这时,控制的角色向水平方向右侧移动4个像素,即向左行走,这个事件每帧都会检测,所以每帧都会发生移动(+ 4个像素距离)
同样的,添加其他三个方向键的检测事件,并且如下对应
phy_position_x -= 4;(左)
phy_position_y -= 4;(上)
phy_position_y += 4;(下)
运行游戏即可看到效果。
创建墙体碰撞
上个动图可以看到角色是可以穿过墙体的,所以需要为了obj_player创建和obj_wall的创建事件。
在碰撞事件中,不用书写任何代码,仅仅加上注释即可,但这声明了,obj_play和obj_wall是发生碰撞的。
修正物理旋转
运行游戏后,能看到角色在移动时,会被移动,为了修正这个问题,在obj_player对象的Create事件中,加入代码即可修复
phy_fixed_rotation = true;
QA
- QA1:phy_position_x和x有什么区别?
- QA2:添加collision事件,又不书写代码这是为什么。
附录(蓝色标识已完成):
- 1.BASIC MOVEMENT AND COLLISIONS(基础移动和碰撞)
- 2.STEP EVENT + VIEWS(步事件和视图)
- 3.VARIABLES AND CHARACTER SPRITES(变量和人物精灵)
- 4.DRAW EVENT, BACKGROUNDS, SCRIPTS, AND STATES(绘制事件,背景,脚本,状态)
- 5.SMOOTH VIEW MOVEMENT(平滑的移动视图)6.BETTER PLAYER MOVEMENT(优化角色移动)
- 7.GAMEPAD INPUT(手柄输入)
- 8.DASH STATE(冲锋状态)
- 9.ADDING ENEMIES, DEPTH, AND INHERITANCE(增加敌人,理解深度和继承)
- 10.PLAYER ATTACK STATE(攻击状态)
- 11.HITBOXES AND KNOCKBACK(受击盒和击退)
- 12.BETTER CHARACTER SPRITE CONTROL(角色精灵控制优化)
- 13.ADDING ENEMY STATES(怪物状态机)
- 14.ENEMIES THAT ATTACK(怪物攻击)
- 15.ADDING STATS FOR THE PLAYER(人物状态)
- 16.LEVEL UP!(升级)
- 17.LIMIT DASH AND FIX A BUG(冲锋限制、修复BUG)
- 18.FIXED ENEMY MOVEMENT(修复怪物移动)
- 19.MOVING BETWEEN ROOMS(场景切换)
- 20.ENEMY LOOT DROP(怪物掉落)
- 21.FIXED ENEMY MOVEMENT(修复怪物移动)
- 22.DIALOG(对话)
- 23.IMPROVED DIALOG(对话优化)
- 24.PAUSE MENU(暂停)
- RPG_Basic(25): 储存游戏的简单方式
- RPG_Basic(26): 读取存档的简单方式
- RPG_Basic(27): 发射炮弹Projectiles
- RPG_Basic(28): 优化人物控制
- RPG_Basic(29): 优化AI
- RPG_Basic(30): 简单的音效
相关参考资料:
- GMS官方说明文档
- [Beginner] Make an RPG--HeartBeast
- GameMaker: Studio 中文教程--青铜的幻想
- GMS2官方中文教程系列--顺子
- yoyogames官网--GameMaker Studio下载和注册
RPG_Basic(30): 简单的音效
Youtube视频地址:HeartBeast
以往的内容:
- RPG_Basic(25): 储存游戏的简单方式
- RPG_Basic(26): 读取存档的简单方式
- RPG_Basic(27): 发射炮弹Projectiles
- RPG_Basic(28): 优化人物控制
- RPG_Basic(29): 优化AI
- RPG_Basic(30): 简单的音效
首先介绍一个制作音效的网站:http://www.bfxr.net/.
这个网站上有预设的模版,如Pickup(拾取),Jump(跳跃)等,可以点击后,然后Play可以听听查看效果。
如果满足需求,可以点击Export Wav,导出wav音乐文件。
然后依次重命名为
snd_enemy_die
snd_player_takes_damage
snd_expr
snd_sword_attack
然后在我们需要播放音效的脚本文件中,插入代码 audio_play_sound(音效名称,优先级,是否循环)
运行游戏,攻击时,就可以听到音效。
同样的,在obj_damage的碰撞事件(和obj_player)中加入播放音效的代码
同样的,在obj_player的碰撞事件(和obj_expr)中加入播放音效的代码
同样的,在obj_enemy_chinlin和obj_enemy_slime的destroy事件中加入播放音效的代码
到这里简单的音效添加就完成了。
RPG_Basic(29):AI优化
Youtube视频地址:HeartBeast
实现效果为
首先打开obj_enemy_slime,在Create事件中,删除test变量,并将变量targetx,targety(基于向目标的方式来移动)改为xaxis, yaxis(基于渐近的方式来移动)
打开scr_enemy_choose_next脚本,在现有的代码,可以看到怪物巡逻的地点,是在房间内随机选取一个点。现在要做一个改变,将target_x个target_y的代码移除
换成xaxis, yaxis,在怪物处于巡逻的状态,选取一个新的移动轴来进行移动
同样的,scr_idle_state脚本不用更改,但怪物巡逻时每帧检测玩家的scr_check_for_player脚本,也要修改targetx, targety为xaxis, yaxis,
在scr_enemy_chase_state和scr_enemy_wander_state追击角色的脚本也同样要替换,并且移除掉条件
这样修改以后,会发现怪物巡逻的脚本scr_enemy_wander_state和怪物追击的脚本scr_enemy_chase_state脚本是一样的。
所以为了方便调用,新建一个脚本scr_move_axis(),来作为向着某个移动轴进行移动
此时保存代码,运行游戏会发现,怪物只会自由移动,而不会追击角色
这是因为在scr_move_axis()脚本中,怪物获取方向的代码不对。
因为xaxis和yaxis已经不再是某个坐标的xy值了,如果仍然用point_direction( x, y, xaxis, yaxis)当然是错的。
xaxis和yaxis实际上应该看待为移动速度的分量,所以这里直接改为point_direction( 0, 0, xaxis, yaxis)即可修复。
导入新的怪物精灵图片,全选所有图片,将其拖入GMS2的工作区
然后依次命名名称Name,设置图片原点Origin
spr_chinlin_run_up
spr_chinlin_run_down
spr_chinlin_run_right
spr_chinlin_stand_up
spr_chinlin_stand_rightS
复制obj_enemy_slime,将复制后的副本对象重命名为obj_chinlin,设置精灵图片为obj_chinlin_stand_right
并设置碰撞形状
由于该怪物对象是从obj_lifeform_parent继承而来,只具有最基本一些属性(例如死亡),如果想要额外的属性,可以创建一个从obj_lifeform_parent继承的怪物父对象,然后该怪物对象从怪物父物体继承就可以了,但这里只不打算额外增加了。
和角色创建movement和facing类似,这里也要在obj_enemy_chin的create事件里创建。首先新建一个宏变量IDLE
然后使用方向,状态变量,和二维数组来更新精灵子图片
由于额外增加了IDLE的状态,所以在scr_enemy_stall_state和scr_enemy_idle_state脚本需要为状态movement赋值
因为在移动时,我们只导入right方向上的精灵图片,这里利用sign函数,根据实例移动方向,对对象的精灵进行水平翻转,并且更新了movement为MOVE
修改函数scr_get_face脚本,添加一个参数作为脚本参数
但是因为在obj_player也使用了scr_get_face()脚本,这里改为传参的函数,那么其他地方也要跟着改变,怎么批量更改呢,这里可以按快捷按钮 Ctrl + Shift + F.会呼出一个弹窗,在弹窗搜索栏,直接输入scr_get_input搜索,会得到搜索结果
然后在obj_enemy_chinlin的step事件中也添加更新精灵索引代码
把obj_enemy_chinlin对象拖入房间,运行游戏即可看到效果