今天要和大家分享的是基于Unity3D开发2D游戏,博主一直钟爱于国产武侠RPG,这个我在开始写Unity3D游戏开发系列文章的时候就已经说过了,所以我们今天要做的就是利用Unity3D来实现在2D游戏中人物的走动控制。下面就请大家跟随我的一起来见证Unity3D强大的魅力吧。首先我们创建一个项目,创建新场景,我们首先创建一个Plane并将其命名为MainMap,然后我们在项目中添加一个Resources文件夹,将事先准备好的地图文件Map0复制到这个目录下,然后我们将这个图片拖拽到MainMap上,我们将MainMap的旋转参数Rotatiion设置为90,180,0,使其与摄像机垂直,然后将摄像机的Projection投影属性设置为 orthographic正交模式,这时我们就能够在屏幕中看到经典的余杭镇场景了。如果我们需要对场景进行进一步的优化的话,可以通过调整摄像机的投影面积大小和距离来实现。参数设置可以参考这里:
接下来,我们再次创建一个Plane将其命名为Player,这就是我们今天要出场的角色李逍遥啦,和准备地图类似,我们将李逍遥的贴图直接拖拽到Player上。刚开始角色会比较大,和画面不协调,我们可以通过调整Scale参数来缩放我们的角色,调整到合适的范围。这里我们直接使用了一张完整的地图,在实际的游戏开发中,一个场景地图可能是由很多瓦片构成的,所谓瓦片,就是指被分割成若干个可以拼接起来的图片。我们知道,仙剑奇侠传作为一款经典的单机游戏,除了剧情以外,就是那些经典、动听的音乐啦,在Unity3D中实现音乐播放是很简单的事情,我们选定MainMap,为主场景添加一个AudioSource组件,并将背景音乐拖拽到AudioSource的AudioClip属性框中,选中Loop使其循环,接下来我们点击运行,运行效果如下图:
接下类,就是今天的重头戏啦,我们今天的主要任务是通过Unity3D的2D帧动画绘制来实现人物的动画和控制,所以接下来我们在项目目录下增加一个Script文件下,新建一个叫做Person的脚本,该脚本封装了我们对人物角色的控制和帧动画的绘制方法。首先我们来准备一组素材:
从名称的命名上,我们就可以看出这是角色在上下左右四个方向上的连续动画图片。下面,我们在Resources目录下创建下面的目录结构,并将上面的图片分别放在对应的文件夹下,我们在脚本中会引用下面的资源:
下面开始编写脚本:
using UnityEngine; using System.Collections; public class Person : MonoBehaviour { //定义角色对象 private GameObject mHero; //定义人物向上动画数组 private Object[] UpAnim; //定义人物向下动画数组 private Object[] DownAnim; //定义人物向左动画数组 private Object[] LeftAnim; //定义人物向右动画数组 private Object[] RightAnim; //当前帧索引 private int mFrameIndex; //当前时间 private float mTotalTime; //定义每秒帧数为10 private float mFPS=10; //定义当前人物动画 private Object[] NowAnim; private Object[] LastAnim; //定义角色行动速度 private float mSpeed=5; //角色当前状态 private PersonState mState=PersonState.Stand; //定义角色状态枚举 private enum PersonState { Stand, Walk } void OnGUI() { GUI.Label(new Rect(10,10,180,40),"李逍遥位置:"+mHero.transform.position.ToString()); } void Start () { //获取人物 mHero=GameObject.Find("Player"); //获取动画数组 UpAnim=Resources.LoadAll("UpAnim"); DownAnim=Resources.LoadAll("DownAnim"); LeftAnim=Resources.LoadAll("LeftAnim"); RightAnim=Resources.LoadAll("RightAnim"); //定义默认动画 NowAnim=UpAnim; LastAnim=NowAnim; } void FixedUpdate() { //向左 if(Input.GetKey(KeyCode.A)) { SetAnimation(LeftAnim); this.mState=PersonState.Walk; mHero.transform.Translate(Vector3.right*Time.deltaTime*mSpeed); } //向右 if(Input.GetKey(KeyCode.D)) { SetAnimation(RightAnim); this.mState=PersonState.Walk; mHero.transform.Translate(Vector3.right*Time.deltaTime*(-mSpeed)); } //向上 if(Input.GetKey(KeyCode.W)) { SetAnimation(UpAnim); this.mState=PersonState.Walk; mHero.transform.Translate(Vector3.forward*Time.deltaTime*(-mSpeed)); } //向下 if(Input.GetKey(KeyCode.S)) { SetAnimation(DownAnim); this.mState=PersonState.Walk; mHero.transform.Translate(Vector3.forward*Time.deltaTime*mSpeed); Vector3 mHeroPos=mHero.transform.position; } DrawTexture(NowAnim); } void Update () { //松开键位时 if(Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D) || Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.W)) { this.mState=PersonState.Stand; } } void DrawTexture(Object[] mAnim) { //如果角色当前状态为站立,则显示帧动画中的第一帧 if(mState==PersonState.Stand) { mHero.renderer.material.mainTexture=(Texture)mAnim[0]; } //否则绘制帧动画 else { mTotalTime+=Time.deltaTime; if(mTotalTime>=1.0/mFPS) { mFrameIndex++; mTotalTime=0; if(mFrameIndex>=mAnim.Length) { mFrameIndex=0; } } mHero.renderer.material.mainTexture=(Texture)mAnim[mFrameIndex]; } } void SetAnimation(Object[] mAnim) { NowAnim=mAnim; if(!LastAnim.Equals(NowAnim)) { this.mFrameIndex=0; LastAnim=NowAnim; } } }
在上面的这部分脚本中,我们在Start()方法中加载了我们预先设定好的资源,然后在FixedUpdate()方法判断用户行为,并根据用户按下的键来确定要绘制的帧动画,我们假定每秒的帧数为10,则每帧显示的时间为0.1秒,如果从上一次刷新到现在的时间超过或者等于这个时间,则表示我们需要更新帧画面了。而当帧画面的索引和该帧动画数组内元素个数相等的时候,则意味着开始循环绘制这组帧动画。我们在上面定义了一个人物状态的枚举类型,这里只是简单的定义了两种类型,即Stand和Walk类型,当用户按下控制键时此类型的值为Walk,当用户松开控制键时此类型的值为Stand,和上一篇文章不同,这里调用的是 FixedUpdate()方法,而不是Update()方法,原因是Update()f方法更新的时间我们无法控制,而FixedUpdate()方法的时间则可以通过Edit->Project Setting->time->Fixed Timestep来指定,具体的大家可以自己阅读代码,这里就不多说了,剩下的事情就是把脚本绑定到Player上,我们运行一下:
就目前这个解决方案而言,存在以下几个问题:
1、人物范围控制,换句话说就是如何保证人物不会从这些房屋、篱笆上直接穿过去
2、人物向下移动时,会钻到地底下
3、摄像机如何跟随人物实现平移
4、小地图的实现
5、场景地图范围控制
针对以上问题,伴随着博主学习Unity3D的深入,我们将在后面的文章中一一为大家解决,请大家关注我的博客,谢谢!