赞
踩
链接:
github仓库
bilibili视频
大作业要求:
制作一款特定技术应用小游戏,并提交技术报告。
历届师兄优秀作品参考:https://blog.csdn.net/pmlpml/article/details/72236930?spm=1001.2014.3001.5502
DDL:2023.01.14日前。
如有特殊情况如中招、生病,请以保重身体为第一要务,合理安排提交日期。
游戏作品的新颖性、技术博客面向大众易读易懂性,占 60%
博客逻辑清晰,图文效果好,文字通顺, 占40%
有较好的 UML 设计图,可以适当提高评分等级
有较严重抄袭行为,要适当降低评分等级
评分成绩采用 10 分制。不设0.5分
我参考的教程视频:这个教程比较短,需要细心看,另外他使用的Unity版本跟老师讲的不一样,请尽量使用跟教程同一个版本,或者参考老师给的教程
配置需要很多耐心,请做好准备!
多图预警!!!


step1:在项目中点击Windows -> Package Manage,勾选如下四个包,并下载(第二个包可能会在下载第一个包的时候自动下载)

step2:继续下载如下一个包,支持Vuforia

可能前期配置有点长,但是请耐心细心的跟着做,不然很可能会踩坑噢…






最后一个前期工作啦!!!请耐心

- step3: 复制license key(下图红色块位置),然后点击Target Manager添加识别图





step1: 如下创建AR Camera

step2: 创建好之后,点击Open…这个按钮

step3: 将前面在Vuforia复制的license key黏贴到这个位置,我们的AR Camera就配置好啦!
(Tips:Max Simultaneous Trackes Images控制同时识别图的数量,我这里是3,根据需求设置)

step4: 如下创建ImageTarget

step5: 创建好之后如下,选择刚刚从Vuforia下载的Database和你想要的识别图




step1: 按照我之前的博客 ch06-物理系统与碰撞——Arrowshooting射箭小游戏,配置各种预制件
step2:经过测试,在AR模式下,高速物体更容易穿模,所以Aroow的配置需做如下更改
首先将Head变大,比例如下,或者更大也可以,但是小心造成箭没击中靶,却停在空中的Bug

然后,将Head的材料变成如下,点击进去,一层一层选中

最后,点击Main Color,将颜色透明度选中到0,这样,这个用于碰撞的Head就变成透明的了

step3:创建两个ImageTarget并将模型位置调成好如下

step4:脚本挂载如下(AR 模式下和ch07有点不同,所以如下挂载就行)

using System.Collections; using System.Collections.Generic; using UnityEngine; public class SSAction : ScriptableObject { public bool enable = true; public bool destroy = false; public GameObject gameobject; public Transform transform; public ISSActionCallback callback; protected SSAction() { } public virtual void Start() { throw new System.NotImplementedException(); } public virtual void Update() { throw new System.NotImplementedException(); } public virtual void FixedUpdate() { throw new System.NotImplementedException(); } } public enum SSActionEventType : int { Started, Competeted } public interface ISSActionCallback { void SSActionEvent(SSAction source, GameObject arrow = null); } public class SSActionManager : MonoBehaviour, ISSActionCallback { private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); private List<SSAction> waitingAdd = new List<SSAction>(); private List<int> waitingDelete = new List<int>(); protected void Update() { foreach (SSAction ac in waitingAdd) actions[ac.GetInstanceID()] = ac; waitingAdd.Clear(); foreach (KeyValuePair<int, SSAction> kv in actions) { SSAction ac = kv.Value; if (ac.destroy) waitingDelete.Add(ac.GetInstanceID()); else if (ac.enable) ac.Update(); } foreach (int key in waitingDelete) { SSAction ac = actions[key]; actions.Remove(key); DestroyObject(ac); } waitingDelete.Clear(); } protected void FixedUpdate() { foreach (SSAction ac in waitingAdd) actions[ac.GetInstanceID()] = ac; waitingAdd.Clear(); foreach (KeyValuePair<int, SSAction> kv in actions) { SSAction ac = kv.Value; if (ac.destroy) waitingDelete.Add(ac.GetInstanceID()); else if (ac.enable) ac.FixedUpdate(); } foreach (int key in waitingDelete) { SSAction ac = actions[key]; actions.Remove(key); DestroyObject(ac); } waitingDelete.Clear(); } public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager) { action.gameobject = gameobject; action.transform = gameobject.transform; action.callback = manager; waitingAdd.Add(action); action.Start(); } public void SSActionEvent(SSAction source, GameObject arrow = null) { if (arrow != null) { ArrowTremble tremble = ArrowTremble.GetSSAction(); this.RunAction(arrow, tremble, this); } else { Controllor scene_controller = (Controllor)SSDirector.GetInstance().CurrentScenceController; } } } public class ArrowFlyActionManager : SSActionManager { private ArrowFlyAction fly; public Controllor scene_controller; protected void Start() { scene_controller = (Controllor)SSDirector.GetInstance().CurrentScenceController; scene_controller.action_manager = this; } public void ArrowFly(GameObject arrow, Vector3 wind, float holdTime) { fly = ArrowFlyAction.GetSSAction(wind, holdTime); this.RunAction(arrow, fly, this); } } public class ArrowFlyAction : SSAction { private float holdTime; public Vector3 wind; private ArrowFlyAction() { } public static ArrowFlyAction GetSSAction(Vector3 wind, float holdTime_) { ArrowFlyAction action = CreateInstance<ArrowFlyAction>(); action.holdTime = holdTime_; action.wind = wind; return action; } public override void Update() { } public override void FixedUpdate() { //加上风的力 this.gameobject.GetComponent<Rigidbody>().AddForce(wind*10, ForceMode.Force); if (this.transform.position.z >=20 || this.gameobject.tag == "hit") { this.destroy = true; this.callback.SSActionEvent(this, this.gameobject); } } public override void Start() { Transform arrow = this.gameobject.transform; arrow.GetComponent<Rigidbody>().isKinematic = false; //这个是添加力的 arrow.GetComponent<Rigidbody>().AddForce((arrow.GetChild(0).position-arrow.position) * 40f * holdTime, ForceMode.Impulse); arrow.SetParent(null);//解除父子关系 } } public class ArrowTremble : SSAction { float radian = 0; float per_radian = 3f; float radius = 0.01f; Vector3 old_pos; public float left_time = 0.8f; private ArrowTremble() { } public override void Start() { old_pos = transform.position; } public static ArrowTremble GetSSAction() { ArrowTremble action = CreateInstance<ArrowTremble>(); return action; } public override void Update() { left_time -= Time.deltaTime; if (left_time <= 0) { transform.position = old_pos; this.destroy = true; this.callback.SSActionEvent(this); } radian += per_radian; float dy = Mathf.Cos(radian) * radius; transform.position = old_pos + new Vector3(0, dy, 0); } public override void FixedUpdate() { } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ArrowCollider : MonoBehaviour { public Controllor scene_controller; public scoreRecorder recorder; void Start() { scene_controller = SSDirector.GetInstance().CurrentScenceController as Controllor; recorder = singleton<scoreRecorder>.Instance; } void OnTriggerEnter(Collider c) { if (c.gameObject.name == "T1" || c.gameObject.name == "T2" || c.gameObject.name == "T3" || c.gameObject.name == "T4" || c.gameObject.name == "T5") { gameObject.transform.parent.gameObject.GetComponent<Rigidbody>().isKinematic = true; gameObject.SetActive(false); //Debug.Log(this.gameObject.transform.position); float dis = Mathf.Sqrt(this.gameObject.transform.position.x * this.gameObject.transform.position.x + this.gameObject.transform.position.y * this.gameObject.transform.position.y); float point = 0; if (dis >= 0 && dis < 1) point = 5f; else if(dis >= 1 && dis < 2) point = 4f; else if(dis >= 2 && dis < 3) point = 3f; else if(dis >= 3 && dis < 4) point = 2f; else if(dis >= 4 && dis < 5) point = 1f; //Debug.Log("集中了靶子:" + c.gameObject.name + " "+ point); recorder.Record((int)Mathf.Floor(point)); } } }

using System.Collections; using System.Collections.Generic; using UnityEngine; public class ArrowFactory : MonoBehaviour { private GameObject arrow = null; private GameObject AB = null; private GameObject ImageTargetAB = null; private List<GameObject> usingArrowList = new List<GameObject>(); private Queue<GameObject> unusedArrowList = new Queue<GameObject>(); public Controllor sceneControler; private int arrownum = 0; private List<GameObject> ArrowList = new List<GameObject>(); public void initiate(GameObject AB_,GameObject ImageTargetAB_) { AB = AB_; ImageTargetAB = ImageTargetAB_; } private void Start() { GameObject a; for(int i = 0; i < 20; i++) { a = GameObject.Find("Arrow (" + i + ")"); ArrowList.Add(a); a.SetActive(false); } } public GameObject GetArrow() { //还原工厂 //AB.transform.SetPositionAndRotation(new Vector3(0, 0, 0), Quaternion.Euler(0, 90, 0)); //AB.transform.localScale = new Vector3(1, 1, 1); //if (unusedArrowList.Count == 0) //{ // //arrow = Instantiate(Resources.Load<GameObject>("Prefabs/Arrow")); // arrow = GameObject.Find("Arrow"); // Debug.Log("Arrow的位置:" + arrow.transform.position); // Debug.Log("Arrow的角度:" + arrow.transform.rotation); //} //else //{ // arrow = unusedArrowList.Dequeue(); // arrow.gameObject.SetActive(true); //} //arrow.transform.parent = AB.transform; //arrow.transform.SetPositionAndRotation(ImageTargetAB.transform.position, Quaternion.Euler(ImageTargetAB.transform.rotation.x, ImageTargetAB.transform.rotation.y+90, ImageTargetAB.transform.rotation.z )); //Debug.Log("Image的位置: " + ImageTargetAB.transform.position); //Debug.Log("Image的角度: " + ImageTargetAB.transform.rotation); //arrow.transform.localScale = new Vector3(1.6f, 1.6f, 1.6f); //usingArrowList.Add(arrow); //return arrow; //因为AR识别的图片角度不精确,没有办法使用工厂模式动态添加Arrow,使用这种方式能更好的保证体验感 if (arrownum < 20) { arrow = ArrowList[arrownum]; arrow.SetActive(true); arrownum++; } usingArrowList.Add(arrow); return arrow; } public void FreeArrow() { for (int i = 0; i < usingArrowList.Count; i++) { if (usingArrowList[i].transform.position.y <= -15 || usingArrowList[i].transform.position.y >= 15) { usingArrowList[i].GetComponent<Rigidbody>().isKinematic = true; usingArrowList[i].SetActive(false); usingArrowList[i].transform.position = new Vector3(0, 0, 0); unusedArrowList.Enqueue(usingArrowList[i]); usingArrowList.Remove(usingArrowList[i]); i--; } } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class Controllor : MonoBehaviour, IUserAction, ISceneController { public scoreRecorder recorder; public ArrowFactory arrow_factory; public ArrowFlyActionManager action_manager; public UserGUI user_gui; SSDirector director; private GameObject AB; private GameObject arrow; private GameObject target; private GameObject ImageTargetAB; private bool game_start = false; private string wind = ""; private float wind_directX; private float wind_directY; public string GetScore() { return recorder.getScore(); } public string GetWind() { return wind; } public void Restart() { SceneManager.LoadScene(0); } public void BeginGame() { game_start = true; } void Update() { if (game_start) arrow_factory.FreeArrow(); } public void LoadResources() { //找到场景中的弓和靶 target = GameObject.Find("target"); AB = GameObject.Find("AB"); ImageTargetAB = GameObject.Find("ImageTargetAB");//这个主要是控制弓箭的方向 } public bool haveArrowOnPort() { return (arrow != null); } void Start() { director = SSDirector.GetInstance(); director.CurrentScenceController = this; LoadResources(); arrow_factory = singleton<ArrowFactory>.Instance; arrow_factory.initiate(AB, ImageTargetAB); recorder = gameObject.AddComponent<scoreRecorder>() as scoreRecorder; user_gui = gameObject.AddComponent<UserGUI>() as UserGUI; action_manager = gameObject.AddComponent<ArrowFlyActionManager>() as ArrowFlyActionManager; } public void create() { if (arrow == null) { wind_directX = Random.Range(-2f, 2f); wind_directY = Random.Range(-2f, 2f); CreateWind(); arrow = arrow_factory.GetArrow(); } } public void UpdateArrowPositioin() { arrow.transform.SetPositionAndRotation(ImageTargetAB.transform.position, Quaternion.Euler(ImageTargetAB.transform.rotation.x, ImageTargetAB.transform.rotation.y+90, ImageTargetAB.transform.rotation.z)); } public void MoveBow(Vector3 fwd,float Xinput,float Yinput) { if (!game_start) { return; } //这里就不直接用触屏移动弓箭了,使用AR的方式移动并旋转角度 //Vector3 vaxis = Vector3.Cross(fwd, Vector3.right); //AB.transform.Rotate(vaxis, -Xinput * 5, Space.World); //Vector3 haxis = Vector3.Cross(fwd, Vector3.up); //AB.transform.Rotate(haxis, -Yinput * 5, Space.World); } public void Shoot(float holdTime) { if (game_start) { Vector3 wind = new Vector3(wind_directX, wind_directY, 0); action_manager.ArrowFly(arrow, wind, holdTime); //这里添加一个音效控件 arrow = null; } } public void CreateWind() { string Horizontal = "", Vertical = "", level = ""; if (wind_directX > 0) { Horizontal = "西"; } else if (wind_directX <= 0) { Horizontal = "东"; } if (wind_directY > 0) { Vertical = "南"; } else if (wind_directY <= 0) { Vertical = "北"; } if ((wind_directX + wind_directY) / 2 > -0.5f && (wind_directX + wind_directY) / 2 < 0.5f) { level = "1 级"; } else if ((wind_directX + wind_directY) / 2 > -1f && (wind_directX + wind_directY) / 2 < 1f) { level = "2 级"; } else if ((wind_directX + wind_directY) / 2 > -1.5f && (wind_directX + wind_directY) / 2 < 1.5f) { level = "3 级"; } else if ((wind_directX + wind_directY) / 2 > -2f && (wind_directX + wind_directY) / 2 < 2f) { level = "4 级"; } wind = Horizontal + Vertical + "风" + " " + level; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public interface ISceneController { void LoadResources(); } public interface IUserAction { void MoveBow(Vector3 fwd, float Xinput, float Yinput); void Shoot(float holdTime); string GetScore(); void Restart(); string GetWind(); void BeginGame(); void create(); bool haveArrowOnPort(); void UpdateArrowPositioin(); }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class scoreRecorder : MonoBehaviour { public int score; void Start() { score = 0; } public void Record(int point) { score = point + score; Debug.Log("scoreRecorder:" + score); } public string getScore() { return score.ToString(); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class singleton<T> : MonoBehaviour where T : MonoBehaviour { protected static T instance; public static T Instance { get { if (instance == null) { instance = (T)FindObjectOfType(typeof(T)); if (instance == null) { Debug.LogError("An instance of " + typeof(T) + " is needed in the scene, but there is none."); } } return instance; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class : object { private static SSDirector _instance; public ISceneController CurrentScenceController { get; set; } public static SSDirector GetInstance() { if (_instance == null) { _instance = new SSDirector(); } return _instance; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class UserGUI : MonoBehaviour { private IUserAction action; GUIStyle style = new GUIStyle(); GUIStyle style2 = new GUIStyle(); GUIStyle style3 = new GUIStyle(); private bool game_start = false; private float deltatime = 0; public scoreRecorder recorder; public AudioSource music;//音源AudioSource相当于播放器,而音效AudioClip相当于磁带 public AudioClip shoot;//这里我要给主角添加跳跃的音效 public Camera cam; private float holdTime =0; private int arrow_sum = 21; void Start() { action = SSDirector.GetInstance().CurrentScenceController as IUserAction; recorder = singleton<scoreRecorder>.Instance; //给对象添加一个AudioSource组件 music = gameObject.AddComponent<AudioSource>(); //设置不一开始就播放音效 music.playOnAwake = false; //加载音效文件,我把跳跃的音频文件命名为jump shoot = Resources.Load<AudioClip>("music/shoot"); //把音源music的音效设置为jump music.clip = shoot; style.normal.textColor = new Color(0, 0, 0, 1); style.fontSize = 32; style2.normal.textColor = new Color(1, 1, 1); style2.fontSize = 64; style3.normal.textColor = new Color(1, 1, 1); style3.fontSize = 32; holdTime = 0; cam = Camera.main; } void Update() { if (game_start) { if (action.haveArrowOnPort()) { //更新箭的位置 //action.UpdateArrowPositioin(); //这里改成每2秒射击一次 deltatime += Time.deltaTime; Vector3 fwd = cam.transform.forward; fwd.Normalize(); if (deltatime >= 1.3) { //action.MoveBow(fwd, Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")); holdTime = deltatime; action.Shoot(holdTime); holdTime = 0; deltatime = 0; } } else if(arrow_sum>0) { deltatime += Time.deltaTime; if (deltatime >= 0.5) { action.create(); deltatime = 0; //播放音效 music.Play(); arrow_sum--; } } } } private void OnGUI() { action = SSDirector.GetInstance().CurrentScenceController as IUserAction; if (game_start) { GUI.Label(new Rect(10, 5, 200, 50), "风向: ", style); GUI.Label(new Rect(10, 45, 200, 50), "分数:", style); //GUI.Label(new Rect(10, 85, 200, 50), "力量:", style); //Debug.Log("风&&&&&&&&&&&&&&&&&&" + action.GetScore()); GUI.Label(new Rect(90, 5, 200, 50), action.GetWind(), style); //GUI.Label(new Rect(90, 45, 200, 50), action.GetScore(), style); GUI.Label(new Rect(90, 45, 200, 50), recorder.score.ToString(), style); //GUI.Label(new Rect(90, 85, 200, 50), holdTime.ToString(), style); if (GUI.Button(new Rect(Screen.width - 200, 5, 200, 100), "重新开始") ) { Time.timeScale = 1; action.Restart(); return; } if (arrow_sum==0 && recorder.score >= 50) { GUI.Label(new Rect(Screen.width / 2 - 220, Screen.width / 2 - 300, 100, 100), "Congratulations!", style2); Time.timeScale = 0; } else if (arrow_sum == 0 && recorder.score < 50)//射完了箭 { GUI.Label(new Rect(Screen.width / 2 - 220, Screen.width / 2 - 300, 100, 100), "Please Try Again!", style2); Time.timeScale = 0; } } else { Time.timeScale = 1; GUI.Label(new Rect(Screen.width / 2 - 220, Screen.width / 2 - 400, 100, 100), "Arrow Shooting", style2); GUI.Label(new Rect(Screen.width / 2 - 180, Screen.width / 2 - 300, 100, 100), " 获得50分即游戏胜利!", style3); if (GUI.Button(new Rect(Screen.width / 2 - 120, Screen.width / 2 - 150, 200, 100), "游戏开始")) { game_start = true; action.BeginGame(); } } } }

using UnityEngine; using System.Collections; using Vuforia; public class clearCamera : MonoBehaviour { // Use this for initialization void Start() { VuforiaARController.Instance.RegisterVuforiaStartedCallback(OnVuforiaStarted); VuforiaARController.Instance.RegisterOnPauseCallback(OnPaused); } void Update() { } private void OnVuforiaStarted() { CameraDevice.Instance.SetFocusMode( CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO); } private void OnPaused(bool paused) { if (!paused) { // resumed // Set again autofocus mode when app is resumed CameraDevice.Instance.SetFocusMode( CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。