bilibili:https://www.bilibili.com/video/BV1ad4y1x7uU/
gitee:https://gitee.com/lin-fengnian/3dgame/tree/master/UFO2/Assets
任务要求:
改进UFO,按 adapter模式 设计图修改飞碟游戏,使它同时支持物理运动与运动学(变换)运动。
实现过程:
- 添加新增 IActionManager.cs文件作为接口。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IActionManager
{
void Fly(GameObject saucer, float speed, Vector3 direction);
}
- 新增 PhysisFlyAction.cs文件
用钢体和物理引擎实现驱动。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysisFlyAction : SSAction
{
float speed;
Vector3 direction;
public static PhysisFlyAction GetSSAction(Vector3 direction, float speed)
{
PhysisFlyAction action = ScriptableObject.CreateInstance<PhysisFlyAction>();
action.speed = speed;
action.direction = direction;
return action;
}
public override void Start()
{
gameObject.GetComponent<Rigidbody>().isKinematic = false;
gameObject.GetComponent<Rigidbody>().velocity = speed * direction;
}
public override void Update()
{
if (this.transform.position.y < -6)
{
this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this);
}
}
}
注意在此处添加缸体rigidBody
- 新增 PhysisActionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysisActionManager : SSActionManager, ISSActionCallback, IActionManager
{
PhysisFlyAction flyAction;
FirstController controller;
protected new void Start()
{
controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
}
public void Fly(GameObject disk, float speed, Vector3 direction)
{
flyAction = PhysisFlyAction.GetSSAction(direction, speed);
RunAction(disk, flyAction, this);
}
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Competed,
int intParam = 0,
string strParam = null,
Object objectParam = null)
{
controller.FreeSaucer(source.gameObject);
}
}
- 新增 RController.cs,用于代替原先FirstController 每回合发射飞盘、计分、轮次增加等功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RController : MonoBehaviour
{
FirstController controller;
IActionManager actionManager;
SaucerFactory saucerFactory;
UserGUI userGUI;
int[] roundDisks;
int mode;
int points;
int round;
int count;
float sendTime;
void Start()
{
controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
actionManager = Singleton<ActionManager>.Instance;
saucerFactory = Singleton<SaucerFactory>.Instance;
userGUI = Singleton<UserGUI>.Instance;
roundDisks = new int[] { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
points = 0;
round = 1;
count = 0;
sendTime = 0;
mode = 1;
}
public int GetPoints()
{
return points;
}
public void SetMode(int mode)
{
this.mode = mode;
}
public void Reset()
{
round = 1;
count = 0;
sendTime = 0;
mode = 1;
points = 0;
}
public void Record(SaucerData disk)
{
points += disk.points;
}
public void SetFlyMode(int flyMode)
{
actionManager = flyMode == 1 ? Singleton<PhysisActionManager>.Instance : Singleton<ActionManager>.Instance as IActionManager;
}
public void SendDisk(int mode)
{
GameObject saucer = saucerFactory.GetSaucer(round);
saucer.transform.position = new Vector3(-saucer.GetComponent<SaucerData>().direction.x * 7, UnityEngine.Random.Range(0f, 8f), 0);
saucer.SetActive(true);
if (mode == 0)
{
actionManager.Fly(saucer, saucer.GetComponent<SaucerData>().speed * 0.5f, saucer.GetComponent<SaucerData>().direction);
}
else if (mode == 2)
{
actionManager.Fly(saucer, saucer.GetComponent<SaucerData>().speed * 1.5f, saucer.GetComponent<SaucerData>().direction);
}
else
{
actionManager.Fly(saucer, saucer.GetComponent<SaucerData>().speed, saucer.GetComponent<SaucerData>().direction);
}
}
void Update()
{
sendTime += Time.deltaTime;
if (sendTime > 1)
{
sendTime = 0;
for (int i = 0; i < 5 && count < roundDisks[round - 1]; i++)
{
count++;
SendDisk(mode);
}
if (count == roundDisks[round - 1] && round < roundDisks.Length)
{
round++;
count = 0;
userGUI.SetRound(round);
}
if (count == roundDisks[round - 1] && round == roundDisks.Length)
{
if (mode == 3)
{
round = 1;
count = 0;
userGUI.SetResult("");
}
else
{
userGUI.SetResult("Game Over!");
}
}
}
}
}
- 修改 FlyAction.cs文件
飞盘到达游戏界面时通过摄像机监视,需要进行回收,竖直方向我们需要添加重力加速度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FlyAction : SSAction
{
float gravity;
float speed;
float time;
Vector3 direction;
public static FlyAction GetSSAction(Vector3 direction, float speed)
{
FlyAction action = ScriptableObject.CreateInstance<FlyAction>();
action.gravity = 10;
action.time = 0;
action.speed = speed;
action.direction = direction;
return action;
}
public override void Start()
{
gameObject.GetComponent<Rigidbody>().isKinematic = true;
}
public override void Update()
{
time += Time.deltaTime;
transform.Translate(Time.deltaTime * gravity * time * Vector3.down);
transform.Translate(direction * speed * Time.deltaTime);
if (this.transform.position.y < -7)
{
this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this);
}
}
}
- 修改 ActionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ActionManager : SSActionManager, ISSActionCallback, IActionManager
{
public FlyAction flyAction;
public FirstController controller;
protected new void Start()
{
controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
controller.actionManager = this;
}
public void Fly(GameObject disk, float speed, Vector3 direction)
{
flyAction = FlyAction.GetSSAction(direction, speed);
RunAction(disk, flyAction, this);
}
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Competed,
int para = 0,
string parastr = null,
Object obj = null)
{
controller.saucerFactory.FreeDisk(source.gameObject);
}
}
- 修改 IUserAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IUserAction
{
void Hit(Vector3 position);
void Restart();
void SetMode(int mode);
void SetFlyMode(int flyMode);
}
- 修改 FirstController.cs
添加hit函数处理点击事件,并添加分数记录。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstController : MonoBehaviour, ISceneController, IUserAction
{
public ActionManager actionManager;
public SaucerFactory saucerFactory;
RController roundController;
UserGUI userGUI;
void Start()
{
LoadResources();
}
public void LoadResources()
{
SSDirector.GetInstance().CurrentScenceController = this;
gameObject.AddComponent<SaucerFactory>();
gameObject.AddComponent<ActionManager>();
gameObject.AddComponent<PhysisActionManager>();
gameObject.AddComponent<RController>();
gameObject.AddComponent<UserGUI>();
saucerFactory = Singleton<SaucerFactory>.Instance;
roundController = Singleton<RController>.Instance;
userGUI = Singleton<UserGUI>.Instance;
}
public void Hit(Vector3 position)
{
RaycastHit[] Rayhits;
Camera camera = Camera.main;
Ray ray = camera.ScreenPointToRay(position);
Rayhits = Physics.RaycastAll(ray);
for (int i = 0; i < Rayhits.Length; i++)
{
RaycastHit ratCastHit = Rayhits[i];
if (ratCastHit.collider.gameObject.GetComponent<SaucerData>() != null)
{
ratCastHit.collider.gameObject.transform.position = new Vector3(0, -7, 0);
roundController.Record(ratCastHit.collider.gameObject.GetComponent<SaucerData>());
userGUI.SetPoints(roundController.GetPoints());
}
}
}
public void Restart()
{
userGUI.SetRound(0);
userGUI.SetMode(1);
userGUI.SetResult("");
userGUI.SetPoints(0);
userGUI.SetFlyMode(0);
roundController.Reset();
}
void Update()
{
}
public void SetMode(int mode)
{
roundController.SetMode(mode);
}
public void SetFlyMode(int flyMode)
{
roundController.SetFlyMode(flyMode);
}
public void FreeSaucer(GameObject disk)
{
saucerFactory.FreeDisk(disk);
}
}
- 修改 UserGUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserGUI : MonoBehaviour
{
private IUserAction userAction;
public string result;
public int points;
public int round;
public int mode;
public void SetResult(string result)
{
this.result = result;
}
public void SetPoints(int points)
{
this.points = points;
}
public void SetRound(int round)
{
this.round = round;
}
public void SetMode(int mode)
{
this.mode = mode;
}
public void SetFlyMode(int flyMode)
{
this.mode = flyMode;
}
void Start()
{
points = 0;
round = 1;
mode = 1;
result = "";
userAction = SSDirector.GetInstance().CurrentScenceController as IUserAction;
}
void OnGUI()
{
GUIStyle guiStyle = new GUIStyle();
guiStyle.fontSize = 50;
guiStyle.normal.textColor = Color.blue;
GUIStyle style = new GUIStyle();
style.normal.textColor = Color.white;
style.fontSize = 30;
GUIStyle resultStyle = new GUIStyle();
resultStyle.fontSize = 50;
resultStyle.normal.textColor = Color.green;
GUI.Label(new Rect(20, 10, 100, 50), "scores: " + points, style);
GUI.Label(new Rect(220, 10, 100, 50), "Round: " + round, style);
GUI.Label(new Rect(350, 100, 50, 200), result, resultStyle);
if (GUI.Button(new Rect(750, 50, 100, 50), "Restart"))
{
userAction.Restart();
}
if (GUI.Button(new Rect(1300, 425, 100, 50), "Kinematics"))
{
userAction.SetFlyMode(0);
}
//物理模式
if (GUI.Button(new Rect(1300, 500, 100, 50), "Physis"))
{
userAction.SetFlyMode(1);
}
if (Input.GetButtonDown("Fire1"))
{
userAction.Hit(Input.mousePosition);
}
}
}