Unity实战之打飞碟游戏
整体描述
利用unity实现简单的打飞碟游戏,射中相应的靶即得分。一轮游戏共五发箭。
设计思路
UML图如下
定义组件
-
弓箭
由两部分组成:箭头和箭身。
箭头是一个比较小的胶囊体,挂载碰撞器。箭身是从Assets Store中下载的免费素材
-
靶
由五个同心、高度不同的圆柱组成,每个圆柱体挂载
RingData
,对应不同的分数
代码实现
CCShootAction
: 实现箭的发射事件
public class CCShootAction : SSAction
{
Vector3 force;
Vector3 wind;
private CCShootAction(){}
// Start is called before the first frame update
public override void Start()
{
gameObject.transform.parent = null;
gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
// force = new Vector3(0, 0, 30);
// Impulse:向此刚体添加瞬时力冲击,考虑其质量。
gameObject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().AddForce(wind, ForceMode.Impulse);
gameObject.GetComponent<Rigidbody>().isKinematic = false;
}
// Update is called once per frame
public override void Update()
{
}
public override void FixedUpdate(){
// 箭飞到场外或者中靶
if(this.transform.position.z > 35 || this.transform.tag == "onTarget"){
Debug.Log("回调");
this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this, SSActionEventType.Completed, 0, null, gameObject);
}
}
public static CCShootAction GetSSAction(Vector3 wind){
CCShootAction shoot = CreateInstance<CCShootAction>();
shoot.force = new Vector3(0, 0, 40);
shoot.wind = wind;
return shoot;
}
}
CCShootActionManager
: 实现射箭动作管理
public class CCShootActionManager : SSActionManager
{
public FirstController firstController;
public CCShootAction shoot;
// Start is called before the first frame update
protected void Start()
{
firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
firstController.actionManager = this;
}
public void Shoot(GameObject arrow, Vector3 wind){
Debug.Log("Shoot");
shoot = CCShootAction.GetSSAction(wind);
this.RunAction(arrow, shoot, this);
}
}
TrembleAction
: 箭射中后的颤抖动作,在回调函数中调用
public class TrembleAction : SSAction
{
float tremble_radius = 0.05f;
float tremble_time = 0.5f;
GameObject arrow;
Vector3 arrow_pos;
private TrembleAction(){}
public static TrembleAction GetSSAction()
{
TrembleAction tremble_action = CreateInstance<TrembleAction>();
return tremble_action;
}
// Start is called before the first frame update
public override void Start()
{
//得到箭中靶时的位置
arrow_pos = gameObject.transform.position;
// this.transform.Translate(new Vector3(0, 0, 0.5f));
Debug.Log(gameObject.transform.name);
}
// Update is called once per frame
public override void Update()
{
tremble_time -= Time.deltaTime;
//需要继续颤抖
if(tremble_time > 0){
// gameObject.transform.Translate(new Vector3(0.02f, 0, 0));
Vector3 head_pos = gameObject.transform.position;
float x = arrow_pos.x + Random.RandomRange(-0.05f, 0.05f);
float y = arrow_pos.y + Random.RandomRange(-0.05f, 0.05f);
float z = arrow_pos.z;
gameObject.transform.position = new Vector3(x, y, z);
}
else{
gameObject.transform.position = arrow_pos;
}
// else{
// transform.position = arrow_pos;
// this.destroy = true;
// this.callback.SSActionEvent(this);
// }
}
}
具体应用在SSActionManager
中
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Completed,
int intParam = 0,
string strParam = null,
GameObject arrow = null){
TrembleAction trembleAction = TrembleAction.GetSSAction();
this.RunAction(arrow, trembleAction, this);
}
ArrowFactory
: 箭的工厂,用于生产、释放弓箭
public class ArrowFactory : MonoBehaviour
{
private List<GameObject> used;
private List<GameObject> free;
public GameObject arrow;
FirstController firstController;
// Start is called before the first frame update
void Start()
{
firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
used = new List<GameObject>();
free = new List<GameObject>();
arrow = null;
}
// Update is called once per frame
void Update()
{
}
public GameObject GetArrow(){
if(free.Count > 0){
arrow = free[0];
free.Remove(free[0]);
if(arrow.tag == "onTarget")//箭在靶子上
{
arrow.GetComponent<Rigidbody>().isKinematic = false;
arrow.tag = "arrow";
arrow.transform.GetChild(0).gameObject.SetActive(true);
}
arrow.SetActive(true);
}
else{
arrow = Instantiate(Resources.Load<GameObject>("Prefabs/arrow1"));
arrow.GetComponent<Rigidbody>().isKinematic = false;
// arrow.AddComponent<Rigidbody>();
}
// firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
// Transform pos = firstController.bow.transform.GetChild(0);
// arrow.transform.position = pos.transform.position;
arrow.transform.parent = firstController.bow.transform; // 把arrow附加在bow上,跟随着bow移动
arrow.transform.position = firstController.bow.transform.position;
used.Add(arrow);
return arrow;
}
public void FreeArrow(GameObject arrow){
foreach(GameObject aa in used){
Debug.Log("befreed");
if(aa.gameObject.GetInstanceID() == arrow.GetInstanceID()){
arrow.SetActive(false);
used.Remove(aa);
aa.tag = "arrow";
break;
}
}
}
public void Clear(){
foreach(GameObject dd in used){
dd.transform.position = new Vector3(0, 0, 100);
Destroy(dd);
}
foreach(GameObject dd in free){
dd.transform.position = new Vector3(0, 0, 100);
Destroy(dd);
}
used.Clear();
free.Clear();
}
}
RingData
: 挂载在每个环上,用于定义不同环的分数
public class RingData : MonoBehaviour {
public int score;
public void Start(){
if(this.gameObject.name=="1"){
score = 5;
}
else if(this.gameObject.name=="2"){
score = 4;
}
else if(this.gameObject.name=="3"){
score = 3;
}
else if(this.gameObject.name=="4"){
score = 2;
}
else{
score = 1;
}
}
}
RingController
: 控制环的撞击事件、计分、回调颤抖动作
public class RingController : MonoBehaviour
{
public ScoreRecorder scoreRecorder;
public ISceneController sceneController;
// Start is called before the first frame update
void Start()
{
sceneController = SSDirector.GetInstance().CurrentScenceController as FirstController;
scoreRecorder = Singleton<ScoreRecorder>.Instance;
this.gameObject.AddComponent<RingData>();
}
// Update is called once per frame
void OnTriggerEnter(Collider arrowCollider){
Debug.Log("碰撞!");
Transform arrow = arrowCollider.gameObject.transform.parent;
Debug.Log(arrow.gameObject.name);
if(arrow == null){
Debug.Log("null");
return;
}
scoreRecorder.RecordScore(this.gameObject.GetComponent<RingData>().score);
Debug.Log("Score:"+this.gameObject.GetComponent<RingData>().score);
arrow.GetComponent<Rigidbody>().isKinematic = true;
arrow.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
arrowCollider.gameObject.SetActive(false);
arrow.tag = "onTarget";
}
}