过于简单,官方有详细教程:Ruby’s Adventure:2D
主要看看发射子弹和范围伤害的实现。
这个是显示一段时间直接消失,不如之前看的另一个项目中的渐变消失效果 【Creator Kit - RPG 代码分析】(3)-游戏玩法-消息提示、音频管理、输入控制、角色控制器
public class NonPlayerCharacter : MonoBehaviour
{
public float displayTime = 4.0f;
public GameObject dialogBox;
float timerDisplay;
void Start()
{
dialogBox.SetActive(false);
timerDisplay = -1.0f;
}
void Update()
{
if (timerDisplay >= 0) // 停留timerDisplay 时间就消失
{
timerDisplay -= Time.deltaTime;
if (timerDisplay < 0)
{
dialogBox.SetActive(false);
}
}
}
public void DisplayDialog() // 展示对话框
{
timerDisplay = displayTime;
dialogBox.SetActive(true);
}
}
发射出子弹,给其一个初始力,超过一定距离(射程)自动销毁,碰撞到敌人处理相应逻辑
/// <summary>
/// Handle the projectile launched by the player to fix the robots. 炮弹
/// </summary>
public class Projectile : MonoBehaviour
{
Rigidbody2D rigidbody2d;
void Awake()
{
rigidbody2d = GetComponent<Rigidbody2D>();
}
void Update()
{
//destroy the projectile when it reach a distance of 1000.0f from the origin
if(transform.position.magnitude > 1000.0f) // 距离超过这个距离就销毁炮弹
Destroy(gameObject);
}
//called by the player controller after it instantiate a new projectile to launch it.
public void Launch(Vector2 direction, float force)
{
rigidbody2d.AddForce(direction * force); // 初始时加一个力
}
void OnCollisionEnter2D(Collision2D other)
{
Enemy e = other.collider.GetComponent<Enemy>();
//if the object we touched wasn't an enemy, just destroy the projectile.
if (e != null) // 看炮弹是否碰到敌人
{
e.Fix();
}
Destroy(gameObject);
}
}
OnTriggerStay2D
会每帧检测碰撞,可以用来实现持续伤害,下面这段代码实现了在伤害区域内 每帧血量-1的功能。
public class DamageZone : MonoBehaviour
{
void OnTriggerStay2D(Collider2D other)
{
RubyController controller = other.GetComponent<RubyController>();
if (controller != null)
{
//the controller will take care of ignoring the damage during the invincibility time.
controller.ChangeHealth(-1);
}
}
}
但是这样血量减得太快了,所以这个Demo 设置了个伤害频率,如下,用无敌时间,控制这个时间段内只能攻击一次。
public void ChangeHealth(int amount)
{
if (amount < 0)
{
if (isInvincible)
return;
isInvincible = true; // 设置无敌
invincibleTimer = timeInvincible; // 无敌时间间隔,假如是1s,也就是说1s内只能受到一次伤害
animator.SetTrigger("Hit");
audioSource.PlayOneShot(hitSound);
Instantiate(hitParticle, transform.position + Vector3.up * 0.5f, Quaternion.identity);
}
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
if(currentHealth == 0)
Respawn();
UIHealthBar.Instance.SetValue(currentHealth / (float)maxHealth);
}
每帧按顺序处理:血量、移动、设置动画、攻击、对话,在FixUpdate
里真正移动。
void Update()
{
// ================= HEALTH ====================
if (isInvincible)
{
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0)
isInvincible = false;
}
// ============== MOVEMENT ======================
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector2 move = new Vector2(horizontal, vertical);
if(!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f))
{
lookDirection.Set(move.x, move.y);
lookDirection.Normalize();
}
currentInput = move;
// ============== ANIMATION =======================
animator.SetFloat("Look X", lookDirection.x);
animator.SetFloat("Look Y", lookDirection.y);
animator.SetFloat("Speed", move.magnitude);
// ============== PROJECTILE ======================
if (Input.GetKeyDown(KeyCode.C))
LaunchProjectile();
// ======== DIALOGUE ==========
if (Input.GetKeyDown(KeyCode.X))
{
RaycastHit2D hit = Physics2D.Raycast(rigidbody2d.position + Vector2.up * 0.2f, lookDirection, 1.5f, 1 << LayerMask.NameToLayer("NPC"));
if (hit.collider != null)
{
NonPlayerCharacter character = hit.collider.GetComponent<NonPlayerCharacter>();
if (character != null)
{
character.DisplayDialog();
}
}
}
}
void FixedUpdate()
{
Vector2 position = rigidbody2d.position;
position = position + currentInput * speed * Time.deltaTime;
rigidbody2d.MovePosition(position);
}
发射炮弹,实例化炮弹并发射出去
void LaunchProjectile()
{
GameObject projectileObject = Instantiate(projectilePrefab, rigidbody2d.position + Vector2.up * 0.5f, Quaternion.identity);
Projectile projectile = projectileObject.GetComponent<Projectile>();
projectile.Launch(lookDirection, 300);
animator.SetTrigger("Launch");
audioSource.PlayOneShot(shootingSound);
}