Unity3D学习FPS游戏(8)装弹和弹夹UI显示

前言:实现了武器的基本发射功能,但是我们弹夹数量是有限,之前并没有做装弹和弹夹显示的功能。本篇实现装弹和弹夹显示。

装弹和弹夹UI显示

  • 装弹
    • 目标
    • 思路和实现
  • 弹夹UI显示
    • 目标
    • 弹夹UI的思路和实现
    • UI代码的思路和实现
  • 武器控制的完整代码
  • 效果
  • 补充知识
    • 锚点

装弹

目标

Unity官方的项目中,如果不是满弹夹的情况,子弹的数量会随时间自动增加。

思路和实现

如果子弹没有满,且在没有开枪的情况下,子弹会自动装填。

由于子弹的自动装填是随着时间慢慢增加的,可以通过协程来实现。

public float reloadBulletTime = 2F;// 每次装弹的时间
public int reloadBulletNum = 10;// 每次装弹的数量
IEnumerator ReloadBullet()
{while (!isFire&&currentBulletNum<bulletNum)// 达到弹夹容量,协程自己会停止运行{yield return new WaitForSeconds(reloadBulletTime);currentBulletNum= (reloadBulletNum+currentBulletNum)>bulletNum?bulletNum:(reloadBulletNum + currentBulletNum);// 判断一下会不会超过弹夹容量}
}

当子弹左键按下的时候,就表示要开枪,这时候就应该停止装弹协程。
当子弹左键松开的时候,就表示停止开枪,这时候就应该开启装弹协程。

private void OpenFire()
{if (Input.GetMouseButtonDown(0)){StopCoroutine("ReloadBullet");isFire = true;StartCoroutine("Shoot");}if (Input.GetMouseButtonUp(0)){isFire = false;StopCoroutine("Shoot");StartCoroutine("ReloadBullet");}
}

弹夹UI显示

目标

子弹数量发生变化的时候,弹夹会有一个UI进度条提醒当前子弹的情况。

弹夹UI的思路和实现

UI毫无疑问得在Canvas上进行。

在之前显示做准星的Canvas上,右键UI-Slider,添加一个滑动条。
默认的Slider中三个部分分别对应界面内容如下,Backgroud是滑动条底色,Fill Area是滑动区域,Handle Slider Area是滑动区域末尾小圆球。
在这里插入图片描述
其中Handle Slider Area小圆球,我们可以删掉,因为我们并不用。
把Fill Area中的Fill拖到和Backgroud平级,并调整strech(伸展)左右铺满,Fill Area作用不大可以删掉只是更好约束了Fill的strech。
在这里插入图片描述
接下来调整颜色和样式,给Backgroud和Fill选择方形的背景图片TEX_Black和TEX_White。下面演示了是如何找到素材和切换背景图片。
在这里插入图片描述
然后修改Fill的颜色,模仿Unity官方案例的蓝色,然后调整Slider大小。
位置为常在的右下角,这个Slider直接拖动到右下角是没有用的,可以通过锚点来常驻右下角。锚点调到右下角后,再拖动到合适位置。这样屏幕无论怎么样变化,Slider位置都是相对右下角进行变化的。
在这里插入图片描述
在这里插入图片描述
添加弹夹的UI,Slider下面右键新增UI-Image,然后切换Source Image为武器的图标。切换图片后,可以Set Native Size,可将图像框的尺寸设置为纹理的原始像素大小,不会变形太厉害。
在这里插入图片描述
调整武器的图标大小到合适。
在这里插入图片描述

UI代码的思路和实现

代码控制Slider,先在代码中添加Slider组件,添加后Unity把组件拖过来就行了。

public Slider bulletSlider;// 弹夹Slider UI

在Start函数中初始化Slider,最大值和当前值。

void Start()
{if (bulletSlider){bulletSlider.maxValue = bulletNum;bulletSlider.value = currentBulletNum;}
}

在子弹数量会发生变化的地方,进行Slider更新,会发生变化的地方只有发射子弹(Shoot)和装弹(ReloadBullet)两个协程中。

IEnumerator Shoot()
{while (isFire){if (currentBulletNum >0){GameObject newBullet = bulletPool.Get();currentBulletNum--;// 更新弹夹数量if (bulletSlider)bulletSlider.value = currentBulletNum;}yield return new WaitForSeconds(shootInterval);}
}
IEnumerator ReloadBullet()
{while (!isFire&&currentBulletNum<bulletNum){yield return new WaitForSeconds(reloadBulletTime);currentBulletNum = (reloadBulletNum+currentBulletNum)>bulletNum?bulletNum:(reloadBulletNum + currentBulletNum);// 更新弹夹数量if (bulletSlider)bulletSlider.value = currentBulletNum;}
}

武器控制的完整代码

这次主要修改的WeaponController的代码,下面是修改后WeaponController的完整代码。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
using UnityEngine.UI;public class WeaponController : MonoBehaviour
{[Header("武器数值")]public Vector3 defaultPosition= new Vector3(0.4F, -0.6F, 1.15F);// 默认位置public Vector3 centerPosition = new Vector3(0F, -0.6F, 0.807F);// 中心位置public float positionLerpRatio = 0.5f;// 线性插值参数[Header("子弹数值")]public Transform shootPoint;// 子弹发射位置public GameObject bullet;// 子弹预制体public float shootInterval = 1;// 子弹间隔时间private bool isFire;// 发射状态public int bulletNum = 100;// 弹夹public int currentBulletNum;// 当前子弹的数量public float reloadBulletTime = 2F;// 每次装弹的时间public int reloadBulletNum = 10;// 每次装弹的数量public Slider bulletSlider;// 弹夹Slider UIprivate ObjectPool<GameObject> bulletPool;// 子弹对象池private void Awake(){currentBulletNum = bulletNum;bulletPool = new ObjectPool<GameObject>(CreateBullet,BulletOnGet, BulletOnRelease, BulletOnDestory,true,10,bulletNum);}GameObject CreateBullet(){GameObject obj = Instantiate(bullet, shootPoint);obj.GetComponent<BulletController>().bulletPool = bulletPool;return obj;}void BulletOnGet(GameObject obj){obj.GetComponent<BulletController>().BulletReset();obj.gameObject.SetActive(true);}void BulletOnRelease(GameObject obj){obj.gameObject.SetActive(false);}void BulletOnDestory(GameObject obj){Destroy(obj);}void Start(){// 弹夹UI初始化if (bulletSlider){bulletSlider.maxValue = bulletNum;bulletSlider.value = currentBulletNum;}}void Update(){ChangePosition();OpenFire();}private void OpenFire(){if (Input.GetMouseButtonDown(0)){StopCoroutine("ReloadBullet");isFire = true;StartCoroutine("Shoot");}if (Input.GetMouseButtonUp(0)){isFire = false;StopCoroutine("Shoot");StartCoroutine("ReloadBullet");}}IEnumerator Shoot(){while (isFire){if (currentBulletNum >0){//GameObject newBullet = Instantiate(bullet, shootPoint);GameObject newBullet = bulletPool.Get();currentBulletNum--;// 弹夹UI更新if (bulletSlider)bulletSlider.value = currentBulletNum;}yield return new WaitForSeconds(shootInterval);}}private void ChangePosition(){// 按下左键if (Input.GetMouseButtonDown(1)){StopCoroutine("ToDefault");StartCoroutine("ToCenter");}// 松开左键if (Input.GetMouseButtonUp(1)){StopCoroutine("ToCenter");StartCoroutine("ToDefault");}}IEnumerator ToCenter() {while (transform.localPosition!=centerPosition){transform.localPosition = Vector3.Lerp(transform.localPosition, centerPosition, positionLerpRatio);yield return null;// 等待一帧}}IEnumerator ToDefault(){while (transform.localPosition != defaultPosition){transform.localPosition = Vector3.Lerp(transform.localPosition, defaultPosition, positionLerpRatio);yield return null;// 等待一帧}}IEnumerator ReloadBullet(){while (!isFire&&currentBulletNum<bulletNum){yield return new WaitForSeconds(reloadBulletTime);currentBulletNum = (reloadBulletNum+currentBulletNum)>bulletNum?bulletNum:(reloadBulletNum + currentBulletNum);// 弹夹UI更新if (bulletSlider)bulletSlider.value = currentBulletNum;}}
}

效果

在这里插入图片描述

补充知识

锚点

Canvas下创建UI会自带四个△为锚点,如下图。
在这里插入图片描述
锚点可以分开,可以构成矩形。
在这里插入图片描述
Unity中UI属性可以设置锚点,红色框部分是锚点在一起,黄色框部分是锚点分开。这两个属性在本篇弹夹显示的UI中都用到的了。
在这里插入图片描述
锚点在一起的时候,图片的大小不会随着父对象的大小改变而改变,但是图片定位是相对锚点进行定位的。例如本文实现弹夹显示在右下角的时候,锚点就被设置在了右下角。

锚点分开的时候,用作与拉伸,锚点的位置会随着父物体的大小进行变动。例如本文实现弹夹显示条,调整父物体Slider的大小时候,里面的显示条也会跟着拉伸。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/465441.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——网络层导论

转发是局部功能——数据平面 路由是全局的功能——控制平面 网卡 网卡&#xff0c;也称为网络适配器&#xff0c;是计算机硬件中的一种设备&#xff0c;主要负责在计算机和网络之间进行数据传输。 一、主要功能 1、数据传输&#xff1a; 发送数据时&#xff0c;网卡将计算机…

6款IntelliJ IDEA插件,让Spring和Java开发如虎添翼

文章目录 1、SonarLint2、JRebel for IntelliJ3、SwaggerHub插件4、Lombok插件5、RestfulTool插件6、 Json2Pojo插件7、结论 对于任何Spring Boot开发者来说&#xff0c;两个首要的目标是最大限度地提高工作效率和确保高质量代码。IntelliJ IDEA 是目前最广泛使用的集成开发环境…

【MySQL】深度学习与解析 : 库的操作知识整合

前言&#xff1a;本节内容是MySQL库的操作&#xff0c; 内容较少&#xff0c; 大体内容为创建库、删除库、修改库、库备份操作。 ps:本节内容适合安装了MySQL的友友们进行观看&#xff0c; 实操更有利于记住哦。 目录 创建数据库 查看数据库列表 创建数据库 删除数据库 …

开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序与私域流量圈层

摘要&#xff1a;本文探讨了私域流量圈层的特点以及其在当今时代的重要性&#xff0c;分析了开源 AI 智能名片 21 链动模式 S2B2C 商城小程序源码在私域流量圈层构建中的作用&#xff0c;阐述了产品在圈层时代被标签化的现象&#xff0c;并以实例展示了如何利用该小程序源码打造…

第11章 LAMP架构企业实战

Linux下LAMP(Linux+Apache+MySQL/MariaDB+Perl/PHP/Python)是一组用来搭建动态网站的开源软件架构,本身是各自独立的软件服务,放在一起使用,拥有了越来越高的兼容度,共同组成了一个强大的Web应用程序平台。 本章介绍互联网主流企业架构LAMP应用案例、PHP解释性语言详解、…

vscode php Launch built-in server and debug, PHP内置服务xdebug调试,自定义启动参数配置使用示例

在vscode中&#xff0c;当我们安装了插件 PHP Debug&#xff08;xdebug.php-debug&#xff09;或者 xdebug.php-pack 后 我们通过内置默认的 php xdebug配置启动php项目后&#xff0c;默认情况下我们在vscode中设置断点是不会生效的&#xff0c;因为我们的内置php服务默认启动时…

揭秘云计算 | 2、业务需求推动IT发展

揭秘云计算 | 1、云从哪里来&#xff1f;-CSDN博客https://blog.csdn.net/Ultipa/article/details/143430941?spm1001.2014.3001.5502 书接上文&#xff1a; 过去几十年间IT行业从大型主机过渡到客户端/服务器&#xff0c;再过渡到现如今的万物互联&#xff0c;IT可把控的资…

Golang | Leetcode Golang题解之第538题把二叉搜索树转换为累加树

题目&#xff1a; 题解&#xff1a; func getSuccessor(node *TreeNode) *TreeNode {succ : node.Rightfor succ.Left ! nil && succ.Left ! node {succ succ.Left}return succ }func convertBST(root *TreeNode) *TreeNode {sum : 0node : rootfor node ! nil {if n…

达梦数据守护集群_动态增加实时备库

目录 1、概述 2、实验环境 2.1环境信息 2.2配置信息 2.3 查看初始化参数 3、动态增加实时备库 3.1数据准备 3.2配置新备库 3.3动态增加MAL配置 3.4 关闭守护进程及监视器 3.5修改归档&#xff08;方法1&#xff1a;动态添加归档配置&#xff09; 3.6 修改归档&…

思维导图工具有哪些?10款思维导图特色介绍

电脑的普及&#xff0c;互联网的便捷。使我们平时工作、学习等场景下&#xff0c;常常离不开思维导图的辅助。思维导图是可以让我们所需要介绍的知识点以图文形式结合&#xff0c;展示出来。帮助我们方便理解。因此&#xff0c;一款好的思维导图工具&#xff0c;能让我们制作的…

7.2 设计模式

设计模式 7.3.1 设计模式的要素7.3.2 创建型设计模式7.3.3 结构性设计模式1. Adapter (适配器)2. Bridge(桥接)3.Composite(组合)4.Decorator(装饰)5.Facade(外观)6.Flyweight(享元)7.Proxy(代理)8. 结构型模式比较 7.3.4 行为型设计模式1 Chain of Responsibility 责任链模式2…

【Wi-Fi】802.11ac wave1 vs 802.11ac wave2

参考链接 difference between 11ac wave1 and wave2 | 11ac-wave1 vs 11ac-wave2 什么是802.11ac和802.11ac Wave2 - 华为 Notes&#xff5c;802.11ac Wave1与Wave2 - 知乎 802.11ac-wave1 2013年&#xff0c;IEEE发布了802.11ac标准&#xff0c;在Wave2出来之后&#xf…

【浪潮商城-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

【MWorks】Ubuntu 系统搭建

升级 Ubuntu系统 sudo apt-get update sudo apt-get upgrade安装流程 sudo chmod x 路径/文件.run安装 sudo 路径/文件.run安装过程中两个选项都填 y 打开安装对应的文件夹 运行 syslab.sh 文件&#xff0c;运行结束后&#xff0c;就可以在左上角开始搜索到syslab了。

单测篇 - 如何mock静态常量

本文对应源码地址&#xff1a; https://github.com/nieandsun/NRSC-STUDY/tree/master/nrsc-unit-test-study 1 如何mock静态常量 先看如下代码&#xff0c;这里如何对方法中的静态常量DEMO_CONSTANT进行mock呢&#xff1f; public class Demo1StaticConstant {/**** 这里的类…

学习方法该升级了,‌AI时代的弯道超车:【心流学习法】行动与意识合一的巅峰进化

你是否曾感到内心如荒漠般干涸&#xff0c;面对浩瀚的知识海洋&#xff0c;热情逐渐消磨殆尽&#xff1f; 你是否渴望忘却时间的流逝&#xff0c;心无旁骛&#xff0c;与知识展开一场纯粹而深邃的对话&#xff1f; ​在AI时代&#xff0c;智能体处理数据、知识迭代的速率让人…

Set

1.概念 Set与Map一样是一个接口&#xff0c;是一颗搜索树&#xff0c;所以在创建Set对象时&#xff0c;必须实现其类&#xff08;HashSet或TreeSet&#xff09; Set<String> setnew HashSet<>(); 2.常用方法 注意 Set中只存储key&#xff0c;并且要求key唯一Set…

蓝桥杯真题——三角回文数(C语言)

问题描述 对于正整数 n, 如果存在正整数 k 使得 n123⋯kk(k1)2n123⋯kk(k1)/2​, 则 n 称为三角数。例如, 66066 是一个三角数, 因为 66066123⋯36366066123⋯363 。 如果一个整数从左到右读出所有数位上的数字, 与从右到左读出所有数位 上的数字是一样的, 则称这个数为回文数…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01目录1. A Perspective for Adapting Generalist AI to Specialized Medical AI Applications and Their Challenges2. Synergi…

C++练习题(2)

//C计算自然数的和 #include <iostream> using namespace std; int main() { int n,sum0; scanf("%d",&n); for(int i0;i<n;i) { sumi; } printf("%d",sum); return 0; } #include <iostream> …