【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/
本章节实现了冷却时间,伤害数字的弹出文本特效
PopUpTextFx.cs
1. 类成员变量
myText
: 存储TextMeshPro
组件的引用,控制文本的显示内容和颜色。speed
: 控制文本上升的速度。disappearanceSpeed
: 在文本透明度消失后,控制文本的上升速度衰减。colorDisappearanceSpeed
: 控制文本透明度的衰减速率。lifeTime
: 文本显示的总时长,超出这个时间后文本会开始消失。textTimer
: 用于倒计时,跟踪文本的生命周期。
2. Update()
方法
文本上升:每帧通过
Vector2.MoveTowards
使文本沿Y轴缓慢上升。speed
控制上升速度,Time.deltaTime
确保上升速度与帧率无关。生命周期管理:
textTimer
递减,当生命周期结束后(textTimer < 0
),文本开始逐渐消失。透明度衰减:文本的透明度(
alpha
)逐渐减少,使用colorDisappearanceSpeed
控制衰减速度。减慢上升速度:当透明度低于50时,减慢文本的上升速度,使其在消失时更加平滑。
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
//2024.12.6 清水河
//Author:suzh1qian
public class PopUpTextFx : MonoBehaviour
{
private TextMeshPro myText;
[SerializeField] private float speed;//上升速度
[SerializeField] private float disappearanceSpeed;//文本消失时上升速度的衰减
[SerializeField] private float colorDisappearanceSpeed;//文本消失时颜色的衰减
[SerializeField] private float lifeTime;
private float textTimer;//计时文本的生命周期
void Start()
{
myText = GetComponent<TextMeshPro>();
textTimer =lifeTime;
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position,
new Vector2(transform.position.x, transform.position.y + 1), speed * Time.deltaTime);// 文本沿Y轴方向上升
textTimer -= Time.deltaTime;// 计时器递减
if (textTimer < 0 )
{
float alpha = myText.color.a - colorDisappearanceSpeed * Time.deltaTime;// 文本的透明度逐渐减少
myText.color = new Color(myText.color.r, myText.color.g, myText.color.b, alpha);
if (myText.color.a < 50)// 当透明度小于50时,减慢文本的上升速度
speed = disappearanceSpeed;
}
}
}
EntityFX.cs
添加部分!!!
功能分解
生成随机位置偏移量:
- 通过
Random.Range
生成随机的偏移值,使弹出文本在一定范围内有随机性,增加视觉多样性。 randomx
:控制X轴上的随机偏移,范围在[-0.5, 0.5]
。randomy
:控制Y轴上的随机偏移,范围在[1.5, 3]
。
- 通过
实例化弹出文本:
- 使用
Instantiate
方法在当前物体位置加上偏移量的地方创建一个新的弹出文本对象。 Quaternion.identity
表示弹出文本没有旋转(即默认角度)。
- 使用
设置文本内容:
- 通过
newText.GetComponent<TextMeshPro>().text
将输入的_text
参数赋值给弹出文本的内容。
- 通过
[Header("弹出文本")]//Pop Up Text
[SerializeField] private GameObject popUpTextPrefab;
public void CreatePopUpText(string _text)//生成弹出文本
{
float randomx = Random.Range(-0.5f, 0.5f);
float randomy = Random.Range(1.5f, 3);
Vector3 positionOffset = new Vector3(randomx, randomy, 0);
GameObject newText = Instantiate(popUpTextPrefab, transform.position + positionOffset, Quaternion.identity);
newText.GetComponent<TextMeshPro>().text = _text;
}
完整代码!!!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using TMPro;
public class EntityFX : MonoBehaviour
{
private Player player;
private SpriteRenderer sr;
[Header("弹出文本")]//Pop Up Text
[SerializeField] private GameObject popUpTextPrefab;
[Header("震动特效")]//Screen shake FX
[SerializeField] private float shakeMultiplier;
private CinemachineImpulseSource screenShake;
public Vector3 shakeSwordImpact;//投掷震动效果向量
public Vector3 shakeHighDamage;//高伤害震动效果向量
[Header("残影特效")]//After image FX
[SerializeField] private float afterImageCooldown;
[SerializeField] private GameObject afterImagePrefab;
[SerializeField] private float colorLooseRate;//颜色丢失率
private float afterImageCooldownTimer;
[Header("闪光特效")]//Flash FX
[SerializeField] private float flashDuration;
[SerializeField] private Material hitMat;
private Material originalMat;
[Header("异常状态颜色")]//Ailment colors
[SerializeField] private Color[] chillColor;
[SerializeField] private Color[] igniteColor;
[SerializeField] private Color[] shockColor;
[Header("异常状态粒子")]//Ailment particles
[SerializeField] private ParticleSystem igniteFx;
[SerializeField] private ParticleSystem chillFx;
[SerializeField] private ParticleSystem shockFx;
[Header("攻击特效")]//Hit FX
[SerializeField] private GameObject hitFX;
[SerializeField] private GameObject criticalHitFx;
[Space]
[SerializeField] private ParticleSystem dustFx;
private void Start()
{
sr = GetComponentInChildren<SpriteRenderer>();
player = PlayerManager.instance.player;
screenShake = GetComponent<CinemachineImpulseSource>();
originalMat = sr.material;
}
private void Update()
{
afterImageCooldownTimer -= Time.deltaTime;
}
public void CreatePopUpText(string _text)//生成弹出文本
{
float randomx = Random.Range(-0.5f, 0.5f);
float randomy = Random.Range(1.5f, 3);
Vector3 positionOffset = new Vector3(randomx, randomy, 0);
GameObject newText = Instantiate(popUpTextPrefab, transform.position + positionOffset, Quaternion.identity);
newText.GetComponent<TextMeshPro>().text = _text;
}
public void ScreenShake(Vector3 _shakePower)
{
screenShake.m_DefaultVelocity = new Vector3(_shakePower.x * player.facingDir , _shakePower.y ) * shakeMultiplier;
screenShake.GenerateImpulse();
}
public void CreateAfterImage()//生成残影
{
if(afterImageCooldownTimer < 0)
{
afterImageCooldownTimer = afterImageCooldown;//重置冷却时间
GameObject newAfterImage = Instantiate(afterImagePrefab, transform.position + new Vector3(0, .25f, 0), transform.rotation);//生成残影实例
newAfterImage.GetComponent<AfterImageFX>().SetupAfterImage(colorLooseRate, sr.sprite);
}
}
public void MakeTransprent(bool _transparent)//攻击命中时候的透明特效
{
if (_transparent)
sr.color = Color.clear;
else
sr.color = Color.white;
}
private IEnumerator FlashFX()//定义了一个私有的协程 FlashFX,用于在一段时间内改变 SpriteRenderer 的材质,然后恢复原始材质。
{
sr.material = hitMat;
Color currentColor = sr.color;//保存最开始的颜色,闪光之后变回去
sr.color = Color.white;
yield return new WaitForSeconds(flashDuration);
sr.color = currentColor;
sr.material = originalMat;
}
//P59,骷髅战士的血条闪烁
private void RedColorBlink()
{
if (sr.color != Color.white)
sr.color = Color.white;
else
{
sr.color = Color.red;
}
}
private void CancelColorChange()
{
CancelInvoke();//调用 CancelInvoke 方法取消所有与当前游戏对象关联的 Invoke 调用。
sr.color = Color.white;
igniteFx.Stop();
chillFx.Stop();
shockFx.Stop();
}
//10月30日
//三个状态的携程
public void ShockFxFor(float _seconds)
{
shockFx.Play();
InvokeRepeating("ShockColorFx", 0, .3f);
Invoke("CancelColorChange", _seconds);
}
public void IgniteFxFor(float _seconds)
{
igniteFx.Play();
InvokeRepeating("IgniteColorFx", 0, .3f);
Invoke("CancelColorChange", _seconds);
}
public void ChillFxFor(float _seconds)
{
chillFx.Play();
InvokeRepeating("ChillColorFx", 0, .3f);
Invoke("CancelColorChange", _seconds);
}
private void ShockColorFx()
{
if (sr.color != shockColor[0])
sr.color = shockColor[0];
else
{
sr.color = shockColor[1];
}
}
private void IgniteColorFx()//燃烧状态颜色
{
if (sr.color != igniteColor[0])
sr.color = igniteColor[0];
else
{
sr.color = igniteColor[1];
}
}
private void ChillColorFx()//燃烧状态颜色
{
if (sr.color != chillColor[0])
sr.color = chillColor[0];
else
{
sr.color = chillColor[1];
}
}
//2024.12.5
public void CreateHitFX(Transform _target, bool _critical)//攻击特效
{
float zRotation = Random.Range(-90, 90);
float xPosition = Random.Range(-.5f, .5f);
float yPosition = Random.Range(-.5f, .5f);
Vector3 hitFXRotation = new Vector3(0, 0, zRotation);//生成的旋转向量
GameObject hitPrefab = hitFX;
if (_critical)//如果暴击
{
hitPrefab = criticalHitFx;
float yRotation = 0;
zRotation = Random.Range(-45, 45);
if (GetComponent<Entity>().facingDir == -1)//如果玩家朝向左边
yRotation = 180;
hitFXRotation = new Vector3(0, yRotation, zRotation);
}
GameObject newHitFX = Instantiate(hitPrefab, _target.position + new Vector3(xPosition, yPosition), Quaternion.identity);//,_target);
newHitFX.transform.Rotate(hitFXRotation);//设置旋转角度
Destroy(newHitFX, .3f);
}
public void PlayDustFX()
{
if (dustFx != null)
dustFx.Play();
}
}
PlayerGroundedState.cs
设置冷却显示
if(player.skill.blackhole.cooldownTimer>0)
{
player.fx.CreatePopUpText("冷却中");
return;
}