1、基本操作演练
- 下载 Fantasy Skybox FREE, 构建自己的游戏场景
下载天空盒,并将其导入
创建 Material (Assets 上下文菜单 -> create -> Material) 起名 mysky,并在Inspector中选择Shader -> Skybox -> 6Sided
在资源贴图中,选择对应位置的贴图,将其放入右侧的空格中
运行后效果如下
还能通过Terrain构建地形以及添加植物等
- 写一个简单的总结,总结游戏对象的使用
游戏对象是所有其他组件的容器,游戏中的所有对象本质上都是游戏对象。
游戏对象主要包括:
实体对象:如3d object的球、方块等
辅助对象:如camera摄像机、light光线、audio声音等
2、编程实践
牧师与魔鬼 动作分离版
UML类图
动作基类(SSAction)
- ScriptableObject 是不需要绑定 GameObject 对象的可编程基类。这些对象受 Unity 引擎场景管理
- protected 防止用户自己 new 对象
- 使用 virtual 申明虚方法,通过重写实现多态。这样继承者就明确使用 Start 和 Update 编程游戏对象行为
- 利用接口(ISSACtionCallback)实现消息通知,避免与动作管理者直接依赖
public class SSAction : ScriptableObject
{
public bool enable = true;
public bool destroy = false;
public GameObject gameObject;
public Transform transform;
public SSActionCallback CallBack;
public virtual void Start()
{
throw new System.NotImplementedException();
}
public virtual void Update()
{
throw new System.NotImplementedException();
}
}
简单动作实现(CCMoveToAction)
- 实现具体动作,将一个物体移动到目标位置,并通知任务完成
public class CCMoveToAction : SSAction
{
public Vector3 target;
public float speed;
private CCMoveToAction() { }
public static CCMoveToAction getAction(Vector3 target, float speed)
{
CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();
action.target = target;
action.speed = speed;
return action;
}
public override void Update()
{
this.transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
if (transform.position == target)
{
destroy = true;
CallBack.SSActionCallback(this);
}
}
public override void Start()
{
}
}
顺序动作组合类实现(CCSequenceAction)
- 实现一个动作组合序列,顺序播放动作:
public class CCSequenceAction : SSAction, SSActionCallback
{
public List<SSAction> sequence;
public int repeat = 1;
public int currentActionIndex = 0;
public static CCSequenceAction getAction(int repeat, int currentActionIndex, List<SSAction> sequence)
{
CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();
action.sequence = sequence;
action.repeat = repeat;
action.currentActionIndex = currentActionIndex;
return action;
}
public override void Update()
{
if (sequence.Count == 0) return;
if (currentActionIndex < sequence.Count)
{
sequence[currentActionIndex].Update();
}
}
public void SSActionCallback(SSAction source)
{
source.destroy = false;
this.currentActionIndex++;
if (this.currentActionIndex >= sequence.Count)
{
this.currentActionIndex = 0;
if (repeat > 0) repeat--;
if (repeat == 0)
{
this.destroy = true;
this.CallBack.SSActionCallback(this);
}
}
}
public override void Start()
{
foreach (SSAction action in sequence)
{
action.gameObject = this.gameObject;
action.transform = this.transform;
action.CallBack = this;
action.Start();
}
}
void OnDestroy()
{
foreach (SSAction action in sequence)
{
DestroyObject(action);
}
}
}
动作管理基类(SSActionManager)
- 这是动作对象管理器的基类,实现了所有动作的基本管理:
public class SSActionManager : MonoBehaviour
{
private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
private List<SSAction> waitingToAdd = new List<SSAction>();
private List<int> watingToDelete = new List<int>();
protected void Update()
{
foreach (SSAction ac in waitingToAdd)
{
actions[ac.GetInstanceID()] = ac;
}
waitingToAdd.Clear();
foreach (KeyValuePair<int, SSAction> kv in actions)
{
SSAction ac = kv.Value;
if (ac.destroy)
{
watingToDelete.Add(ac.GetInstanceID());
}
else if (ac.enable)
{
ac.Update();
}
}
foreach (int key in watingToDelete)
{
SSAction ac = actions[key];
actions.Remove(key);
DestroyObject(ac);
}
watingToDelete.Clear();
}
public void addAction(GameObject gameObject, SSAction action, SSActionCallback ICallBack)
{
action.gameObject = gameObject;
action.transform = gameObject.transform;
action.CallBack = ICallBack;
waitingToAdd.Add(action);
action.Start();
}
}
动作管理器(FirstSceneActionManager)
- 管理船和游戏角色的移动,这个类体现了动作分离的思想
public class FirstSceneActionManager : SSActionManager, SSActionCallback
{
public SSActionEventType Complete = SSActionEventType.Completed;
public void BoatMove(BoatController Boat)
{
Complete = SSActionEventType.Started;
CCMoveToAction action = CCMoveToAction.getAction(Boat.GetDestination(), Boat.GetMoveSpeed());
addAction(Boat.GetGameObject(), action, this);
Boat.ChangeState();
}
public void GameObjectsMove(GameObjects GameObject, Vector3 Destination)
{
Complete = SSActionEventType.Started;
Vector3 CurrentPos = GameObject.GetPosition();
Vector3 MiddlePos = CurrentPos;
if (Destination.y > CurrentPos.y)
{
MiddlePos.y = Destination.y;
}
else
{
MiddlePos.x = Destination.x;
}
SSAction action1 = CCMoveToAction.getAction(MiddlePos, GameObject.GetMoveSpeed());
SSAction action2 = CCMoveToAction.getAction(Destination, GameObject.GetMoveSpeed());
SSAction seqAction = CCSequenceAction.getAction(1, 0, new List<SSAction> { action1, action2 });
this.addAction(GameObject.GetGameobject(), seqAction, this);
}
public void SSActionCallback(SSAction source)
{
Complete = SSActionEventType.Completed;
}
}