ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

GameMaker角色开发:从概念设计到状态机实现的完整流程

GameMaker角色开发:从概念设计到状态机实现的完整流程 在实际游戏开发或角色建模项目中我们常常会遇到一个需求如何将一个来自特定文化背景或作品的角色例如“布洛妮娅”与一个风格迥异的经典IP设定如“少年泰坦”Teen Titans的团队风格进行有机融合并最终在游戏引擎如Gm可能指GameMaker Studio中实现为一个可交互的游戏角色。这不仅仅是简单的贴图替换它涉及到角色设定的重构、视觉风格的统一、技能体系的设计以及在特定引擎下的技术实现。本文将围绕“布洛妮娅”角色进行“少年泰坦”风格的二次创作并探讨在GameMaker Studio中将其实现为可控角色的完整流程。本文适合对2D游戏开发、角色设计、像素艺术或同人创作感兴趣的开发者。无论你是想学习如何在GameMaker中构建一个复杂的角色状态机还是想了解如何将不同源的角色设定进行合理融合都能从中获得从概念设计到代码落地的具体指导。我们将从角色设定分析开始逐步完成精灵Sprite制作、动画状态机State Machine搭建、物理与碰撞处理最终实现一个包含移动、跳跃、攻击等基本能力的可玩角色。1. 理解角色融合从“布洛妮娅”到“少年泰坦”风格在进行技术实现前我们必须先完成概念设计。这一步决定了后续所有美术资源和逻辑代码的方向。1.1 源角色“布洛妮娅”的核心特征分析“布洛妮娅”通常指代《崩坏3》或《崩坏星穹铁道》中的布洛妮娅·扎伊切克。其核心特征并非我们直接复制的对象而是我们进行风格化创作的灵感来源。我们需要提炼其标志性元素视觉符号银灰色螺旋卷双马尾、蓝色瞳孔、常穿着带有机械或军装元素的服饰。能力倾向通常与“重装小兔”这个大型机器人助手关联擅长远程火力支援、部署力场或进行战术指挥属于“策士”或“炮手”定位。性格气质冷静、理性、具有领导力后期角色往往带有守护与牺牲的精神。我们的目标不是复制而是提取这些“基因”并将其植入新的土壤——“少年泰坦”的世界观。1.2 “少年泰坦”风格的关键要素“少年泰坦”Teen Titans风格尤其是其经典动画版具有鲜明的特征美式卡通化造型概括性强线条简洁有力色彩对比鲜明动作夸张富有表现力。团队定位清晰每个成员能力独特且互补如领袖罗宾、力量野兽小子、魔法渡鸦、科技钢骨、敏捷星火。叙事基调在应对危机和日常搞笑间平衡角色性格鲜明且有成长弧光。融合的关键在于将布洛妮娅的“策士/炮手”定位用少年泰坦的视觉语言和叙事逻辑重新演绎。例如她的“重装小兔”可以转化为一个更具卡通感、造型更简洁的浮游炮或机甲伙伴她的军装可以改为更街头、更便于活动的泰坦制服风格并保留其标志性的蓝灰色调和双马尾发型。1.3 确立游戏内的角色能力框架在GameMaker中实现前我们需要将融合后的设定转化为具体的游戏机制。一个基础的可操作角色通常需要以下能力模块能力模块描述与融合设定的关联移动左右行走、奔跑、跳跃、二段跳、蹬墙跳等。体现角色敏捷性即使是策士型角色在泰坦团队中也需具备基础机动能力。普攻近战连击或远程基础射击。可将“重装小兔”的辅助射击设计为普攻例如发射小型能量弹。技能消耗资源如能量、冷却的强力招式。对应源角色的招牌技能如“引力奇点”可改为发射一个吸引敌人的能量场“火炮轰击”可改为召唤浮游炮齐射。状态idle待机、run奔跑、jump跳跃、attack攻击、hurt受伤等。每个状态都应有符合“美式卡通”风格的夸张动画如待机时的小动作跳跃时的预备姿势。属性生命值HP、能量值MP、攻击力、防御力等。数值设计需平衡确保她在团队中定位清晰例如高攻击、中等生命、技能消耗大。2. 开发环境准备与项目初始化在开始制作前需要准备好工具并搭建项目结构。2.1 工具与软件准备GameMaker Studio 2本文以GMS2为例版本建议使用较新的稳定版如2023.X。确保已安装并拥有可用许可证。像素绘图软件用于绘制角色精灵和动画。推荐Aseprite专业像素动画软件对帧动画支持极佳。GraphicsGale轻量级老牌像素工具。Photoshop或Clip Studio Paint配合像素画笔也能完成但不如前者专注。声音效果工具可选用于制作技能音效、跳跃音效等。可使用BFXR、ChipTone等在线或免费工具生成。思维导图或文档工具用于规划角色状态机、技能列表避免开发时逻辑混乱。2.2 在GameMaker中创建新项目打开GMS2点击“New Project”。选择“空白项目”模板命名为Bronya_TeenTitans。选择目标平台如Windows、Mac、HTML5这将影响部分导出设置。创建成功后首先配置项目的基本设置进入File - Preferences - General Settings。建议将“Default Script Editor”设为你习惯的代码编辑器如VS Code便于管理复杂脚本。进入Game Options为当前平台如Windows设置初始窗口大小例如 960x540并决定是否允许全屏和调整窗口大小。2.3 规划资源目录结构清晰的项目结构是维护的基础。在GMS2的“Resource Tree”中创建以下资源组右键点击资源树空白处 - Create GroupSprites_Bronya: 存放角色所有精灵动画idle, run, jump, attack等。Objects_Bronya: 存放角色对象、其发射的子弹对象、技能特效对象等。Scripts: 存放所有通用脚本如状态机脚本、工具函数、常量定义。Rooms: 存放游戏关卡测试房间。Sounds: 存放音效。Fonts: 存放字体。Backgrounds: 存放背景图。3. 制作角色精灵与动画视觉表现是融合设计的第一道关卡。我们将遵循“少年泰坦”的卡通风格来绘制像素精灵。3.1 确定像素风格与尺寸风格采用有限的色板如16色或32色线条清晰色彩明快。避免过度细节强调剪影的识别度。尺寸角色精灵大小需要与游戏世界比例匹配。一个常见的比例是角色高度占32x32像素到64x64像素。我们设定布洛妮娅的精灵大小为48x48像素这能保证足够的细节空间又不会让动画工作量过大。朝向通常只需绘制面向右侧的动画GameMaker可以通过镜像image_xscale -1来获得向左的动画。3.2 绘制核心动画帧在Aseprite或其他软件中为以下每个状态绘制动画序列spr_bronya_idle(待机)4-6帧。可以设计为呼吸起伏、头发轻微飘动、眼神偶尔眨动。这是表现角色个性的好机会。spr_bronya_run(奔跑)6-8帧。体现卡通感的夸张跑步姿势手臂摆动幅度大头发和衣摆有强烈的跟随运动。spr_bronya_jump(跳跃)4-5帧。包括下蹲预备、起跳上升、空中姿态、下落、落地缓冲。起跳和落地帧要夸张。spr_bronya_attack(攻击)根据普攻方式设计。如果是远程射击可以设计为3-4帧举枪/召唤武器、发射、后坐力、收回。注意发射帧要与生成子弹对象的代码帧同步。spr_bronya_hurt(受伤)2-3帧。角色后仰、闪烁在GM中可通过image_alpha控制有时伴随表情变化。spr_bronya_skill(技能)为每个独立技能制作专属动画帧数可以更多8-12帧表现力更强。绘制要点保持所有动画的中心点Origin一致通常设在脚底或角色中心。在GameMaker精灵编辑器中可以调整。导出为Strip条带PNG序列图或直接在Aseprite中导出为.gif然后在GM中导入为精灵序列。3.3 在GameMaker中导入并配置精灵在Sprites_Bronya组下右键创建新精灵。命名为spr_bronya_idle点击“Edit Image”导入你绘制好的序列图。GM会自动将其分割为帧。在精灵属性中设置“Origin”。对于平台游戏角色通常设为“Bottom Centre”这样碰撞和移动更易处理。调整“Collision Mask”。对于精确像素碰撞可以选择“Precise (Slow)”对于性能优先可以选择“Rectangle”或“Ellipse”。初期测试可用“Rectangle”。重复以上步骤导入所有状态精灵。4. 构建角色对象与基础状态机这是游戏逻辑的核心。我们将创建一个代表布洛妮娅的对象并为其编写一个有限状态机FSM来控制所有行为。4.1 创建角色对象与变量定义在Objects_Bronya组下创建新对象命名为obj_bronya_player。为其分配一个初始精灵如spr_bronya_idle。在对象的“Create Event”中初始化所有关键变量。这些变量将驱动状态机和角色能力。// obj_bronya_player - Create Event // 物理与移动变量 hspd 0; // 水平速度 vspd 0; // 垂直速度 grv 0.5; // 重力加速度 walksp 4; // 行走速度 runsp 8; // 奔跑速度 jumpsp -12; // 跳跃初速度向上为负 jumps_left 2; // 允许的连跳次数1为单跳2为二段跳 jumps_max 2; // 状态机变量 state “idle”; // 当前状态 state_timer 0; // 状态计时器 // 角色属性 hp 100; hp_max 100; mp 50; mp_max 50; attack_power 10; // 输入与地面检测 grounded false; // 是否在地面 face_dir 1; // 面向方向1右 -1左 // 攻击相关 can_attack true; attack_cooldown 0.3; // 普攻冷却时间 attack_timer 0;4.2 实现基础状态机框架状态机的核心思想是在每一步Step Event中根据state变量的值执行对应状态的逻辑并处理状态之间的转换。我们将逻辑分散到不同的脚本中以便管理。首先创建一个控制状态机的脚本文件scr_player_state_machine。// scr_player_state_machine switch (state) { case “idle”: scr_state_idle(); break; case “run”: scr_state_run(); break; case “jump”: scr_state_jump(); break; case “attack”: scr_state_attack(); break; case “hurt”: scr_state_hurt(); break; // ... 可以添加更多状态如 “skill1”, “skill2” }然后在obj_bronya_player的Step Event中调用这个状态机并处理一些每帧都要更新的通用逻辑如重力、输入检测和冷却。// obj_bronya_player - Step Event // 1. 处理通用物理重力 if (!grounded) { vspd grv; // 限制最大下落速度 vspd min(vspd, 15); } // 2. 地面检测这是一个简化版实际需用place_meeting检查脚下 // 假设有一个检测地面的逻辑将 grounded 设为 true/false scr_check_ground(); // 3. 处理冷却 if (attack_timer 0) attack_timer - 1 / room_speed; // room_speed 是每秒帧数 if (attack_timer 0) can_attack true; // 4. 执行当前状态逻辑 scr_player_state_machine(); // 5. 应用速度并处理水平碰撞简化示例 x hspd; if (place_meeting(x, y, obj_wall)) { // obj_wall 是墙对象 // 简单地将角色推离墙体 while (!place_meeting(xsign(hspd), y, obj_wall)) { x sign(hspd); } hspd 0; } // 6. 应用垂直速度并处理垂直碰撞 y vspd; if (place_meeting(x, y, obj_wall)) { while (!place_meeting(x, ysign(vspd), obj_wall)) { y sign(vspd); } vspd 0; if (sign(vspd) 0) grounded true; // 向下碰撞时落地 }4.3 实现具体状态逻辑现在我们需要为每个状态编写具体的脚本。以idle、run、jump为例。脚本scr_state_idle// scr_state_idle // 目标处理待机状态下的输入检测和状态转换 // 设置对应动画 sprite_index spr_bronya_idle; image_speed 0.2; // 动画播放速度 // 重置水平速度 hspd 0; // 状态转换检查 var _keyLeft keyboard_check(vk_left) or keyboard_check(ord(“A”)); var _keyRight keyboard_check(vk_right) or keyboard_check(ord(“D”)); if (_keyLeft or _keyRight) { state “run”; // 按下左右键切换到奔跑 break; // 跳出当前状态逻辑 } if (keyboard_check_pressed(vk_space) and (grounded or jumps_left 0)) { state “jump”; // 按下空格切换到跳跃 break; } if (keyboard_check_pressed(vk_control) and can_attack) { state “attack”; // 按下Ctrl切换到攻击 break; }脚本scr_state_run// scr_state_run // 目标处理移动并检测方向、跳跃和攻击 sprite_index spr_bronya_run; image_speed 0.3; var _keyLeft keyboard_check(vk_left) or keyboard_check(ord(“A”)); var _keyRight keyboard_check(vk_right) or keyboard_check(ord(“D”)); var _moveDir _keyRight - _keyLeft; // 右为1左为-1不动为0 if (_moveDir ! 0) { face_dir _moveDir; // 更新面向 image_xscale face_dir; // 镜像精灵 hspd _moveDir * walksp; // 应用速度 } else { // 没有水平输入回到待机 state “idle”; break; } // 跳跃和攻击检测同idle状态 if (keyboard_check_pressed(vk_space) and (grounded or jumps_left 0)) { state “jump”; break; } if (keyboard_check_pressed(vk_control) and can_attack) { state “attack”; break; }脚本scr_state_jump// scr_state_jump // 目标处理跳跃物理和状态转换 sprite_index spr_bronya_jump; // 进入跳跃状态的瞬间 if (state_timer 0) { audio_play_sound(snd_jump, 1, false); // 播放跳跃音效 if (grounded) { jumps_left jumps_max - 1; // 地面起跳消耗一次 vspd jumpsp; } else { // 空中跳跃二段跳 jumps_left--; vspd jumpsp * 0.9; // 二段跳可以稍弱 } grounded false; } state_timer; // 跳跃上升阶段允许水平控制 var _keyLeft keyboard_check(vk_left) or keyboard_check(ord(“A”)); var _keyRight keyboard_check(vk_right) or keyboard_check(ord(“D”)); var _moveDir _keyRight - _keyLeft; if (_moveDir ! 0) { face_dir _moveDir; image_xscale face_dir; hspd _moveDir * walksp * 0.8; // 空中移动速度稍慢 } else { hspd 0; } // 状态转换落地回到idle或在空中时按下攻击键 if (grounded) { state “idle”; state_timer 0; break; } if (keyboard_check_pressed(vk_control) and can_attack) { state “attack”; state_timer 0; break; }脚本scr_state_attack// scr_state_attack // 目标播放攻击动画生成攻击效果并强制完成动画 sprite_index spr_bronya_attack; image_speed 0.4; // 攻击动画可以快一些 image_index 0; // 确保从第一帧开始 // 进入攻击状态时锁定输入并开始冷却 if (state_timer 0) { can_attack false; attack_timer attack_cooldown; hspd 0; // 攻击时通常停止水平移动 // 在动画特定帧如第2帧生成子弹/攻击判定 // 这个检查可以放在Step Event中根据 image_index 触发 } state_timer; // 判断攻击动画是否播放完毕 if (image_index sprite_get_number(sprite_index) - 1) { // 动画播放完毕回到之前的状态 if (grounded) { state “idle”; } else { state “jump”; } state_timer 0; break; } // 在攻击动画期间可以检测是否按下了方向键为下次移动做准备 // 但通常不立即切换状态以保证攻击动画的完整性4.4 创建攻击效果子弹对象攻击需要产生实际效果。我们创建一个简单的子弹对象。创建一个精灵spr_bullet绘制一个简单的能量弹图形。创建对象obj_bullet分配该精灵。在obj_bullet的 Create Event 中初始化// obj_bullet - Create Event speed 15; // 子弹速度 direction other.face_dir * 90; // 假设“other”是发射者face_dir1朝右(90度)-1朝左(-90度) image_angle direction; // 让子弹图片旋转对准方向 damage obj_bronya_player.attack_power; // 从玩家对象获取攻击力 life room_width / speed * 1.5; // 根据房间宽度计算存活时间避免飞出屏幕不消失在obj_bullet的 Step Event 中// 移动 x lengthdir_x(speed, direction); y lengthdir_y(speed, direction); // 生命周期递减 life--; if (life 0) { instance_destroy(); } // 碰撞检测示例碰到墙或敌人消失 if (place_meeting(x, y, obj_wall)) { instance_destroy(); } var _enemy instance_place(x, y, obj_enemy); if (_enemy ! noone) { // 对敌人造成伤害 _enemy.hp - damage; // 可以在这里创建击中特效 instance_destroy(); }回到obj_bronya_player修改scr_state_attack或在Step Event中添加逻辑在攻击动画的特定帧生成子弹// 在 obj_bronya_player 的 Step Event 中状态机执行后添加 if (state “attack”) { // 例如在攻击动画的第2帧索引为1生成子弹 if (floor(image_index) 1 !has_fired) { // has_fired 是一个防止重复触发的临时变量 has_fired true; var _bullet instance_create_layer(x 20 * face_dir, y - 10, “Instances”, obj_bullet); with (_bullet) { // 子弹的Create Event中已从other.face_dir获取方向这里可以覆盖或调整 } } // 动画结束时重置发射标志 if (image_index sprite_get_number(sprite_index) - 1) { has_fired false; } }5. 整合测试与运行验证完成核心代码后需要在游戏中测试角色行为。5.1 创建测试房间在Rooms组下创建新房间room_test。在房间编辑器中创建几个图层例如Background背景、Platforms平台、Instances实例。在Platforms层使用Tile图块或放置obj_wall对象搭建一个简单平台场景包括地面、几个台阶和一个深渊。在Instances层放置一个obj_bronya_player实例。在房间属性中设置一个合适的背景色并确保room_speed游戏帧率设置为60。5.2 运行与调试点击GMS2工具栏上的“Run”按钮绿色三角形编译并运行游戏。使用 A/D 或左右方向键测试左右移动观察idle和run动画的切换是否流畅角色是否按预期移动和转向。按下空格键测试跳跃。检查单跳、二段跳是否生效跳跃高度和手感是否合适可通过调整jumpsp和grv微调。按下 Ctrl 键测试攻击。观察攻击动画是否播放子弹是否从正确位置角色前方生成并沿正确方向飞行是否能被墙壁阻挡。让角色走到平台边缘掉落测试重力系统和落地检测grounded变量是否正常工作。尝试在跳跃中攻击在攻击后移动检查状态转换是否有冲突或卡顿。5.3 常见问题与排查在测试中你可能会遇到以下典型问题问题现象可能原因检查与解决思路角色无法移动或移动方向相反1. 输入检测代码键位错误。2.hspd计算逻辑有误正负号。3. 碰撞体Mask设置过大与墙壁卡住。1. 在Step Event中用show_debug_message打印_keyLeft,_keyRight,_moveDir的值。2. 检查image_xscale是否随face_dir正确改变。3. 在房间编辑器中查看角色的碰撞遮罩确保其大小合理。跳跃手感“飘”或“沉”1.jumpsp初速度和grv重力数值不匹配。2. 空中移动速度 (walksp * 0.8) 不合适。1. 调整jumpsp绝对值越大跳越高和grv越大下落越快。一个经典组合是jumpsp -12,grv 0.5。2. 微调空中移动系数。攻击动画被打断或子弹发射多次1. 状态转换条件过于宽松在攻击中接收到了移动输入并切换了状态。2. 子弹生成逻辑没有防重复触发机制。1. 在scr_state_attack中在动画播放完之前限制状态转换除了强制结束的情况。2. 使用has_fired这样的布尔变量确保一帧内只生成一次子弹并在动画结束时重置。角色穿墙或卡进墙里1. 碰撞检测代码顺序或逻辑错误。2. 速度 (hspd,vspd) 过大单帧移动距离超过了碰撞体宽度。1. 使用place_meeting进行预判碰撞并使用while循环微量调整位置直到接触这是平台游戏的标准做法。2. 如果速度可能很大考虑使用collision_line或分步移动。二段跳在空中可以无限跳jumps_left变量没有在落地时正确重置。确保在检测到角色落地grounded true时重置jumps_left jumps_max。6. 扩展方向与生产环境考量一个基础可操作角色完成后可以考虑向更完整、更健壮的生产级项目发展。6.1 功能扩展更多技能为布洛妮娅设计2-3个符合其“少年泰坦”化设定的技能如范围轰炸、护盾力场。每个技能都是一个独立的状态state “skill_q”拥有自己的动画、冷却时间、资源消耗和效果生成逻辑。动画混合当前状态机是“硬切换”动作衔接可能生硬。可以引入动画混合技术例如在奔跑停止时播放一个“刹车”动画跳跃落地时播放“翻滚”或“蹲下”动画作为过渡。粒子与特效为跳跃尘土、攻击轨迹、技能释放、受击等添加粒子效果大幅提升视觉表现力。GameMaker内置了粒子系统。音效与音乐为每个动作添加合适的音效并配置背景音乐。UI与状态显示在屏幕角落添加血条HP、能量条MP和技能图标冷却指示器。6.2 代码结构优化脚本模块化将输入处理、物理模拟、伤害计算、动画事件回调等进一步拆分成独立脚本使主状态机脚本更清晰。使用父对象与继承如果你计划制作多个可玩角色或敌人可以将共通的功能如基础移动、生命值管理放在一个父对象中让obj_bronya_player和其他角色对象继承它并重写特定部分。数据驱动将角色的移动速度、跳跃力、生命值、技能参数等提取到外部数据结构如DS Map、JSON文件或INI文件中。这样平衡调整时无需修改代码也便于制作角色选择界面。状态机框架对于极其复杂的角色可以考虑使用更正式的状态机模式甚至使用第三方状态机库或自己编写一个基于枚举和函数指针的状态机管理器。6.3 生产环境注意事项性能大量粒子、复杂碰撞检测尤其是Precise模式和每帧运行的复杂脚本可能影响性能。需进行性能剖析优化循环和冗余计算。输入处理当前使用键盘直接检测对于支持手柄或移动端触摸的项目需要抽象一层输入管理器。网络同步如果目标是制作多人游戏所有状态位置、速度、动画帧都需要通过网络同步并处理预测和补偿这是另一个维度的复杂性。资源管理所有精灵、音效都应通过GameMaker的“资源树”正确引用。对于大量资源考虑使用纹理页Texture Pages和音频组Audio Groups进行优化管理。错误处理与日志在关键逻辑点添加show_debug_message或写入日志文件便于上线后排查问题。通过以上步骤我们完成了从“布洛妮娅”角色概念出发融合“少年泰坦”视觉风格并在GameMaker Studio中实现为一个具备移动、跳跃、攻击等基本能力的可操作游戏角色的全过程。这个角色可以作为你平台游戏或动作游戏项目的起点后续的深度和广度取决于你想要构建的世界。记住迭代和测试是关键不断调整手感、平衡数值、丰富表现才能让这个融合创作的角色真正活起来。
返回列表