当前位置:网站首页>【Unity入门计划】制作RubyAdventure03-使用碰撞体&触发器实现世界交互
【Unity入门计划】制作RubyAdventure03-使用碰撞体&触发器实现世界交互
2022-08-10 07:59:00 【flashinggg】
目录
学习的教程
【unity2021入门教程】68-2D游戏开发教程系列-03-RubyAdventure2DRpg官方教程-16-完善触发器代码_哔哩哔哩_bilibili
已进行步骤
【Unity入门计划】制作RubyAdventure01-玩家的创建&移动_flashinggg的博客-CSDN博客
【Unity入门计划】制作RubyAdventure02-处理瓦片地图&碰撞_flashinggg的博客-CSDN博客
8 添加生命系统
先在之前的Ruby Controller脚本中,加上一个简单的生命上限&规定初始生命值
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RubyController : MonoBehaviour
{
//设置最大生命值(生命上限)
public int maxHealth = 5;
//当前生命值,默认为0
private int currentHealth;
private void Start()
{
//初始化当前生命值
currentHealth = maxHealth;
}
// 每帧都会执行一次Update函数
void Update()
{
...
}
//控制速度,比update快一点
void FixedUpdate()
{
ChangeHealth(1);
}
//更改生命值
//amount是游戏中加血/减血的操作
void ChangeHealth(int amount)
{
//限制当前生命值范围为[0,maxHealth]
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
//输出
Debug.Log("当前生命值为:" + currentHealth + "/" + maxHealth);
}
}
演示效果
9 使用触发器实现吃血包
之前写过一个触发器的简单博客:【Unity入门计划】基本概念(2)-触发器 Trigger_flashinggg的博客-CSDN博客
它是一个特殊的碰撞体,只检测碰撞,不阻止移动。
9.1 添加一个可以被吃掉的血包
关于数据保护内容,我另开了一个博客进行简单的记录介绍:【Unity入门计划】Unity实例-C#如何通过封装实现对数据成员的保护
先从Project中加入一个可以充当血包的精灵,同时创建一个预制件,给他一个2D碰撞体并设置为触发器。
挂一个检测触发并进行相应设置的脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HealthCollectible : MonoBehaviour
{
//设置每次碰撞加的血量
public int amount = 1;
private int CollideTimes;
//添加触发器事件,每次碰撞触发器时执行其中的代码
private void OnTriggerEnter2D(Collider2D other)
{
CollideTimes++;
Debug.Log($"和当前物体发生碰撞的是:{other},当前是第{CollideTimes}次发生碰撞!");
//获取Ruby对象的脚本组件,还是用GetComponent方法
RubyController rubyController=other.GetComponent<RubyController>();
if(rubyController != null)
{
//血量+1
if (rubyController.health<rubyController.maxHealth)
{
rubyController.ChangeHealth(amount);
//销毁血包
Destroy(gameObject);
}
else Debug.Log("血量已满!");
}
else
{
Debug.LogError("未获取到当前游戏对象");
}
}
}
同时RubyController中也要定义一个属性,访问私有变量currentHealth。
//设置最大生命值(生命上限)
public int maxHealth = 5;
//当前生命值,默认为0
internal int currentHealth;
//C#中支持面向对象程序设计中的封装,实现对数据成员进行保护
//数据成员变量本身是私有的,只能通过某一种方法或者属性访问
//属性是共有的,可以通过取值器--get,赋值器--set,设定对应字段的访问规则
//满足规则才能访问该成员变量
public int health { get { return currentHealth; } }
这里只贴出了结果代码,具体过程直接参考对应的教程即可。
10 使用触发器添加伤害区域
10.1 设置伤害区域
还是跟之前一样,添加伤害区域精灵,变成预制体,勾选Is Trigger,再挂脚本实现一些进入后减血的操作。
挂一个减血脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DamageZone : MonoBehaviour
{
public int damageHealth = -1;
public int damageSpeed;
private double TruedamageHealth = -0.02;
private double True = 0;
int round=1;
private void OnTriggerStay2D(Collider2D other)
{
RubyController rubyController=other.GetComponent<RubyController>();
if(rubyController != null)
{
True += damageSpeed*TruedamageHealth;
if (round==1||True < round * damageHealth)
{
round++;
rubyController.ChangeHealth(damageHealth);
}
}
}
}
这里我优化了一下,加入了可以控制减血速度的变量,详情可以看:【Unity入门计划】用双血条方法控制伤害区域减血速度_flashinggg的博客-CSDN博客
10.2 设置无敌时间
关于无敌时间的讨论
教程中把无敌时间设置在了玩家减血的方法里,意思就是无论伤害来自敌人还是来自陷阱,只要受到伤害,就会进入2秒的无敌时间。
先讨论一下这个方法是否无敌:
- 我们假设Ruby走入了陷阱,血量-1,由于受到伤害进入了无敌时间(教程中设置为2s),此时Ruby有2s的时间赶快离开陷阱!这2s里Ruby将不受任何攻击的影响,过了无敌时间后就恢复到会受到攻击的状态。同时,如果想要更贴近现有游戏的情景,无敌时间也会伴随着玩家的闪烁,以此展示当前处于无敌状态了。
- 我们假设Ruby被敌人发射炮弹/近身攻击了!血量-1,此时Ruby进入了无敌状态,此时敌人发射的连续炮弹、进行的连招攻击将不再有多重伤害的减血效果。
因此,我认为对于一个基础教程的游戏项目制作,把脚本直接挂在玩家对象上是可行的,意味着敌人也是基础的敌人、没有可以“连招攻击”的敌人,也没有叠加伤害一说。
如果希望敌人进行的连招攻击会对玩家造成叠加伤害,最好是将无敌时间的脚本挂在陷阱、敌人身上,便于修改。
这里因为只是跟着教程学习,因此我就跟着教程思路走,还是把脚本挂在玩家身上。
加入了无敌时间系统的玩家脚本代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RubyController : MonoBehaviour
{
//设置无敌时间
public float timeInvincible = 2.0f;
//设置判断是否无敌的bool变量
bool isInvincible;
//规定一个无敌时间计数器,倒计时
float invincibleTimer;
//声明刚体对象
Rigidbody2D rigidbody2D;
//在方法外声明水平和数值量
float horizontal;
float vertical;
//设置最大生命值(生命上限)
public int maxHealth = 5;
//当前生命值,默认为0
private int currentHealth;
//C#中支持面向对象程序设计中的封装,实现对数据成员进行保护
//数据成员变量本身是私有的,只能通过某一种方法或者属性访问
//属性是共有的,可以通过取值器--get,赋值器--set,设定对应字段的访问规则
//满足规则才能访问该成员变量
public int health { get { return currentHealth; } }
private void Start()
{
//游戏运行前,获取当前游戏对象的刚体组件
//这里用到了GetComponent获取当前所在对象的吗某个组件 - GetComponent<>()
rigidbody2D = GetComponent<Rigidbody2D>();
//初始化当前生命值
currentHealth = maxHealth;
}
// 每帧都会执行一次Update函数
void Update()
{
//判断是否无敌
if (isInvincible)
{
//是,则计时器开始倒计时:deltaTime获取两帧之间的时间间隔
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0)
{
isInvincible = false;//倒计时结束,不再是无敌时间
}
}
//声明新变量
//获取水平轴并储存在新变量中
horizontal = Input.GetAxis("Horizontal");
//获取垂直轴
vertical = Input.GetAxis("Vertical");
}
//控制速度,比update快一点
void FixedUpdate()
{
Vector2 position = transform.position;
//对x轴移动距离做了细微的更改
position.x += horizontal * 3.0f * Time.deltaTime;
//对y轴也做相应更改
position.y += vertical * 3.0f * Time.deltaTime;
rigidbody2D.position = position;
}
//更改生命值
//amount是游戏中加血/减血的操作
public void ChangeHealth(int amount)
{
if (amount < 0)//if >0加血,则不进入无敌时间
{
if (isInvincible)//当前处于无敌状态,则不减血
{
return;//直接中段当前方法
}
//不是无敌状态,接下来会减血,因此提前改成true
isInvincible = true;
//重置计时器
invincibleTimer = timeInvincible;
}
//限制当前生命值范围为[0,maxHealth]
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
//输出
Debug.Log("当前生命值为:" + currentHealth + "/" + maxHealth);
}
}
10.3 平铺伤害区域/平铺精灵
有时候需要平铺伤害区域,Unity自带有平铺精灵的功能。
1 精灵渲染器Draw Mode -> Tiled
还记得精灵渲染器里的Draw Mode,默认是Simple,选择Tiled
2 精灵素材中Mesh Type -> Full Rect
在对应的精灵素材属性中,Mesh Type选择Full Rect
再进入Scene中调整当前游戏对象,T键框选,发现可以实现平铺了。
还需要将碰撞体也平铺对应
3 2D碰撞体组件 -> 勾选Auto Tilling
此时就完成了伤害区域平铺的操作了。
11 添加敌人
首先需要在官网下载敌人Robot的图片。
同样的操作,再Unity中把他变成精灵,挂上Order的脚本。
11.1 敌人来回移动
关于来回移动代码的编写,可以看看我的这篇博客:【Unity入门计划】2D游戏实现敌人来回移动控制脚本
11.2 敌人伤害
这里想要实现Ruby碰撞敌人后,掉血的操作。由于需要真实的碰撞感,因此不能使用之前的OnTriggerEnter,而是采取碰撞检测。
//碰撞检测
//添加敌人伤害的逻辑
private void OnCollisionEnter2D(Collision2D other)
{
//获取和当前collision碰撞的对象的脚本组件
RubyController player = other.gameObject.GetComponent<RubyController>();
if (player != null)
{
player.ChangeHealth(Hurt);
}
}
Collision2D 2D碰撞类
官方文档:UnityEngine.Collision2D - Unity 脚本 API
在之前的一篇【Unity入门计划】基本概念(2)-触发器 Trigger中就有说到碰撞检测的三种类别。
在【Unity入门计划】Collision2D类&Collider2D类这篇博客中针对涉及到两个不同类的碰撞检测和触发检测,我对它们的回调函数在脚本中的使用进行一个简单的讨论。
边栏推荐
- [机缘参悟-65]:《兵者,诡道也》-7-三十六计解读-败战计
- Based on STC8G2K64S4 single-chip microcomputer to display analog photosensitive analog value through OLED screen
- Rust learning: 6.4_ enumeration of composite types
- .NET-7.WPF学习经验总结
- If the data of the oracle business table is added, deleted, or modified, will the index of the table write redo and undo?
- 上课笔记(7)(1)——#647. 找树根和孩子(root)
- Rust learning: 6.2_ Tuples of composite types
- 关于数据中心的设计方案,数据中心网络规划设计
- Rust学习:6.1_复合类型之切片
- WooCommerce installation and rest api usage
猜你喜欢
随机推荐
2022-08-01 Advanced Network Engineering (24) STP Advanced Knowledge
PLSQL学习第四天
编程老手如何在autojs和冰狐智能辅助之间选择?
js reduce
初使jest 单元测试
ABAP Data Types 和XSD Type 映射关系以及XSD Type属性
If the data of the oracle business table is added, deleted, or modified, will the index of the table write redo and undo?
Uni-app develops WeChat applet using local images as background images
英国国家卫生服务遭受攻击,系统出现大面积故障
SQL SERVER 数据库,表的数据发生增删改,该表的索引会在ldf日志中记录吗?
自动化测试框架Pytest(三)——自定义allure测试报告
PHP笔记 28 29 30 31
winget包管理器
day16--The use of the packet capture tool Charles
LaTeX出现错误代码Command \algorithmic already defined
raid5的写性能,是不的比raid10快一些?
Day37 LeetCode
NPU architecture and force analysis
DGIOT supports industrial equipment rental and remote control
90. (cesium house) cesium height monitoring events