当前位置: 首页 > news >正文

Vuforia AR篇(九)— AR塔防下篇

目录

  • 前言
  • 一、搭建UI
  • 二、创建脚本
  • 三、效果

前言

在增强现实(AR)技术快速发展的今天,Vuforia作为一个强大的AR开发平台,为开发者提供了许多便捷的工具和功能。在本篇博客中,我们将介绍如何使用Vuforia在Unity中创建一个简单的塔防游戏。通过结合Vuforia的图像识别和增强现实技术,我们可以将传统的塔防游戏带入一个全新的维度。


一、搭建UI

创建Canvas,并设置16:9

在这里插入图片描述

创建button,然后设置图片

在这里插入图片描述

在素材中选择一个合适的塔,然后做成自己的预制体

在这里插入图片描述

设置所有炮塔基座的tag和layer

在这里插入图片描述

设置敌人的tag和layer

在这里插入图片描述

设置所有炮塔基座的碰撞器

在这里插入图片描述

创建敌人显示的UI

创建一个image,然后选择上一期素材的图片

在这里插入图片描述

在图片下面创建一个text用于显示血量的数值

在这里插入图片描述

复制几份,然后显示不同的数值

在这里插入图片描述

在这里插入图片描述

创建敌人血条

创建一个Slider,用于制作血条显示,把图片修改成line并且删除子物体

在这里插入图片描述

创建一个子image,把图片也改成line,修改图片的填充选项,然后血条就完成了

在这里插入图片描述

在这里插入图片描述

设置Scrollbar的Handle Rect,至此血条UI设计完成

在这里插入图片描述

二、创建脚本

GameManager脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GameManager : MonoBehaviour
{public static GameManager Instance { get; private set; }public List<Transform> pointList;//玩家当前点击的塔public int currentChoice;//存储塔的预制体public List<GameObject> towerList;//存储塔的费用public List<int> towerCostList;//玩家总金币public int totalCoin;//玩家剩下的金币public int remainingCoin;//敌人血量public int maxHealth;public int currentHealth;private GameUi _gameUi;private SpawnManager _sm;//需要创建的敌人数量public int totalCreateEnemys;//击杀的敌人数量public int hasKilledEnemys;//当前游戏状态public bool isFinish;public bool isPause;public bool isPlant;void Awake(){if (Instance == null){Instance = this;}else{Destroy(gameObject);}_sm = GetComponent<SpawnManager>();//初始化totalCreateEnemys = 4;_sm.createNum = 4;totalCoin = remainingCoin = 100;maxHealth = currentHealth = 5;}void Start(){//开启敌人生成携程StartCoroutine(_sm.CreateEnemyCoroutine(3));}void Update(){if (Input.GetMouseButtonDown(0)){if (Camera.main != null){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;bool isHit = Physics.Raycast(ray, out hit);if (isHit){if (hit.transform.CompareTag("BaseBox")){//如果点击到了炮台基座if (hit.transform.childCount == 0){if (remainingCoin >= towerCostList[currentChoice]){if (isPlant){GameObject go = Instantiate(towerList[currentChoice], hit.transform.position,Quaternion.identity);go.transform.SetParent(hit.transform);go.transform.localPosition = new Vector3(0, 0.02f, 0);//更新金币和UIremainingCoin -= towerCostList[currentChoice];_gameUi.SetCoinUI();}}}}}}}if (currentHealth <= 0 || hasKilledEnemys >= totalCreateEnemys){GameEnd();}}//游戏结束private void GameEnd(){isFinish = true;StopAllCoroutines();_gameUi.ExitPanelShow();}//根据扫描情况开始或者暂停游戏public void PauseOrContinueGame(){Time.timeScale = !isPause ? 0f : 1f;isPause = !isPause;}
}

在这里插入图片描述

创建塔的脚本

using System; 
using System.Collections; 
using System.Collections.Generic; 
using UnityEngine; public class Tower : MonoBehaviour
{// 存储检测到的碰撞体数组public Collider[] colliders; public int maxSize;public float rotationSpeed;//攻击间隔public float attackInternal;//攻击开始的时间public float startTime;//tower的特效public GameObject hitEffect;public GameObject firePoint1;public GameObject firePoint2;private void Awake(){maxSize = 10; // 初始化最大碰撞体数量为10colliders = new Collider[maxSize]; // 初始化碰撞体数组rotationSpeed = 100;attackInternal = 0.5f;}private void Update(){//获取最近的敌人GameObject go = LookForTarget();if (go!=null){//修改炮台方向RotateTower(go);}startTime += Time.deltaTime;if (startTime>attackInternal){NormalAttack();startTime = 0;}}// 检测塔范围内的敌人public virtual GameObject LookForTarget(){// 清空数据Array.Clear(colliders,0,colliders.Length);// 使用OverlapSphereNonAlloc方法检测塔范围内的敌人,结果存储在colliders数组中Physics.OverlapSphereNonAlloc(transform.position, 1, colliders, LayerMask.GetMask("Enemy"));GameObject closestObj = null; float distance = float.MaxValue; for (int i = 0; i < colliders.Length; i++) {if (colliders[i]!=null){GameObject currentObj = colliders[i].gameObject; // 计算当前对象与塔的距离float tempDistance = Vector3.Distance(transform.position, currentObj.transform.position); // 如果当前对象距离小于已知最小距离if (tempDistance < distance) {distance = tempDistance; closestObj = colliders[i].gameObject; }}}return closestObj; }// 控制塔朝向敌人public void RotateTower(GameObject go){Vector3 dir = go.transform.position - transform.position;Vector3 rotationDir = Vector3.RotateTowards(transform.forward, dir, 0.5f, 360f);Quaternion targetRotation = Quaternion.LookRotation(rotationDir);transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);}// 塔的攻击public void NormalAttack(){GameObject target = LookForTarget();    if (target!=null){Enemy enemy = target.GetComponent<Enemy>();if (enemy!=null){//生成攻击特效var o = Instantiate(hitEffect, firePoint1.transform.position, transform.rotation);//删除特效Destroy(o,0.2f);enemy.Hurt();}}}
}

在这里插入图片描述

创建UI的脚本


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class GameUi : MonoBehaviour
{public Button towerBtn;public Text enemyText;public Text coinText;public Text healthText;//存储血条public List<Slider> sliders;//游戏结束UIpublic Image gameOverUI;//游戏结束按钮public Button gameOverBtn;void Awake(){towerBtn.onClick.AddListener(CreateTower);gameOverBtn.onClick.AddListener(ExitGame);SetBloodPositionInfo();SetGamOverShow();}void Start(){}void Update(){}private void CreateTower(){GameManager.Instance.isPlant = true;GameManager.Instance.currentChoice = 0;}public void SetEnemyUI(){enemyText.text = $"{GameManager.Instance.hasKilledEnemys}/{GameManager.Instance.totalCreateEnemys}";}public void SetCoinUI(){coinText.text = $"{GameManager.Instance.remainingCoin}/{GameManager.Instance.totalCoin}";}public void SetHealthUI(){healthText.text = $"{GameManager.Instance.currentHealth}/{GameManager.Instance.maxHealth}";}//设置血条的位置信息public void SetBloodPositionInfo(){for (int i = 0; i < sliders.Count; i++){var rectTransform = sliders[i].GetComponent<RectTransform>();rectTransform.position = new Vector3(-10000f, 0f, 0f);sliders[i].gameObject.SetActive(false);}}//查找到没有激活的血条然后显示出来public Slider FindNoActivationBloodShow(){//获取一个没有激活的slidervar slider = sliders.Find(x => !x.gameObject.activeSelf);slider.gameObject.SetActive(true);return slider;}public void SetGamOverShow(){var rectTransform = gameOverUI.GetComponent<RectTransform>();rectTransform.position = new Vector3(-10000f, 0f, 0f);}public void ExitPanelShow(){var rectTransform = gameOverUI.GetComponent<RectTransform>();rectTransform.position = new Vector3(Screen.width / 2f, Screen.height / 2f, 0f);}//退出游戏public void ExitGame(){Application.Quit();}
}

在这里插入图片描述

创建SpawnManager脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SpawnManager : MonoBehaviour
{public GameObject enemyPrefab;public GameObject parent;//需要创建的敌人数量public int createNum;void Awake(){createNum = 4;}void Start (){CreateEnemy();}void Update (){}public void CreateEnemy(){GameObject enemy = Instantiate(enemyPrefab, parent.transform);enemy.transform.SetParent(parent.transform);enemy.transform.localPosition = new Vector3(-1f, 0.25f, 4f);}public IEnumerator CreateEnemyCoroutine(float duration){int count = 0;while (true){if (count<createNum){yield return new WaitForSeconds(duration);CreateEnemy();count++;}else{break;}}}}

在这里插入图片描述

创建Enemy脚本


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class Enemy : MonoBehaviour
{public int currentIndex;public float moveSpeed;//血量public int maxHp;public int currentHp;private Slider _slider;private RectTransform _rt;//血条跟随偏移public float xOffest;public float yOffest;private GameUi _gameUi;void Awake(){moveSpeed = 0.2f;currentIndex = 0;currentHp = maxHp = 10;_gameUi = GameObject.Find("Canvas").GetComponent<GameUi>();_slider = _gameUi.FindNoActivationBloodShow();_rt = _slider.GetComponent<RectTransform>();xOffest = 5;yOffest = 5;}void Start(){}void Update(){if (!GameManager.Instance.isFinish){BloodFollow();Move();}//当摄像头没有扫描到图片的时候,暂停游戏并隐藏UIif (GameManager.Instance.isPause){SetSliderInfoWhenPause();}}public void Move(){int nextPoint = currentIndex + 1;if (GameManager.Instance.pointList.Count <= nextPoint){ReachFinalPoint();return;}Vector3 v3 = transform.InverseTransformPoint(GameManager.Instance.pointList[nextPoint].position);transform.Translate(v3 * (Time.deltaTime * moveSpeed));if (IsArrive(GameManager.Instance.pointList[nextPoint])){currentIndex++;}}bool IsArrive(Transform t){float distance = Vector3.Distance(transform.position, t.position);if (distance < 0.05f){return true;}return false;}// 受伤的方法public void Hurt(int damge = 2){currentHp -= damge;_slider.value = currentHp * 1.0f / (maxHp * 1.0f);if (currentHp<=0){Die();}}//死亡效果public void Die(){_rt.position = new Vector3(-10000f, 0f, 0f);_slider.value = 1;_slider.gameObject.SetActive(false);GameManager.Instance.hasKilledEnemys += 1;_gameUi.SetEnemyUI();Destroy(gameObject);}//血条跟随public void BloodFollow(){if (Camera.main != null){Vector2 point = Camera.main.WorldToScreenPoint(transform.position);_rt.position = point + new Vector2(xOffest, yOffest);}}//隐藏UIpublic void SetSliderInfoWhenPause(){if (_rt!=null){_rt.position = new Vector3(-10000f, 0, 0);}}//移动到最后一个点处理方法public void ReachFinalPoint(){_rt.position = new Vector3(-10000f, 0, 0);_slider.value = 1;_slider.gameObject.SetActive(false);GameManager.Instance.currentHealth -= 1;_gameUi.SetHealthUI();GameObject.Destroy(gameObject);}}

在这里插入图片描述

根据扫描情况开始或者暂停游戏方法赋值

在这里插入图片描述

三、效果

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 简单分享下python打包手机app的apk
  • 【C++】初识面向对象:类与对象详解
  • 十八.核心动画 - 使用CAGradientLayer图层构建渐变视图
  • 用Python在Word文档中创建和执行条件邮件合并
  • bootstrap之表格
  • module ‘pkgutil‘ has no attribute ‘ImpImporter‘. Did you mean: ‘zipimporter‘?
  • javascript:检测图片的宽高
  • 社交及时通讯平台完整版源码,uniapp技术,可打包成app
  • QEMU理解与分析系列(1):QEMU简介
  • Flutter 电视投屏模块
  • 单例模式(java)
  • jupyter notebook魔法命令
  • Phpstorm实现本地SSH开发远程机器(或虚拟机)项目
  • Java并发—ReetrantLock详解
  • 拷贝函数promax讲解
  • [数据结构]链表的实现在PHP中
  • 【面试系列】之二:关于js原型
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • CentOS7 安装JDK
  • eclipse的离线汉化
  • JavaScript HTML DOM
  • js面向对象
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Spring Boot快速入门(一):Hello Spring Boot
  • SpriteKit 技巧之添加背景图片
  • Unix命令
  • vagrant 添加本地 box 安装 laravel homestead
  • 猴子数据域名防封接口降低小说被封的风险
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 来,膜拜下android roadmap,强大的执行力
  • 如何设计一个比特币钱包服务
  • 深度学习中的信息论知识详解
  • 使用docker-compose进行多节点部署
  • 算法系列——算法入门之递归分而治之思想的实现
  • 王永庆:技术创新改变教育未来
  • 用mpvue开发微信小程序
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • ​油烟净化器电源安全,保障健康餐饮生活
  • ( 10 )MySQL中的外键
  • (pojstep1.3.1)1017(构造法模拟)
  • (二)linux使用docker容器运行mysql
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (简单) HDU 2612 Find a way,BFS。
  • (数据结构)顺序表的定义
  • (算法)Game
  • (原创)可支持最大高度的NestedScrollView
  • **PHP二维数组遍历时同时赋值
  • .gitignore文件—git忽略文件
  • .net core使用ef 6
  • .net 获取url的方法
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .php文件都打不开,打不开php文件怎么办