Unity学习——射箭游戏
射箭游戲
游戲視頻<https://www.bilibili.com/video/av71160101/>
游戲工程文件https://github.com/JennySRH/3DGame/tree/master/ShootTarget
上下左右控制箭移動,空格鍵發射
靶對象
靶對象共有5環,由5個圓柱體組成,射中最中心的環得分5,射中最外層環得分為1。每個圓柱體都添加了mesh collider,勾選Convex,并且勾選了is Trigger作為觸發器。
對于靶對象而言,它需要完成兩種行為:
Target上將掛載兩個腳本,一個是TargetData,掛載到每一個環上,用來得到該環的分數;另一個是TargetTrigger,用來檢測哪一個環被觸發。
/* TargetData.cs */ public class TargetData : MonoBehaviour {// 掛載到Target上的每一環,用來返回該環對應的分數。public int GetScore(){string name = this.gameObject.name;int score = 6 - (name[0] - '0');return score;} } /*TargetTrigger.cs*/ using System.Collections; using System.Collections.Generic; using UnityEngine;public class TargetTrigger : MonoBehaviour {// 當有箭射中某一環后觸發void OnTriggerEnter(Collider arrow_head){//得到箭身Transform arrow = arrow_head.gameObject.transform.parent;if (arrow == null){return;}if (arrow.tag == "Arrow"){arrow_head.gameObject.SetActive(false);//箭身速度為0arrow.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);arrow.GetComponent<Rigidbody>().isKinematic = true;arrow.tag = "Hit";// 分數控制器int score = this.gameObject.gameObject.GetComponent<TargetData>().GetScore();Singleton<ScoreController>.Instance.AddScore(score);//Debug.Log(score);}}}然后將所有的圓柱體放到一個空物體上,做成預制。
箭
每一個箭由head和body組成,head裝有collider。
箭掛載了JoyStick可以通過上下左右來控制方向,如果按下空格鍵將添加剛體Rigidbody,然后交由相應的動作控制器進行控制。
/*JoyStick.cs*/using System.Collections; using System.Collections.Generic; using UnityEngine;public class JoyStick : MonoBehaviour {public float speedX = 1.0F;public float speedY = 1.0F;bool flag = true;// Update is called once per framevoid Update(){// 只有在射出前能移動if(flag){float translationY = Input.GetAxis("Vertical") * speedY;float translationX = Input.GetAxis("Horizontal") * speedX;translationY *= Time.deltaTime;translationX *= Time.deltaTime;// 限制移動的范圍if (transform.position.x - translationX < 1.5 && transform.position.x - translationX > -1.5&& transform.position.y + translationY > -0.8 && transform.position.y + translationY < 0.8){transform.position = transform.position + new Vector3(-translationX, translationY, 0);}if (Input.GetButton("Jump")){// 如果空格下,則給箭增加剛體,使其能夠進行物理學的運動this.gameObject.AddComponent<Rigidbody>();this.gameObject.GetComponent<Rigidbody>().useGravity = false;flag = false;}}} }風
風是由一系列透明的觸發器組成的。
觸發器們掛載了WindTrigger用來檢測是否有箭頭觸發,然后交由相應的動作控制器控制。
/*WindTrigger*/ using System.Collections; using System.Collections.Generic; using UnityEngine;public class WindTrigger : MonoBehaviour {void OnTriggerEnter(Collider arrow_head){//得到箭身Transform arrow = arrow_head.gameObject.transform.parent;if (arrow == null){return;}if (arrow.tag == "Arrow"){arrow.GetComponent<CCAction>().Move();}} }風力大小和風向由WindController生成,掛載到全局的空物體上,使用單例模式獲得。
/*WindController.sc*/ using System.Collections; using System.Collections.Generic; using UnityEngine;public class WindController : MonoBehaviour {private float time = 5;private float strength = 0.5f;private Vector3 direction = new Vector3(0.01f,0,0);// Update is called once per framevoid Update(){if(time > 0){time -= Time.deltaTime;}else{time = 5;strength = UnityEngine.Random.Range(0.5f, 0.7f);direction = new Vector3(UnityEngine.Random.Range(-0.02f, 0.02f), UnityEngine.Random.Range(-0.02f, 0.02f), 0);}}public float GetStrength(){return strength;}public Vector3 GetDirection(){return direction;} }場景控制器——FirstSceneController
由于本次作業依舊沿用了之前的MVC框架,所以只展示重要部分代碼。
FirstSceneController掛載到空物體上,用來加載第一個場景(一共也只有一個場景)。
/*FirstSceneController.cs*/ using System.Collections; using System.Collections.Generic; using UnityEngine;public class FirstSceneController : MonoBehaviour, ISceneController {// 靶對象public GameObject target;// 箭隊列public Queue<GameObject> arrowQueue = new Queue<GameObject>();// 當前正在操控的箭public GameObject arrow;// 風public GameObject wind;public void LoadSource(){// 清除記分Singleton<ScoreController>.Instance.ClearScore();// 靶對象初始化if (target != null){Destroy(target);}target = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Target"));if(arrow != null){Singleton<ArrowFactory>.Instance.FreeArrow(arrow);}// 箭隊列初始化while (arrowQueue.Count > 0){Singleton<ArrowFactory>.Instance.FreeArrow(arrowQueue.Dequeue());}arrowQueue.Clear();// 初始化一個箭對象arrow = Singleton<ArrowFactory>.Instance.GetArrow();arrowQueue.Enqueue(arrow);}// Start is called before the first frame updatevoid Start(){this.gameObject.AddComponent<ArrowFactory>();this.gameObject.AddComponent<ScoreController>();this.gameObject.AddComponent<IGUI>();this.gameObject.AddComponent<WindController>();wind = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Wind"));// 設置第一個場景控制器為當前場景控制器Director.GetInstance().CurrentSceneController = this;Director.GetInstance().CurrentSceneController.LoadSource();}// Update is called once per framevoid Update(){if(arrow.tag == "WaveEnd"){arrow = Singleton<ArrowFactory>.Instance.GetArrow();arrowQueue.Enqueue(arrow);}} }運動學控制器——CCAction (顫抖效果)
CCAction掛載到每個Arrow上,用來負責Arrow射中靶對象后的抖動效果以及遇到風之后產生的偏移效果。
/*CCAction.cs*/ using System.Collections; using System.Collections.Generic; using UnityEngine;public class CCAction : MonoBehaviour, IAction {private float time = 1;float radian = 0;float radius = 0.01f; Vector3 initPosition;public void Move(){Move(Singleton<WindController>.Instance.GetDirection(), Singleton<WindController>.Instance.GetStrength());}public void Move(Vector3 direction, float strength){this.transform.position += direction * strength;}// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){if(time > 0){if (this.gameObject.tag == "Hit"){time -= Time.deltaTime;// 弧度每次增加radian += 0.05f;// 顫抖float dy = Mathf.Cos(radian) * radius;transform.position = initPosition + new Vector3(0, dy, 0);}else{initPosition = transform.position;}}if(time <= 0){this.gameObject.tag = "WaveEnd";transform.position = initPosition;}} }動力學控制器——PhysicalAction
PhysicalAction也掛載到Arrow對象上,用來控制Arrow發射的運動效果。
/*PhysicalAction.cs*/ using System.Collections; using System.Collections.Generic; using UnityEngine;public class PhysicalAction : MonoBehaviour, IAction {float force = 3;public void Move(){}public void Move(float force){this.force = force;}// Update is called once per framevoid Update(){// 如果沒有射中靶對象if(this.gameObject.transform.position.z < -1){this.gameObject.tag = "WaveEnd";}}void FixedUpdate(){// 如果射中了靶對象if (this.gameObject.GetComponent<Rigidbody>() != null){this.gameObject.GetComponent<Rigidbody>().AddForce(new Vector3(0, 0, -1) * force);}}}記分器——ScoreController
ScoreController也是使用單例模式,作為全局唯一來記錄分數。
{score = 0;}public void AddScore(int score){this.score += score;}public int GetScore(){return this.score;}}效果展示
改進打飛碟游戲
增加一個運動的接口類ActionManager,物理運動PhysicalAction和運動學變換CCAction都將實現該接口。
public interface IActionManager {void Move(Vector3 direction, float speed); }CCAction
public class CCAction : MonoBehaviour, IActionManager {public Vector3 direction;public float speed;public void Move(Vector3 direction,float speed){this.direction = direction;this.speed = speed;}// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){this.gameObject.transform.position += speed * direction * Time.deltaTime;} }對于PhysicalManager而言,Move函數是與其功能不匹配的,但是我們又不想丟棄這個CCAction和ActionManager,所以我們可以通過adapter模式,進行適配。
PhysicalManager
using System.Collections; using System.Collections.Generic; using UnityEngine;public class PhysicalManager : MonoBehaviour, IActionManager {public float speed;public void Move(float speed){this.speed = speed;}public void Move(Vector3 direction, float speed){Move(speed);}void FixedUpdate(){Rigidbody rigid = this.gameObject.GetComponent<Rigidbody>();if(rigid){//Debug.Log(speed);rigid.AddForce(Vector3.down * speed);} }// Start is called before the first frame updatevoid Start(){this.gameObject.GetComponent<Rigidbody>().useGravity = false;}}總結
以上是生活随笔為你收集整理的Unity学习——射箭游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数字图像处理】图像感兴趣区域与图像放大
- 下一篇: 图像放大和缩小