空间与运动

1、简答并用程序验证

(1)游戏对象运动的本质是什么

游戏对象运动本质就是使用矩阵变换(平移、旋转、缩放)改变游戏对象的空间属性(位置、欧拉角、比例)。

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

第一种方法

利用transform改变position来实现抛物线运动,水平方向的移动速度是不变的,竖直方向是有一定的加速度变化的,两个方向的运动矢量相加即可实现抛物线运动。
代码如下:

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

public class paowu1 : MonoBehaviour {

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

第二种方法

声明一个Vector3变量,通过改变该变量打到抛物的矢量变化,然后与对象的position相加。
代码如下:

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

public class paowu2 : MonoBehaviour {

	public float speed;
	// Use this for initialization
	void Start () {
        speed = 0;
	}
	
	// Update is called once per frame
	void Update () {
        Vector3 vec = new Vector3( Time.deltaTime*5, -Time.deltaTime*(speed/10), 0);
        speed++;

        this.transform.position += vec;
	}
}

第三种方法

利用transform的Translate函数,和上种方法类似,传入一个Vector3变量来改变position。
代码如下:

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

public class paowu3 : MonoBehaviour {

	public float speed;
	// Use this for initialization
	void Start () {
        speed = 0;
	}
	
	// Update is called once per frame
	void Update () {
        Vector3 vec = new Vector3(Time.deltaTime * 5, -Time.deltaTime * (speed / 10), 0);
        speed++;
        transform.Translate(vec);
    }
}

(3)写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。

首先上网下载太阳系贴图
太阳系贴图

将贴图图片拖入Assets,再拖放到球体对象上,就能成功贴图。以此方法按太阳系球体的大小、位置创建各个星球(题目中要求各星球不在同一法平面,可以适当调整位置)。
初始位置如下:
在这里插入图片描述
根据初始位置算出各个星球绕太阳旋转的轴(行星球心与太阳球心连线的垂直轴),利用Rotate()进行自转,利用RotateAround()进行公转。然后将各Transform变量与Unity中的对象联系即可。其中月亮属于地球的child。
代码如下:

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

public class taiyangxi : MonoBehaviour
{

    public Transform sun;
    public Transform shuixing;
    public Transform jinxing;
    public Transform earth;
    public Transform huoxing;
    public Transform muxing;
    public Transform tuxing;
    public Transform tianwangxing;
    public Transform haiwangxing;
    public Transform moon;

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        sun.Rotate(Vector3.up * 30 * Time.deltaTime);

        shuixing.Rotate(Vector3.up * 40 * Time.deltaTime);
        shuixing.RotateAround(sun.position, new Vector3(1, -8, 0), 30 * Time.deltaTime);

        jinxing.Rotate(Vector3.up * 50 * Time.deltaTime);
        jinxing.RotateAround(sun.position, new Vector3(10, -23, 0), 100 * Time.deltaTime);

        earth.Rotate(Vector3.up * 60 * Time.deltaTime);
        earth.RotateAround(sun.position, new Vector3(0, 1, 0), 50 * Time.deltaTime);

        huoxing.Rotate(Vector3.up * 40 * Time.deltaTime);
        huoxing.RotateAround(sun.position, new Vector3(1, -2, 0), 70 * Time.deltaTime);

        muxing.Rotate(Vector3.up * 20 * Time.deltaTime);
        muxing.RotateAround(sun.position, new Vector3(2, 23, 0), 30 * Time.deltaTime);

        tuxing.Rotate(Vector3.up * 10 * Time.deltaTime);
        tuxing.RotateAround(sun.position, new Vector3(2, -11, 0), 40 * Time.deltaTime);

        tianwangxing.Rotate(Vector3.up * 30 * Time.deltaTime);
        tianwangxing.RotateAround(sun.position, new Vector3(3, -62, 0), 20 * Time.deltaTime);

        haiwangxing.Rotate(Vector3.up * 60 * Time.deltaTime);
        haiwangxing.RotateAround(sun.position, new Vector3(3, 34, 0), 100 * Time.deltaTime);

        moon.Rotate(Vector3.up * 60 * Time.deltaTime);
        moon.RotateAround(earth.position, Vector3.up, 500 * Time.deltaTime);
    }
}

旋转过程效果图如下:
在这里插入图片描述

2、编程实践

(1)列出游戏中提及的事务(Objects)

游戏中的对象有:牧师、魔鬼、小船、开始岸、结束岸

(2)用表格列出玩家动作表(规则表)

动作条件
开船船上有对象
牧师上船船在岸边,岸上有牧师,船上少于两个对象
魔鬼上船船在岸边,岸上有魔鬼,船上少于两个对象
船上左边对象下船船在岸边,船上左边有对象
船上右边对象下船船在岸边,船上右边有对象

(3)将游戏中对象做成预制

将游戏中需要的对象进行预制,分别是正方体的牧师、球体的魔鬼、长方体的小船和长方体的岸边。代码中需要使用Resources类,因此需要在Assets文件夹下创建一个Resources文件夹,并将预制的对象放入其中。

相关参考博客:
Unity3D的Resource类使用
在这里插入图片描述

(4)MVC结构程序

分别创建三个脚本Model、View、Controller。按要求游戏只能有主摄像机和一个empty对象,其中Model和Controller脚本挂在主摄像机下,View挂在empty下。

(5)游戏具体设计

游戏开始界面:
在这里插入图片描述
游戏成功界面:
在这里插入图片描述
游戏失败界面:
在这里插入图片描述

Model

Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。
该脚本中定义了游戏对象的位置和完善游戏动作的函数,同时负责加载预制的游戏对象。
代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using mygame;
 
public class Model : MonoBehaviour {
 
    Stack<GameObject> start_priests = new Stack<GameObject>();
    Stack<GameObject> end_priests = new Stack<GameObject>();
    Stack<GameObject> start_devils = new Stack<GameObject>();
    Stack<GameObject> end_devils = new Stack<GameObject>();
 
    GameObject[] boat = new GameObject[2];
    GameObject boat_obj;
    public float speed = 50;

    SSDirector one;
 
    //对象的位置
    Vector3 boatStartPos = new Vector3(-6, 0, 0);
    Vector3 boatEndPos = new Vector3(6, 0, 0);
    Vector3 sideStartPos = new Vector3(-10, 0, 0);
    Vector3 sideEndPos = new Vector3(10, 0, 0);
 
    float gap = 1.1f;
    Vector3 priestsStartPos = new Vector3(-11, 1, 0);
    Vector3 priestsEndPos = new Vector3(13, 1, 0);
    Vector3 devilsStartPos = new Vector3(-7, 1, 0);
    Vector3 devilsEndPos = new Vector3(10, 1, 0);
    
 
    // Use this for initialization
    void Start () {
		one = SSDirector.GetInstance();
        one.setModel(this);
        loadSrc();
	}
	
	// Update is called once per frame
	void Update () {
        setposition(start_priests, priestsStartPos);
        setposition(end_priests, priestsEndPos);
        setposition(start_devils, devilsStartPos);
        setposition(end_devils, devilsEndPos);
 
        if(one.state == State.SE_move)
        {
            boat_obj.transform.position = Vector3.MoveTowards(boat_obj.transform.position, boatEndPos, Time.deltaTime * speed);
            if (boat_obj.transform.position == boatEndPos)
            {
                one.state = State.End;
            }
        }
        else if(one.state == State.ES_move)
        {
            boat_obj.transform.position = Vector3.MoveTowards(boat_obj.transform.position, boatStartPos, Time.deltaTime * speed);
            if (boat_obj.transform.position == boatStartPos)
            {
                one.state = State.Start;
            }
        }
        else
        {
            check();
        }
	}
 
    //加载游戏对象
    void loadSrc()
    {   
        //sides
        Instantiate(Resources.Load("sides"), sideStartPos, Quaternion.identity);
        Instantiate(Resources.Load("sides"), sideEndPos, Quaternion.identity);
 
        //boat
        boat_obj = Instantiate(Resources.Load("boat"), boatStartPos, Quaternion.identity) as GameObject;
        
        //prisets and devils
        for(int i = 0; i < 3; i++)
        {
            start_priests.Push(Instantiate(Resources.Load("Priests")) as GameObject);
            start_devils.Push(Instantiate(Resources.Load("Devils")) as GameObject);
        }
    }
 
    void setposition(Stack<GameObject> aaa, Vector3 pos)
    {
        GameObject[] temp = aaa.ToArray();
        for(int i = 0; i < aaa.Count; i++)
        {
            temp[i].transform.position = pos + new Vector3(-gap * i, 0, 0);
        }
    }
 
    //上船
    void getOnTheBoat(GameObject obj)
    {
        obj.transform.parent = boat_obj.transform;
        if(boatNum() != 0)
        {
            if (boat[0] == null)
            {
                boat[0] = obj;
                obj.transform.localPosition = new Vector3(-0.3f, 2.5f, 0);
            }
            else
            {
                boat[1] = obj;
                obj.transform.localPosition = new Vector3(0.3f, 2.5f, 0);
            }
        }
    }
    //判断船上是否有空位
    int boatNum()
    {
        int num = 0;
        for(int i = 0; i < 2; i++)
        {
            if (boat[i] == null)
            {
                num++;
            }
        }
        return num;
    }
 
    //船移动
    public void moveBoat()
    {
        if(boatNum() != 2)
        {
            if(one.state == State.Start)
            {
                one.state = State.SE_move;
            }
            else if(one.state == State.End)
            {
                one.state = State.ES_move;
            }
        }
    }
 
    //下船
    public void getOffTheBoat(int side)
    {
        if (boat[side] != null)
        {
            boat[side].transform.parent = null;
            if(one.state == State.Start)
            {
                if (boat[side].tag == "Priests")
                {
                    start_priests.Push(boat[side]);
                }
                else
                {
                    start_devils.Push(boat[side]);
                }
            }
            else if(one.state == State.End)
            {
                if (boat[side].tag == "Priests")
                {
                    end_priests.Push(boat[side]);
                }
                else
                {
                    end_devils.Push(boat[side]);
                }
            }
            boat[side] = null;
        }
    }
 
    void check()
    {   
        if(end_devils.Count == 3 && end_priests.Count == 3)
        {
            one.state = State.Win;
            return;
        }
 
        int bp = 0, bd = 0;
        for(int i = 0; i < 2; i++)
        {
            if (boat[i] != null && boat[i].tag == "Priests")
            {
                bp++;
            }
            else if (boat[i] != null && boat[i].tag == "Devils")
            {
                bd++;
            }
        }
 
        int sp = 0, sd = 0, ep = 0, ed = 0;
        if(one.state == State.Start)
        {
            sp = start_priests.Count + bp;
            ep = end_priests.Count;
            sd = start_devils.Count + bd;
            ed = end_devils.Count;
        }
        else if(one.state == State.End)
        {
            sp = start_priests.Count;
            ep = end_priests.Count + bp;
            sd = start_devils.Count;
            ed = end_devils.Count + bd;
        }
 
        if((sp != 0 && sp < sd) || (ep != 0 && ep < ed))
        {
            one.state = State.Lose;
        }
    }
 
    //游戏对象从岸上到船上的变化
    public void priS()
    {
        if(start_priests.Count != 0 && boatNum() != 0 && one.state == State.Start)
        {
            getOnTheBoat(start_priests.Pop());
        }
    }
    public void priE()
    {
        if(end_priests.Count != 0 && boatNum() != 0 && one.state == State.End)
        {
            getOnTheBoat(end_priests.Pop());
        }
    }
    public void delS()
    {
        if(start_devils.Count != 0 && boatNum() != 0 && one.state == State.Start)
        {
            getOnTheBoat(start_devils.Pop());
        }
    }
    public void delE()
    {
        if(end_devils.Count != 0 && boatNum() != 0 && one.state == State.End)
        {
            getOnTheBoat(end_devils.Pop());
        }
    }
 
    //重置游戏
    public void Reset()
    {
        boat_obj.transform.position = boatStartPos;
        one.state = State.Start;
 
        int num1 = end_devils.Count, num2 = end_priests.Count;
        for(int i = 0; i < num1; i++)
        {
            Debug.Log(i);
            start_devils.Push(end_devils.Pop());
        }
 
        for (int i = 0; i < num2; i++)
        {
            start_priests.Push(end_priests.Pop());
        }

        getOffTheBoat(0);
        getOffTheBoat(1);
    }
}

View

View(视图)是应用程序中处理数据显示的部分。
该脚本中设置了游戏的UI即游戏需要的Button。
代码如下:

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

public class View : MonoBehaviour
{

    SSDirector one;
    UserAction action;

    // Use this for initialization
    void Start()
    {
        one = SSDirector.GetInstance();
        action = SSDirector.GetInstance() as UserAction;
    }

    private void OnGUI()
    {
        GUI.skin.label.fontSize = 30;
        if (one.state == State.Win)
        {
            if (GUI.Button(new Rect(350, 150, 300, 100), "WIN\n(click here to reset)"))
            {
                action.reset();
            }
        }
        if (one.state == State.Lose)
        {
            if (GUI.Button(new Rect(350, 150, 300, 100), "LOSE\n(click here to reset)"))
            {
                action.reset();
            }
        }

        if (GUI.Button(new Rect(450, 80, 100, 50), "GO"))
        {
            action.moveBoat();
        }
        if (GUI.Button(new Rect(350, 300, 75, 50), "LeftOFF"))
        {
            action.offBoatL();
        }
        if (GUI.Button(new Rect(550, 300, 75, 50), "RightOFF"))
        {
            action.offBoatR();
        }
        if (GUI.Button(new Rect(50, 130, 75, 50), "PriestsON"))
        {
            action.priestSOnSide();
        }
        if (GUI.Button(new Rect(200, 130, 75, 50), "DevilsON"))
        {
            action.devilSOnSide();
        }
        if (GUI.Button(new Rect(750, 130, 75, 50), "DevilsON"))
        {
            action.devilEOnSide();
        }
        if (GUI.Button(new Rect(900, 130, 75, 50), "PriestsON"))
        {
            action.priestEOnSide();
        }
    }
}

Controller

Controller(控制器)是应用程序中处理用户交互的部分。
该脚本中定义了一个命名空间mygame,用于调用Model中的函数。
代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using mygame;
 
namespace mygame
{
    public enum State { Start, SE_move, ES_move, End, Win, Lose };
 
    public interface UserAction {
        void priestSOnSide();
        void priestEOnSide();
        void devilSOnSide();
        void devilEOnSide();
        void moveBoat();
        void offBoatL();
        void offBoatR();
        void reset();
    }
 
    public class SSDirector : System.Object, UserAction
    {
        private static SSDirector _instance;
 
        public Controller currentScenceController;
        public State state = State.Start;
        private Model game_obj;
 
        public static SSDirector GetInstance()
        {
            if(_instance == null)
            {
                _instance = new SSDirector();
            }
            return _instance;
        }
 
        public Model getModel()
        {
            return game_obj;
        }
        
        internal void setModel(Model someone)
        {
            if(game_obj == null)
            {
                game_obj = someone;
            }
        }
 
        public void priestSOnSide()
        {
            game_obj.priS();
        }
        public void priestEOnSide()
        {
            game_obj.priE();
        }
        public void devilSOnSide()
        {
            game_obj.delS();
        }
        public void devilEOnSide()
        {
            game_obj.delE();
        }
        public void moveBoat()
        {
            game_obj.moveBoat();
        }
        public void offBoatL()
        {
            game_obj.getOffTheBoat(0);
        }
        public void offBoatR()
        {
            game_obj.getOffTheBoat(1);
        }
        public void reset()
        {
            game_obj.Reset();
        }
    }
 }
 
public class Controller : MonoBehaviour {
 
    // Use this for initialization
    void Start()
    {
        SSDirector one = SSDirector.GetInstance();
    }

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

    }
}

游戏视频链接如下:
Priests&Devils

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值