(译)【Unity教程】使用Unity开发Windows Phone上的横版跑酷游戏

译者注:html

目前移动设备的跨平台游戏开发引擎基本都是采用Cocos2d-x或者Unity。通常而言2d用cocos2d-x 3d用unity,可是对于Windows Phone开发者,程序员

cocos2d-x for wp8是微软维护的,版本升级十分缓慢,到如今仍是 V2.0 preview,咱们不可能拿一个不太稳定的版本去开发游戏。与之相反,Unity4.2发布以后,架构

支持WP8和Windows8,固然也包括其余平台,开发调试都是十分便捷,所以使用Unity来开发目标用户在WP上的游戏,是个很好的选择。app

 

这是一篇译文,原文很长,因而我把它分红了两部分,并且加入了本身的一些修改和理解,点击一下连接观看第一部分效果。(须要安装最新的unity插件)dom

http://jeekun.sinaapp.com/share/flash/flash.htmlide

原文:http://catlikecoding.com/unity/tutorials/runner/函数

介绍                                                                                                                                       

在这篇教程里,咱们将学习如何去制做一款简单的无尽跑酷游戏,在这里你将学到:学习

  • 生成一个分层的背景
  • 重用对象
  • 使用物理引擎
  • 经过检测输入来控制玩家跳跃
  • 实现能量增长
  • 一个简单的事件管理器
  • 按需控制物体的开关
  • 制做一个简单的GUI

游戏设计                                                                                                                                  ui

在开始以前,咱们应该先考虑一下在游戏里面加入什么。咱们要作的是一个2D侧卷轴游戏,可是仍是太宽泛了,让咱们来缩小一下范围。this

游戏的玩法咱们将控制一我的物不断的向屏幕右侧奔跑,从一个平台跳到另一个平台,要跑的尽量的远。这些平台有不一样的特性,有的会让你加速,

有的会让你减速。咱们还包含单一的能量球,可让你在空中跳跃。

游戏图形咱们将使用纯Cube和标准的粒子系统来制做(程序员的悲哀。。。) 玩家,平台,包括背景,通通都是Cube,而粒子系统将被用于制做运动轨迹,

不少漂浮物将会给人更好的速度和深度的感受。

另外,游戏不包括特效音和背景音。

创建场景                                                                                                                                   

打开Unity,建立一个新的工程,不要导入任何的包。

咱们是要作的2D视角的游戏,可是还想有一点3D的效果,Orthographic摄像机是不能用于3D游戏的,所以咱们得采用默认的Perspective类型。这样的话,将物体放到离镜头不一样

的距离,咱们就能获得一个分层的滚动背景。

就让咱们假定,前景是在距离0,第一个背景在距离50,第二个背景在距离100。让咱们分别放三个Cube在这三个深度,而且将他们做为建立场景的引导者。我本身已经试过了一些角度和颜色组合,

以为还能够,固然你也能够本身去实验一些新的数值。

 

下面正式开始:

首先添加一个平行光(GameObject->Create Other->Directional Light),设置旋转为(20,330,0)

而后设置摄像机的参数,颜色为(115,140,220)

其余数值见图:

建立3个Cube, Position 分别是(0,0,0) (0,0,50) (0,0,100),名字对应的是 Runner, Skyline Close, Skyline Far Away,后两个Skyline Cube 不须要

碰撞器(Box Collider),直接在属性面板里,右键移除组件便可。 Runner是此次游戏的猪觉,在这里我称之为 “奔跑者”,后面同之。

给3个Cube分别建立材质(Project 视图,Create-> Material),命名为Runner Mat, Skyline Close Mat, Skyline Far Away Mat. 而后分别拖放到对应的Cube上。

我使用了默认的 diffuse Shader , 颜色分别设为, White, (100, 120, 220), (110, 140, 220), 设置完成后的值以下:

           

为了使项目的组织架构更好,咱们在Project视图里增长2个文件夹,Runner, Skyline, 而后把材质放到对应的文件夹里。

运行一下,能够看到3个Cube都出如今了视野里面。

开始跑步吧                                                                                                                                           

到目前为止,咱们作的还没什么奇特的,场景里面什么也没有发生,可是接下来就是见证奇迹的时刻了。

让咱们来让 “奔跑者” 向右边移动来模拟一下这个游戏吧。

在Runner文件夹里建立一个C#脚本,Runner.cs

using UnityEngine;
using System.Collections;

public class Runner : MonoBehaviour {

    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
        transform.Translate(5f * Time.deltaTime, 0f, 0f);
    }
}

把脚本拖到层次视图的Runner 上面,运行,怎么样,看到主角开始跑了吧。可是有个问题,摄像头没有跟随它在运动,没一会就跑出咱们的视野了,

这样的游戏根本无法玩啊,也不是咱们想要的。解决的方法很简单,把摄像机对象拖到Runner里,让他成为Runner的Child.

   如今再运行的话就没有问题了,并且咱们能够发现,远处的Cube要比进出的Cube移动的好像快一些,固然这就是视差的问题了。

生整天际线                                                                                                                                        

如今咱们已经有了基本的运动了,接下来让咱们生成一行的Cube来实现无止境的天际线。首先有件事情咱们必须意识到,名为无尽的,其实只须要一部分存在地图中就能够了,

由于随着镜头不断的右移,左侧的天际线不断消失在视野中,他们是能够被销毁的,没有必要再继续占用资源了。或者,咱们能够将它移动位置,在右侧重建场景,省去了重复的

建立开支。

经过这个特性,咱们只须要不多的资源就能够建立无止尽的天际线了。

在Skyline 文件夹中建立一个SkylineManager的脚本,由于要经过一个脚本建立两个天际线,因此须要传一个值进来,知道是要建立具体哪一种。

public Transform prefab;

一样的,为了场景层次视图中的组织结构友好,咱们须要设置一下层次。 首先新建一个空对象,起名Managers, 做为父容器。

而后给它建立一个子对象 Skyline Close Manager,而后把脚本拖到这个对象上来。

接下来把Skyline Close和Skyline Far Away 这两个Cube拖拽到Project中的Skyline文件夹下,使之成为Prefab,而后将层次视图中的两个对象删除,

设置好以后,层次视图和Project视图以下所示:

      

如今咱们须要一个起点指示咱们从哪里开始构建天际线,咱们能够经过Manger对象自己的位置,并且咱们须要一个数量值来决定多少个Cube组合起来才能填充完屏幕,

新建一个变量叫作 numberOfObjects ,另外声明一个变量 nextPosition ,指示左边的对象无效以后,应该在哪里重建。

public Transform prefab;
public int numberOfObjects;

private Vector3 nextPosition;

void Start()
{
    nextPosition = transform.localPosition;
}

下一步是建立初始行的Cube,经过一个for循环来实现,实例化咱们以前建立为prefab的Cube,每个cube的位置都是nextPosition,并且随着没添加一个动态修改这个变量的值

void Start()
{
    nextPosition = transform.localPosition;

    for (int i = 0; i < numberOfObjects; i++)
    {
       Transform o = (Transform)Instantiate(prefab);
        o.localPosition = nextPosition;
        nextPosition.x += o.localScale.x;
    }
}

如今设置Skyline Close Manager 的Position 为(0, -1, 0) 而且设置 numberOfObjects 变量的值为10 ,运行

 

能够看到出现了一连串的Cube了,有点“地平线”的影子了,可是有个问题就是“天际线”自己不会随着镜头运动,去往左侧就消失不见了。

咱们回收重用Cube的策略是只回收那些离玩家超过必定距离的,所以必定要知道玩家跑了有多远,为了达到这个目的,咱们在 Runner.cs 里

添加一个静态变量,并且时时更新它。

public static float distanceTraveled;

// Use this for initialization
void Start () {
    
}
    
// Update is called once per frame
void Update () {
  transform.Translate(5f * Time.deltaTime, 0f, 0f);

    //由于起始位置是 0
  distanceTraveled = transform.position.x;
}

如今咱们将要把咱们的组成地平线的物体放到一个队列里,而且不断的检查是否要回收,由于是队列,只须要检查第一个便可,若是是须要回收,

从队列中移除,修改位置,而后放到队列最后边就能够了。

咱们用一个recycleOffset变量来配置具体物体落后玩家多远的话 能够回收,这里设置为 60 .

public class SkylineManager : MonoBehaviour {

    public Transform prefab;
    public int numberOfObjects;
    public float recycleOffset;

    private Vector3 nextPosition;
    private Queue<Transform> objectQueue;

    void Start()
    {
        objectQueue = new Queue<Transform>(numberOfObjects);
        nextPosition = transform.localPosition;

        for (int i = 0; i < numberOfObjects; i++)
        {
            Transform o = (Transform)Instantiate(prefab);
            o.localPosition = nextPosition;
            nextPosition.x += o.localScale.x;

            objectQueue.Enqueue(o);
        }
    }

    // Update is called once per frame
    void Update () {
        if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
        {
            Transform o = objectQueue.Dequeue();
            o.localPosition = nextPosition;
            nextPosition.x += o.localScale.x;
            objectQueue.Enqueue(o);
        }
    }
}

如今运行,在Scene视图里,能够看到Cube行 是随着 “奔跑者” 不断的从新修正本身的位置的。可是他如今看起来还不像天际线,为了生成更像实际的

没有规则的天际线,让咱们在它生成或者充值的时候随机放大它。

首先考虑到会有重复的代码产生,首先写个函数Recycle ,在start或者update的时候都调用它。

public class SkylineManager : MonoBehaviour
{

    public Transform prefab;
    public int numberOfObjects;
    public float recycleOffset;

    private Vector3 nextPosition;
    private Queue<Transform> objectQueue;

    void Start()
    {
        objectQueue = new Queue<Transform>(numberOfObjects);
        for (int i = 0; i < numberOfObjects; i++)
        {
            objectQueue.Enqueue((Transform)Instantiate(prefab));
        }
        nextPosition = transform.localPosition;
        for (int i = 0; i < numberOfObjects; i++)
        {
            Recycle();
        }
    }

    void Update()
    {
        if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
        {
            Recycle();
        }
    }

    private void Recycle()
    {
        Transform o = objectQueue.Dequeue();
        o.localPosition = nextPosition;
        nextPosition.x += o.localScale.x;
        objectQueue.Enqueue(o);
    }
}

下一步,让咱们加入两个变量分别表示容许的放大最大和最小值,当放大一个物体以后,咱们要肯定能够保证后面的物体和前面的

都是底部对齐的,

public class SkylineManager : MonoBehaviour
{
    public Transform prefab;
    public int numberOfObjects;
    public float recycleOffset;

    public Vector3 minSize, maxSize;

    private Vector3 nextPosition;
    private Queue<Transform> objectQueue;

    void Start()
    {
        objectQueue = new Queue<Transform>(numberOfObjects);
        for (int i = 0; i < numberOfObjects; i++)
        {
            objectQueue.Enqueue((Transform)Instantiate(prefab));
        }
        nextPosition = transform.localPosition;
        for (int i = 0; i < numberOfObjects; i++)
        {
            Recycle();
        }
    }

    void Update()
    {
        if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
        {
            Recycle();
        }
    }

    private void Recycle()
    {
        Vector3 scale = new Vector3(
            Random.Range(minSize.x, maxSize.x),
            Random.Range(minSize.y, maxSize.y),
            Random.Range(minSize.z, maxSize.z));

        Vector3 position = nextPosition;
        position.x += scale.x * 0.5f;
        position.y += scale.y * 0.5f;

        Transform o = objectQueue.Dequeue();
        o.localScale = scale;
        o.localPosition = position;
        nextPosition.x += scale.x;
        objectQueue.Enqueue(o);
    }
}

为了获得一个漂亮的天际线效果,把这个Manager放到(-60,-60, 50),而且将MinSize 设置为(10,20,10) MaxSize设置为(30,60,10)Recycle Offset 设置为60

让咱们继续添加第二个天际线层,选中Skyline Close Manager "CTRL+D " 复制一份,而且更名为 Skyline Far Away Manager, 将它的prefab属性改成 Skyline Far Away 这个预设。

它的位置设置为(-100,-100, 100) 它的Recycle Offset 为 75,MinSize为(10,50,10) MaxSize为(30,100,10) 固然你也能够照你本身的喜爱来设置新的值

   

产平生台                                                                                                                   

生成平台跟生整天际线很像,稍微有点不一样的是平台的高度须要随机设定,并且他们之间须要有沟壑。而且咱们须要约束平台的高度,好让它不会影响天际线的显示,

若是平台超出这个范围了,咱们须要给它纠正过来。

在Project视图里新建一个文件夹,取名字叫作Platform, 而后在里面建立一个C#脚本,叫作 PlatformManager, 而后把SkylineManager的脚本拷贝到这里来,

修改一部分源码以下:

public class PlatformManager : MonoBehaviour {

    public Transform prefab;
    public int numberOfObjects;
    public float recycleOffset;

    public Vector3 minSize, maxSize, minGap, maxGap;
    public float minY, maxY;

    private Vector3 nextPosition;
    private Queue<Transform> objectQueue;

    void Start()
    {
        objectQueue = new Queue<Transform>(numberOfObjects);
        for (int i = 0; i < numberOfObjects; i++)
        {
            objectQueue.Enqueue((Transform)Instantiate(prefab));
        }
        nextPosition = transform.localPosition;
        for (int i = 0; i < numberOfObjects; i++)
        {
            Recycle();
        }
    }

    void Update()
    {
        if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
        {
            Recycle();
        }
    }

    private void Recycle()
    {
        Vector3 scale = new Vector3(
            Random.Range(minSize.x, maxSize.x),
            Random.Range(minSize.y, maxSize.y),
            Random.Range(minSize.z, maxSize.z));

        Vector3 position = nextPosition;
        position.x += scale.x * 0.5f;
        position.y += scale.y * 0.5f;

        Transform o = objectQueue.Dequeue();
        o.localScale = scale;
        o.localPosition = position;
        nextPosition.x += scale.x;
        objectQueue.Enqueue(o);

        nextPosition += new Vector3(
            Random.Range(minGap.x, maxGap.x) + scale.x,
            Random.Range(minGap.y, maxGap.y),
            Random.Range(minGap.z, maxGap.z));

        if (nextPosition.y < minY)
        {
            nextPosition.y = minY + maxGap.y;
        }
        else if (nextPosition.y > maxY)
        {
            nextPosition.y = maxY - maxGap.y;
        }
    }
}

而后就要建立一个用于显示平台的形状了,在Skyline文件夹里,选中Skyline Close Mat ,Ctrl+D复制一份,颜色改成(255,60,255)而后拖放到Platform里,

更名为Platform Regular Mat, 而后建立一个Cube,把这个Meterial 拖放到Cube上,而后把Cube拖回到Platform文件夹里,使之成为预设,更名为Platform 

在层次视图里建立一个 Empty GameObject,命名为Platform Manager, 一样也放到Managers 下面,成为它的子对象。把Platform Manager这个脚本拖放到对象上,成为它的

组件。参考下图设置一下脚本的各个变量的值。

跳跃和坠落                                                                                                                        

如今有平台了,是时候升级一下咱们的“奔跑者”了,咱们使用物理引擎来实现跑,跳,坠落等效果。选中在层次视图里选中“奔跑者”,而后Compnent->physics->rigid body,

给它添加物理引擎支持,由于咱们不想让它旋转也不想跳出咱们的视野,所以要给他添加 Z轴约束而且锁定全部的旋转方向。

由于运动将会在平台上平滑的移动来完成,让咱们来建立一个没有摩擦的材质(Project 视图上 Platform文件夹上 Create->Physics Material)。 具体设置以下图所示。

将这个物理材质设置为层次试图里的 Runner的 Box Collider 组件的 Material 属性

把Runner的Position 设置为(0,2,0)这样的话 一开始 “跑步者” 就会降落在平台上,而后开始运动。

运行一下,能够看到“跑步者”落到平台,而后向右侧运动,跟设想的如出一辙,可是假如它蹭到平台的边缘,就会发现运动有些奇怪。这是由于即便在这个状况下,Update也不会不断修改奔跑者”位置的,

让咱们换一种方式,使用物理引擎,采用添加“力”来使物体位置改变。

把Runner.cs代码修改以下:

public class Runner : MonoBehaviour {

    public static float distanceTraveled;

    public float acceleration;

    private bool touchingPlatform;

    void Update()
    {
        distanceTraveled = transform.localPosition.x;
    }

    void FixedUpdate()
    {
     //碰撞的时候不会继续做用力
if (touchingPlatform) { rigidbody.AddForce(acceleration, 0f, 0f, ForceMode.Acceleration); } } void OnCollisionEnter() { touchingPlatform = true; } void OnCollisionExit() { touchingPlatform = false; } }

设置acceleration的值为5

在Platform文件夹里,像刚才那样给Platform也建立物理材质,命名为 Platform Regular PMat, 设置以下,而后把它复制给Platform的预设(prefab)

如今平台有了一些摩擦力,可是由于有持续做用力,因此咱们的“跑步者”可以克服这些阻力。下面再给Runner.cs 添加一个变量来控制“跑步者”的跳跃速度。

添加变量 jumpVeclocity 设置为 (1,7,0)

将 Runner.cs 代码改成以下:

public class Runner : MonoBehaviour {

    public static float distanceTraveled;
    public Vector3 jumpVelocity;

    public float acceleration;

    private bool touchingPlatform;

    void Update()
    {
        if (touchingPlatform && Input.GetKeyDown(KeyCode.A))
        {
            Debug.Log(1);
            rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
        }
        distanceTraveled = transform.localPosition.x;
    }

    void FixedUpdate()
    {
        if (touchingPlatform)
        {
            rigidbody.AddForce(acceleration, 0f, 0f, ForceMode.Acceleration);
        }
    }

    void OnCollisionEnter()
    {
        touchingPlatform = true;
    }

    void OnCollisionExit()
    {
        touchingPlatform = false;
    }
}

如今运行,而后按下鼠标左键,就可让咱们的“跑步者”跳跃了。

可是玩一会就发现,假如“奔跑者”碰到平台的边缘,咱们能够经过不断的按鼠标左键来防止坠落。

这是一个bug,须要修复一下。

解决方案很简单,一旦玩家按下鼠标左键,就将touchingPlatform变量的值设为false,就不能够连续的跳跃了。

    void Update()
    {
        if (touchingPlatform && Input.GetKeyDown(KeyCode.A))
        {
            touchingPlatform = false;
            rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
        }
        distanceTraveled = transform.localPosition.x;
    }

部署到Windows Phone                                                                                                        

由于Unity的跨平台作的实在是太好了,咱们只须要简单两步就能够生成Windows Phone的工程,在菜单栏 File-> Build Setting弹出对话框

而后选择 Player Setting

修改一下 Orientation ,连上你的WP8手机,而后点击 Build & Run ,会弹出一个选择文件夹的对话框,由于Unity会帮咱们生成工程,因此这也就是工程的所在地,

新建文件夹 Projects->WP8 而后选择,等待一会编译完成,会发现游戏开始了,很兴奋吧!这么简单就能够作一款游戏,so easy, 老板不再担忧项目进度了。

可是!!!

还有问题,由于没有处理回退事件,因此如今的游戏是没法经过后退按钮退出的,找到编译出来的项目工程,打开,而后注释后退事件的代码:

private void PhoneApplicationPage_BackKeyPress(object sender, CancelEventArgs e)
{
      //e.Cancel = UnityApp.BackButtonPressed();
}

OK,至此,第一部分项目完成了,请等待 后续 的到来。

附项目下载地址:点击下载

相关文章
相关标签/搜索