学习目标:
前面学习了制作了生命值和能量值系统,今天来是试着做一下得分系统,以及将我们的能量使用分为两部分。
得分系统:
为了方便以后制作暂停菜单,我们需要将生命条和能量条以及得分系统放在同一个Canvas上,先把三者创建的Canvas组件移除掉,给一个空对象创建Canvas,别忘了设置他们的锚点。
再给它创建一个Image,使用纵向布局,再创建两个Text
创建一个ScoreManager对象以及同名脚本方便我们管理分数
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScoreManager : PersistentSingleTon<ScoreManager>
{
int score;
int currentScore;
[SerializeField] Vector3 scoreTextScale = new Vector3(1.2f, 1.2f, 1f);
public void ResetScore()
{
score = 0;
currentScore = 0;
ScoreDisplay.UpdateText(score);
}
public void AddScore(int scorePoint)
{
currentScore += scorePoint;
StartCoroutine(nameof(AddScoreCoroutine));
}
IEnumerator AddScoreCoroutine()
{
ScoreDisplay.ScaleText(scoreTextScale);
while(currentScore > score)
{
score += 1;
ScoreDisplay.UpdateText(score);
yield return null;
}
ScoreDisplay.ScaleText(Vector3.one);
}
}
给我们的ScoreText新创建一个脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreDisplay : MonoBehaviour
{
//得分UI的显示与更新
static Text scoreText;
private void Awake()//用于脚本自身初始化
{
scoreText = GetComponent<Text>();
}
private void Start() //初始化工作晚于Awake运行,留给其他脚本进行初始化和调用其他脚本的函数
{
ScoreManager.Instance.ResetScore();
}
public static void UpdateText(int score)
{
scoreText.text = score.ToString();
}
public static void ScaleText(Vector3 targetScale)
{
scoreText.transform.localScale = targetScale;
}
}
当然我们要给我们的Enemy绑定这个脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : Character
{
[SerializeField] int deathEnergyBouns = 3;
[SerializeField] int scorePoint = 100;
public override void Die()
{
ScoreManager.Instance.AddScore(scorePoint);
PlayerEnergy.Instance.Obtain(deathEnergyBouns);
EnemyManager.Instance.RemoveList(gameObject);
base.Die();
}
}
这样得分系统就算是做完了。
制作能量使用第①部分闪避:
首先还得是在Plyaer上添加一个动作表
在PlayerInput脚本中
public event UnityAction onDodge = delegate { };
public void OnDodge(InputAction.CallbackContext context)
{
if(context.phase == InputActionPhase.Performed)
{
onDodge.Invoke();
}
}
我们可以为玩家添加闪避动作,通过关闭碰撞体即可实现,先检查一遍PlayerEnergy脚本。
using System.Collections;
using UnityEngine;
public class PlayerEnergy : Singleton<PlayerEnergy>
{
[SerializeField] float overdriveInterval = 0.1f;
[SerializeField] EnergyBar energyBar;
public const int MAX = 100;
public const int PERCENT = 1;
int energy;
protected override void Awake()
{
waitForOverdriveInterval = new WaitForSeconds(overdriveInterval);
base.Awake();
}
private void OnEnable()
{
PlayerOverdirve.on += PlayerOverdriveOn;
PlayerOverdirve.off += PlayerOverdriveOff;
}
private void OnDisable()
{
PlayerOverdirve.on -= PlayerOverdriveOn;
PlayerOverdirve.off -= PlayerOverdriveOff;
}
void Start()
{
energyBar.Initialize(energy, MAX);
Obtain(100);
}
public void Obtain(int value) //获得能量
{
if (energy == MAX || !gameObject.activeSelf || !avaliable) return;
energy = Mathf.Clamp(energy + value, 0, MAX);
energyBar.UpdateStates(energy, MAX); //更新能量条
}
public void Use(int value)
{
energy -= value;
energyBar.UpdateStates(energy, MAX);
if(energy == 0 && !avaliable)
{
PlayerOverdirve.off.Invoke();
}
}
public bool IsEnough(int value) => energy >= value; //判断能量是否能使用
}
点开Player脚本为它创建闪避Dodge相关的模块
[Header("--- DODGE ---")]
[SerializeField] int dodgeEnergyCost = 25;
[SerializeField] float maxRoll = 360f;
[SerializeField] float rollSpeed = 360f;
[SerializeField] Vector3 dodgeScale = new Vector3(0.5f, 0.5f, 0.5f);
[SerializeField] AudioData dodgeSFX;
bool isDodging = false;
float currentRoll;
float dodgeDuration;
private void Awake()
{
rigi2D = GetComponent<Rigidbody2D>();
collider = GetComponent<Collider2D>();
var size = transform.GetChild(0).GetComponent<Renderer>().bounds.size;
paddingX = size.x / 2;
paddingY = size.y / 2;
dodgeDuration = maxRoll / rollSpeed;
rigi2D.gravityScale = 0f;
waitForFireInterval = new WaitForSeconds(fireInterval);
waitForOverdriveFireInterval = new WaitForSeconds(fireInterval /= overdriveFireFactor);
waitHealthGeneratedTime = new WaitForSeconds(healthGenerateTime);
waitDeceletationTime = new WaitForSeconds(decelarationTime);
}
protected override void OnEnable()
{
//增加委托/订阅事件
base.OnEnable();
input.onMove += Move;
input.onStopMove += StopMove;
input.onFire += Fire;
input.onStopFire += StopFire;
input.onDodge += Dodge;
}
private void OnDisable()
{
//取消委托
input.onMove -= Move;
input.onStopMove -= StopMove;
input.onFire -= Fire;
input.onStopFire -= StopFire;
input.onDodge -= Dodge;
}
void Dodge()
{
if (isDodging || !PlayerEnergy.Instance.IsEnough(dodgeEnergyCost)) return;
StartCoroutine(nameof(DodgeCoroutine));
}
IEnumerator DodgeCoroutine()
{
isDodging = true;
AudioManager.Instance.PlayRandomSFX(dodgeSFX);
//消耗能量
PlayerEnergy.Instance.Use(dodgeEnergyCost);
//无敌状态
collider.isTrigger = true;
currentRoll = 0f;
TimeController.Instance.BulletTime(slowMotionDuration, slowMotionDuration);
var scale = transform.localScale;
while(currentRoll < maxRoll)
{
currentRoll += rollSpeed * Time.deltaTime;
//让玩家绕着X轴旋转
transform.rotation = Quaternion.AngleAxis(currentRoll, Vector3.right);
BezierCurve.QuadraticPoint(Vector3.one, Vector3.one,dodgeScale,currentRoll / maxRoll);
yield return null;
}
collider.isTrigger = false;
isDodging = false;
}
里面还涉及复制减速的TimeController
再创建一个同名脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TimeController : Singleton<TimeController>
{
[SerializeField, Range(0, 1)] float bulletTimeScale = 0.1f;
float defaultFixedDeltaTime;
float t;
protected override void Awake()
{
base.Awake();
defaultFixedDeltaTime = Time.fixedDeltaTime;
}
public void BulletTime(float duration)
{
Time.timeScale = bulletTimeScale;
StartCoroutine(SlowOutCoroutine(duration));
}
public void BulletTime(float inDuration,float outDuration)
{
StartCoroutine(SlowInAndOutCoroutine(inDuration, outDuration));
}
public void BulletTime(float inDuration,float keepingDuration,float outDuration)
{
StartCoroutine(SlowInKeepAndOutCoroutine(inDuration,keepingDuration,outDuration));
}
public void SlowIn(float duration)
{
StartCoroutine(SlowInCoroutine(duration));
}
public void ShowOut(float duration)
{
StartCoroutine(SlowOutCoroutine(duration));
}
IEnumerator SlowInKeepAndOutCoroutine(float inDuration,float keepingDuration,float outDuration)
{
yield return StartCoroutine(SlowInCoroutine(inDuration));
yield return new WaitForSecondsRealtime(keepingDuration);
StartCoroutine(SlowOutCoroutine(outDuration));
}
IEnumerator SlowInAndOutCoroutine(float inDuration,float outDuration)
{
yield return StartCoroutine(SlowInCoroutine(inDuration));
StartCoroutine(SlowOutCoroutine(outDuration));
}
IEnumerator SlowInCoroutine(float duration)
{
t = 0f;
while (t < 1f)
{
t += Time.unscaledDeltaTime / duration;
Time.timeScale = Mathf.Lerp(1f, bulletTimeScale, t) ;
Time.fixedDeltaTime = defaultFixedDeltaTime * Time.timeScale;
yield return null;
}
}
IEnumerator SlowOutCoroutine(float duration)
{
t = 0f;
while (t < 1f)
{
t += Time.unscaledDeltaTime / duration;
Time.timeScale = Mathf.Lerp(bulletTimeScale, 1f, t);
Time.fixedDeltaTime = defaultFixedDeltaTime * Time.timeScale;
yield return null;
}
}
}
以及还有一个 BezierCurve的脚本用于计算二次贝塞尔曲线的,
using UnityEngine;
public class BezierCurve
{
/// <summary>
/// Return a point of quadratic Bezier curve.
/// 返回二次贝塞尔曲线上的点。
/// </summary>
public static Vector3 QuadraticPoint(Vector3 startPoint, Vector3 endPoint, Vector3 controlPoint, float by)
{
// * Math Formula Method
// float oneMinusT = 1f - t;
// return oneMinusT * oneMinusT * startPoint + t * t * endPoint + 2 * oneMinusT * t * controlPoint;
return Vector3.Lerp(
Vector3.Lerp(startPoint, controlPoint, by),
Vector3.Lerp(controlPoint, endPoint, by),
by);
}
/// <summary>
/// Return a point of cubic Bezier curve.
/// 返回三次贝塞尔曲线上的点。
/// </summary>
public static Vector3 CubicPoint(Vector3 startPoint, Vector3 endPoint, Vector3 controlPointStart, Vector3 controlPointEnd, float t)
{
// * Method 01
// float oneMinusT = 1f - t;
// return oneMinusT * oneMinusT * oneMinusT * startPoint +
// t * t * t * endPoint +
// 3 * t * oneMinusT * oneMinusT * controlPointStart +
// 3 * t * t * oneMinusT * controlPointEnd;
// * Method 02
// var AB = Vector3.Lerp(startPoint, controlPointStart, t);
// var BC = Vector3.Lerp(controlPointStart, controlPointEnd, t);
// var CD = Vector3.Lerp(controlPointEnd, endPoint, t);
// var AB2BC = Vector3.Lerp(AB, BC, t);
// var BC2CD = Vector3.Lerp(BC, CD, t);
// return Vector3.Lerp(AB2BC, BC2CD, t);
// * Method 03
// return Vector3.Lerp(
// Vector3.Lerp(
// Vector3.Lerp(startPoint, controlPointStart, t),
// Vector3.Lerp(controlPointStart, controlPointEnd, t),
// t),
// Vector3.Lerp(
// Vector3.Lerp(controlPointStart, controlPointEnd, t),
// Vector3.Lerp(controlPointEnd, endPoint, t), t),
// t);
// * Method 04
// var AB = Vector3.Lerp(startPoint, controlPointStart, t);
// var BC = Vector3.Lerp(controlPointStart, controlPointEnd, t);
// var CD = Vector3.Lerp(controlPointEnd, endPoint, t);
// return QuadraticBezierCurvePoint(AB, CD, BC, t);
// * Method 05
return QuadraticPoint(
Vector3.Lerp(startPoint, controlPointStart, t),
Vector3.Lerp(controlPointEnd, endPoint, t),
Vector3.Lerp(controlPointStart, controlPointEnd, t), t);
}
}
将默认需要使用的能量设置为25。
制作能量使用第②部分闪避:
再制作一个动作表绑定为鼠标中键
public event UnityAction onOverDirve = delegate { };
public void OnOverdrive(InputAction.CallbackContext context)
{
if(context.phase == InputActionPhase.Performed)
{
onOverDirve.Invoke();
}
}
然后我们再扩展PlayerEnergy脚本
using System.Collections;
using UnityEngine;
public class PlayerEnergy : Singleton<PlayerEnergy>
{
[SerializeField] float overdriveInterval = 0.1f;
[SerializeField] EnergyBar energyBar;
public const int MAX = 100;
public const int PERCENT = 1;
int energy;
bool avaliable = true; //当处于能量爆发时为false
WaitForSeconds waitForOverdriveInterval;
protected override void Awake()
{
waitForOverdriveInterval = new WaitForSeconds(overdriveInterval);
base.Awake();
}
private void OnEnable()
{
PlayerOverdirve.on += PlayerOverdriveOn;
PlayerOverdirve.off += PlayerOverdriveOff;
}
private void OnDisable()
{
PlayerOverdirve.on -= PlayerOverdriveOn;
PlayerOverdirve.off -= PlayerOverdriveOff;
}
void Start()
{
energyBar.Initialize(energy, MAX);
Obtain(75);
}
public void Obtain(int value) //获得能量
{
if (energy == MAX || !gameObject.activeSelf || !avaliable) return;
energy = Mathf.Clamp(energy + value, 0, MAX);
energyBar.UpdateStates(energy, MAX); //更新能量条
}
public void Use(int value)
{
energy -= value;
energyBar.UpdateStates(energy, MAX);
if(energy == 0 && !avaliable)
{
PlayerOverdirve.off.Invoke();
}
}
public bool IsEnough(int value) => energy >= value; //判断能量是否能使用
void PlayerOverdriveOn()
{
avaliable = false;
StartCoroutine(nameof(KeepUsingCoroutine));
}
void PlayerOverdriveOff()
{
avaliable = true;
StopCoroutine(nameof(KeepUsingCoroutine));
}
IEnumerator KeepUsingCoroutine()
{
while(gameObject.activeSelf && energy > 0)
{
yield return waitForOverdriveInterval;
Use(PERCENT);
}
}
}
然后再为我们的Player创建一个叫PlayerOverDrive的脚本,
这里不用event事件是方便委托在其它类函数中被调用。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class PlayerOverdirve : MonoBehaviour
{
//在其它类中被调用
public static UnityAction on = delegate { }; //委托能量的开启
public static UnityAction off = delegate { }; //委托能量的开启
[SerializeField] GameObject triggerVFX;
[SerializeField] GameObject engineVFXNormal;
[SerializeField] GameObject engineVFXOverdrive;
[SerializeField] AudioData onSFX;
[SerializeField] AudioData offSFX;
private void Awake()
{
on += On;
off += Off;
}
private void OnDisable()
{
on -= On;
off -= Off;
}
void On()
{
triggerVFX.SetActive(true);
engineVFXNormal.SetActive(false);
engineVFXOverdrive.SetActive(true);
AudioManager.Instance.PlayRandomSFX(onSFX);
}
void Off()
{
engineVFXNormal.SetActive(true);
engineVFXOverdrive.SetActive(false);
AudioManager.Instance.PlayRandomSFX(offSFX);
}
}
在Player脚本中添加相关Overdrive相关的脚本
这里将完整的Player脚本拖出来,大家可以复制粘贴然后自行看看Overdrive相关的脚本
using System.Collections;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Player : Character
{
[SerializeField] StateBar_HUD stateBar_HUD;
[SerializeField] bool genearatedHealth = true;
[SerializeField] float healthGenerateTime;
[SerializeField,Range(0f,1f)] float healthRegeneatePercent;
[Header("--- INPUT ---")]
[SerializeField] PlayerInput input;
[Header("--- MOVE ---")]
[SerializeField] float accelarationTime = 3f;
[SerializeField] float decelarationTime = 3f;
[SerializeField] float moveSpeed = 10f;
[SerializeField] float moveRotatinAngle = 50f;
float paddingX;
float paddingY;
[SerializeField] float fireInterval= 0.2f;
float t;
readonly float slowMotionDuration = 1f;
Vector2 previousVelocity;
Quaternion previousRotation;
[Header("--- FIRE ---")]
[SerializeField] float keepingDuration = 5f;
[SerializeField] GameObject projectTile1;
[SerializeField] GameObject projectTile2;
[SerializeField] GameObject projectTile3;
[SerializeField] GameObject projectTileOverdirve;
[SerializeField] AudioData projectileLaunchSFX;
[SerializeField, Range(0, 2)] int weaponPower = 0;
[SerializeField] Transform muzlleMiddle;
[SerializeField] Transform muzzleTop;
[SerializeField] Transform muzzleBottom;
Rigidbody2D rigi2D;
new Collider2D collider;
[Header("--- COROUTINE ---")]
Coroutine moveCoroutine;
Coroutine healthRegenerateCoroutine;
WaitForSeconds waitDeceletationTime;
WaitForSeconds waitForFireInterval;
WaitForSeconds waitForOverdriveFireInterval;
WaitForSeconds waitHealthGeneratedTime;
[Header("--- DODGE ---")]
[SerializeField] int dodgeEnergyCost = 25;
[SerializeField] float maxRoll = 360f;
[SerializeField] float rollSpeed = 360f;
[SerializeField] Vector3 dodgeScale = new Vector3(0.5f, 0.5f, 0.5f);
[SerializeField] AudioData dodgeSFX;
bool isDodging = false;
float currentRoll;
float dodgeDuration;
[Header("--- OVERDRIVE ---")]
[SerializeField] int overdriveDodgeFactor = 2;
[SerializeField] float overdriveFireFactor = 1.2f;
[SerializeField] float overdriveSpeedFactor = 1.2f;
bool isOverdirving = false;
private void Awake()
{
rigi2D = GetComponent<Rigidbody2D>();
collider = GetComponent<Collider2D>();
var size = transform.GetChild(0).GetComponent<Renderer>().bounds.size;
paddingX = size.x / 2;
paddingY = size.y / 2;
dodgeDuration = maxRoll / rollSpeed;
rigi2D.gravityScale = 0f;
waitForFireInterval = new WaitForSeconds(fireInterval);
waitForOverdriveFireInterval = new WaitForSeconds(fireInterval /= overdriveFireFactor);
waitHealthGeneratedTime = new WaitForSeconds(healthGenerateTime);
waitDeceletationTime = new WaitForSeconds(decelarationTime);
}
protected override void OnEnable()
{
//增加委托/订阅事件
base.OnEnable();
input.onMove += Move;
input.onStopMove += StopMove;
input.onFire += Fire;
input.onStopFire += StopFire;
input.onDodge += Dodge;
input.onOverDirve += Overdrive;
PlayerOverdirve.on += OverdriveOn;
PlayerOverdirve.off += OverdriveOff;
}
private void OnDisable()
{
//取消委托
input.onMove -= Move;
input.onStopMove -= StopMove;
input.onFire -= Fire;
input.onStopFire -= StopFire;
input.onDodge -= Dodge;
input.onOverDirve -= Overdrive;
PlayerOverdirve.on -= OverdriveOn;
PlayerOverdirve.off -= OverdriveOff;
}
void Start()
{
rigi2D.gravityScale = 0f;
waitForFireInterval = new WaitForSeconds(fireInterval);
waitHealthGeneratedTime = new WaitForSeconds(healthGenerateTime);
stateBar_HUD.Initialize(health, maxHealth);
input.EnableGamePlayInput(); //激活动作表
}
public override void TakeDamage(float damage)
{
base.TakeDamage(damage);
stateBar_HUD.UpdateStates(health, maxHealth);
TimeController.Instance.BulletTime(slowMotionDuration);
if (gameObject.activeSelf)
{
if(healthRegenerateCoroutine != null)
{
StopCoroutine(healthRegenerateCoroutine);
}
healthRegenerateCoroutine = StartCoroutine(HealthPercentageCoroutine(waitHealthGeneratedTime, healthRegeneatePercent));
}
}
public override void RestoreHealth(float value)
{
base.RestoreHealth(value);
stateBar_HUD.UpdateStates(health, maxHealth);
}
public override void Die()
{
stateBar_HUD.UpdateStates(0f, maxHealth);
base.Die();
}
#region WALK
void Move(Vector2 moveInput) //就是你输入信号的二维值
{
//Vector2 moveAmount = moveInput * moveSpeed;
//rigi2D.velocity = moveAmount;
if (moveCoroutine != null)
{
StopCoroutine(moveCoroutine);
}
Quaternion moveRotation = Quaternion.AngleAxis(moveRotatinAngle * moveInput.y,Vector3.right); //right即红色的X轴,初始旋转角度
moveCoroutine=StartCoroutine(MoveCoroutine(accelarationTime,(moveInput.normalized * moveSpeed),moveRotation));
StopCoroutine(nameof(DeceletationCoroutine));
StartCoroutine(nameof(MoveRangeLimitationCoroutine));
}
void StopMove()
{
//rigi2D.velocity = Vector2.zero;
if (moveCoroutine != null)
{
StopCoroutine(moveCoroutine);
}
moveCoroutine = StartCoroutine(MoveCoroutine(decelarationTime,Vector2.zero, Quaternion.identity));
StartCoroutine(nameof(DeceletationCoroutine));
}
IEnumerator MoveCoroutine(float time,Vector2 moveVelocity,Quaternion moveRotation)
{
t = 0f;
previousVelocity = rigi2D.velocity;
previousRotation = transform.rotation;
while(t< 1f)
{
t += Time.fixedDeltaTime / time;
rigi2D.velocity = Vector2.Lerp(previousVelocity, moveVelocity,t);
transform.rotation = Quaternion.Lerp(previousRotation, moveRotation,t);
yield return new WaitForFixedUpdate();
}
}
IEnumerator MoveRangeLimitationCoroutine()
{
while (true)
{
transform.position = ViewPort.Instance.PlayerMoveablePosition(transform.position,paddingX,paddingY);
yield return null;
}
}
IEnumerator DeceletationCoroutine()
{
yield return waitDeceletationTime;
StopCoroutine(nameof(MoveRangeLimitationCoroutine));
}
#endregion
#region FIRE
void Fire()
{
StartCoroutine(nameof(FireCoroutine));
}
void StopFire()
{
StopCoroutine(nameof(FireCoroutine));
}
IEnumerator FireCoroutine()
{
while (true)
{
switch (weaponPower)
{
case 0:
PoolManager.Release(isOverdirving?projectTileOverdirve:projectTile1, muzlleMiddle.position, Quaternion.identity);
break;
case 1:
PoolManager.Release(isOverdirving ? projectTileOverdirve : projectTile1, muzzleTop.position, Quaternion.identity);
PoolManager.Release(isOverdirving ? projectTileOverdirve : projectTile1, muzzleBottom.position, Quaternion.identity);
break;
case 2:
PoolManager.Release(isOverdirving ? projectTileOverdirve : projectTile1, muzzleTop.position, Quaternion.identity);
PoolManager.Release(isOverdirving ? projectTileOverdirve : projectTile2, muzlleMiddle.position, Quaternion.identity);
PoolManager.Release(isOverdirving ? projectTileOverdirve : projectTile3, muzzleBottom.position, Quaternion.identity);
break;
default:break;
}
AudioManager.Instance.PlayRandomSFX(projectileLaunchSFX);
yield return isOverdirving? waitForOverdriveFireInterval : waitForFireInterval;
}
}
#endregion
#region DODGE
void Dodge()
{
if (isDodging || !PlayerEnergy.Instance.IsEnough(dodgeEnergyCost)) return;
StartCoroutine(nameof(DodgeCoroutine));
}
IEnumerator DodgeCoroutine()
{
isDodging = true;
AudioManager.Instance.PlayRandomSFX(dodgeSFX);
//消耗能量
PlayerEnergy.Instance.Use(dodgeEnergyCost);
//无敌状态
collider.isTrigger = true;
currentRoll = 0f;
TimeController.Instance.BulletTime(slowMotionDuration, slowMotionDuration);
var scale = transform.localScale;
while(currentRoll < maxRoll)
{
currentRoll += rollSpeed * Time.deltaTime;
//让玩家绕着X轴旋转
transform.rotation = Quaternion.AngleAxis(currentRoll, Vector3.right);
BezierCurve.QuadraticPoint(Vector3.one, Vector3.one,dodgeScale,currentRoll / maxRoll);
//if(currentRoll < maxRoll / 2f)
//{
// scale.x = Mathf.Clamp(scale.x - Time.deltaTime / dodgeDuration, dodgeScale.x, 1f);
// scale.y = Mathf.Clamp(scale.y - Time.deltaTime / dodgeDuration, dodgeScale.y, 1f);
// scale.z = Mathf.Clamp(scale.z - Time.deltaTime / dodgeDuration, dodgeScale.z, 1f);
//}
//else
//{
// scale.x = Mathf.Clamp(scale.x + Time.deltaTime / dodgeDuration, dodgeScale.x, 1f);
// scale.y = Mathf.Clamp(scale.y + Time.deltaTime / dodgeDuration, dodgeScale.y, 1f);
// scale.z = Mathf.Clamp(scale.z + Time.deltaTime / dodgeDuration, dodgeScale.z, 1f);
//}
//transform.localScale = scale;
yield return null;
}
collider.isTrigger = false;
isDodging = false;
}
#endregion
#region OVERDRIVE
void Overdrive()
{
if (!PlayerEnergy.Instance.IsEnough(PlayerEnergy.MAX)) return;
PlayerOverdirve.on.Invoke();
}
void OverdriveOn()
{
isOverdirving = true;
moveSpeed *= overdriveFireFactor;
dodgeEnergyCost *= overdriveDodgeFactor;
TimeController.Instance.BulletTime(slowMotionDuration,keepingDuration,slowMotionDuration);
}
void OverdriveOff()
{
isOverdirving = false;
moveSpeed /= overdriveFireFactor;
dodgeEnergyCost /= overdriveDodgeFactor;
}
#endregion
}
然后设置相应的参数。
学习产出: