作业三

本文探讨游戏对象运动的本质,详细介绍了如何实现物体的抛物线运动,并通过三种方法实现。此外,还展示了如何构建一个完整的太阳系模拟,包括行星的旋转和自转。同时,涵盖编程实践,列举了游戏对象、玩家动作表,以及基于MVC结构的游戏代码框架设计,强调了向量和变换在扩展Transform方法中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简答题

游戏对象运动的本质

游戏对象运动的本质,就是游戏对象跟随每一帧发生变化的过程。在变化的过程中,主要是指游戏对象的transform中的rotation与position两个属性。其中,rotation是指游戏对象所处位置的角度变化,而position则是指游戏对象在坐标系中位置的改变。

请用三种方法以上方法,实现物体的抛物线运动

要实现物体的抛物线运动,我们需要将物体在水平方向和垂直方向上分别进行位移,两者叠加之后即可实现抛物运动。在水平方向上我们让其速度保持不变,在竖直方向上让其速度逐渐增加。
我们都定义水平方向的速度为vx而竖直方向上的速度的vy
第一种方法,直接利用物体position的改变来进行操作:

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

public class paraCurve1 : MonoBehaviour {

    public float vx = 1;
    public float vy = 0;
    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        vy += 0.5f;
        this.transform.position += Vector3.right * Time.deltaTime * vx;
        this.transform.position += Vector3.down * Time.deltaTime * vy;
    }
}

第二种方法,我们将物体的改变用一个新的Vector3向量来表示,将其和物体原本向量叠加:

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

public class paraCurve2 : MonoBehaviour {

    public float vx = 1;
    public float vy = 0;
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        vy += 0.5f;
        Vector3 change = new Vector3(Time.deltaTime * vx, - Time.deltaTime * vy, 0);
        this.transform.position += change;
	}
}

第三种方法,我们调用transform中的translate函数来改变position,同样也会利用到Vector3向量:

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

public class paraCurve3 : MonoBehaviour {

    public float vx = 1;
    public float vy = 0;
    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        vy += 0.5f;
        Vector3 change = new Vector3(Time.deltaTime * vx, -Time.deltaTime * vy, 0);
        this.transform.Translate(change);
    }
}

实现一个完整的太阳系

我们首先按照太阳系行星和它们所处的位置、大小建立一个对象树:
在这里插入图片描述
然后为它们添加一些简单的贴图,按照位置排列在太阳的周围:
在这里插入图片描述
为了实现行星绕太阳旋转,我们需要利用到RotationAround函数来进行实现,其包括参数:旋转中心、旋转轴和旋转速度。为了简便整个代码,我们将所有旋转写在一个C
#文件里面,利用GameObject.Find函数找到每个对象。在围绕太阳旋转的同时,我们还利用Rotation函数给每个行星添加了自转,为了简便我们令所有行星的自转速度相同。

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

public class SolarSystem : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        GameObject.Find("Mercury").transform.RotateAround(Vector3.zero, new Vector3(1, 1, 0), 25 * Time.deltaTime);
        GameObject.Find("Mercury").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Venus").transform.RotateAround(Vector3.zero, new Vector3(0, 1, 1), 20 * Time.deltaTime);
        GameObject.Find("Venus").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Earth").transform.RotateAround(Vector3.zero, new Vector3(0, 1, 0), 30 * Time.deltaTime);
        GameObject.Find("Earth").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Mars").transform.RotateAround(Vector3.zero, new Vector3(2, 1, 0), 45 * Time.deltaTime);
        GameObject.Find("Mars").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Jupiter").transform.RotateAround(Vector3.zero, new Vector3(1, 2, 0), 35 * Time.deltaTime);
        GameObject.Find("Jupiter").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Saturn").transform.RotateAround(Vector3.zero, new Vector3(0, 1, 2), 40 * Time.deltaTime);
        GameObject.Find("Saturn").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Uranus").transform.RotateAround(Vector3.zero, new Vector3(0, 2, 1), 45 * Time.deltaTime);
        GameObject.Find("Uranus").transform.Rotate(Vector3.up * Time.deltaTime * 365);
        GameObject.Find("Neptune").transform.RotateAround(Vector3.zero, new Vector3(1, 1, 1), 50 * Time.deltaTime);
        GameObject.Find("Neptune").transform.Rotate(Vector3.up * Time.deltaTime * 365);
    }
}

最终得到的太阳系:
在这里插入图片描述

编程实践

列出游戏对象

游戏对象包括:牧师、魔鬼、小船、左岸、右岸。

玩家动作表

事件触发条件
牧师上船船有空位&&在船靠的岸上有牧师
魔鬼上船船有空位&&在船靠的岸上有魔鬼
船左边人下船船左边有人
船右边人下船船右边有人
开船船上有人

编程

首先我们需要确定我们的代码结构,我们首先看看老师上课给出的MVC结构:
在这里插入图片描述
我们首先需要定义一个导演,此处导演应该使用单例模式保证导演实例有且仅有一个,其负责在场景初始化时控制对应的场景。

using Interfaces;

public class SSDirector : System.Object {

    private static SSDirector _instance;
    public Scene currentScenceController { get; set; }
    public bool running { get; set; }

    public static SSDirector getInstance()
    {
        // ...
    }

    public int getFPS()
    {
        // ...
    }

    public void setFPS(int framePerSecond)
    {
        // ...
    }
}

然后我们就可以开始定义接口了,根据MVC模式的特点,我们需要把提供给用户界面的接口API暴露出来。因为接口可能不唯一,为了方便调用,我们可以直接用一个namespace进行管理,这样只需要使用这个命名空间我们就能使用下面所有的接口了。我们定义的两个接口如下所示:

public interface Scene
{
    void LoadResources();
}

public interface Objects
{
    void MoveBoat();
    void ObjectIsClicked(GameObjects characterCtrl);
    void Restart();
}

定义好接口之后,我们就需要实现这些接口,我们定义一个控制器来实现这些接口。引用接口的方法是在class外面声明刚才的命名空间并在class后加上相对应的名称。整体框架如下,其中的函数是需要实现的,包括相应用户点击以及判断游戏的状态:

using Interfaces;

public class Controller : MonoBehaviour, Scene, Objects
{
    InteracteGUI UserGUI;
    public Boat boat;
    public Coast fromCoast;
    public Coast toCoast;
    private GameObjects[] GameObjects;

    void Awake()
    {
        // ...
    }

    public void LoadResources()
    {
        // ...
    }

    public void ObjectIsClicked(GameObjects Objects)
    {
        // ...
    }

    public void MoveBoat()
    {
        // ...
    }

    int Check()
    {
        // ...
    }

    public void Restart()
    {
        // ...
    }
}

然后我们需要加上物体的移动控制,定义一个Move类来进行实现:

public class Move : MonoBehaviour
{

    readonly float Speed = 20;

    Vector3 Target;
    Vector3 Middle;
    int state = 0; 
    bool To_Middle = true;

    void Update()
    {
        // ...
    }

    public void SetDestination(Vector3 position)
    {
       // ...
    }

    public void Reset()
    {
        // ...
    }
}

然后就是游戏主要的对象,也就是牧师和魔鬼的定义,这两个对象我们可以用同一个类进行定义:

public class GameObjects
{
    readonly GameObject Instance;
    readonly Move Move;
    readonly ClickGUI clickGUI;
    readonly int type;

    bool OnBoat = false;
    Coast coast;


    public GameObjects(string Type)
    {
        // ...
    }

    public void setName(string name)
    {
        // ...
    }

    public void setPosition(Vector3 position)
    {
        // ...
    }

    public void moveToPosition(Vector3 position)
    {
        // ...
    }

    public int getType()
    {
        // ...
    }

    public string getName()
    {
        // ...
    }

    public void getOnBoat(Boat boat)
    {
        // ...
    }

    public void getOnCoast(Coast Coast)
    {
        // ...
    }

    public bool isOnBoat()
    {
        // ...
    }

    public Coast getCoastController()
    {
        // ...
    }

    public void reset()
    {
        // ...
    }
}

写完这些对象之后,剩下的就是河和船的控制了,我们分别用两个类来声明,首先是河的控制:

public class Coast
{
    readonly GameObject coast;
    readonly Vector3 startPos = new Vector3(...);
    readonly Vector3 destPos = new Vector3(...);
    readonly Vector3[] positions;
    readonly int state;

    GameObjects[] stores;

    public Coast(string str)
    {
        // ...
    }

    public int getEmptyIndex()
    {
        // ...
    }

    public Vector3 getEmptyPosition()
    {
        // ...
    }

    public void getOnCoast(GameObjects ObjectControl)
    {
        // ...
    }

    public GameObjects getOffCoast(string passenger_name)
    {
        // ...
    }

    //return the game state
    public int get_State()
    {
        // ...
    }

    //count the priests and devils
    public int[] GetobjectsNumber()
    {
        // ...
    }

    //reset the objects
    public void reset()
    {
        // ...
    }
}

最后是船的控制:

public class Boat
{
    readonly GameObject boat;
    readonly Move Moving;
    readonly Vector3 startPosition = new Vector3(...);
    readonly Vector3 destPosition = new Vector3(...);
    readonly Vector3[] startPos;
    readonly Vector3[] destPos;

    int state;
    GameObjects[] passengers = new GameObjects[2];

    public Boat()
    {
        // ...
    }

    //find an empty seat
    public int getEmptyIndex()
    {
        // ...
    }

    //whether the boat is empty
    public bool isEmpty()
    {
        // ...
    }

    //calculate the position
    public Vector3 getEmptyPosition()
    {
        // ...
    }

    public void GetOnBoat(GameObjects ObjectControl)
    {
        // ...
    }

    public GameObjects GetOffBoat(string name)
    {
        // ...
    }

    public GameObject getGameobj()
    {
        // ...
    }

    public int getState()
    {
        // ...
    }

    public int[] GetobjectsNumber()
    {
        // ...
    }

    public void Move()
    {
        // ...
    }

    public void reset()
    {
        // ...
    }
}

定义好上述的类之后,最后添加的是和用户交互的GUI,分为游戏的按钮类和点击物体类:

using Interfaces;

public class InteracteGUI : MonoBehaviour {
    Objects ObjectsController;
    static int GameState = 0;
    public int SetState { get { return GameState; } set { GameState = value; } }

	void Start () {
        // ...
    }

    private void OnGUI()
    {
        // ...
    }
}
using Interfaces;

public class ClickGUI : MonoBehaviour
{
    Objects UserAcotionController;
    GameObjects GameObjectsInScene;

    public void setController(GameObjects object)
    {
        // ...
    }

    void Start()
    {
        // ...
    }

    void OnMouseDown()
    {
        // ...
    }
}

最后,只需要创建一个空的对象,将Controller挂载到这个空的对象上就可以了。
为了游戏的美观性,我们可以再从网络上下载一些素材,丰富游戏。最终的效果如下所示:
在这里插入图片描述

思考题

使用向量与变换,实现并扩展 Tranform 提供的方法,如 Rotate、RotateAround 等:
  要实现Rotate函数,我们可以利用Quaternion.AngleAxis函数,这个函数是绕axis轴旋转angle,创建一个旋转。所以我们根据旋转角angle以及旋转轴axis,获得这个旋转。然后我们再改变t的位置和旋转即可:

void Rotate(Transform t, Vector3 axis, float angle)
{
	var rotate = Quaternion.AngleAxis(angle, axis);
    t.position = rotate * t.position;
    t.rotation *= rotate;
}

同样的,要实现RotateAround函数,我们也需要利用Quaternion.AngleAxis函数先获得这个旋转。因为这时候是围绕中心旋转的,所以我们要计算一下位移,也就是求this.positon和center的位移。将其进行旋转之后再加上中心的位移即可。

void RotateAround(Transform t, Vector3 center, Vector3 axis, float angle)
{
    var rotate = Quaternion.AngleAxis(angle, axis);
    var direction = position - center;
    direction *= rotate;
    t.position = center + direction;
    t.rotation *= rotate ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值