一款类似“恐龙快打”的 横版街机格斗游戏 该如何制作?| 一起来学习 顺便送源码码文不易,建议收藏学习
Posted 呆呆敲代码的小Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一款类似“恐龙快打”的 横版街机格斗游戏 该如何制作?| 一起来学习 顺便送源码码文不易,建议收藏学习相关的知识,希望对你有一定的参考价值。
- 📢博客主页:https://blog.csdn.net/zhangay1998
- 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
- 📢本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
- 📢未来很长,值得我们全力奔赴更美好的生活✨
目录
📢引言
- ❄️轻拾月光,听风声缱绻,如刹时花开。
- 🌻浩浩九州,一文一墨皆是骄阳~
- ☔️最近在上海天天下雨,风还很大!但还是要每天兢兢业业的当一个打工仔呀!
- 🔓周末窝在家正在想着接下来要发一篇什么文章呢,突然来了一条消息
- 🔔叮咚~ 原来是 憨憨的小云儿 发来的消息~
- 小云儿👩:小Y哥哥,是不是最近天气不咋好,你也没心情制作游戏了呀😳!
- 小Y(博主):咦~ 是不是你又想玩我制作的游戏了呀!才故意这么说的🙃
- 小云儿👩:(偷笑)…哈哈哈嗝~ 小YY你变聪明了啊,不像是以前呆头呆脑的小Y哥哥了😏!
- 小Y:Emma…我啥时候不聪明了!说吧,你最近又想学哪种类型的游戏了,说出来我听听🤪!
- 小云儿👩:嘿嘿~小Y哥哥,我最近又对恐龙快打那样的横版格斗游戏玩法非常感兴趣,你能不能😛…
- 小Y:恐龙快打呀~ 我之前也很喜欢玩!可是要从头做一款这个游戏确实有点麻烦唉🙄~
- 小云儿👩:哎呀,小Y哥哥 你最棒啦~ 一定难不住你的对吗🧐!
- 小Y:那好伐,那我想想办法给你整一个出来,我这就开始动手做👊!
- 小云儿👩:好咧小Y哥哥,那我就慢慢期待了!老规矩!可以动手做,不阔以动脚做哦🍓!
🎬横版格斗游戏
- 今天给大家带来一款横版格斗游戏,跟小时候玩过的恐龙快打一个类型😀!
- 由于最近时间并不是很充裕,所以就在网上寻找一些可以用的素材😂
- 突然发现了一款插件,这款插件居然完美符合我要做的一个横版格斗游戏所需的工具😜
- 插件和本文涉及到的资源在文章最后都会提供源码工程的🤪!
简单游戏效果:
💫游戏制作思路
既然要做一款横版格斗游戏,那还是老规矩,先来整一下游戏思路😘!
我们先来想一下一个基本的横版格斗游戏都需要那些操作呢😊~
- 首先有一个游戏场景那是必然的,还要有一个人物,是我们玩家可以操控的,下面称他为“主角”!
- 然后这个场景需要根据玩家的位置,来进行摄像机的调整已达到一个视角的操控!
- 接下来就是要有敌人,因为对打才是这种游戏玩法的核心所在!
- 还有攻击方式,包括拳打脚踢和跳跃等
- 敌人同样可以进行这些操作!
- 还要有一个血条,在边缘显示我们的血量和当前打的敌人的血条!
- 场景中还需要存在一些可交互的游戏物体
- 比如可以打碎的箱子,可以吃的游戏物品
- 还可以加一些可以拿起来的武器,比如刀枪棍棒等等!
- 当然这些都是一个基本的游戏框架做出来的后话了!
- 这样一说,感觉这个游戏做起来好像不难的样子哈,那我们就来的尝试一下吧
- 如果遇到问题了,在进行补充说明!
🎉开始制作
首先打开Unity新建一个项目,博主开发这个使用的Unity2017.4.40
如果有小伙伴下载本文中的游戏资源,酌情使用Unity版本哦~
每个细节都写出来肯定是不现实哒,由于制作过程是在是又臭又长
所以文章中只把关键性操作和配置介绍出来,一起加油~
🏳️🌈第一步:新建项目,导入资源包
- 前边说过了,我们现在从头制作一款游戏,如果模型之类的都要自己做那是不现实的
- 而且模型这一块也会有专门的美术相关人员负责
- 所以我们自己闲暇之余自己做游戏肯定要省去这一步
- 直接寻找自己适合的资源即可!
- 所以这里我们导入一个资源包
新建一个Unity项目,设置名字和对应路径
然后将资源啊包导入即可!资源包和工程在文章末尾都会提供!
简单看一下工程中的资源
模型资源
动画资源
图片素材
声音资源
差不多这些东西就够我们做一个Demo使用了!
🏳️🌈第二步:游戏场景搭建
- 那现在一些基本的模型和图片等素材有了,接下来就是需要一个游戏场景了👈!
- 那是不是要我们自己搭建一个呢😬~
- 正常的话是这样没错,但是我这么懒又没有时间,怎么会自己去费工夫搭建场景呢哈哈🤣!
- 所以我们这里直接拿一个现成的场景来搞一下😝
- 因为毕竟说到底搭建场景就是一个苦力活,对自身学习也没有太大的帮助😲~
一起来看一下这个场景吧!
🏳️🌈第三步:模型动画设置
- 场景已经有了,那现在就开始给模型配置动画吧
- 因为动画片段都是资源包中有了的,所以我们这里只需要创建动画控制器Animator Controller就好啦
- 看到这有的小伙伴就要说了,啥都有了,那你做的也太简单了吧!!!
- 害,这都是多亏了前辈们将框架结构搭建出来了。
- 我们能做的就是站在巨人的肩膀上,做一些微不足道的打工仔的搬砖活罢了,一切为了学习和生活!
废话不多说,先来右键创建一个Animator Controller,如下图
敌人动画设置
- 因为主角的动画控制器配置略微有些麻烦,因为主角可执行的动画确实太多了
- 所以我们这里先从敌人的动画控制器配置开始
- 创建完Animator Controller以后双击打开这个动画控制器
一开始是这样的,只有这三个动画状态
敌人的动画片段资源路径为:Enemy - > Animations文件夹下
我们先把待机状态Idle加进去当做默认状态,默认是黄色的,直接把动画片段拖到Animator窗口即可
然后将敌人的动画片段都拖上去,并简单的排个序!示例如下
-
当前还只是将动画片段拖上去了,并没有进行逻辑关系设置
-
那接下来先配置一下动画状态,只有先创建完动画状态
-
在接下来的动画过度逻辑中才能正确的操作下去!
-
来看一下设置的动画状态吧,下图所示
其中,GroundHit、Death、Idel、Walk、KnockDown_Up、KnockDown_Down、KnockDown_End等等都是Trigger类型
Blend和MovementSpeed都是Float类型的,isDead是Bool类型的 -
为什么要这样设置不用的类型呢,这里再简单说一下
-
因为攻击、死亡等状态都是需要执行的时候,执行一次就好,所以采用Trigger类型最合适!
-
那移动速度这种自然用Float控制比较好,还可以控制
-
最后还有一个isDead是否死亡肯定用Bool 值判断最好啦!简单的一个true和False表示是否死亡!
-
然后给每个动画片段添加上动画过度参数,还不知道怎样添加的可以再去仔细看看我这篇动画基础教程哦
给对应的动画过渡按照对应的动画状态添加上动画参数就好了!最终添加完的效果如下
主角动画设置
主角的动画片段相比较敌人的就会更多了一些,但是整体思路是一样的
先来看一下主角都有哪些动画片段
动画参数:
- 具体动画控制器配置如下,看起来很复杂,其实就是一个动画之间过渡的参数配置
- 这里就不挨个来说具体怎样配置的那些参数了,不知道咋配置的可以直接在源码工程里看一下就好啦!
- 想明白思路之后其实就是一个体力活!
🏳️🌈第四步:模型基本移动跳跃等以及相机跟随等设置
基本的模型动画配置完了,那接下来就是角色移动的相关问题了
这里的话就要开始写代码了,一起来顺着思路看一下吧!
- 这里的话我们采用两种移动方式
- 一种是使用键盘控制角色移动,另一种则是通过虚拟按键来进行移动
- 下面来看一下挂在主角身上的脚本PlayerMovement
- 该脚本主要是控制主角的移动跳跃等功能的逻辑编写
先来看一下代码
[Header("Settings")]
public float walkSpeed = 3f;
public float ZSpeed = 1.5f;
public float JumpForce = 8f;
public bool AllowDepthJumping;
public float AirAcceleration = 3f;
public float AirMaxSpeed = 3f;
public float rotationSpeed = 15f;
public float jumpRotationSpeed = 30f;
public float lookAheadDistance = .2f;
public float landRecoveryTime = .1f;
public float landTime = 0;
public LayerMask CollisionLayer;
这里提供了一些基本的设置信息,可以在unity面板上看到
private List<UNITSTATE> MovementStates = new List<UNITSTATE> {
UNITSTATE.IDLE,
UNITSTATE.WALK,
UNITSTATE.JUMPING,
UNITSTATE.JUMPKICK,
UNITSTATE.LAND,
};
然后定义了一个列表存储了动画的几种状态,其中这个UNITSTATE是在另一个脚本中定义的属性
UnitState脚本内容如下,该脚本主要是用来管控角色的动画状态
using UnityEngine;
public class UnitState : MonoBehaviour {
public UNITSTATE currentState = UNITSTATE.IDLE;
public void SetState(UNITSTATE state){
currentState = state;
}
}
public enum UNITSTATE {
IDLE,
WALK,
JUMPING,
LAND,
JUMPKICK,
PUNCH,
KICK,
ATTACK,
DEFEND,
HIT,
DEATH,
THROW,
PICKUPITEM,
KNOCKDOWN,
KNOCKDOWNGROUNDED,
GROUNDPUNCH,
GROUNDKICK,
GROUNDHIT,
STANDUP,
USEWEAPON,
};
- 然后还需要定义一个脚本用来控制Input输入
- 那就来创建一个新脚本InputManager
- 这里面是实际的Input输入方式控制
- 加入了键盘输入控制方式自定义
[Header("Keyboard keys")]
public KeyCode Left = KeyCode.LeftArrow;
public KeyCode Right = KeyCode.RightArrow;
public KeyCode Up = KeyCode.UpArrow;
public KeyCode Down = KeyCode.DownArrow;
public KeyCode PunchKey = KeyCode.Z;
public KeyCode KickKey = KeyCode.X;
public KeyCode DefendKey = KeyCode.C;
public KeyCode JumpKey = KeyCode.Space;
[Header("Joypad keys")]
public KeyCode JoypadPunch = KeyCode.JoystickButton2;
public KeyCode JoypadKick = KeyCode.JoystickButton3;
public KeyCode JoypadDefend = KeyCode.JoystickButton1;
public KeyCode JoypadJump = KeyCode.JoystickButton0;
具体代码如下:
//delegates
public delegate void InputEventHandler(Vector2 dir);
public static event InputEventHandler onInputEvent;
public delegate void CombatInputEventHandler(INPUTACTION action);
public static event CombatInputEventHandler onCombatInputEvent;
[Space(15)]
public UIManager _UIManager; //link to the UI manager
[HideInInspector]
public Vector2 dir;
private bool TouchScreenActive;
public static bool defendKeyDown;
void Start(){
_UIManager = GameObject.FindObjectOfType<UIManager>();
//automatically enable touch controls on ios or android
#if UNITY_IOS || UNITY_ANDROID
UseTouchScreenInput = true;
UseKeyboardInput = UseJoypadInput = false;
#endif
}
public static void InputEvent(Vector2 dir){
if( onInputEvent != null) onInputEvent(dir);
}
public static void CombatInputEvent(INPUTACTION action){
if(onCombatInputEvent != null) onCombatInputEvent(action);
}
public static void OnDefendButtonPress(bool state){
defendKeyDown = state;
}
void Update(){
//use keyboard
if (UseKeyboardInput) KeyboardControls();
//use joypad
if (UseJoypadInput) JoyPadControls();
//use touchScreen
EnableDisableTouchScrn(UseTouchScreenInput);
}
void KeyboardControls(){
//vector
float x = 0f;
float y = 0f;
if (Input.GetKey (Left)) x = -1f;
if (Input.GetKey (Right))x = 1f;
if (Input.GetKey (Up)) y = 1f;
if (Input.GetKey (Down)) y = -1f;
dir = new Vector2(x,y);
InputEvent(dir);
//Combat input
if(Input.GetKeyDown(PunchKey)){
CombatInputEvent(INPUTACTION.PUNCH);
}
if(Input.GetKeyDown(KickKey)){
CombatInputEvent(INPUTACTION.KICK);
}
if(Input.GetKeyDown(JumpKey)){
CombatInputEvent(INPUTACTION.JUMP);
}
defendKeyDown = Input.GetKey(DefendKey);
}
void JoyPadControls(){
float x = Input.GetAxis("Joypad Left-Right");
float y = Input.GetAxis("Joypad Up-Down");
dir = new Vector2(x,y);
InputEvent(dir.normalized);
if(Input.GetKeyDown(JoypadPunch)){
CombatInputEvent(INPUTACTION.PUNCH);
}
if(Input.GetKeyDown(JoypadKick)){
CombatInputEvent(INPUTACTION.KICK);
}
if(Input.GetKey(JoypadJump)){
CombatInputEvent(INPUTACTION.JUMP);
}
defendKeyDown = Input.GetKey(JoypadDefend);
}
//enables or disables the touch screen interface
public void EnableDisableTouchScrn(bool state){
InputEvent(dir.normalized);
if (_UIManager != null) {
if (state) {
//show touch screen
if(!TouchScreenActive) {
_UIManager.ShowMenu ("TouchScreenControls", false);
TouchScreenActive = true;
}
} else {
//hide touch screen
if (TouchScreenActive) {
TouchScreenActive = false;
_UIManager.CloseMenu ("TouchScreenControls");
}
}
}
}
//returns true if the defend key is held down
public bool isDefendKeyDown(){
return defendKeyDown;
}
}
public enum INPUTACTION {
NONE,
PUNCH,
KICK,
JUMP,
DEFEND,
WEAPONATTACK,
}
public enum INPUTTYPE {
KEYBOARD = 0,
JOYPAD = 5,
TOUCHSCREEN = 10,
}
- 这个脚本中不止自定义了几种键盘输入方式
- 而且包括具体的键盘输入的方法调用和虚拟键盘输入方法的调用
- 定义了几个枚举,说明了一下不同输入要执行的输出效果!
- 还可以自由选择键盘输入或者虚拟按钮输入!
[Header("使用键盘输入")]
public bool UseKeyboardInput;
[Header("使用手柄输入")]
public bool UseJoypadInput;
[Header("使用虚拟按键输入")]
public bool UseTouchScreenInput;
相机跟随
给相机写一个脚本,挂载到摄像机上即可!
通过控制摄像机的偏移量,让相机一直保持正面对着角色~
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public Transform target;
[Header ("Follow Settings")]
public float distanceToTarget = 5; // The distance to the target
public float heightOffset = 5; // the height offset of the camera relative to it's target
public float viewAngle = 10; //a downwards rotation
public Vector3 AdditionalOffset; //any additional offset
public bool FollowZAxis; //enable or disable the camera following the z axis
[Header ("Damp Settings")]
public float DampX = 3f;
public float DampY = 3f;
public float DampZ = 3f;
[Header ("View Area")]
public float MinLeft;
public float MaxRight;
[Header ("Wave Area collider")]
public bool UseWaveAreaCollider;
public BoxCollider CurrentAreaCollider;
public float AreaColliderViewOffset;
void Start(){
//set player as follow target
if (!target) SetPlayerAsTarget();
//set camera start position
if (target) {
Vector3 playerPos = target.transform.position;
transform.position = new Vector3(playerPos.x, playerPos.y - heightOffset, playerPos.z + (distanceToTarget));
}
}
void Update () {
if (target){
//initial values
float currentX = transform.position.x;
float currentY = transform.position.y;
float currentZ = transform.position.z;
Vector3 playerPos = target.transform.position;
//Damp X
currentX = Mathf.Lerp(currentX, playerPos.x, DampX * Time.deltaTime);
//DampY
currentY = Mathf.Lerp(currentY, playerPos.y - heightOffset, DampY * Time.deltaTime);
//DampZ
if (FollowZAxis) {
currentZ = Mathf.Lerp (currentZ, playerPos.z + distanceToTarget, DampZ * Time.deltaTime);
} else {
currentZ = distanceToTarget;
}
//Set cam position
if(CurrentAreaCollider == null) UseWaveAreaCollider = false;
if (!UseWaveAreaCollider) {
transform.position = new Vector3 (Mathf.Clamp (currentX, MaxRight, MinLeft), currentY, currentZ) + AdditionalOffset;
} else {
transform.position = new Vector3 (Mathf.Clamp (currentX, CurrentAreaCollider.transform.position.x + AreaColliderViewOffset, MinLeft), currentY, currentZ) + AdditionalOffset;
}
//Set cam rotation
transform.rotation = new Quaternion(0,180f,viewAngle,0);
}
}
void SetPlayerAsTarget(){
GameObject player =以上是关于一款类似“恐龙快打”的 横版街机格斗游戏 该如何制作?| 一起来学习 顺便送源码码文不易,建议收藏学习的主要内容,如果未能解决你的问题,请参考以下文章