(譯)【Unity教程】使用Unity開發Windows Phone上的橫版跑酷游戲


譯者注:

目前移動設備的跨平台游戲開發引擎基本都是采用Cocos2d-x或者Unity。一般而言2d用cocos2d-x 3d用unity,但是對於Windows Phone開發者,

cocos2d-x for wp8是微軟維護的,版本升級十分緩慢,到現在還是 V2.0 preview,我們不可能拿一個不太穩定的版本去開發游戲。與之相反,Unity4.2發布之后,

支持WP8和Windows8,當然也包括其他平台,開發調試都是十分便捷,因此使用Unity來開發目標用戶在WP上的游戲,是個很好的選擇。

 

這是一篇譯文,原文很長,於是我把它分成了兩部分,而且加入了自己的一些修改和理解,點擊一下鏈接觀看第一部分效果。(需要安裝最新的unity插件)

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

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

介紹                                                                                                                                       

在這篇教程里,我們將學習如何去制作一款簡單的無盡跑酷游戲,在這里你將學到:

  • 生成一個分層的背景
  • 重用對象
  • 使用物理引擎
  • 通過檢測輸入來控制玩家跳躍
  • 實現能量增加
  • 一個簡單的事件管理器
  • 按需控制物體的開關
  • 制作一個簡單的GUI

游戲設計                                                                                                                                  

在開始之前,我們應該先考慮一下在游戲里面加入什么。我們要做的是一個2D側卷軸游戲,但是還是太寬泛了,讓我們來縮小一下范圍。

游戲的玩法我們將控制一個人物不斷的向屏幕右側奔跑,從一個平台跳到另外一個平台,要跑的盡可能的遠。這些平台有不同的特性,有的會讓你加速,

有的會讓你減速。我們還包含單一的能量球,可以讓你在空中跳躍。

游戲圖形我們將使用純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,至此,第一部分項目完成了,請等待 后續 的到來。

附項目下載地址:點擊下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM