unity进阶篇6-可收集对象开发(血量/生命值等)
如何给一个角色增加血量条,然后有一个物品可以扣血和加血
如何给一个角色增加血量条,然后有一个物品可以扣血和加血
- 给角色赋予血量条
我们先在角色上设置一个血量条
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class HealthLine : MonoBehaviour{public int MaxHealth = 5;public int CurrentHealth;private void Start(){CurrentHealth = MaxHealth;}public void ChangeHealth(int amount){//Mathf是C#的一种功能,Mathf.Clamp相当于设定数学里的一个区间//public static float Clamp(float value, float min, float max);//详情看unity手册,Mathf里有很多功能可以使用,Clamp是其中一种CurrentHealth = Mathf.Clamp(CurrentHealth + amount, 0, MaxHealth);Debug.Log($"当前生命值:{CurrentHealth} / {MaxHealth}");//第二种描写方式//Debug.Log("当前生命值" + CurrentHealth + "/" + MaxHealth);}}这只是在控制台显示生命值,当然我们需要一个媒介来进行扣血和加血,然后显示我们当前的血量是多少,这个媒介就是触发器
- 设置一个扣血或加血的物体
- 首先我们需要添加一个触发器 触发器详情
- Add Component
- Box Collider 2D
- 勾选 Is Trigger
- 创建一个脚本,名字自定义
- 脚本需要包含一个OnTriggerEnter2D库,然后在这个库中编辑相关功能
当我们勾选了Is Trigger 后,这个加血的物件仍然是碰撞体,虽然无法跟它相碰撞,但是它是有和角色碰撞的,如何用代码验证是否碰撞:
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class Healthbox : MonoBehaviour{//记录碰撞次数private int colliderCount;////添加触发器碰撞事件,每次碰撞触发器时,执行其中的代码//other获取的是精灵(Ruby)private void OnTriggerEnter2D(Collider2D other){colliderCount++;Debug.Log($"当前发生碰撞的是{other},第{colliderCount}次碰撞");}}每当角色与加血的物体碰撞,它将会在控制台输出以下内容:
- 我们接下来要给这个加血的物品添加其他代码,如人物碰到后加1点血
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class Healthbox : MonoBehaviour{//赋值amout为1,当角色与物体进行碰撞时,血条的数值将加一或减一;private int amount = 1;//记录碰撞次数private int colliderCount;////添加触发器碰撞事件,每次碰撞触发器时,执行其中的代码//other获取的是精灵(Ruby)private void OnTriggerEnter2D(Collider2D other){colliderCount++;Debug.Log($"当前发生碰撞的是{other},第{colliderCount}次碰撞");//获得Ruby游戏对象的脚本组件对象(这里的脚本组件指的是挂在角色上的血条组件)//获取(连接)Ruby上的血条组件HealthLine healthLine = other.GetComponent<HealthLine>();//当角色与加血或扣血的物体进行碰撞后,将改变血条的数值。healthLine.ChangeHealth(amount);}}HealthLine是脚本文件名,我创建了另一个脚本文件,更好的区分不同脚本不同功能的使用。
- 如果我们想要让角色与加血的物体进行碰撞后(类似于角色喝血瓶),该物体需要进行消除处理,该如何写代码。
我们可以使用C#的销毁函数(功能)Destory
它的作用是Removes a GameObject, component or asset.
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class Healthbox : MonoBehaviour{//赋值amout为1,当角色与物体进行碰撞时,血条的数值将加一或减一;private int amount = 1;//记录碰撞次数private int colliderCount;////添加触发器碰撞事件,每次碰撞触发器时,执行其中的代码//other获取的是精灵(Ruby)private void OnTriggerEnter2D(Collider2D other){colliderCount++;Debug.Log($"当前发生碰撞的是{other},第{colliderCount}次碰撞");//获得Ruby游戏对象的脚本组件对象(这里的脚本组件指的是挂在角色上的血条组件)//获取(连接)Ruby上的血条组件HealthLine healthLine = other.GetComponent<HealthLine>();//当角色与加血或扣血的物体进行碰撞后,将改变血条的数值。healthLine.ChangeHealth(amount);//销毁(移除)该物体Destroy(gameObject);}}
- 消除功能也有了,那如果角色是满血的,该如何判断此状况,所以我们还需要写判断语句。
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class Healthbox : MonoBehaviour{//赋值amout为1,当角色与物体进行碰撞时,血条的数值将加一或减一;private int amount = 1;//记录碰撞次数private int colliderCount;////添加触发器碰撞事件,每次碰撞触发器时,执行其中的代码//other获取的是精灵(Ruby)private void OnTriggerEnter2D(Collider2D other){colliderCount++;Debug.Log($"当前发生碰撞的是{other},第{colliderCount}次碰撞");//获得Ruby游戏对象的脚本组件对象(这里的脚本组件指的是挂在角色上的血条组件)//获取(连接)Ruby上的血条组件HealthLine healthLine = other.GetComponent<HealthLine>();if (healthLine != null){if (healthLine.CurrentHealth<healthLine.MaxHealth){//当角色与加血或扣血的物体进行碰撞后,将改变血条的数值。healthLine.ChangeHealth(amount);//销毁(移除)该物体Destroy(gameObject);}else{Debug.Log("当前玩家角色血条已满,无需加血");}}else{Debug.LogError("healthLine脚本并未获取到。。");}}}直接使用if语句
- 如何防止别人擅自进入更改数值呢,比如把加血加1点变成加10点,我们不能允许这样的更改
除了默认的private外,我们还可以使用封装语句
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class HealthLine : MonoBehaviour{public int MaxHealth = 5;//设置当前生命值属性health//C#中支持面向对象程序设计中的封装概念,对数据成员对保护//数据成员变量,默认一般都应该设置为私有,只能通过当前类都方法或属性进行访问//属性是公有的,可以通过取值器get、赋值器set设定对应字段的访问规则,满足规则才能够访问。public int health{get { return CurrentHealth; }//set { CurrentHealth = value; }}private int CurrentHealth;private void Start(){CurrentHealth = MaxHealth;}public void ChangeHealth(int amount){//Mathf是C#的一种功能,Mathf.Clamp相当于设定数学里的一个区间//public static float Clamp(float value, float min, float max);//详情看unity手册,Mathf里有很多功能可以使用,Clamp是其中一种CurrentHealth = Mathf.Clamp(CurrentHealth + amount, 0, MaxHealth);Debug.Log($"当前生命值:{CurrentHealth} / {MaxHealth}");//第二种描写方式//Debug.Log("当前生命值" + CurrentHealth + "/" + MaxHealth);}}代码中可以看到多添加了public int health, 然后将CurrentHealth更改为private,为什么要这么做呢。
//设置当前生命值属性health//C#中支持面向对象程序设计中的封装概念,对数据成员对保护//数据成员变量,默认一般都应该设置为私有,只能通过当前类都方法或属性进行访问//属性是公有的,可以通过取值器get、赋值器set设定对应字段的访问规则,满足规则才能够访问。//health现在是只读属性public int health{get { return CurrentHealth; }//set { CurrentHealth = value; }}private int CurrentHealth;当我们设置完后,如果我们想更改CurrentHealth的值,只能通过ChangeHealth来改,CurrentHealth只能通过Health来取(return)。
这是一个数据的保护,就很难通过外挂来更改数值(如果没有访问Health的访问权限)。
我们可以发现我们通过更改了CurrentHealth的封装后,在Healthbox里的判断句出现了错误
if (healthLine != null){//由于CurrentHealth进行了封装,我们需要将CurrentHealth更改为health.if (healthLine.Currenthealth<healthLine.MaxHealth){//当角色与加血或扣血的物体进行碰撞后,将改变血条的数值。healthLine.ChangeHealth(amount);//销毁(移除)该物体Destroy(gameObject);}//由于CurrentHealth进行了封装,我们需要将CurrentHealth更改为health.
if (healthLine != null){if (healthLine.health<healthLine.MaxHealth){//当角色与加血或扣血的物体进行碰撞后,将改变血条的数值。healthLine.ChangeHealth(amount);//销毁(移除)该物体Destroy(gameObject);}
设置一个掉血区域
- 设置一个掉血区域
首先我们需要选取一张图片来作为我们的掉血区域
- Art - Sprite - Environment - Damagable
- 添加为预制件(Prefabs)
- 添加Box Collider2D
- 勾选Is Trigger
- 在自己创建的掉血区域里添加脚本
using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class DamageArea : MonoBehaviour{private int DamageNum = -1;private void OnTriggerStay2D(Collider2D other){//获取血条组件HealthLine healthLine = other.GetComponent<HealthLine>();//判断组件是否获取到if (healthLine != null){//扣1滴血healthLine.ChangeHealth(DamageNum);}}}
- 我们在unity试运行,发现掉血太快了,如何解决
我们需要设置时间间隔,每两秒扣一次血
所以我们需要在HealthLine脚本上两秒间隔代码。Time.deltaTime的官方文档
using System;using System.Collections;using System.Collections.Generic;using UnityEditor.UIElements;using UnityEngine;public class HealthLine : MonoBehaviour{public int MaxHealth = 5;//设置当前生命值属性health//C#中支持面向对象程序设计中的封装概念,对数据成员对保护//数据成员变量,默认一般都应该设置为私有,只能通过当前类都方法或属性进行访问//属性是公有的,可以通过取值器get、赋值器set设定对应字段的访问规则,满足规则才能够访问。//health现在是只读属性public int health{get { return CurrentHealth; }//set { CurrentHealth = value; }}//判断无敌状态private bool isInvincible;//无敌时间private float TimeInvincible = 2.0f;//无敌时间计时private float InvincibleTimer;int CurrentHealth;private void Start(){CurrentHealth = MaxHealth;}private void Update(){//判断无敌状态if (isInvincible){//如果无敌,进入倒计时//invincibleTimer = invincibleTimer - Time.deltaTime;//每次update减去一帧所消耗到时间InvincibleTimer -= Time.deltaTime; //Time.deltaTime的意思是从最后一帧到当前帧到间隔//直到计时器中的时间用完if (InvincibleTimer < 0){//取消无敌状态isInvincible = false;}}}public void ChangeHealth(int amount){//判断是否在扣血的区域if (amount<0){//判断是否在无敌状态if (isInvincible){//在无敌状态直接弹出函数return;}//重制无敌状态isInvincible = true;//重制无敌时间InvincibleTimer = TimeInvincible;}//Mathf是C#的一种功能,Mathf.Clamp相当于设定数学里的一个区间//public static float Clamp(float value, float min, float max);//详情看unity手册,Mathf里有很多功能可以使用,Clamp是其中一种CurrentHealth = Mathf.Clamp(CurrentHealth + amount, 0, MaxHealth);Debug.Log($"当前生命值:{CurrentHealth} / {MaxHealth}");//第二种描写方式//Debug.Log("当前生命值" + CurrentHealth + "/" + MaxHealth);//假设区域伤害为两秒一次}}



