1 需求实现
人机交互Input 中实现了通过键盘控制坦克运动,通过鼠标控制坦克发射炮弹,本文将在此基础上,增加血条(HP)功能。炮弹命中后,HP 值会减少,因此需要应用到 刚体组件Rigidbody 和 碰撞体组件Collider;从不同角度攻击敌人时,敌人的血条始终朝向相机,因此需要用到 相机跟随;血条通过 Image 显示,因此需要用到 UGUI之Image;玩家的血条始终显示在屏幕左上角,因此需要使用到 锚点。
1)需求实现
- 前后箭头键或 W, S 键控制玩家前进或后退;
- 左右箭头键或 A, D 键控制玩家左右转向;
- 鼠标左键或空格键控制玩家发射炮弹;
- 玩家血条显示在屏幕左上角;
- 相机在玩家后上方的位置,始终跟随玩家,朝玩家正前方看;
- 玩家移动时,敌人转向玩家,当偏离玩家的角度小于5°时,发射炮弹;
- 敌人血条显示在其上方,并且始终看向相机。
2)涉及技术栈
2 游戏对象
1)游戏界面

2)游戏对象层级结构

3 Transform组件参数
1)玩家 Transform 组件参数
| Name | Type | Position | Rotation | Scale | Color/Texture | 
| Player | Empty | (0, 0.25, -5) | (0, 0, 0) | (1, 1, 1) | #228439FF | 
| Botton | Cube | (0, 0, 0) | (0, 0, 0) | (2, 0.5, 2) | #228439FF | 
| Top | Cube | (0, 0.5, 0) | (0, 0, 0) | (1, 0.5, 1) | #228439FF | 
| Gun | Cylinder | (0, 0, 1.5) | (90, 0, 0) | (0.2, 1, 0.4) | #228439FF | 
| FirePoint | Empty | (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 组件参数
| Name | Type | Rect | Width/Height | Pos | Color/Texture | 
| PlayerHP | Canvas | —— | —— | —— | —— | 
| Panel | Panel | (0, 0, 0, 0) | —— | (-, -, 0) | #FFFFFF00 | 
| HealthBG | Image | (0, 0.25, -5) | (200, 20) | (125, -30, 0) | #FFFFFFFF | 
| Health | Image | (0, 0.25, -5) | (200, 20) | (125, -30, 0) | #FF2230FF | 
补充: 玩家 PlayerHP 的 Canvas 渲染模式是 Screen Space - Overlay,Health 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal。
3)敌人 Transform 组件参数
| Name | Type | Position | Rotation | Scale | Color/Texture | 
| Enemy | Empty | (0, 0.25, 5) | (0, 180, 0) | (1, 1, 1) | #15D3F9FF | 
| Botton | Cube | (0, 0, 0) | (0, 0, 0) | (2, 0.5, 2) | #15D3F9FF | 
| Top | Cube | (0, 0.5, 0) | (0, 0, 0) | (1, 0.5, 1) | #15D3F9FF | 
| Gun | Cylinder | (0, 0, 1.5) | (90, 0, 0) | (0.2, 1, 0.4) | #15D3F9FF | 
| FirePoint | Empty | (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 组件参数
| Name | Type | Width/Height | Pos | Color/Texture | 
| HP | Canvas | (2, 0.2) | (0, 0.85, 0) | —— | 
| HealthBG | Image | (2, 0.2) | (0, 0, 0) | #FFFFFFFF | 
| Health | Image | (2, 0.2) | (0, 0, 0) | #FF2230FF | 
补充: 敌人 HP 的 Canvas 渲染模式是 World Space,Health 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal。
5)地面和炮弹 Transform 组件参数
| Name | Type | Position | Rotation | Scale | Color/Texture | 
| Plane | Plane | (0, 0, 0) | (0, 0, 0) | (10, 10, 10) | GrassRockyAlbedo | 
| Bullet | Sphere | (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 运行效果

转载:https://blog.csdn.net/m0_37602827/article/details/125862315
 
					