当前位置: 首页 > 工具软件 > ruby2d > 使用案例 >

【Ruby‘s Adventure:2D】(全)-发射子弹、持续伤害

华坚成
2023-12-01

前言

过于简单,官方有详细教程: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);
    }
 类似资料: