3D遊戲編程與設計3——空間與運動

1、簡答並用程序驗證

  • 遊戲對象運動的本質是什麼?
    遊戲對象運動的本質是遊戲對象的空間屬性的改變,包括遊戲對象 Transform 屬性中 Position 和 Rotation 屬性的改變。
public class ExampleClass : MonoBehaviour
{
    void Update()
    {
        this.transform.position += Vector3.left * Time.deltaTime;
    }
}
  • 請用三種以上方法,實現物體的拋物線運動。(如,修改 Transform 屬性,使用向量 Vector3 的方法…)
    假設該物體的拋物線運動是 x 軸正方向速度保持不變,y 軸負方向保持一定加速度的運動。

① 第一種方法是通過修改 Transform 屬性來實現拋物線運動。 代碼如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class parabolaBehavior1 : MonoBehaviour
{
    private float xSpeed = 5f;
    private float ySpeed = 0;
    private float gravity = 9.8f;

    void Start()
    {
        Debug.Log("start!");
    }

    void Update()
    {
        this.transform.position += Vector3.right * Time.deltaTime * xSpeed;
        this.transform.position += Vector3.down * Time.deltaTime * ySpeed;
        ySpeed += gravity * Time.deltaTime;
    }
}

② 第二種方法是通過使用向量 Vector3 的方法來實現拋物線運動。代碼如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class parabolaBehavior2 : MonoBehaviour
{
    private float xSpeed = 5f;
    private float ySpeed = 0;
    private float gravity = 9.8f;

    void Start()
    {
        Debug.Log("start!");
    }

    void Update()
    {
        Vector3 trans = new Vector3(xSpeed * Time.deltaTime, -ySpeed * Time.deltaTime, 0);
        this.transform.position += trans;
        ySpeed += gravity * Time.deltaTime;
    }
}

③ 第三種方法是通過使用 Translate 方法來實現拋物線運動。代碼如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class parabolaBehavior3 : MonoBehaviour
{
    private float xSpeed = 5f;
    private float ySpeed = 0;
    private float gravity = 9.8f;

    void Start()
    {
        Debug.Log("start!");
    }

    void Update()
    {
        Vector3 trans = new Vector3(xSpeed * Time.deltaTime, -ySpeed * Time.deltaTime, 0);
        this.transform.Translate(trans);
        ySpeed += gravity * Time.deltaTime;
    }
}
  • 寫一個程序,實現一個完整的太陽系,其他星球圍繞太陽的轉速必須不一樣,且不在一個法平面上。

① 首先在場景中創建一個太陽、八個行星和一個月亮,八大行星距離太陽由進到遠分別爲水星、金星、地球、火星、木星、土星、天王星和海王星。將下載好的貼圖拖入球體,分別設置好每個球體的大小和位置,將太陽作爲八大行星的父類,地球作爲月亮的父類。製作太陽系預製。
在這裏插入圖片描述
在這裏插入圖片描述
② 編寫腳本,讓八大行星圍繞太陽的轉速不一樣,且不在一個法平面上。
使用 Transform 對象的 RotateAround 方法,第一個參數是圍繞的旋轉點即太陽的位置,第二個參數是旋轉的法向量,使用隨機的 y 和 z,製造不同的運動法平面,第三個參數是旋轉的速度,實現公轉。
使用 Transform 對象的 Rotation 方法,參數是旋轉的速度,實現球體的自轉。
將寫好的腳本掛到 Sun 上,並將對應對象拖到 Script 中的 Transform 對象中。
在這裏插入圖片描述
實現代碼如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Rotate : MonoBehaviour
{
    public Transform sun;
    public Transform mercury;
    public Transform venus;
    public Transform earth;
    public Transform mars;
    public Transform jupiter;
    public Transform saturn;
    public Transform uranus;
    public Transform neptune;
    public Transform moon;

    Vector3[] a = new Vector3[9];
    float y, z;

    // Start is called before the first frame update
    void Start()
    {
        sun.position = Vector3.zero;
        for(int i = 0; i < 9; i++)
        {
            y = Random.Range(1, 360);
            z = Random.Range(1, 360);
            a[i] = new Vector3(0, y, z);
        }
    }

    // Update is called once per frame
    void Update()
    {
        mercury.RotateAround(sun.position, a[0], 47 * Time.deltaTime);
        mercury.Rotate(Vector3.up * 47 * Time.deltaTime);

        venus.RotateAround(sun.position, a[1], 35 * Time.deltaTime);
        venus.Rotate(Vector3.up * 35 * Time.deltaTime);

        earth.RotateAround(sun.position, a[2], 30 * Time.deltaTime);
        earth.Rotate(Vector3.up * 30 * Time.deltaTime);

        mars.RotateAround(sun.position, a[3], 24 * Time.deltaTime);
        mars.Rotate(Vector3.up * 24 * Time.deltaTime);

        jupiter.RotateAround(sun.position, a[4], 13 * Time.deltaTime);
        jupiter.Rotate(Vector3.up * 13 * Time.deltaTime);

        saturn.RotateAround(sun.position, a[5], 11 * Time.deltaTime);
        saturn.Rotate(Vector3.up * 11 * Time.deltaTime);

        uranus.RotateAround(sun.position, a[6], 9 * Time.deltaTime);
        uranus.Rotate(Vector3.up * 9 * Time.deltaTime);

        neptune.RotateAround(sun.position, a[7], 8 * Time.deltaTime);
        neptune.Rotate(Vector3.up * 8 * Time.deltaTime);

        moon.RotateAround(earth.position, Vector3.right, Time.deltaTime * 400);
    }
}

③ 給八大行星添加足跡組件 Trail Render,記錄行星移動軌跡。
在這裏插入圖片描述
在太陽上添加一個點光源。
在這裏插入圖片描述
運行結果如圖:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2、編程實踐

  • 閱讀以下游戲腳本

Priests and Devils 牧師和魔鬼
Priests and Devils is a puzzle game in which you will help the Priests and Devils to cross the river within the time limit. There are 3 priests and 3 devils at one side of the river. They all want to get to the other side of this river, but there is only one boat and this boat can only carry two persons each time. And there must be one person steering the boat from one side to the other side. In the flash game, you can click on them to move them and click the go button to move the boat to the other direction. If the priests are out numbered by the devils on either side of the river, they get killed and the game is over. You can try it in many > ways. Keep all priests alive! Good luck!
《牧師和魔鬼》是一款益智遊戲,玩家可以在限定的時間內幫助牧師和魔鬼過河。在河的一邊有三個牧師和三個魔鬼。他們都想去這條河的另一邊,但是隻有一條船,而且這條船每次只能載兩個人。一定有一個人把船從一邊開到另一邊。在遊戲中,你可以點擊對象來移動它們,然後點擊go按鈕將船移動到另一個方向。如果牧師被河兩岸的魔鬼所殺,遊戲也就結束了。你可以用很多方式來嘗試。讓所有的牧師都活着!

程序需要滿足的要求:

  • play the game( http://www.flash-game.net/game/2535/priests-and-devils.html )
  • 列出遊戲中提及的事物(Objects)
  • 用表格列出玩家動作表(規則表),注意,動作越少越好
  • 請將遊戲中對象做成預製
  • 在 GenGameObjects 中創建 長方形、正方形、球 及其色彩代表遊戲中的對象。
  • 使用 C# 集合類型 有效組織對象
  • 整個遊戲僅 主攝像機 和 一個 Empty 對象, 其他對象必須代碼動態生成!!! 。 整個遊戲不許出現 Find 遊戲對象, SendMessage 這類突破程序結構的 通訊耦合 語句。 違背本條準則,不給分
  • 請使用課件架構圖編程,不接受非 MVC 結構程序
  • 注意細節,例如:船未靠岸,牧師與魔鬼上下船運動中,均不能接受用戶事件!

遊戲中提及的事物(Objects):
遊戲對象:3牧師、3魔鬼
場景:2陸地、河、船

玩家動作表(規則表):

玩家動作 條件
開船 船在開始岸、船在結束岸、船上有人
開始岸牧師上船 船在開始岸,船有空位,開始岸有牧師
開始岸魔鬼上船 船在開始岸,船有空位,開始岸有魔鬼
結束岸牧師上船 船在結束岸,船有空位,結束岸有牧師
結束岸魔鬼上船 船在結束岸,船有空位,結束岸有魔鬼

將遊戲中對象做成預製:
在這裏插入圖片描述
整個遊戲僅 主攝像機 和 一個 Empty 對象, 其他對象由代碼動態生成:
在這裏插入圖片描述
使用 MVC 架構。Model 是場景中所有的遊戲對象,View 是 UserGUI 提供用戶交互,Controller 是 FirstController 和 Director。

遊戲初始界面如圖:
在這裏插入圖片描述
遊戲失敗界面如圖:
在這裏插入圖片描述
在這裏插入圖片描述
遊戲獲勝界面如圖:
在這裏插入圖片描述
遊戲代碼如下:
boatBehavior.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class boatBehavior : MonoBehaviour
{

    public boatAction action;

    // Use this for initialization
    void Start()
    {
        action = SSDirector.getInstance().currentSceneController as boatAction;
    }

    private void OnMouseDown()
    {
        action.boat_move(this.gameObject);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

priestBehavior.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class priestBehavior : MonoBehaviour
{

    private priestAction action;

    // Use this for initialization
    void Start()
    {
        action = SSDirector.getInstance().currentSceneController as priestAction;
    }

    private void OnMouseDown()
    {
        action.priest_move(this.gameObject);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

devilBehavior.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class devilBehavior : MonoBehaviour
{

    private devilAction action;

    // Use this for initialization
    void Start()
    {
        action = SSDirector.getInstance().currentSceneController as devilAction;
    }

    private void OnMouseDown()
    {
        action.devil_move(this.gameObject);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

UserGUI.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour
{

    private IUserAction action;

    // Use this for initialization
    void Start()
    {
        action = SSDirector.getInstance().currentSceneController as IUserAction;
    }

    void onGUI()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}

Interface.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IsceneController
{
    void LoadResources();
    void Restart();
}

public interface IUserAction
{


}

public interface devilAction
{
    void devil_move(GameObject obj);
}

public interface priestAction
{
    void priest_move(GameObject obj);
}

public interface boatAction
{
    void boat_move(GameObject obj);
}

Director.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSDirector : System.Object
{

    // singlton instance
    private static SSDirector _instance;

    public IsceneController currentSceneController { get; set; }
    public bool running { get; set; }

    //get instance anytime anywhere!
    public static SSDirector getInstance()
    {
        if (_instance == null)
        {
            _instance = new SSDirector();
        }
        return _instance;
    }

    public int getFPS()
    {
        return Application.targetFrameRate;
    }

    public void setFPS(int fps)
    {
        Application.targetFrameRate = fps;
    }
}

FirstController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSDirector : System.Object
{

    // singlton instance
    private static SSDirector _instance;

    public IsceneController currentSceneController { get; set; }
    public bool running { get; set; }

    //get instance anytime anywhere!
    public static SSDirector getInstance()
    {
        if (_instance == null)
        {
            _instance = new SSDirector();
        }
        return _instance;
    }

    public int getFPS()
    {
        return Application.targetFrameRate;
    }

    public void setFPS(int fps)
    {
        Application.targetFrameRate = fps;
    }
}

視頻鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章