Unity 中常用的游戏对象主要有以下几类:
每个对象都有 Active、Name、Tag、Layer、Transform 等基本属性,用于控制游戏对象的渲染、样式、位置等等。也可给游戏对象添加脚本,赋予其行为方式,实现 UI 交互。
动作分离:可以通过对游戏对象增加可执行的动作,可以划分出很多的基础动作,如上船、下船等,提取基础动作,然后使用类的方法来执行游戏对象的动作,同时通过配备动作管理者,让其调度游戏对象执行动作。
动作管理者 SSActionManager:通过创建类来管理动作的集合,展示了集合对象的使用方法。管理 SequenceAction 和 SSAction,传递游戏对象,控制游戏对象做动作和切换动作。SSActionManager 继承了 ISSActionCallback 接口,通过这个接口,当动作做完时会告诉 SSActionManager,SSActionManager 决定如何执行下一个动作。实现代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSActionManager : MonoBehaviour {
private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
private List<SSAction> waitingAdd = new List<SSAction>();
private List<int> waitingDelete = new List<int>();
// Use this for initialization
protected void Start () {
}
// Update is called once per frame
protected void Update () {
foreach(SSAction ac in waitingAdd)
{
actions[ac.GetInstanceID()] = ac;
}
waitingAdd.Clear();
foreach(KeyValuePair<int, SSAction> kv in actions)
{
SSAction ac = kv.Value;
if(ac.destroy)
{
waitingDelete.Add(ac.GetInstanceID());// release action
ac.destroy = false;
}
else if(ac.enable)
{
ac.Update(); // update action
}
}
foreach (int key in waitingDelete)
{
SSAction ac = actions[key];
actions.Remove(key);
DestroyObject(ac);
Debug.Log("delete");
}
waitingDelete.Clear();
}
public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager)
{
action.gameobject = gameobject;
action.transform = gameobject.transform;
action.callback = manager;
waitingAdd.Add(action);
action.Start();
}
}
组合动作实现 CCSequenceAction:SequenceAction 继承了 ISSActionCallback,因为组合动作是每一个动作的顺序完成,它管理这一连串动作中的每一个小的动作,所以当每个小的动作完成时,也要发消息告诉它,它得到消息后去处理下一个动作。SequenceAction 也继承了 SSAction,因为组合动作需要游戏对象,需要标识是否摧毁,有一个组合动作的管理者的接口。实现代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCSequenceAction : SSAction, ISSActionCallback {
public List<SSAction> sequence;
public int repeat = -1;//repeat forever
public int start = 0;
public static CCSequenceAction GetSSAction(int repeat, int start, List<SSAction> sequence)
{
CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();
action.repeat = repeat;
action.sequence = sequence;
action.start = 0;
return action;
}
// Use this for initialization
public override void Start () {
foreach (SSAction action in sequence)
{
action.gameobject = this.gameobject;
action.transform = this.transform;
action.callback = this;
action.Start();
}
}
// Update is called once per frame
public override void Update () {
if (sequence.Count == 0) return;
if(start < sequence.Count)
{
sequence[start].Update();
}
}
public void SSActionEvent (SSAction source, SSActionEventType events = SSActionEventType.Completed, int intParam = 0, string strParam = null, Object objectParam = null)
{
source.destroy = false;
this.start++;
if(this.start >= sequence.Count)
{
this.start = 0;
if (repeat > 0) repeat--;
if(repeat == 0)
{
this.destroy = true;
this.callback.SSActionEvent(this);
}
}
}
void OnDestroy()
{
//TODO: something
}
}
移动动作实现 CCMoveToAction:以速度 speed 向目的地 target 移动。实现代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCMoveToAction : SSAction {
public Vector3 target;
public static CCMoveToAction GetSSAction(Vector3 target)
{
CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();
action.target = target;
return action;
}
// Use this for initialization
public override void Start () {
}
// Update is called once per frame
public override void Update () {
this.transform.position = Vector3.MoveTowards(this.transform.position, target, Time.deltaTime * 2);
if (this.transform.position == target)
{
this.destroy = true;
this.callback.SSActionEvent(this);
}
}
}
动作基类 SSAction:继承了 ScriptableObject。实现代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSAction : ScriptableObject {
public bool enable = true;
public bool destroy = false;
public GameObject gameobject { get; set; }
public Transform transform { get; set; }
public ISSActionCallback callback { get; set; }
protected SSAction() {}
// Use this for initialization
public virtual void Start () {
throw new System.NotImplementedException();
}
// Update is called once per frame
public virtual void Update () {
throw new System.NotImplementedException();
}
}
SSDirector:移动游戏对象。实现代码如下:
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;
}
}
FirstConstroller 实现代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//游戏中提及的事物:牧师、恶魔、船、河、岸
//玩家动作:点击恶魔、点击牧师、点击船、点击重新开始按钮
public class FirstController : MonoBehaviour, ISceneController, devilAction, priestAction, boatAction
{
public CCActionManager actionManager;
public bool boat_is_right = true;
public bool boat_left_empty = true;
public bool boat_right_empty = true;
List<bool> right_position_empty = new List<bool>();
List<bool> left_position_empty = new List<bool>();
public bool boat_move_to_left;
public bool boat_move_to_right;
public GameObject boat_to_be_moved = null;
public GameObject right_on_boat = null;
public GameObject left_on_boat = null;
public int left_devil_count;
public int left_priest_count;
public int right_devil_count;
public int right_priest_count;
public bool game_over;
public string left_type = null;
public string right_type = null;
public GameObject priest1;
public GameObject priest2;
public GameObject priest3;
public GameObject devil1;
public GameObject devil2;
public GameObject devil3;
public GameObject boat;
public bool win;
public float time;
// the first scripts
void Awake()
{
left_devil_count = 0;
left_priest_count = 0;
right_priest_count = 3;
right_devil_count = 3;
game_over = false;
int i;
for (i = 0; i < 6; i++)
{
right_position_empty.Add(false);
left_position_empty.Add(true);
//right_position_empty[i] = false;
//left_position_empty[i] = true;
}
SSDirector director = SSDirector.getInstance();
director.setFPS(60);
director.currentSceneController = this;
director.currentSceneController.LoadResources();
boat_move_to_right = false;
boat_move_to_left = false;
win = false;
Debug.Log("left_priest:" + left_priest_count.ToString());
Debug.Log("left_devil:" + left_devil_count.ToString());
Debug.Log("right_priest:" + right_priest_count.ToString());
Debug.Log("right_devil:" + right_devil_count.ToString());
}
// loading resources for first scene
public void LoadResources()
{
GameObject left_land = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/land"));
left_land.name = "left_land";
left_land.transform.position = new Vector3(-left_land.transform.position.x, left_land.transform.position.y, left_land.transform.position.z);
GameObject right_land = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/land"));
left_land.name = "right_land";
GameObject river = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/river"));
river.name = "river";
priest1 = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/priest"));
priest1.name = "priest1";
priest1.transform.position = new Vector3(6, priest1.transform.position.y, priest1.transform.position.z);
priest2 = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/priest"));
priest2.name = "priest2";
priest2.transform.position = new Vector3(7, priest2.transform.position.y, priest2.transform.position.z);
priest3 = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/priest"));
priest3.name = "priest3";
priest3.transform.position = new Vector3(8, priest3.transform.position.y, priest3.transform.position.z);
devil1 = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/devil"));
devil1.name = "devil1";
devil1.transform.position = new Vector3(9, devil1.transform.position.y, devil1.transform.position.z);
devil2 = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/devil"));
devil2.name = "devil2";
devil2.transform.position = new Vector3(10, devil2.transform.position.y, devil2.transform.position.z);
devil3 = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/devil"));
devil3.name = "devil3";
devil3.transform.position = new Vector3(11, devil3.transform.position.y, devil3.transform.position.z);
boat = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/boat"));
boat.name = "boat";
}
public void Restart()
{
boat_is_right = true;
boat_left_empty = true;
boat_right_empty = true;
int i;
for (i = 0; i < 6; i++)
{
right_position_empty[i] = false;
left_position_empty[i] = true;
}
boat_move_to_right = false;
boat_move_to_left = false;
boat_to_be_moved = null;
right_on_boat = null;
left_on_boat = null;
left_devil_count = 0;
left_priest_count = 0;
right_devil_count = 3;
right_priest_count = 3;
game_over = false;
left_type = null;
right_type = null;
priest1.transform.position = new Vector3(6, 2.5f, 0);
priest2.transform.position = new Vector3(7, 2.5f, 0);
priest3.transform.position = new Vector3(8, 2.5f, 0);
devil1.transform.position = new Vector3(9, 2.5f, 0);
devil2.transform.position = new Vector3(10, 2.5f, 0);
devil3.transform.position = new Vector3(11, 2.5f, 0);
boat.transform.position = new Vector3(3, 0, 0);
win = false;
time = 60;
StartCoroutine(Timer());
}
public void devil_move(GameObject obj)
{
if (boat_move_to_left || boat_move_to_right || game_over || win)
{
return;
}
if (boat_is_right)
{
if (obj.transform.position.x >= 6)
{
if (boat_left_empty)
{
//Debug.Log((int)obj.transform.position.x - 6);
right_position_empty[(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(2, 2, 0);
boat_left_empty = false;
left_on_boat = obj;
left_type = "devil";
}
else if (boat_right_empty)
{
right_position_empty[(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(4, 2, 0);
boat_right_empty = false;
right_on_boat = obj;
right_type = "devil";
}
}
else if (obj.transform.position.x >= 2 && obj.transform.position.x <= 4)
{
if (obj.transform.position.x == 2)
{
boat_left_empty = true;
left_on_boat = null;
left_type = null;
}
else
{
boat_right_empty = true;
right_on_boat = null;
right_type = null;
}
int i;
for (i = 0; i < 6; i++)
{
if (right_position_empty[i])
{
obj.transform.position = new Vector3(i + 6, 2.5f, 0);
right_position_empty[i] = false;
break;
}
}
}
}
else
{
if (obj.transform.position.x <= -6)
{
if (boat_left_empty)
{
left_position_empty[-(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(-4, 2, 0);
boat_left_empty = false;
left_on_boat = obj;
left_type = "devil";
}
else if (boat_right_empty)
{
left_position_empty[-(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(-2, 2, 0);
boat_right_empty = false;
right_on_boat = obj;
right_type = "devil";
}
}
else if (obj.transform.position.x >= -4 && obj.transform.position.x <= -2)
{
if (obj.transform.position.x == -4)
{
boat_left_empty = true;
left_on_boat = null;
left_type = null;
}
else
{
boat_right_empty = true;
right_on_boat = null;
right_type = null;
}
int i;
for (i = 0; i < 6; i++)
{
if (left_position_empty[i])
{
//Debug.Log((int)obj.transform.position.x - 6);
obj.transform.position = new Vector3(-i - 6, 2.5f, 0);
left_position_empty[i] = false;
break;
}
}
}
}
}
public void priest_move(GameObject obj)
{
if (boat_move_to_left || boat_move_to_right || game_over || win)
{
return;
}
if (boat_is_right)
{
if (obj.transform.position.x >= 6)
{
if (boat_left_empty)
{
Debug.Log((int)obj.transform.position.x - 6);
right_position_empty[(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(2, 2, 0);
boat_left_empty = false;
left_on_boat = obj;
left_type = "priest";
}
else if (boat_right_empty)
{
right_position_empty[(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(4, 2, 0);
boat_right_empty = false;
right_on_boat = obj;
right_type = "priest";
}
}
else if (obj.transform.position.x >= 2 && obj.transform.position.x <= 4)
{
if (obj.transform.position.x == 2)
{
boat_left_empty = true;
left_on_boat = null;
left_type = null;
}
else
{
boat_right_empty = true;
right_on_boat = null;
right_type = null;
}
int i;
for (i = 0; i < 6; i++)
{
if (right_position_empty[i])
{
obj.transform.position = new Vector3(i + 6, 2.5f, 0);
right_position_empty[i] = false;
break;
}
}
}
}
else
{
if (obj.transform.position.x <= -6)
{
if (boat_left_empty)
{
left_position_empty[-(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(-4, 2, 0);
boat_left_empty = false;
left_on_boat = obj;
left_type = "priest";
}
else if (boat_right_empty)
{
left_position_empty[-(int)obj.transform.position.x - 6] = true;
obj.transform.position = new Vector3(-2, 2, 0);
boat_right_empty = false;
right_on_boat = obj;
right_type = "priest";
}
}
else if (obj.transform.position.x >= -4 && obj.transform.position.x <= -2)
{
if (obj.transform.position.x == -4)
{
boat_left_empty = true;
left_on_boat = null;
left_type = null;
}
else
{
boat_right_empty = true;
right_on_boat = null;
right_type = null;
}
int i;
for (i = 0; i < 6; i++)
{
if (left_position_empty[i])
{
obj.transform.position = new Vector3(-i - 6, 2.5f, 0);
left_position_empty[i] = false;
break;
}
}
}
}
}
public void boat_move(GameObject boat)
{
if (boat_move_to_left || boat_move_to_right || game_over || win)
{
Debug.Log("error!");
return;
}
if (left_type != null || right_type != null)
{
if (boat_is_right)
{
//boat_to_be_moved = boat;
boat_move_to_left = true;
actionManager.RunAction(boat, actionManager.boatToLeft,actionManager);
Debug.Log("toLeft");
if (left_on_boat != null)
actionManager.RunAction(this.left_on_boat, actionManager.leftToLeft, actionManager);
if (right_on_boat != null)
actionManager.RunAction(right_on_boat, actionManager.rightToLeft, actionManager);
boat_is_right = false;
if (left_type == "devil")
{
left_devil_count++;
right_devil_count--;
}
else if (left_type == "priest")
{
left_priest_count++;
right_priest_count--;
}
if (right_type == "devil")
{
left_devil_count++;
right_devil_count--;
}
else if (right_type == "priest")
{
left_priest_count++;
right_priest_count--;
}
}
else
{
//boat_to_be_moved = boat;
boat_move_to_right = true;
actionManager.RunAction(boat, actionManager.boatToRight, actionManager);
if (left_on_boat != null)
actionManager.RunAction(this.left_on_boat, actionManager.leftToRight, actionManager);
if (right_on_boat != null)
actionManager.RunAction(right_on_boat, actionManager.rightToRight, actionManager);
boat_is_right = true;
if (left_type == "devil")
{
left_devil_count--;
right_devil_count++;
}
else if (left_type == "priest")
{
left_priest_count--;
right_priest_count++;
}
if (right_type == "devil")
{
left_devil_count--;
right_devil_count++;
}
else if (right_type == "priest")
{
left_priest_count--;
right_priest_count++;
}
}
}
Debug.Log("left_priest:" + left_priest_count.ToString());
Debug.Log("left_devil:" + left_devil_count.ToString());
Debug.Log("right_priest:" + right_priest_count.ToString());
Debug.Log("right_devil:" + right_devil_count.ToString());
}
public void game_over_judge()
{
if ((right_devil_count > right_priest_count && right_priest_count != 0) || (left_devil_count > left_priest_count && left_priest_count != 0))
{
game_over = true;
time = 0;
}
else if (left_priest_count == 3 && left_devil_count == 3)
{
win = true;
time = 0;
}
}
// Use this for initialization
void Start()
{
time = 60;
StartCoroutine(Timer());
}
public IEnumerator Timer()
{
while (time > 0)
{
yield return new WaitForSeconds(1);
print(time);
time--;
}
game_over = true;
}
// Update is called once per frame
void Update()
{
/*if (boat_move_to_left && boat_to_be_moved != null)
{
this.boat_to_be_moved.transform.position = Vector3.MoveTowards(this.boat_to_be_moved.transform.position, new Vector3(-3, 0, 0), Time.deltaTime * 2);
if (left_on_boat != null)
this.left_on_boat.transform.position = Vector3.MoveTowards(this.left_on_boat.transform.position, new Vector3(-4, 2, 0), Time.deltaTime * 2);
if (right_on_boat != null)
this.right_on_boat.transform.position = Vector3.MoveTowards(this.right_on_boat.transform.position, new Vector3(-2, 2, 0), Time.deltaTime * 2);
if (this.boat_to_be_moved.transform.position == new Vector3(-3, 0, 0))
{
boat_move_to_left = false;
game_over_judge();
}
}
if (boat_move_to_right && boat_to_be_moved != null)
{
this.boat_to_be_moved.transform.position = Vector3.MoveTowards(this.boat_to_be_moved.transform.position, new Vector3(3, 0, 0), Time.deltaTime * 2);
if (left_on_boat != null)
this.left_on_boat.transform.position = Vector3.MoveTowards(this.left_on_boat.transform.position, new Vector3(2, 2, 0), Time.deltaTime * 2);
if (right_on_boat != null)
this.right_on_boat.transform.position = Vector3.MoveTowards(this.right_on_boat.transform.position, new Vector3(4, 2, 0), Time.deltaTime * 2);
if (this.boat_to_be_moved.transform.position == new Vector3(3, 0, 0))
{
boat_move_to_right = false;
game_over_judge();
}
}*/
}
void OnGUI()
{
GUI.Box(new Rect(Screen.width / 2 - 75, 10, 150, 40), "Left Time: \n" + time.ToString());
if (game_over)
{
GUI.Window(0, new Rect(Screen.width / 2 - Screen.width / 12, Screen.height / 2 - Screen.height / 12, Screen.width / 6, Screen.height / 6), game_over_window, "Game Over!");
}
if (win)
{
GUI.Window(0, new Rect(Screen.width / 2 - Screen.width / 12, Screen.height / 2 - Screen.height / 12, Screen.width / 6, Screen.height / 6), win_window, "You Win!");
}
}
void game_over_window(int id)
{
if (GUI.Button(new Rect(Screen.width / 24, Screen.height / 24 + 5, Screen.width / 12, Screen.height / 12), "Restart"))
{
Debug.Log("Restart");
Restart();
}
}
void win_window(int id)
{
if (GUI.Button(new Rect(Screen.width / 24, Screen.height / 24 + 5, Screen.width / 12, Screen.height / 12), "Restart"))
{
Debug.Log("Restart");
Restart();
}
}
}