当前位置:   article > 正文

Unity3d学习笔记(7)--打靶游戏_固定靶射击游戏 unity 3d

固定靶射击游戏 unity 3d

一.游戏简介:

这是一个简单的打靶游戏,总共有五环,从外到里依次是一到五环,打到一环得一分,二环得二分,依此类推

玩家可以通过方向键或asdw键来控制发射的位置,还有,在游戏当中,还会有风来影响箭的飞行方向


二.游戏效果图:



三.UML图:



四.游戏主要代码和设置说明:

1.游戏中是用了虚拟轴来控制箭的位置,不过移动箭的代码是挂在一个空对象上的,而箭是它的子对象,当箭射出的时候,就把它的parent置为null,这样在

   箭射出后就不能控制箭了,移动的代码如下:

  1. void Update () {
  2. float translationY = Input.GetAxis("Vertical") * speed;
  3. float translationX = Input.GetAxis("Horizontal") * speed;
  4. translationY *= Time.deltaTime;
  5. translationX *= Time.deltaTime;
  6. this.gameObject.transform.Translate(0, translationY, 0);
  7. this.gameObject.transform.Translate(-translationX, 0, 0);
  8. }

2.游戏中箭的初始方向和初始速度都是固定的

  1. horizontalSpeed = gameobject.GetComponent<ArrowData>().speed;
  2. direction = Vector3.back;
  3. rigid = this.gameobject.GetComponent<Rigidbody>();
  4. rigid.velocity = direction * horizontalSpeed;

3.游戏中靶是有五个圆柱体和一个空对象组成的,圆柱体是空对象的子对象,通过圆柱体细微的高度差异,就可以显示各个环的颜色,

   通过mesh触发器,就可以和箭产生出发事件,各个圆柱的设置差不多,只是其中一个:



4.但各个圆柱的触发区域有重叠的地方,我这里是用一个数组来记录有哪些环出发了,然后选得分最大的那个环

 hitedTarget = new bool[5] { false, false, false, false, false };
  1. public void setHitedTarget(int ring)
  2. {
  3.     hitedTarget[ring - 1] = true;
  4. }
  1. private void OnTriggerEnter(Collider other)
  2.     {
  3.         if (other.gameObject.GetComponent<Rigidbody>())
  4.         {
  5.             other.gameObject.transform.FindChild("head").gameObject.SetActive(false);
  6.             other.gameObject.GetComponent<Rigidbody>().isKinematic = true;
  7.             sceneController.setHitedTarget((int)this.gameObject.name[0] - (int)'0'); //环的名字是对应第几环
  8.         }
  9.        
  10.     }

5.游戏中还会有风产生,风是挂载在箭上的脚本,本来是应该归动作管理器管理的,但这里偷懒,直接挂在箭上

  1. void FixedUpdate() {
  2. if (rigid.useGravity) //当箭射出时,刚体的useGravity属性才会置为true
  3. {
  4. rigid.AddForce(force);
  5. }
  6. }

五.全部源代码

1.ArrowData.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class ArrowData : MonoBehaviour {
  5. public Vector3 size;
  6. public Color color;
  7. public float speed;
  8. public Vector3 direction;
  9. public bool destroy;
  10. public bool used;
  11. }

2.ArrowFactory.cs

  1. /**
  2. * 这个文件是用来生产飞碟的工厂
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public class ArrowFactory : MonoBehaviour
  8. {
  9. public GameObject ArrowPrefab;
  10. public GameObject person;
  11. float time = 0;
  12. /**
  13. * used是用来保存正在使用的箭
  14. * free是用来保存未激活的箭
  15. */
  16. private Dictionary<int, ArrowData> used = new Dictionary<int, ArrowData>();
  17. private List<ArrowData> free = new List<ArrowData>();
  18. private List<int> wait = new List<int>();
  19. private void Awake()
  20. {
  21. ArrowPrefab = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/arrow"), Vector3.zero, Quaternion.identity);
  22. person = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/person"), new Vector3(0,0,3), Quaternion.identity);
  23. ArrowPrefab.SetActive(false);
  24. }
  25. public GameObject GetArrow()
  26. {
  27. GameObject newArrow = null;
  28. if (free.Count > 0)
  29. {
  30. newArrow = free[0].gameObject;
  31. free.Remove(free[0]);
  32. }
  33. else
  34. {
  35. newArrow = GameObject.Instantiate<GameObject>(ArrowPrefab, Vector3.zero, Quaternion.identity);
  36. }
  37. ArrowData data = newArrow.GetComponent<ArrowData>();
  38. data.destroy = false;
  39. data.speed = 15f;
  40. data.used = false;
  41. data.transform.rotation = Quaternion.identity;
  42. newArrow.transform.position = new Vector3(0, 0, 3);
  43. Rigidbody rigid = newArrow.GetComponent<Rigidbody>();
  44. rigid.isKinematic = false;
  45. rigid.useGravity = false;
  46. rigid.velocity = Vector3.zero;
  47. used.Add(data.GetInstanceID(), data);
  48. newArrow.transform.parent = person.transform;
  49. newArrow.SetActive(true);
  50. return newArrow;
  51. }
  52. public void FreeArrow(GameObject Arrow)
  53. {
  54. ArrowData tmp = null;
  55. int key = Arrow.GetComponent<ArrowData>().GetInstanceID();
  56. if (used.ContainsKey(key))
  57. {
  58. tmp = used[key];
  59. }
  60. if (tmp != null)
  61. {
  62. tmp.gameObject.SetActive(false);
  63. free.Add(tmp);
  64. used.Remove(key);
  65. }
  66. }
  67. private void Update()
  68. {
  69. time += Time.deltaTime;
  70. if (time > 10f)
  71. {
  72. clear();
  73. time = 0;
  74. }
  75. foreach (var tmp in used.Values)
  76. {
  77. if (tmp.destroy)
  78. {
  79. wait.Add(tmp.GetInstanceID());
  80. }
  81. }
  82. foreach (int tmp in wait)
  83. {
  84. FreeArrow(used[tmp].gameObject);
  85. }
  86. wait.Clear();
  87. }
  88. public void clear()
  89. {
  90. foreach (var tmp in used.Values)
  91. {
  92. if (tmp.GetComponent<ArrowData>().used)
  93. {
  94. tmp.gameObject.SetActive(false);
  95. tmp.destroy = true;
  96. }
  97. }
  98. }
  99. }

3.CCActionManager.cs

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. public class CCActionManager : SSActionManager, ISSActionCallback {
  6. public FirstSceneControl sceneController;
  7. protected void Start()
  8. {
  9. sceneController = (FirstSceneControl)Director.getInstance().currentSceneControl;
  10. sceneController.actionManager = this;
  11. }
  12. public void SSActionEvent(SSAction source,
  13. SSActionEventType events = SSActionEventType.Competeted,
  14. int intParam = 0,
  15. string strParam = null,
  16. UnityEngine.Object objectParam = null)
  17. {
  18. if (!source.gameobject.activeSelf)
  19. {
  20. source.gameobject.GetComponent<ArrowData>().destroy = true;
  21. }
  22. if (source is CCFlyAction)
  23. {
  24. source.gameobject.GetComponent<ArrowData>().used = true;
  25. sceneController.setGameState(GameState.DART_FINISH);
  26. source.reset();
  27. }
  28. }
  29. public void StartThrow(GameObject Arrow)
  30. {
  31. CCFlyActionFactory cf = Singleton<CCFlyActionFactory>.Instance;
  32. RunAction(Arrow, cf.GetSSAction(), (ISSActionCallback)this);
  33. Arrow.transform.parent = null;
  34. Arrow.GetComponent<Rigidbody>().useGravity = true;
  35. }
  36. }

4.CCFlyAction.cs

  1. /**
  2. * 这个文件是实现飞碟的飞行动作
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public class CCFlyAction : SSAction {
  8. float horizontalSpeed;
  9. Vector3 direction;
  10. Rigidbody rigid;
  11. public override void Start () {
  12. enable = true;
  13. horizontalSpeed = gameobject.GetComponent<ArrowData>().speed;
  14. direction = Vector3.back;
  15. rigid = this.gameobject.GetComponent<Rigidbody>();
  16. rigid.velocity = direction * horizontalSpeed;
  17. rigid.useGravity = false;
  18. }
  19. // Update is called once per frame
  20. public override void FixedUpdate () {
  21. if (gameobject.activeSelf && rigid)
  22. {
  23. if (this.transform.position.y < -4)
  24. {
  25. this.destroy = true;
  26. this.enable = false;
  27. this.gameobject.SetActive(false);
  28. this.callback.SSActionEvent(this);
  29. }
  30. if (rigid.isKinematic)
  31. {
  32. this.enable = false;
  33. this.callback.SSActionEvent(this);
  34. }
  35. }
  36. }
  37. public static CCFlyAction GetCCFlyAction()
  38. {
  39. CCFlyAction action = ScriptableObject.CreateInstance<CCFlyAction>();
  40. return action;
  41. }
  42. }


5.CCFlyActionFactory.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class CCFlyActionFactory : MonoBehaviour {
  5. private Dictionary<int, SSAction> used = new Dictionary<int, SSAction>();
  6. private List<SSAction> free = new List<SSAction>();
  7. private List<int> wait = new List<int>();
  8. public CCFlyAction Fly;
  9. // Use this for initialization
  10. void Start () {
  11. Fly = CCFlyAction.GetCCFlyAction();
  12. }
  13. private void Update()
  14. {
  15. foreach (var tmp in used.Values)
  16. {
  17. if (tmp.destroy)
  18. {
  19. wait.Add(tmp.GetInstanceID());
  20. }
  21. }
  22. foreach (int tmp in wait)
  23. {
  24. FreeSSAction(used[tmp]);
  25. }
  26. wait.Clear();
  27. }
  28. public SSAction GetSSAction()
  29. {
  30. SSAction action = null;
  31. if (free.Count > 0)
  32. {
  33. action = free[0];
  34. free.Remove(free[0]);
  35. }
  36. else
  37. {
  38. action = ScriptableObject.Instantiate<CCFlyAction>(Fly);
  39. }
  40. used.Add(action.GetInstanceID(), action);
  41. return action;
  42. }
  43. public void FreeSSAction(SSAction action)
  44. {
  45. SSAction tmp = null;
  46. int key = action.GetInstanceID();
  47. if (used.ContainsKey(key))
  48. {
  49. tmp = used[key];
  50. }
  51. if (tmp != null)
  52. {
  53. tmp.reset();
  54. free.Add(tmp);
  55. used.Remove(key);
  56. }
  57. }
  58. public void clear()
  59. {
  60. foreach (var tmp in used.Values)
  61. {
  62. tmp.enable = false;
  63. tmp.destroy = true;
  64. }
  65. }
  66. }


6.CCMoveDartAction.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class CCMoveDartAction : MonoBehaviour {
  5. // Use this for initialization
  6. void Start () {
  7. }
  8. float speed = 4f;
  9. // Update is called once per frame
  10. void Update () {
  11. float translationY = Input.GetAxis("Vertical") * speed;
  12. float translationX = Input.GetAxis("Horizontal") * speed;
  13. translationY *= Time.deltaTime;
  14. translationX *= Time.deltaTime;
  15. this.gameObject.transform.Translate(0, translationY, 0);
  16. this.gameObject.transform.Translate(-translationX, 0, 0);
  17. }
  18. }


7.collision.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class collision : MonoBehaviour {
  5. public FirstSceneControl sceneController;
  6. // Use this for initialization
  7. void Start() {
  8. sceneController = (FirstSceneControl)Director.getInstance().currentSceneControl;
  9. }
  10. private void OnTriggerEnter(Collider other)
  11. {
  12. if (other.gameObject.GetComponent<Rigidbody>())
  13. {
  14. other.gameObject.transform.FindChild("head").gameObject.SetActive(false);
  15. other.gameObject.GetComponent<Rigidbody>().isKinematic = true;
  16. sceneController.setHitedTarget((int)this.gameObject.name[0] - (int)'0');
  17. }
  18. }
  19. }


8.Director.cs

  1. /**
  2. * 这个文件是用来场景控制的,负责各个场景的切换,
  3. * 虽然目前只有一个场景
  4. */
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. public class Director : System.Object {
  9. /**
  10. * currentSceneControl标志目前正在使用的场景
  11. */
  12. public ISceneControl currentSceneControl { get; set; }
  13. /**
  14. * Director这个类是采用单例模式
  15. */
  16. private static Director director;
  17. private Director()
  18. {
  19. }
  20. public static Director getInstance()
  21. {
  22. if (director == null)
  23. {
  24. director = new Director();
  25. }
  26. return director;
  27. }
  28. }


9. FirstSceneControl.cs

  1. /**
  2. * 这个文件是用来控制主游戏场景的
  3. */
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. public class FirstSceneControl : MonoBehaviour, ISceneControl, IUserAction {
  9. /**
  10. * actionManager是用来指定当前的动作管理器
  11. */
  12. public CCActionManager actionManager { get; set; }
  13. /**
  14. * scoreRecorder是用来指定当前的记分管理对象的
  15. */
  16. public ScoreRecorder scoreRecorder { get; set; }
  17. public bool[] hitedTarget = null;
  18. /**
  19. * gameState是用来保存当前的游戏状态
  20. */
  21. private GameState gameState;
  22. private GameObject currentArrow;
  23. void Awake () {
  24. Director director = Director.getInstance();
  25. director.currentSceneControl = this;
  26. gameState = GameState.DART_START;
  27. hitedTarget = new bool[5] { false, false, false, false, false };
  28. this.gameObject.AddComponent<ScoreRecorder>();
  29. this.gameObject.AddComponent<ArrowFactory>();
  30. this.gameObject.AddComponent<CCFlyActionFactory>();
  31. scoreRecorder = Singleton<ScoreRecorder>.Instance;
  32. director.currentSceneControl.LoadResources();
  33. }
  34. private void Update()
  35. {
  36. /**
  37. * 以下代码用来管理游戏的状态
  38. */
  39. if (gameState == GameState.DART_FINISH)
  40. {
  41. int ring = check();
  42. scoreRecorder.Record(ring);
  43. gameState = GameState.DART_START;
  44. }
  45. if (gameState == GameState.DART_START)
  46. {
  47. ArrowFactory df = Singleton<ArrowFactory>.Instance;
  48. currentArrow = df.GetArrow();
  49. gameState = GameState.WAIT;
  50. }
  51. if (gameState == GameState.SHOOT)
  52. {
  53. actionManager.StartThrow(currentArrow);
  54. gameState = GameState.RUNNING;
  55. }
  56. }
  57. public void LoadResources()
  58. {
  59. GameObject DartsBoard = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/dartsboard"));
  60. GameObject plane = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/plane"));
  61. }
  62. public string GetWindInfo()
  63. {
  64. float wind = currentArrow.GetComponent<wind>().GetForce();
  65. if (wind < 0)
  66. {
  67. return "Right " + (-wind).ToString();
  68. }
  69. else
  70. {
  71. return "Left " + wind.ToString();
  72. }
  73. }
  74. public int GetScore()
  75. {
  76. return scoreRecorder.score;
  77. }
  78. public GameState getGameState()
  79. {
  80. return gameState;
  81. }
  82. public void setGameState(GameState gs)
  83. {
  84. gameState = gs;
  85. }
  86. public void setHitedTarget(int ring)
  87. {
  88. hitedTarget[ring - 1] = true;
  89. }
  90. public int check()
  91. {
  92. int result = -1;
  93. for (int i = 4; i >= 0; i--)
  94. {
  95. if (hitedTarget[i])
  96. {
  97. result = i;
  98. break;
  99. }
  100. }
  101. for (int i = 4; i >= 0; i--)
  102. {
  103. hitedTarget[i] = false;
  104. }
  105. return result + 1;
  106. }
  107. }


10.ISceneControl.cs

  1. /*
  2. * 场景控制的必须实现的接口
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public interface ISceneControl {
  8. void LoadResources();
  9. }


11.ISSActionCallback.cs

  1. /**
  2. * 这个接口负责动作与动作管理器间的通信
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public enum SSActionEventType:int { Started, Competeted }
  8. public interface ISSActionCallback {
  9. void SSActionEvent(SSAction source,
  10. SSActionEventType events = SSActionEventType.Competeted,
  11. int intParam = 0,
  12. string strParam = null,
  13. Object objectParam = null);
  14. }

12.IUserAction.cs

  1. /**
  2. * UI界面与场景管理器通信的接口
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public enum GameState { RUNNING, DART_START, DART_FINISH, WAIT, SHOOT}
  8. public interface IUserAction {
  9. GameState getGameState();
  10. void setGameState(GameState gs);
  11. int GetScore();
  12. string GetWindInfo();
  13. }

13.ScoreRecorder.cs

  1. /**
  2. * 这个类是用来记录玩家得分的
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public class ScoreRecorder : MonoBehaviour {
  8. /**
  9. * score是玩家得到的总分
  10. */
  11. public int score;
  12. /**
  13. * scoreTable是一个得分的规则表,每种飞碟的颜色对应着一个分数
  14. */
  15. private Dictionary<int, int> scoreTable = new Dictionary<int, int>();
  16. // Use this for initialization
  17. void Start () {
  18. score = 0;
  19. scoreTable.Add(0, 0);
  20. scoreTable.Add(1, 1);
  21. scoreTable.Add(2, 2);
  22. scoreTable.Add(3, 3);
  23. scoreTable.Add(4, 4);
  24. scoreTable.Add(5, 5);
  25. }
  26. public void Record(int ring)
  27. {
  28. score += scoreTable[ring];
  29. }
  30. public void Reset()
  31. {
  32. score = 0;
  33. }
  34. }


14.Singleton.cs

  1. /**
  2. * 这是一个实现单例模式的模板,所有的MonoBehaviour对象都用这个模板来实现单实例
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
  8. {
  9. protected static T instance;
  10. public static T Instance
  11. {
  12. get
  13. {
  14. if (instance == null)
  15. {
  16. instance = (T)FindObjectOfType(typeof(T));
  17. if (instance == null)
  18. {
  19. Debug.LogError("An instance of " + typeof(T)
  20. + " is needed in the scene, but there is none.");
  21. }
  22. }
  23. return instance;
  24. }
  25. }
  26. }


15.SSAction.cs

  1. /**
  2. * 所有动作的基类
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. public class SSAction : ScriptableObject {
  8. public bool enable = false;
  9. public bool destroy = false;
  10. public GameObject gameobject { get; set; }
  11. public Transform transform { get; set; }
  12. public ISSActionCallback callback { get; set; }
  13. protected SSAction() { }
  14. public virtual void Start () {
  15. throw new System.NotImplementedException();
  16. }
  17. // Update is called once per frame
  18. public virtual void FixedUpdate () {
  19. throw new System.NotImplementedException();
  20. }
  21. public void reset()
  22. {
  23. enable = false;
  24. destroy = false;
  25. gameobject = null;
  26. transform = null;
  27. callback = null;
  28. }
  29. }

16.SSActionManager.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class SSActionManager : MonoBehaviour {
  5. private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); //保存所以已经注册的动作
  6. private List<SSAction> waitingAdd = new List<SSAction>(); //动作的等待队列,在这个对象保存的动作会稍后注册到动作管理器里
  7. private List<int> waitingDelete = new List<int>(); //动作的删除队列,在这个对象保存的动作会稍后删除
  8. // Update is called once per frame
  9. protected void FixedUpdate()
  10. {
  11. //把等待队列里所有的动作注册到动作管理器里
  12. foreach (SSAction ac in waitingAdd) actions[ac.GetInstanceID()] = ac;
  13. waitingAdd.Clear();
  14. //管理所有的动作,如果动作被标志为删除,则把它加入删除队列,被标志为激活,则调用其对应的Update函数
  15. foreach (KeyValuePair<int, SSAction> kv in actions)
  16. {
  17. SSAction ac = kv.Value;
  18. if (ac.destroy)
  19. {
  20. waitingDelete.Add(ac.GetInstanceID());
  21. }
  22. else if (ac.enable)
  23. {
  24. ac.FixedUpdate();
  25. }
  26. }
  27. //把删除队列里所有的动作删除
  28. foreach (int key in waitingDelete)
  29. {
  30. SSAction ac = actions[key];
  31. actions.Remove(key);
  32. DestroyObject(ac);
  33. }
  34. waitingDelete.Clear();
  35. }
  36. //初始化一个动作
  37. public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager)
  38. {
  39. action.gameobject = gameobject;
  40. action.transform = gameobject.transform;
  41. action.callback = manager;
  42. waitingAdd.Add(action);
  43. action.Start();
  44. }
  45. }

17.UserGUI.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class UserGUI : MonoBehaviour
  5. {
  6. private IUserAction action;
  7. void Start () {
  8. action = Director.getInstance().currentSceneControl as IUserAction;
  9. }
  10. private void OnGUI()
  11. {
  12. if (GUI.Button(new Rect(900, 500, 90, 90), "shoot") && (action.getGameState() == GameState.WAIT))
  13. {
  14. action.setGameState(GameState.SHOOT);
  15. }
  16. GUI.Label(new Rect(500, 90, 90, 90), "Force: " + action.GetWindInfo());
  17. GUI.Label(new Rect(900, 90, 90, 90), "Score: " + action.GetScore().ToString());
  18. }
  19. }

18.wind.cs

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class wind : MonoBehaviour {
  5. Vector3 force;
  6. Rigidbody rigid;
  7. void Start() {
  8. float xforce = Random.Range(-0.5f, 0.5f);
  9. force = new Vector3(xforce, 0, 0);
  10. rigid = this.gameObject.GetComponent<Rigidbody>();
  11. }
  12. void FixedUpdate() {
  13. if (rigid.useGravity)
  14. {
  15. rigid.AddForce(force);
  16. }
  17. }
  18. public float GetForce()
  19. {
  20. return force.x;
  21. }
  22. }





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/104139
推荐阅读
相关标签
  

闽ICP备14008679号