Unity實現3D射箭小遊戲
Unity 小遊戲:3D射箭,供大傢參考,具體內容如下
前兩周因為實訓太忙,再加上自己對老師所講的設計模式並不是很理解,所以就沒有寫博客。這次博客是記錄3D射箭遊戲的實現過程。
1. 準備資源
我是在網上找的弓與箭的資源,至於靶子,創建五個不同大小的同心圓柱體,如圖所示:
需要註意的是,五個圓柱體並不在同一個平面上,這樣才能夠看清每一環的顏色,並且在檢測碰撞時不會出現各種問題。
另外,如果靶子放得離相機太近,就沒有射箭的感覺瞭;離相機太遠,好像又看不清靶子瞭,然後我試著把靶子Material的Shader改為 Sprites/Default ,這樣靶子離相機遠一點也能看得很清晰。
2. 佈置場景
把弓箭作為Main Camera的子物體,這樣我們可以在用鼠標控制鏡頭移動時,使弓箭一直指向屏幕中心,以達到第一人稱控制器的效果。
在此項目中,沒有選擇使用GUI來做UI界面,而是創建瞭一個Canvas,在這裡面添加瞭一個Image用來顯示弓箭的準心,以及四個Text來顯示得分、風向、風力、提示等。
3. 編輯腳本
遊戲采用MVC架構,大部分功能是自己實現的,也有一小些函數是借鑒大神的。整體上感覺有很多缺陷,但是又不知道怎麼修改才好,我也很無奈啊!°(°ˊДˋ°) °
下面是我的UML圖:
以下是完整代碼:
SSDirector.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SSDirector : System.Object { private static SSDirector _instance; public ISceneCotroller currentScenceCotroller { get; set; } public bool running { get; set; } public static SSDirector getInstance() { if (_instance == null) { _instance = new SSDirector (); } return _instance; } }
ISceneCotroller.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public interface ISceneCotroller { void LoadResources (); }
IUserAction.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public interface IUserAction { string getMyScore (); float getWind (); void Openbow (); void Draw (); void Shoot (); }
ActionManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ActionManager : MonoBehaviour { private float Force = 0f; private int maxPower = 2500; private float power; public Transform arrowSpawn; public Transform myArrow; public Transform bow; //播放拉弓動畫 public void Openbow () { bow.GetComponent<Animation>().Play("Draw"); bow.GetComponent<Animation>()["Draw"].speed = 1; bow.GetComponent<Animation>()["Draw"].wrapMode = WrapMode.Once; arrowSpawn.GetComponent<MeshRenderer>().enabled = true; //重置 power 為 0 power = 0; } //拉弓,從power為0到power為3000 public void Draw () { if(power < maxPower) { power += maxPower * Time.deltaTime; } } //射箭 public void Shoot () { float percent = bow.GetComponent<Animation>()["Draw"].time / bow.GetComponent<Animation>()["Draw"].length; float shootTime = 1 * percent; bow.GetComponent<Animation>().Play("Shoot"); bow.GetComponent<Animation>()["Shoot"].speed = 1; bow.GetComponent<Animation>()["Shoot"].time = shootTime; bow.GetComponent<Animation>()["Shoot"].wrapMode = WrapMode.Once; arrowSpawn.GetComponent<MeshRenderer>().enabled = false; Transform arrow= Instantiate (myArrow, arrowSpawn.transform.position, transform.rotation); arrow.transform.GetComponent<Rigidbody>().AddForce(transform.forward * power); wind (arrow); Force = Random.Range (-100, 100); } //產生風 private void wind(Transform arrow) { arrow.transform.GetComponent<Rigidbody> ().AddForce (new Vector3 (Force, 0, 0), ForceMode.Force); } //返回風 public float getWindForce() { return Force; } }
ScoreRecorder.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ScoreRecorder : MonoBehaviour { private string Score = "0"; //判斷得分 public void countScore(string type) { Score = type; } //返回分數 public string getScore () { return Score; } }
FirstScene.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FirstScene : MonoBehaviour, ISceneCotroller, IUserAction { private ActionManager actionManager; private ScoreRecorder scoreRecorder; void Awake () { SSDirector director = SSDirector.getInstance (); director.currentScenceCotroller = this; director.currentScenceCotroller.LoadResources (); actionManager = (ActionManager)FindObjectOfType (typeof(ActionManager)); scoreRecorder = (ScoreRecorder)FindObjectOfType (typeof(ScoreRecorder)); } //加載預制物體靶子 public void LoadResources () { Debug.Log ("loading...\n"); GameObject target = Instantiate<GameObject> ( Resources.Load<GameObject> ("Prefabs/target")); target.name = "target"; } //獲得分數 public string getMyScore () { return scoreRecorder.getScore (); } //獲得風向和風力 public float getWind () { return actionManager.getWindForce (); } //拉弓 public void Openbow () { actionManager.Openbow (); } //蓄力 public void Draw () { actionManager.Draw (); } //射箭 public void Shoot () { actionManager.Shoot (); } }
UserGUI.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class UserGUI : MonoBehaviour { private IUserAction userAction; private FirstScene scene; private Quaternion m_CharacterTargetRot; public Text Score; public Text WindDirection; public Text WindForce; // Use this for initialization void Start () { userAction = SSDirector.getInstance ().currentScenceCotroller as IUserAction; } void Awake () { m_CharacterTargetRot = transform.localRotation; } void Update () { //鏡頭跟隨鼠標 float xRot = Input.GetAxis ("Mouse X") * 3f; float yRot = Input.GetAxis ("Mouse Y") * -3f; m_CharacterTargetRot *= Quaternion.Euler (yRot, xRot, 0f); transform.localRotation = Quaternion.Slerp (transform.localRotation, m_CharacterTargetRot, 5f * Time.deltaTime); //按空格鍵使弓箭瞄準靶心 if (Input.GetKeyDown (KeyCode.Space)) { m_CharacterTargetRot = Quaternion.Euler (0f, 0f, 0f); transform.localRotation = Quaternion.Slerp (transform.localRotation, m_CharacterTargetRot, 5f * Time.deltaTime); } //鼠標左鍵按下,開始拉弓 if (Input.GetMouseButtonDown (0)) { userAction.Openbow (); } //鼠標左鍵按住不放,蓄力 if (Input.GetMouseButton (0)) { userAction.Draw (); } //鼠標左鍵抬起。射箭 if (Input.GetMouseButtonUp (0)) { userAction.Shoot (); } Score.text = "Score : " + userAction.getMyScore (); //顯示上一輪分數 float force = userAction.getWind (); if (force < 0) { WindDirection.text = "Wind Direction : <---"; //顯示風向 } else if (force > 0) { WindDirection.text = "Wind Direction : --->"; } else { WindDirection.text = "Wind Direction : No"; } WindForce.text = "Wind Force : " + Mathf.Abs (userAction.getWind ()); //顯示風力 } }
Arrow.cs
using UnityEngine; using System.Collections; public class Arrow : MonoBehaviour { private RaycastHit hit; void Update (){ //檢測在移動的箭 if(GetComponent<Rigidbody>().velocity.magnitude > 0.5f) { CheckForHit(); } else { enabled = false; } if (transform.position.y < -5) { Destroy (this.gameObject); //將掉出地面以下的箭銷毀 } } //檢測是否碰撞 void CheckForHit (){ float myVelocity = GetComponent<Rigidbody>().velocity.magnitude; float raycastLength = myVelocity * 0.03f; if(Physics.Raycast(transform.position, transform.forward, out hit, raycastLength)) { GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll; //使箭停留在靶子上 transform.position = hit.point; transform.parent = hit.transform; enabled = false; } else { Quaternion newRot = transform.rotation; newRot.SetLookRotation(GetComponent<Rigidbody>().velocity); transform.rotation = newRot; //箭沒中靶,則繼續做拋物線運動 } } }
Target.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Target : MonoBehaviour { private ScoreRecorder scoreRecorder; public string score; //對應靶環的分數 public void Start() { scoreRecorder = (ScoreRecorder)FindObjectOfType (typeof(ScoreRecorder)); } void OnTriggerEnter(Collider other) { if (other.gameObject.tag == "Arrow") { scoreRecorder.countScore (score); //記錄分數 } } }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- None Found