Unity3D血条(HP)

Posted little_fat_sheep

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D血条(HP)相关的知识,希望对你有一定的参考价值。

1 需求实现

        人机交互Input 中实现了通过键盘控制坦克运动,通过鼠标控制坦克发射炮弹,本文将在此基础上,增加血条(HP)功能。炮弹命中后,HP 值会减少,因此需要应用到 刚体组件Rigidbody 和 碰撞体组件Collider;从不同角度攻击敌人时,敌人的血条始终朝向相机,因此需要用到 相机跟随;血条通过 Image 显示,因此需要用到 UGUI之Image;玩家的血条始终显示在屏幕左上角,因此需要使用到 锚点

        1)需求实现

  • 前后箭头键或 W, S 键控制玩家前进或后退;
  • 左右箭头键或 A, D 键控制玩家左右转向;
  • 鼠标左键或空格键控制玩家发射炮弹;
  • 玩家血条显示在屏幕左上角;
  • 相机在玩家后上方的位置,始终跟随玩家,朝玩家正前方看;
  • 玩家移动时,敌人转向玩家,当偏离玩家的角度小于5°时,发射炮弹;
  • 敌人血条显示在其上方,并且始终看向相机。

        2)涉及技术栈

2 游戏对象

        1)游戏界面

        2)游戏对象层级结构

        3)Transform组件参数

        1. 玩家 Transform 组件参数

NameTypePositionRotationScaleColor/Texture
PlayerEmpty(0, 0.25, -5)(0, 0, 0)(1, 1, 1)#228439FF
BottonCube(0, 0, 0)(0, 0, 0)(2, 0.5, 2)#228439FF
TopCube(0, 0.5, 0)(0, 0, 0)(1, 0.5, 1)#228439FF
GunCylinder(0, 0, 1.5)(90, 0, 0)(0.2, 1, 0.4)#228439FF
FirePointEmpty(0, 1.15, 0)(0, 0, 0)(1, 1, 1)——

        补充:Player 游戏对象添加了刚体组件,并修改 Mass = 100,Drag = 1,AngularDrag = 0.1,Freeze Rotation 中勾选 X 和 Z。 

        2. 玩家 HP RectTransform 组件参数

NameTypeRectWidth/HeightPosColor/Texture
PlayerHPCanvas————————
PanelPanel(0, 0, 0, 0)——(-, -, 0)#FFFFFF00
HealthBGImage(0, 0.25, -5)(200, 20)(125, -30, 0)#FFFFFFFF
HealthImage(0, 0.25, -5)(200, 20)(125, -30, 0)#FF2230FF

        补充: 玩家 PlayerHP 的 Canvas 渲染模式是 Screen Space - Overlay,Health 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal。

        3. 敌人 Transform 组件参数

NameTypePositionRotationScaleColor/Texture
EnemyEmpty(0, 0.25, 5)(0, 180, 0)(1, 1, 1)#15D3F9FF
BottonCube(0, 0, 0)(0, 0, 0)(2, 0.5, 2)#15D3F9FF
TopCube(0, 0.5, 0)(0, 0, 0)(1, 0.5, 1)#15D3F9FF
GunCylinder(0, 0, 1.5)(90, 0, 0)(0.2, 1, 0.4)#15D3F9FF
FirePointEmpty(0, 1.15, 0)(0, 0, 0)(1, 1, 1)——

        补充:Enemy 游戏对象添加了刚体组件,并修改 Mass = 100,Drag = 0.5,AngularDrag = 0.1,Freeze Rotation 中勾选 X 和 Z。  

        4. 敌人 HP RectTransform 组件参数

NameTypeWidth/HeightPosColor/Texture
HPCanvas(2, 0.2)(0, 0.85, 0)——
HealthBGImage(2, 0.2)(0, 0, 0)#FFFFFFFF
HealthImage(2, 0.2)(0, 0, 0)#FF2230FF

        补充: 敌人 HP 的 Canvas 渲染模式是 World Space,Health 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal。

        5. 地面和炮弹 Transform 组件参数

NameTypePositionRotationScaleColor/Texture
PlanePlane(0, 0, 0)(0, 0, 0)(10, 10, 10)GrassRockyAlbedo
BulletSphere(0, 0.5, -5)(0, 0, 0)(0.3, 0.3, 0.3)#228439FF

        补充:炮弹作为预设体拖拽到 Assets/Resources/Prefabs 目录下,并且添加了刚体组件。

3 脚本组件

        1)CameraController

        CameraController.cs

using UnityEngine;
 
public class CameraController : MonoBehaviour 
	private Transform player; // 玩家
	private Vector3 relaPlayerPos; // 相机在玩家坐标系中的位置
	private float targetDistance = 15f; // 相机看向玩家前方的位置
 
	private void Start() 
		relaPlayerPos = new Vector3(0, 4, -8);
		player = GameObject.Find("Player/Top").transform;
	
 
	private void LateUpdate() 
		CompCameraPos();
	

	private void CompCameraPos()  // 计算相机坐标
		Vector3 target = player.position + player.forward * targetDistance;
		transform.position = transformVecter(relaPlayerPos, player.position, player.right, player.up, player.forward);
		transform.rotation = Quaternion.LookRotation(target - transform.position);
	

	// 求以origin为原点, locX, locY, locZ 为坐标轴的本地坐标系中的向量 vec 在世界坐标系中对应的向量
	private Vector3 transformVecter(Vector3 vec, Vector3 origin, Vector3 locX,  Vector3 locY,  Vector3 locZ) 
		return vec.x * locX + vec.y * locY + vec.z * locZ + origin;
	

        说明: CameraController 脚本组件挂在 MainCamera 游戏对象上。

        2)PlayerController

        PlayerController.cs

using System;
using UnityEngine;

public class PlayerController : MonoBehaviour 
	private Transform firePoint; // 开火点
	private GameObject bulletPrefab; // 炮弹预设体
	private float tankMoveSpeed = 4f; // 坦克移动速度
	private float tankRotateSpeed = 2f; // 坦克转向速度
	private float fireWaitTime = float.MaxValue; // 距离上次开火已等待的时间
	private float bulletCoolTime = 0.15f; // 炮弹冷却时间

	private void Start() 
		firePoint = transform.Find("Top/Gun/FirePoint");
		bulletPrefab = (GameObject) Resources.Load("Prefabs/Bullet");
	

	private void Update() 
		fireWaitTime += Time.deltaTime;
		float hor = Input.GetAxis("Horizontal");
        float ver = Input.GetAxis("Vertical");
		Move(hor, ver);
		if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) 
			Fire();
		
	

	private void Move(float hor, float ver)  // 坦克移动
		if (Math.Abs(hor) > 0.1f || Math.Abs(ver) > 0.1f) 
			GetComponent<Rigidbody>().velocity = transform.forward * tankMoveSpeed * ver;
			GetComponent<Rigidbody>().angularVelocity = Vector3.up * tankRotateSpeed * hor;
		
	

	private void Fire()  // 开炮
		if (fireWaitTime > bulletCoolTime) 
			BulletInfo bulletInfo = new BulletInfo("PlayerBullet", Color.red, transform.forward, 10f, 15f);
			GameObject bullet = Instantiate(bulletPrefab, firePoint.position, Quaternion.identity);
			bullet.AddComponent<BulletController>().SetBulletInfo(bulletInfo);
			fireWaitTime = 0f;
		
	

        说明: PlayerController 脚本组件挂在 Player 游戏对象上。 

        3)EnemyController

        EnemyController.cs

using UnityEngine;
using UnityEngine.UI;

public class EnemyController : MonoBehaviour 
	private Transform target; // 目标
	private Transform top; // 炮头
	private Transform firePoint; // 开火点
	private Transform hp; // 血条
	private GameObject bulletPrefab; // 炮弹预设体
	private float rotateSpeed = 0.4f; // 坦克转向速度
	private float fireWaitTime = float.MaxValue; // 距离上次开火已等待的时间
	private float bulletCoolTime = 1f; // 炮弹冷却时间

	private void Start () 
		target = GameObject.Find("Player/Top").transform;
		top = transform.Find("Top");
		firePoint = transform.Find("Top/Gun/FirePoint");
		hp = transform.Find("HP");
		bulletPrefab = (GameObject) Resources.Load("Prefabs/Bullet");
	

	private void Update () 
		fireWaitTime += Time.deltaTime;
		LookAtTarget();
		float angle = Vector3.Angle(target.position - top.position, top.forward);
		if (LookAtTarget()) 
			Fire();
		
		HPLookAtCamera();
	

	private bool LookAtTarget() 
		Vector3 dir = target.position - top.position;
		float angle = Vector3.Angle(dir, top.forward);
		if (angle > 5) 
			int axis = Vector3.Dot(Vector3.Cross(dir, top.forward), Vector3.up) > 0 ? -1 : 1;
			GetComponent<Rigidbody>().angularVelocity = axis * Vector3.up * rotateSpeed;
			return false;
		
		GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
		return true;
	

	private void HPLookAtCamera() 
		Vector3 cameraPos = Camera.main.transform.position;
		Vector3 target = new Vector3(cameraPos.x, hp.position.y, cameraPos.z);
		hp.LookAt(target);
	

	private void Fire() 
		if (fireWaitTime > bulletCoolTime) 
			BulletInfo bulletInfo = new BulletInfo("EnemyBullet", Color.yellow, top.forward, 5f, 10f);
			GameObject bullet = Instantiate(bulletPrefab, firePoint.position, Quaternion.identity); // 通过预设体创建炮弹
			bullet.AddComponent<BulletController>().SetBulletInfo(bulletInfo);
			fireWaitTime = 0;
		
	

        说明: EnemyController 脚本组件挂在 Enemy 游戏对象上。  

        4)BulletController

        BulletController.cs

using UnityEngine;
using UnityEngine.UI;

public class BulletController : MonoBehaviour 
	private BulletInfo bulletInfo; // 炮弹信息
	private volatile bool isDying = false;

	private void Start () 
		gameObject.name = bulletInfo.name;
		GetComponent<MeshRenderer>().material.color = bulletInfo.color;
		float lifeTime = bulletInfo.fireRange / bulletInfo.speed; // 存活时间
		Destroy(gameObject, lifeTime);
	

	private void Update () 
		transform.GetComponent<Rigidbody>().velocity = bulletInfo.flyDir * bulletInfo.speed;
	

	private void OnCollisionEnter(Collision other) 
		if (isDying) 
			return;
		
		if (IsHitEnemy(gameObject.name, other.gameObject.name)) 
			other.transform.Find("HP/Health").GetComponent<Image>().fillAmount -= 0.1f;
			isDying = true;
			Destroy(gameObject, 0.1f);
		 else if (IsHitPlayer(gameObject.name, other.gameObject.name)) 
			GameObject.Find("PlayerHP/Panel/Health").GetComponent<Image>().fillAmount -= 0.1f;
			isDying = true;
			Destroy(gameObject, 0.1f);
		
	

	public void SetBulletInfo(BulletInfo bulletInfo) 
		this.bulletInfo = bulletInfo;
	

	private bool IsHitEnemy(string name, string otherName)  // 射击到敌军
		return name.Equals("PlayerBullet") && otherName.Equals("Enemy");
	

	private bool IsHitPlayer(string name, string otherName)  // 射击到玩家
		return name.Equals("EnemyBullet") && otherName.Equals("Player");
	

        说明: BulletController 脚本组件挂在 Bullet 游戏对象上(代码里动态添加)。   

        5)BulletInfo

        BulletInfo.cs

using UnityEngine;

public class BulletInfo 
	public string name; // 炮弹名
	public Color color; // 炮弹颜色
	public Vector3 flyDir; // 炮弹飞出方向
	public float speed; // 炮弹飞行速度
	public float fireRange; // 炮弹射程

	public BulletInfo(string name, Color color, Vector3 flyDir, float speed, float fireRange) 
		this.name = name;
		this.color = color;
		this.flyDir = flyDir;
		this.speed = speed;
		this.fireRange = fireRange;
	

4 运行效果

以上是关于Unity3D血条(HP)的主要内容,如果未能解决你的问题,请参考以下文章

unity3d中怎样制作血条跟随角色运动

UE4 C++ 绑定敌人血条

饥荒-哈姆雷特 菩萨低眉 (敌人攻击你时角色自动 加满血条San值,敌人直接死亡)

饥荒-哈姆雷特 菩萨低眉 (敌人攻击你时角色自动 加满血条San值,敌人直接死亡)

Unity3D 多层血条特效

Unity3D 多层血条特效