Unity3D课程学习笔记(二)

 

1.1.游戏对象运动的本质是什么?

游戏对象运动的本质是游戏对象坐标位置,方向的变换。

1.2.三种方法实现物体的抛物线运动

实现基本抛物线的原理为:

水平方向上\(x=v_{0}t\)

竖直方向上\(y=at^{2}\)

1.2.1.用Position实现

实现的代码如下所示:

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

public class MoveOne : MonoBehaviour {
	private float speed = 0.25f;
	private float acceleration = 0.20f;
	// Use this for initialization
	void Start () {
		
	}

	// Update is called once per frame
	void Update () {
		this.transform.position += Vector3.right * speed * Time.time;
		this.transform.position += Vector3.up * acceleration * Time.time * Time.time;
	}
}

效果图如下所示:

Unity3D课程学习笔记(二)_第1张图片

1.2.2.用Translate实现

实现代码如下所示:

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

public class MoveOne : MonoBehaviour {
	private float speed = 0.25f;
	private float acceleration = 0.20f;
	// Use this for initialization
	void Start () {
		
	}

	// Update is called once per frame
	void Update () {
		transform.Translate (transform.right * speed * Time.fixedTime, Space.World);
		transform.Translate (transform.up * acceleration * Time.fixedTime * Time.fixedTime, Space.World);
	}
}

该代码的效果和1.2.1的效果图是一样的,只是实现的方法不一样。

1.2.3.用Vector3.Moveforward实现

首先创建两个对象,Target1和Target2,两个对象的位置放置在很远的地方,然后让物体朝着两个目标个体移动,即可得到抛物线的运动轨迹。

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

public class MoveOne : MonoBehaviour {
	private float speed = 2.0f;
	public Transform target1;
	public Transform target2;
	// Use this for initialization
	void Start () {	
	}

	// Update is called once per frame
	void Update () {
		transform.position = Vector3.MoveTowards (transform.position, target1.position, Time.time);
		transform.position = Vector3.MoveTowards (transform.position, target2.position, speed * Time.time * Time.time);
	}
}

该代码的实现效果和1.2.1的效果一样

1.3.实现一个完整的太阳系

第三个步骤是通过实现一个太阳系来熟悉游戏对象运动的操作

首先我们先制作好样式,就是八大行星的壁纸贴图等等,相关的素材可以在网上找到,直接将其贴到相应创造出来的球体即可以

然后我们开始写公转和自转的脚本,因为八大行星都是绕太阳公转,而月球是绕地球公转的,所有八大行星都以太阳为中心点旋转,而月球则以地球为中心点旋转。

实现公转的代码如下所示:

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

public class Revolution : MonoBehaviour {
	public Transform point;
	public float speed;
	private float ry,rz;

	void Start () {
		ry = Random.Range (0, 360);
		rz = Random.Range (0, 360);
	}

	void Update () {
		Vector3 axis = new Vector3(0,ry,rz);
		this.transform.RotateAround(point.position,axis,speed * Time.deltaTime);
	}
}

为了保证各大行星绕地球公转不在同一个法平面内,在开始程序的时候应该要随机产生一个向量,使得该行星能够绕这个轴公转

解决了公转的问题后,就要解决行星的自转问题了,行星的自转的脚本代码如下所示:

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

public class Rotation : MonoBehaviour {
	private float speed = 0.5f;
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		this.transform.RotateAround (this.transform.position, Vector3.up, speed);
	}
}

之后我们就基本能够制作出太阳系的轮廓了,为了能够增加效果,我们给行星运动的时候加上一些轨迹

Add Component => Trail Renderer

Unity3D课程学习笔记(二)_第2张图片

在这个框内调好Element 0的样式,Width宽度,Color颜色后就能够在行星运动的时候显示轨迹了

完成这步以后我们要给这个空间加上一个背景,加上背景的话,我们可以先创造一个立方体,然后把立方体的样式设置为我们的背景图案,然后把它的y和z属性设置得很大,而x属性设置得比较小,就能创造出一个背景来了

Unity3D课程学习笔记(二)_第3张图片

然后我们就能得到大致的效果图

Unity3D课程学习笔记(二)_第4张图片

2.牧师与恶魔

游戏中提及的事物:牧师,恶魔,船,河流

游戏的规则表如下所示:

Unity3D课程学习笔记(二)_第5张图片

游戏的设计采用MVC模式,游戏中的所有GameObject就是Model,View包括UserGUI和ClickGUI,Controller包括FirstController->SceneController->MyCharcaterController,BoatController,CoastController.

导演Director即相应场景控制器的声明代码如下:

namespace Game {
	/*单例模式*/
	public class Director : System.Object {
		private static Director _instance;
		public SceneController currentSceneController { get; set; }

		public static Director getInstance() {
			if (_instance == null) {
				_instance = new Director ();
			}
			return _instance;
		}
	}

    /*场景控制器,生成对象,背景等等*/
	public interface SceneController {
		void loadResources ();
        void loadBackground();
	}

    /*用户行为,即用户能够执行的操作*/
	public interface UserAction {
		void moveBoat();
		void characterIsClicked(MyCharacterController characterCtrl);
		void restart();
        bool isGameOver();
	}

	/*The Function of move, 能够使物体运动的类*/
	public class Moveable: MonoBehaviour {
		
		readonly float move_speed = 20;

		int moving_status;	
        // 0->not moving, 1->moving to middle, 2->moving to dest
		Vector3 middle;
        Vector3 dest;

        void Update() {
			if (moving_status == 1) {
				transform.position = Vector3.MoveTowards (transform.position, middle, move_speed * Time.deltaTime);
				if (transform.position == middle) {
					moving_status = 2;
				}
			} else if (moving_status == 2) {
				transform.position = Vector3.MoveTowards (transform.position, dest, move_speed * Time.deltaTime);
				if (transform.position == dest) {
					moving_status = 0;
				}
			}
		}

        /*通过设置目的地可以达到物体移动的效果*/
		public void setDestination(Vector3 _dest) {
			dest = _dest;
			middle = _dest;
			if (_dest.y == transform.position.y) {	
                // boat moving
				moving_status = 2;
			}
			else if (_dest.y < transform.position.y) {	
                // character from coast to boat
				middle.y = transform.position.y;
			} else {								
                // character from boat to coast
				middle.x = transform.position.x;
			}
			moving_status = 1;
		}

		public void reset() {
			moving_status = 0;
		}
	}
}

 

相应的对象由相应的Controller实现,下面创建了一个namespace,用于聚集各类Controller类

 

BackgroundController用于控制生成背景图案

    public class BackgroundController
    {
        readonly GameObject background;
        public BackgroundController()
        {
            background = Object.Instantiate(Resources.Load("Perfabs/Background", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
        }
        public void setName(string _name)
        {
            background.name = _name;
        }
        public void setPosition(Vector3 background_position)
        {
            background.transform.position = background_position;
        }
        public string getName()
        {
            return background.name;
        }
    }

MyCharacterController用于控制牧师和魔鬼对象

    public class MyCharacterController
    {
        readonly GameObject character;
        readonly Moveable moveableScript;
        readonly ClickGUI clickGUI;
        readonly int characterType; 
        // 0->priest, 1->devil

        bool _isOnBoat;
        CoastController coastController;


        public MyCharacterController(string which_character)
        {

            if (which_character == "priest")
            {
                character = Object.Instantiate(Resources.Load("Perfabs/Priest", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
                characterType = 0;
            }
            else
            {
                character = Object.Instantiate(Resources.Load("Perfabs/Devil", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
                characterType = 1;
            }
            moveableScript = character.AddComponent(typeof(Moveable)) as Moveable;

            clickGUI = character.AddComponent(typeof(ClickGUI)) as ClickGUI;
            clickGUI.setController(this);
        }

        public void setName(string name)
        {
            character.name = name;
        }

        public void setPosition(Vector3 pos)
        {
            character.transform.position = pos;
        }

        public void moveToPosition(Vector3 destination)
        {
            moveableScript.setDestination(destination);
        }

        public int getType()
        { 
            return characterType;
        }

        public string getName()
        {
            return character.name;
        }

        public void getOnBoat(BoatController boatCtrl)
        {
            coastController = null;
            character.transform.parent = boatCtrl.getGameobj().transform;
            _isOnBoat = true;
        }

        public void getOnCoast(CoastController coastCtrl)
        {
            coastController = coastCtrl;
            character.transform.parent = null;
            _isOnBoat = false;
        }

        public bool isOnBoat()
        {
            return _isOnBoat;
        }

        public CoastController getCoastController()
        {
            return coastController;
        }

        public void reset()
        {
            moveableScript.reset();
            coastController = (Director.getInstance().currentSceneController as FirstController).fromCoast;
            getOnCoast(coastController);
            setPosition(coastController.getEmptyPosition());
            coastController.getOnCoast(this);
        }
    }

BoatController用于控制船的对象

    public class BoatController
    {
        readonly GameObject boat;
        readonly Moveable moveableScript;
        readonly Vector3 fromPosition = new Vector3(3.0f, 0.8f, 0);
        readonly Vector3 toPosition = new Vector3(-3.0f, 0.8f, 0);
        readonly Vector3[] from_positions;
        readonly Vector3[] to_positions;

        int to_or_from; 
        // to->-1; from->1
        MyCharacterController[] passenger = new MyCharacterController[2];

        public BoatController()
        {
            to_or_from = 1;

            from_positions = new Vector3[] { new Vector3(2.5F, 2.0F, 0), new Vector3(3.5F, 2.0F, 0) };
            to_positions = new Vector3[] { new Vector3(-2.5F, 2.0F, 0), new Vector3(-3.5F, 2.0F, 0) };

            boat = Object.Instantiate(Resources.Load("Perfabs/Boat", typeof(GameObject)), fromPosition, Quaternion.identity, null) as GameObject;
            boat.name = "boat";

            moveableScript = boat.AddComponent(typeof(Moveable)) as Moveable;
            boat.AddComponent(typeof(ClickGUI));
        }


        public void Move()
        {
            if (to_or_from == -1)
            {
                moveableScript.setDestination(fromPosition);
                to_or_from = 1;
            }
            else
            {
                moveableScript.setDestination(toPosition);
                to_or_from = -1;
            }
        }

        public int getEmptyIndex()
        {
            for (int i = 0; i < passenger.Length; i++)
            {
                if (passenger[i] == null)
                {
                    return i;
                }
            }
            return -1;
        }

        public bool isEmpty()
        {
            for (int i = 0; i < passenger.Length; i++)
            {
                if (passenger[i] != null)
                {
                    return false;
                }
            }
            return true;
        }

        public Vector3 getEmptyPosition()
        {
            Vector3 pos;
            int emptyIndex = getEmptyIndex();
            if (to_or_from == -1)
            {
                pos = to_positions[emptyIndex];
            }
            else
            {
                pos = from_positions[emptyIndex];
            }
            return pos;
        }

        public void GetOnBoat(MyCharacterController characterCtrl)
        {
            int index = getEmptyIndex();
            passenger[index] = characterCtrl;
        }

        public MyCharacterController GetOffBoat(string passenger_name)
        {
            for (int i = 0; i < passenger.Length; i++)
            {
                if (passenger[i] != null && passenger[i].getName() == passenger_name)
                {
                    MyCharacterController charactorCtrl = passenger[i];
                    passenger[i] = null;
                    return charactorCtrl;
                }
            }
            return null;
        }

        public GameObject getGameobj()
        {
            return boat;
        }

        public int get_to_or_from()
        {
            return to_or_from;
        }

        public int[] getCharacterNum()
        {
            int[] count = { 0, 0 };
            for (int i = 0; i < passenger.Length; i++)
            {
                if (passenger[i] == null)
                    continue;
                if (passenger[i].getType() == 0)
                { 
                    count[0]++;
                }
                else
                {
                    count[1]++;
                }
            }
            return count;
        }

        public void reset()
        {
            moveableScript.reset();
            if (to_or_from == -1)
            {
                Move();
            }
            passenger = new MyCharacterController[2];
        }
    }

CoastController用于控制河岸对象

    public class CoastController
    {
        readonly GameObject coast;
        readonly Vector3 from_pos = new Vector3(9, -2, 0);
        readonly Vector3 to_pos = new Vector3(-9, -2, 0);
        readonly Vector3[] positions;
        readonly int to_or_from;    // to->-1, from->1

        // change frequently
        MyCharacterController[] passengerPlaner;

        public CoastController(string _to_or_from)
        {
            positions = new Vector3[] {
                new Vector3(5.4F,2.4F,0),
                new Vector3(6.6F,2.4F,0),
                new Vector3(7.8F,2.4F,0),
                new Vector3(9.0F,2.4F,0),
                new Vector3(10.2F,2.4F,0),
                new Vector3(11.4F,2.4F,0)};

            passengerPlaner = new MyCharacterController[6];

            if (_to_or_from == "from")
            {
                coast = Object.Instantiate(Resources.Load("Perfabs/Stone", typeof(GameObject)), from_pos, Quaternion.identity, null) as GameObject;
                coast.name = "from";
                to_or_from = 1;
            }
            else
            {
                coast = Object.Instantiate(Resources.Load("Perfabs/Stone", typeof(GameObject)), to_pos, Quaternion.identity, null) as GameObject;
                coast.name = "to";
                to_or_from = -1;
            }
        }

        public int getEmptyIndex()
        {
            for (int i = 0; i < passengerPlaner.Length; i++)
            {
                if (passengerPlaner[i] == null)
                {
                    return i;
                }
            }
            return -1;
        }

        public Vector3 getEmptyPosition()
        {
            Vector3 pos = positions[getEmptyIndex()];
            pos.x *= to_or_from;
            return pos;
        }

        public void getOnCoast(MyCharacterController characterCtrl)
        {
            int index = getEmptyIndex();
            passengerPlaner[index] = characterCtrl;
        }

        public MyCharacterController getOffCoast(string passenger_name)
        {   // 0->priest, 1->devil
            for (int i = 0; i < passengerPlaner.Length; i++)
            {
                if (passengerPlaner[i] != null && passengerPlaner[i].getName() == passenger_name)
                {
                    MyCharacterController charactorCtrl = passengerPlaner[i];
                    passengerPlaner[i] = null;
                    return charactorCtrl;
                }
            }
            return null;
        }

        public int get_to_or_from()
        {
            return to_or_from;
        }

        public int[] getCharacterNum()
        {
            int[] count = { 0, 0 };
            for (int i = 0; i < passengerPlaner.Length; i++)
            {
                if (passengerPlaner[i] == null)
                    continue;
                if (passengerPlaner[i].getType() == 0)
                {   // 0->priest, 1->devil
                    count[0]++;
                }
                else
                {
                    count[1]++;
                }
            }
            return count;
        }

        public void reset()
        {
            passengerPlaner = new MyCharacterController[6];
        }
    }

最后是FirstController和UserGUI和ClickGUI的代码

public class FirstController : MonoBehaviour, SceneController, UserAction {
    /*动态常量 readonly*/
	readonly Vector3 water_pos = new Vector3(0,-2.0F,0);
    readonly Vector3 background_pos = new Vector3(0, 0, 20);


	UserGUI userGUI;
    public BackgroundController Background;
	public CoastController fromCoast;
	public CoastController toCoast;
	public BoatController boat;
	private MyCharacterController[] characters;

	void Awake() {
		Director director = Director.getInstance ();
		director.currentSceneController = this;
		userGUI = gameObject.AddComponent () as UserGUI;
		characters = new MyCharacterController[6];
        loadBackground();
		loadResources ();
	}

    public void loadBackground()
    {
        /*创造背景*/
        Background = new BackgroundController();
        Background.setPosition(background_pos);
    }

	public void loadResources() {
        /*在Resources文件夹中加载Water,只有GameObject类型的才被加载,加载到water_pos的位置,无旋转,完全对齐于世界*/
		GameObject water = Instantiate (Resources.Load ("Perfabs/Water", typeof(GameObject)), water_pos, Quaternion.identity, null) as GameObject;
		water.name = "water";

        /*创造两个对岸*/
		fromCoast = new CoastController ("from");
		toCoast = new CoastController ("to");

        /*创造船*/
		boat = new BoatController ();

        /*创造牧师与魔鬼*/
		loadCharacter ();
	}

	private void loadCharacter() {
		for (int i = 0; i < 3; i++) {
			MyCharacterController Character = new MyCharacterController ("priest");
            Character.setName("priest" + i);
            Character.setPosition (fromCoast.getEmptyPosition ());
            Character.getOnCoast (fromCoast);
			fromCoast.getOnCoast (Character);

			characters [i] = Character;
		}

		for (int i = 0; i < 3; i++) {
			MyCharacterController Character = new MyCharacterController ("devil");
            Character.setName("devil" + i);
            Character.setPosition (fromCoast.getEmptyPosition ());
            Character.getOnCoast (fromCoast);
			fromCoast.getOnCoast (Character);

			characters [i+3] = Character;
		}
	}


	public void moveBoat() {
		if (boat.isEmpty ()) return;
		boat.Move ();
		userGUI.status = check_game_over ();
	}

	public void characterIsClicked(MyCharacterController characterCtrl) {
		if (characterCtrl.isOnBoat ()) {
			CoastController whichCoast;
			if (boat.get_to_or_from () == -1) { // to->-1; from->1
				whichCoast = toCoast;
			} else {
				whichCoast = fromCoast;
			}

			boat.GetOffBoat (characterCtrl.getName());
			characterCtrl.moveToPosition (whichCoast.getEmptyPosition ());
			characterCtrl.getOnCoast (whichCoast);
			whichCoast.getOnCoast (characterCtrl);

		} else {
			CoastController whichCoast = characterCtrl.getCoastController ();

			if (boat.getEmptyIndex () == -1) {
				return;
			}

			if (whichCoast.get_to_or_from () != boat.get_to_or_from ())	
                // boat is not on the side of character
				return;

			whichCoast.getOffCoast(characterCtrl.getName());
			characterCtrl.moveToPosition (boat.getEmptyPosition());
			characterCtrl.getOnBoat (boat);
			boat.GetOnBoat (characterCtrl);
		}
		userGUI.status = check_game_over ();
	}

    public bool isGameOver()
    {
        return check_game_over() != 0;
    }

	int check_game_over() {
		int from_priest = 0;
		int from_devil = 0;
		int to_priest = 0;
		int to_devil = 0;

		int[] fromCount = fromCoast.getCharacterNum ();
		from_priest += fromCount[0];
		from_devil += fromCount[1];

		int[] toCount = toCoast.getCharacterNum ();
		to_priest += toCount[0];
		to_devil += toCount[1];

		if (to_priest + to_devil == 6)
			return 2;

		int[] boatCount = boat.getCharacterNum ();
		if (boat.get_to_or_from () == -1)
        {	
			to_priest += boatCount[0];
			to_devil += boatCount[1];
		}
        else
        {	
			from_priest += boatCount[0];
			from_devil += boatCount[1];
		}
		if (from_priest < from_devil && from_priest > 0)
        {
			return 1;
		}
		if (to_priest < to_devil && to_priest > 0)
        {
			return 1;
		}
		return 0;
	}

	public void restart() {
		boat.reset ();
		fromCoast.reset ();
		toCoast.reset ();
		for (int i = 0; i < characters.Length; i++) {
			characters [i].reset ();
		}
	}
}

ClickGUI和UserGUI的代码如下:

public class UserGUI : MonoBehaviour {
	private UserAction Player;
	public int status = 0;
	GUIStyle style;
	GUIStyle Button;

	void Start() {
		Player = Director.getInstance ().currentSceneController as UserAction;

		style = new GUIStyle();
		style.fontSize = 40;
		style.alignment = TextAnchor.MiddleCenter;

        Button = new GUIStyle("button");
        Button.fontSize = 30;
	}
	void OnGUI() {
		if (status == 1) {
			GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "Gameover!", style);
			if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Restart", Button)) {
				status = 0;
				Player.restart ();
			}
		} else if(status == 2) {
			GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "You win!", style);
			if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Restart", Button)) {
				status = 0;
				Player.restart ();
			}
		}

        if (GUI.Button(new Rect(0, 0, 150, 50), "Reset"))
        {
            Player.restart();
        }
	}
}
public class ClickGUI : MonoBehaviour {
	UserAction Player;
	MyCharacterController characterController;

	public void setController(MyCharacterController characterCtrl) {
		characterController = characterCtrl;
	}

	void Start() {
        Player = Director.getInstance ().currentSceneController as UserAction;
	}

    void OnMouseDown() {
        if(!Player.isGameOver())
        {
            if (gameObject.name == "boat")
            {
                Player.moveBoat();
            }
            else
            {
                Player.characterIsClicked(characterController);
            }
        }

	}
}

最后的效果图如下所示,虽然大部分代码都是参考师兄的....但是感觉还是在搬砖过程中了解到不少东西....

Unity3D课程学习笔记(二)_第6张图片

 

你可能感兴趣的:(Unity3D)