final-期末大作业-制作AR射箭小游戏(Unity AR配置详细教程)

要求

大作业要求:

制作一款特定技术应用小游戏,并提交技术报告。

  1. 内容(请参考以下技术主题,但不限于这些主题):
  • 运用手机拍若干全景图,贴到天空盒或球型天空,做一个简单校园漫游功能。
  • 粒子系统效果制作,必须带一个控制组件,控制粒子呈现效果。
  • UI系统制作,包括展开式公告牌,背包系统。不包括血条等简单应用。
  • DoTween 组件仿写与实践
  • 坦克大战,必须包含3D导航技术
  • Vuforia组件与AR游戏创作

历届师兄优秀作品参考:https://blog.csdn.net/pmlpml/article/details/72236930?spm=1001.2014.3001.5502

  1. 报告提交方式和要求:
  • 博客网站选择,推荐: 博客园、简书、csdn、gitee page等公共博客或静态网站平台。
  • 游戏效果展示,博客 GIF: 工具抠抠视频秀;游戏视频:3分钟,上传流媒体网站分享,如 bilibili 这类广告少的网站
  • 完整代码保存在 Gitee,GitHub,避免不重要细节放在博客之中
  • 尊重他人劳动,在最后给出参考的博客、教材等
  1. 提交时间:

DDL:2023.01.14日前。
如有特殊情况如中招、生病,请以保重身体为第一要务,合理安排提交日期。

  1. 成绩评价:
  • 游戏作品的新颖性、技术博客面向大众易读易懂性,占 60%

  • 博客逻辑清晰,图文效果好,文字通顺, 占40%

  • 有较好的 UML 设计图,可以适当提高评分等级

  • 有较严重抄袭行为,要适当降低评分等级

  • 评分成绩采用 10 分制。不设0.5分


配置Unity开发AR的环境

我参考的教程视频:这个教程比较短,需要细心看,另外他使用的Unity版本跟老师讲的不一样,请尽量使用跟教程同一个版本,或者参考老师给的教程

配置需要很多耐心,请做好准备!

多图预警!!!


配置Unity2019.3.9f1

  • step1:请在Unity Hub中的install点击版本设置,如下
    在这里插入图片描述
  • step2:点击Add modules后,勾选如下的包并下载,下载较慢,需等待一段时间
    在这里插入图片描述

创建项目,并配置项目内环境

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

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

  • 在这里插入图片描述


发布到手机的配置

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

  • step1:手机配置,以华为手机为例,本机系统是鸿蒙2.0(亲测这里当安卓用是没问题的)
    在这里插入图片描述
  • step2:点击手机 设置 -> 关于手机,看到版本号,敲击八下后进入开发者模式,然后用USB将手机和电脑连接(这里记得选择文件传输
  • step3:回到Unity,选中左上角 File -> Buiding Settings
    在这里插入图片描述
  • step4:进入后选中Android,并点击右下角的switch platform转到安卓,并配置如下,注意Run Device选中你自己的手机设备,
    在这里插入图片描述
  • step5: 然后点击左下角的Player Settings,配置如下(主要是改一下红字的配置)在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

Vuforia数据库创建

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

  • step1: 到Vudoria官网点击Develop(这里需要注册一个账号)在这里插入图片描述
  • step2: 点击右上角第一个按钮Get Basic,输入license Name然后确认
  • 在这里插入图片描述- step3: 复制license key(下图红色块位置),然后点击Target Manager添加识别图

在这里插入图片描述

  • step4:点击Add Database,然后输入DatabaseName点击Create

在这里插入图片描述

  • step5:然后点击创建好的Database(上图中的ArrowShooting)进入如下界面
    在这里插入图片描述
  • step6:填好上面的内容,即创建了你的第一张AR识别图,然后点击Download Database下载两个文件Android Studio, Xcode or Visual Studio和Unity Editor
    在这里插入图片描述
  • step6:下载完之后将zip文件解压,解压完毕后如下,全部拖到项目中
    在这里插入图片描述
  • step7:点击import
    在这里插入图片描述

开始我们的项目!

  • step1: 如下创建AR Camera
    在这里插入图片描述

  • step2: 创建好之后,点击Open…这个按钮
    在这里插入图片描述

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

  • step4: 如下创建ImageTarget
    在这里插入图片描述

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

在这里插入图片描述

  • step6: 先将Perfabs拖到场景中确定好位置,再将Perfabs拖到ImageTareget下,这样就能顺利的使用AR的识别图功能啦

在这里插入图片描述

  • step7: 点击File->Build And Run,这是你的手机需要与电脑用USB相连,然后就等待安装啦
    在这里插入图片描述
  • step8: 安装之后,拍摄你的识别图,效果如下
    在这里插入图片描述

接下来是射箭小游戏!

  • step1: 按照我之前的博客 ch06-物理系统与碰撞——Arrowshooting射箭小游戏,配置各种预制件

  • step2:经过测试,在AR模式下,高速物体更容易穿模,所以Aroow的配置需做如下更改

    • 首先将Head变大,比例如下,或者更大也可以,但是小心造成箭没击中靶,却停在空中的Bug
      在这里插入图片描述

    • 然后,将Head的材料变成如下,点击进去,一层一层选中
      在这里插入图片描述

    • 最后,点击Main Color,将颜色透明度选中到0,这样,这个用于碰撞的Head就变成透明的了
      在这里插入图片描述

  • step3:创建两个ImageTarget并将模型位置调成好如下
    在这里插入图片描述

  • step4:脚本挂载如下(AR 模式下和ch07有点不同,所以如下挂载就行)
    在这里插入图片描述

代码

  • action.cs: 这个跟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() { }
}



  • ArrowCollider.cs:基本上没有变化,只修改了分数,这个是挂载到ArrowHead上的脚本,用于检碰撞

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));
		}

	}
}


  • ArrowFactory.cs:这里改变了GetArrow这个函数,因为AR识别图的精度问题,将弓箭旋转后,脚本往往不能很好的添加弓箭到正确的位置,所以我提前在弓箭上挂载了20支箭,增加游玩体验感
    在这里插入图片描述

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--;


			}
		}
	}

    

}


  • Controllor.cs:这个也基本上跟ch07一样

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;
	}

}


  • interface.cs

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();
}



  • scoreRecorder .cs

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();
    }
}


  • singleton.cs
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;
		}
	}
}



  • SSDirector .cs

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;
	}
}


  • UserGUI.cs:这里相比ch07添加了声音播放器,并且每1.3秒发射箭矢,20支箭得到50分即位获胜,否则失败,点击“重新开始”即可重新开始游戏

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();
			}
		}

	}
}


  • clearCamera.cs:在场景中创建一个空的GameObject,并挂载clearCamera脚本会使摄像头更加清晰
    在这里插入图片描述

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);
        }
    }
}




感想:

  • 因为全体缓考,所以自己也有更多时间完成大作业,选择了完成配置繁琐的AR大作业,因为课时不够,老师上课并没有介绍这个部分,全靠自学,说起来还踩了不少坑。不过踩坑之后,我发现自己对于每一个配置细节都非常清晰,也就有了上面这么多图片的配置介绍。
  • AR作业本可以选择看起来炫酷的模型,这样效果更惊艳,也无需更复杂的逻辑控制。但是我选择了制作一个简单的小游戏,这样也算是对整个学期学习内容的回顾了。
  • 本学期的Unity学习之路告一段落啦,从无法控制GmaeObject位置和移动的小白,到现在基本掌握编写小游戏,还尝试了AR的菜鸟,花了许多心血的,也从师兄师姐的博客中学习到很多东西,非常感恩。

链接:
github仓库
bilibili视频

猜你喜欢

转载自blog.csdn.net/yesor_not/article/details/128502082