一、创建尖刺预制体
1. 在prefabs文件夹新建一个尖刺预制体,并添加到场景面板上
2. 为尖刺预制体添加Box Collider 2D组件,设置碰撞体积,设置属性IsTrigger为true
3. 在Scripts文件夹新建一个Spine脚本,并添加到尖刺预制体上
二、编辑Ruby脚本
详情见:【Unity2D:C#Script】为角色添加回血效果
using Cinemachine.Utility;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor.Rendering;
using UnityEngine;
public class Ruby : MonoBehaviour {
public int maxHealthPoint = 100;
public int healthPoint;
private int speed = 5;
// 创建rb2d对象
private Rigidbody2D rb2d;
void Start() {
// 设置游戏的帧率为60帧
Application.targetFrameRate = 60;
healthPoint = maxHealthPoint;
// 用rb2d接收Rigidbody组件
rb2d = GetComponent<Rigidbody2D>();
}
void Update() {
// 创建float型Horizontal变量和Vertical变量,用来接受键盘输入
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// 创建一个二维变量position来存储Rigidbody2D组件中的坐标
Vector2 position = transform.position;
// 控制Ruby移动
position.x += horizontal * speed * Time.deltaTime;
position.y += vertical * speed * Time.deltaTime;
/*transform.position = position;*/
rb2d.MovePosition(position);
}
public void changeHealthPoint(int value) {
healthPoint = Mathf.Clamp(healthPoint+value, 0, maxHealthPoint);
Debug.Log("HP:" + healthPoint + " / " + maxHealthPoint);
}
}
三、编辑Spine脚本
1. 仿照上一章的内容,Spine脚本代码为:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spine : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision) {
Ruby ruby = collision.GetComponent<Ruby>();
if(ruby != null) {
if(ruby.healthPoint < ruby.maxHealthPoint) {
ruby.changeHealthPoint(-40);
Destroy(gameObject);
}
}
}
}
2. 因为尖刺不是消耗品,和Ruby发生碰撞后不会消失,因此可以删除Destory()方法。同时无论Ruby是否满血,碰到尖刺都会损失生命值,因此也可以删掉判断Ruby是否满血的if条件语句
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spine : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision) {
Ruby ruby = collision.GetComponent<Ruby>();
if(ruby != null) {
ruby.changeHealthPoint(-40);
}
}
}
3. 测试后发现,只有当Ruby进入尖刺时才会损失生命值,而我们想要的效果是只要Ruby在尖刺范围内就持续掉血。此时,需要将OnTriggerEnter2D()方法替换为OnTriggerStay2D()方法。与此同时,还需要将Ruby的Rigidbody 2D组件的SleepMode属性设置为Never Sleep,否则当Ruby不移动时将无法出发碰撞检测
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spine : MonoBehaviour
{
private void OnTriggerStay2D(Collider2D collision) {
Ruby ruby = collision.GetComponent<Ruby>();
if(ruby != null) {
ruby.changeHealthPoint(-40);
}
}
}
四、为主角添加无敌时间
1. 修改后,Ruby虽然可以在尖刺范围内持续掉血,可是Ruby的血量在一瞬间就减到了0,是因为OnTriggerStay2D()方法每帧都执行一次,相当于每秒执行60次。因此我们需要给Ruby脚本添加无敌时间。首先添加三个变量:整型常量InvincibleTime(用const关键字来创建常量),是无敌状态的持续时间;浮点型变量invinibleTimer,作为计算无敌时间冷却的计时器;布尔变量isInvinible,表示现在是否处于无敌状态
using Cinemachine.Utility;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor.Rendering;
using UnityEngine;
public class Ruby : MonoBehaviour {
// Ruby基础属性
public int maxHealthPoint = 100;
public int healthPoint;
private int speed = 5;
// 无敌时间
public const int InvincibleTime = 2;
public double invinibleTimer;
public bool isInvinible;
// 创建rb2d对象
private Rigidbody2D rb2d;
void Start() {
// 设置游戏的帧率为60帧
Application.targetFrameRate = 60;
healthPoint = maxHealthPoint;
// 用rb2d接收Rigidbody组件
rb2d = GetComponent<Rigidbody2D>();
}
void Update() {
// 创建float型Horizontal变量和Vertical变量,用来接受键盘输入
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// 创建一个二维变量position来存储Rigidbody2D组件中的坐标
Vector2 position = transform.position;
// 控制Ruby移动
position.x += horizontal * speed * Time.deltaTime;
position.y += vertical * speed * Time.deltaTime;
rb2d.MovePosition(position);
}
public void changeHealthPoint(int value) {
healthPoint = Mathf.Clamp(healthPoint+value, 0, maxHealthPoint);
Debug.Log("HP:" + healthPoint + " / " + maxHealthPoint);
}
}
2. 在Start()方法中初始化变量invinibleTimer和isInvinible;在Update()方法中判断isInvinible是否为true,若为true,invinibleTimer将每秒减少1,当invinibleTimer减到小于0时,说明无敌状态已经结束,设置isInvinible的值为false
using Cinemachine.Utility;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor.Rendering;
using UnityEngine;
public class Ruby : MonoBehaviour {
// Ruby基础属性
public int maxHealthPoint = 100;
public int healthPoint;
private int speed = 5;
// 无敌时间
public const int InvincibleTime = 2;
public double invinibleTimer;
public bool isInvinible;
// 创建rb2d对象
private Rigidbody2D rb2d;
void Start() {
// 设置游戏的帧率为60帧
Application.targetFrameRate = 60;
// 用rb2d接收Rigidbody组件
rb2d = GetComponent<Rigidbody2D>();
// 初始化变量
healthPoint = maxHealthPoint;
invinibleTimer = 0;
}
void Update() {
// 创建float型Horizontal变量和Vertical变量,用来接受键盘输入
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// 创建一个二维变量position来存储Rigidbody2D组件中的坐标
Vector2 position = transform.position;
// 控制Ruby移动
position.x += horizontal * speed * Time.deltaTime;
position.y += vertical * speed * Time.deltaTime;
rb2d.MovePosition(position);
// 无敌时间计时器
if(isInvinible == true) {
invinibleTimer -= Time.deltaTime;
if(invinibleTimer < 0) {
isInvinible = false;
}
}
}
public void changeHealthPoint(int value) {
healthPoint = Mathf.Clamp(healthPoint+value, 0, maxHealthPoint);
Debug.Log("HP:" + healthPoint + " / " + maxHealthPoint);
}
}
注:Time.deltaTime等于每帧的秒数,每秒调用的次数(等于帧数)* 每帧的秒数=1秒,因此invinibleTimer -= Time.deltaTime的含义就是invinibleTimer的值每秒减少1
3. 打开Spine脚本,给减少生命值的语句加一层if条件语句,同时设置invinibleTimer和invinibleTimer的值
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spine : MonoBehaviour
{
private void OnTriggerStay2D(Collider2D collision) {
Ruby ruby = collision.GetComponent<Ruby>();
if(ruby != null) {
if(ruby.isInvinible == false) {
ruby.changeHealthPoint(-40);
ruby.invinibleTimer = 2;
ruby.isInvinible = true;
}
}
}
}
进入Unity,可以看到Ruby的无敌效果已经制作完成,本章完。