在街机类的横轴游戏Arcade Game,我们需要背景,但又不想这个背景浪费我们太多的美工时间,可是又不想给玩家一种偷工减料,粗制滥造的感觉。这时我们需要一个无限的横轴背景。如下图所示:
无限的横轴背景和《【Unity3D】连续滚动的背景》(点击打开链接)的原理差不多,只是这次允许玩家自由操纵游戏主角的移动。因此,我们需要在此的制作上加点东西。
一、场景布置
还是这个经典的,我用画图就能画出来的背景:
首先,将这张图片拖入Unity3D之后,你先需要在Unity3D整三个Plane。这三个Plane皆沿X轴旋转90度,然后将上面导入的图片,作为Plane的材质,同时由于Unity3D中的Plane的默认大小是10x10,因此,三个Plane一字排开,分别需要在(10,0,0)(0,0,0)(-10,0,0)这三个位置。
之后,根据我画的图片背景,调整游戏主角——立方体Cube的位置,我这里放在了(0,-2,0.5)这个位置。灯光Directional light自然是必不可少的,同时需要调整主摄像机Main Camera的位置和焦距,来最终完成游戏场景,这里Main Camera的位置和焦距,我设置如下所示:
放在一个远离场景的位置(0,0,100),同时将焦距设置得接近0的无限近景,这样主要是为了减少各种视觉上的凹凸感。
二、脚本编写
接下来,我们需要完成3个工作,一个是主角需要移动,一个是主摄像机Main Camera需要跟着主角移动,最后一个是,场景跟着主角移动,以让玩家觉得,这个横轴背景是无限的。
1、主角移动,这个其实没什么可以说的,原理在《【Unity3D】键盘鼠标控制视角的移动》(点击打开链接)中已经提到过了,直接对立方体Cube赋予以下PlayerController.cs即可,当然这里由于是横轴游戏,所以我们只实现左右/AD两个键的功能。这里的 public int SENSITIVETY在场景内设置为SENSITIVETY=1,方便后期调节。
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public int SENSITIVETY;
void Update()
{
if (Input.GetAxis("Horizontal") != 0)
{
transform.Translate(-Input.GetAxis("Horizontal") * SENSITIVETY, 0, 0);
}
}
}
2、Main Camera跟着主角移动,对主摄像机赋予如下的CameraController.cs。这里的public GameObject Player;就是那个立方体Cube。
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour
{
public GameObject Player;
private Vector3 offset;
void Start()
{
this.offset = this.transform.position - Player.transform.position;//先求出摄像机和主角的两点距离,也就是我们在当前场景布置的两者距离向量
}
void Update()
{
this.transform.position = new Vector3(Player.transform.position.x + this.offset.x, this.transform.position.y, this.transform.position.z);
//在每一帧保证摄像机始终在X轴方向和玩家的距离一直,当然,这要不是横轴游戏,自然其它轴也应该保持一段距离
}
}
上述脚本的目的如下:
这也类似,实际上电影摄影上,对一些主角跑动场景,拍摄的思想了。
3、场景跟着主角移动
上面的两个脚本只能实现摄像机跟随主角移动,但是,场景还是无法连续,这里需要利用一个补位的思想。
我们要求,一旦Cube去到下图的红色位置,最左边的板,需要立即去到最右边来,反之亦然。这也是为何我在最开始,将摄像机弄得如此之远,焦距如此之近,目的就是为了玩家的可见范围仅想与一块版内,看不到这个板的补位过程,从而视觉上看起来是一个无限的横轴背景。
因此,需要对各个Plane,赋予以下的SceneController.cs:
using UnityEngine;
using System.Collections;
public class SceneController : MonoBehaviour {
public GameObject MainCamera;//摄像机
public float SCENE_WIDTH;//板的宽度,即Plane的宽度
public int SCENE_NUM;//板的数量
private float total_width;//求现有Plane并排在一起的总宽,用于计算板的补位点
private Vector3 scene_position;//此板所在的位置
void Start () {
total_width = SCENE_WIDTH * SCENE_NUM;
scene_position = this.transform.position;
}
void Update () {
if (scene_position.x + total_width / 2.0f < MainCamera.transform.position.x)
{
scene_position.x += total_width;
this.transform.position = scene_position;
}
if (MainCamera.transform.position.x < scene_position.x - total_width / 2.0f)
{
scene_position.x -= total_width;
this.transform.position = scene_position;
}
}
}
这里的板宽和板数不在脚本中直接指定,是开一个接口给美工等在场景内便于调节。
每一块板,当检测到当前摄像机,已经离自己有板长的一半之远,立即去到下一个位置补位,以完成上述效果。