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;
    }
}

视频链接

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