如下图所示,我们盘点一下2D游戏中必备的几个元素。
摄像机:无论是3D游戏还是2D游戏摄像机都是非常重要的属性,移动摄像机即可更改屏幕中显示的内容,游戏地图的坐标永远都不会发生改变。
地图:2D游戏中的地图一般是由tile拼接而成,它可由地图编辑器生成然后将每一块tile绘制在整个贴图中,最后将贴图贴在平面网格面之上即可。还有一种作法是将两个或两个以上屏幕大小平面以队列的形式排在屏幕后面,当摄像机移动超出第一块面显示范围时,将它的坐标移动在第二块面后面,此时地图就形成了一个排序的队列。为了让地图的效果更加完美,一般地图可以由好几层来组成,比如背景层、与主角的遮挡曾、物理层等等。
地图拼接:地图的排序队列中两张图应当是可以无缝拼接,这个应当是由美术来提供资源,这里我就不那么细致了将远离说明白即可。
主角:它的范围就比较广的,敌人、物品等等出现在地图之上的都可以使用它。如果控制主角移动,摄像机移动的同时主角也当跟随移动,并且保持屏幕中的移动比例,除非摄像机无法移动,这时将直接移动主角在屏幕中的坐标。 说的有点绕了呵呵,大家仔细想想哈哈。。
然而上面的一切面是由Plane面来完成。
再Unity层次视图中选择摄像机对象,右侧监测面板视图中我们看看摄像机组件的一些属性,如下图所示。需要注意的就是Projection 投影类型。
首先我们应当修改摄像机的属性,默认摄像机投影的类型是Perspective,它保持摄像机以扩散的的形式照射着不利于2D平面的展示。这里我们应当选择Orthographic,这样摄像机将直直的照射在显示的区域。
Perspective类型
Orthographic
从侧面观察摄像机,通过这两张图我相信大家应当能看懂为什么2D游戏要用Orthographic了吧,摄像机的投影类型是可以在代码中动态的修改的。
1 |
//得到游戏中摄像机对象 |
2 |
Camera |
3 |
//设置摄像机投影类型OrthoGraphic |
4 |
camera.isOrthoGraphic true ;
|
5 |
//设置摄像机投影类型Perspective |
6 |
camera.isOrthoGraphic false ;
|
在代码中取得摄像机投影的区域大小,它也可以动态的修改,这样就可是实现摄像机拉近与拉远的效果。根据投影区域的大小配合着整个地图的宽高来写判断条件,避免移动摄像机时超过地图的范围。
1 |
Camera |
2 |
Debug.Log(camera.orthographicSize); |
接着我们使用代码来得到地图面的宽高,这段代码写的就比较精细,因为网格面是可以缩放的,首先得到网格面的宽与高,然后分别乘以缩放系数就可以得到真实面的宽与高,然而Unity中的坐标是以“米”为单位。下面代码中用到了中文,如果要想在编辑器中显示中文C#语言需要修改编码格式为UTF-16。JavaScript修改编码格式UTF-8或UTF-16即可。
01 |
using UnityEngine;
|
02 |
using System.Collections;
|
03 |
04 |
public class Test : MonoBehaviour
|
05 |
{ |
06 |
07 |
void Start ()
|
08 |
{
|
09 |
10 |
GameObject plane = GameObject.Find( "Plane0" );
|
11 |
//得到面默认宽度
|
12 |
float size_x = plane.GetComponent<MeshFilter>().mesh.bounds.size.x;
|
13 |
//得到面宽度的缩放比例
|
14 |
float scal_x = plane.transform.localScale.x;
|
15 |
//得到面默认高度
|
16 |
float size_z = plane.GetComponent<MeshFilter>().mesh.bounds.size.z;
|
17 |
//得到面高度缩放比例
|
18 |
float scal_z = plane.transform.localScale.z;
|
19 |
20 |
//原始宽度乘以缩放比例计算出真实宽度
|
21 |
float mapWidth = size_x * scal_x;
|
22 |
float mapHeight = size_z * scal_z;
|
23 |
24 |
Debug.Log( "得到面的位置:" +plane.transform.position);
|
25 |
Debug.Log( "得到面的宽度:" + mapWidth);
|
26 |
Debug.Log( "得到面的高度:" + mapHeight);
|
27 |
}
|
28 |
29 |
} |
有了摄像机照射的区域以及背景地图的宽高尺寸那么就可以在代码中编写逻辑判断条件啦。下面我们来使用简单的代码控制摄像机移动以及主角移动。
01 |
using UnityEngine;
|
02 |
using System.Collections;
|
03 |
04 |
public class Controller : MonoBehaviour
|
05 |
{ |
06 |
07 |
//动画数组
|
08 |
private Object[] anim;
|
09 |
//主角对象
|
10 |
private GameObject hero;
|
11 |
//限制一秒多少帧
|
12 |
private float fps = 10;
|
13 |
//帧序列
|
14 |
private int nowFram;
|
15 |
//记录当前时间
|
16 |
private float time;
|
17 |
18 |
void Start ()
|
19 |
{
|
20 |
//得到资源名称为down文件夹中的所有对象资源
|
21 |
anim = Resources.LoadAll( "down" );
|
22 |
//得到主角的对象
|
23 |
hero = GameObject.Find( "hero" );
|
24 |
}
|
25 |
26 |
void FixedUpdate ()
|
27 |
{
|
28 |
//上、下、左、右平移摄像机
|
29 |
if (Input.GetKey (KeyCode.A))
|
30 |
{
|
31 |
transform.Translate(-0.01f,0,0);
|
32 |
33 |
}
|
34 |
35 |
if (Input.GetKey (KeyCode.D))
|
36 |
{
|
37 |
transform.Translate(0.01f,0,0);
|
38 |
}
|
39 |
40 |
if (Input.GetKey (KeyCode.W))
|
41 |
{
|
42 |
transform.Translate(0,0.01f,0);
|
43 |
}
|
44 |
45 |
if (Input.GetKey (KeyCode.S))
|
46 |
{
|
47 |
transform.Translate(0,-0.01f,0);
|
48 |
}
|
49 |
50 |
//上、下、左、右平移主角
|
51 |
if (Input.GetKey (KeyCode.J))
|
52 |
{
|
53 |
54 |
hero.transform.Translate(0.001f,0,0);
|
55 |
}
|
56 |
57 |
if (Input.GetKey (KeyCode.L))
|
58 |
{
|
59 |
60 |
hero.transform.Translate(-0.001f,0,0);
|
61 |
}
|
62 |
63 |
if (Input.GetKey (KeyCode.I))
|
64 |
{
|
65 |
hero.transform.Translate(0,0,-0.001f);
|
66 |
}
|
67 |
68 |
if (Input.GetKey (KeyCode.K))
|
69 |
{
|
70 |
hero.transform.Translate(0,0,0.001f);
|
71 |
}
|
72 |
73 |
DrawAnimation(anim);
|
74 |
}
|
75 |
76 |
void DrawAnimation(Object[] tex)
|
77 |
{
|
78 |
79 |
//计算限制帧的时间
|
80 |
time += Time.deltaTime;
|
81 |
//超过限制帧切换贴图
|
82 |
if (time >= 1.0 / fps){
|
83 |
//帧序列切换
|
84 |
nowFram++;
|
85 |
//限制帧清空
|
86 |
time = 0;
|
87 |
//超过帧动画总数从第0帧开始
|
88 |
if (nowFram >= tex.Length)
|
89 |
{
|
90 |
nowFram = 0;
|
91 |
}
|
92 |
}
|
93 |
//将对应的贴图赋予主角对象,强制将资源文件转换成贴图
|
94 |
hero.renderer.material.mainTexture = (Texture)tex[nowFram];
|
95 |
}
|
96 |
} |