自学内容网 自学内容网

Unity教程(十八)战斗系统 攻击逻辑

Unity开发2D类银河恶魔城游戏学习笔记

Unity教程(零)Unity和VS的使用相关内容
Unity教程(一)开始学习状态机
Unity教程(二)角色移动的实现
Unity教程(三)角色跳跃的实现
Unity教程(四)碰撞检测
Unity教程(五)角色冲刺的实现
Unity教程(六)角色滑墙的实现
Unity教程(七)角色蹬墙跳的实现
Unity教程(八)角色攻击的基本实现
Unity教程(九)角色攻击的改进

Unity教程(十)Tile Palette搭建平台关卡
Unity教程(十一)相机
Unity教程(十二)视差背景

Unity教程(十三)敌人状态机
Unity教程(十四)敌人空闲和移动的实现
Unity教程(十五)敌人战斗状态的实现
Unity教程(十六)敌人攻击状态的实现
Unity教程(十七)敌人战斗状态的完善

Unity教程(十八)战斗系统 攻击逻辑
Unity教程(十九)战斗系统 受击反馈


如果你更习惯用知乎
Unity开发2D类银河恶魔城游戏学习笔记目录



前言

本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记,如有错误,欢迎指正。

本节实现战斗系统的攻击逻辑部分。

Udemy课程地址

对应视频:
Attack Logic
Collider’s collision exception


一、概述

本节我们先实现战斗的逻辑,即在攻击动画播放过程中找到攻击对象并造成伤害,这里伤害我们先用控制台信息代表,后续再进行具体实现。
在这里插入图片描述
在这里插入图片描述

二、攻击逻辑的实现

(1)攻击检测

在实体Entity类中添加攻击检测和攻击距离两个变量,并在OnDrawGizmos函数中绘制出攻击范围。

Gizmos函数详情见Unity官方手册
Gizmos可以绘制图形的图形如下表:

函数功能
DrawCube使用 center 和 size 绘制一个实心盒体。
DrawFrustum绘制一个摄像机视锥体,并且将当前设置的 Gizmos.matrix 用于其位置和旋转。
DrawGUITexture在该场景中绘制一个纹理。
DrawIcon在 Scene 视图中的某个位置绘制一个图标。
DrawLine绘制一条从 from 开始到 to 的线。
DrawMesh绘制一个网格。
DrawRay绘制一条从 from 开始到 from + direction 的射线。
DrawSphere使用 center 和 radius 绘制一个实心球体。
DrawWireCube使用 center 和 size 绘制一个线框盒体。
DrawWireMesh绘制一个线框网格。
DrawWireSphere使用 center 和 radius 绘制一个线框球体。

Entity类中添加代码如下:
添加变量:

    [Header("Collision Info")]
    public Transform attackCheck;
    public float attackCheckRadius;
    [SerializeField] protected Transform groundCheck;
    [SerializeField] protected float groundCheckDistance;
    [SerializeField] protected Transform wallCheck;
    [SerializeField] protected float wallCheckDistance;
    [SerializeField] protected LayerMask whatIsGround;

绘制攻击范围:

    protected virtual void OnDrawGizmos()
    {
        Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));
        Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x + wallCheckDistance, wallCheck.position.y));
        Gizmos.DrawWireSphere(attackCheck.position, attackCheckRadius);
    }

在Player下创建空物体attackCheck用于攻击检测。
将空物体attackCheck拖入变量,并给attackCheckRadius设置合适的值。
在这里插入图片描述
在这里插入图片描述
移动attackCheck到Player身前合适位置,圆圈绘制出的就是Player的攻击范围。
在这里插入图片描述
同理,设置小怪的攻击检测。
在这里插入图片描述

(2)伤害函数

在Entity中添加伤害函数Damage(),实现受击后的反馈。目前不进行具体实现,先输出一条调试信息代替。

    public virtual void Damage()
    {
        Debug.Log(gameObject.name + " was damaged");
    }

(2)攻击触发器

我们先以Player的攻击为例。
在玩家触发器PlayerAnimationTriggers类中,添加攻击触发器attackTrigger函数。
每次攻击时,要记录所有在攻击范围内的敌人。然后每个攻击范围内的敌人将调用自己的Damage函数实现受伤的反馈。

检测攻击范围内的敌人调用Physics2D.OverlapCircleAll函数,它会返回圆内的所有碰撞体。
Collider2D[] OverlapCircleAll (Vector2 point, float radius, int layerMask, float minDepth, float maxDepth);
参数表如下

参数介绍
point圆形的中心。
radius圆形的半径。
layerMask筛选器,用于检查仅在指定层上的对象。
minDepth仅包括 Z 坐标(深度)大于或等于该值的对象。
maxDepth仅包括 Z 坐标(深度)小于或等于该值的对象。

在PlayerAnimationTriggers中添加代码:

    private void AttackTrigger()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(player.attackCheck.position, player.attackCheckRadius);

        foreach(var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null)
                hit.GetComponent<Enemy>().Damage();
        }
    }

在触发攻击伤害的帧添加事件调用attackTrigger

如需添加事件帧的详细介绍请见
Unity教程(八)角色基本攻击的实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,在玩家攻击时,控制台输出对骷髅产生伤害
在这里插入图片描述
敌人的攻击触发器实现与玩家一样,代码如下:

    private void AttackTrigger()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(enemy.attackCheck.position, enemy.attackCheckRadius);

        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Player>() != null)
                hit.GetComponent<Player>().Damage();
        }
    }

同样设置事件帧

在这里插入图片描述
在这里插入图片描述

三、解决碰撞问题

现在攻击时,因为两者之间存在碰撞,骷髅会推着玩家走,而玩家甚至可以在骷髅头上走,这看起来很不对劲。
在这里插入图片描述
在制作游戏时,有些会采用碰撞伤害,有些则只有攻击时造成伤害。在这里我们采用第二种,让玩家可以穿过敌人,只在被攻击击中时受到伤害。
解决方式很简单,只需要调整层次之间的碰撞即可。
首先必须确保玩家和敌人处于各自层级。

在这里插入图片描述
在这里插入图片描述
调整层次碰撞矩阵,将Player和Enemy层次间的碰撞勾掉
Edit -> Project Settings -> Physics 2D -> Layer Collision Matrix

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
目前存在一个问题,在骷髅与玩家重合时会不停碰撞导致骷髅抽搐,这个问题会在后续解决。
在这里插入图片描述

总结 完整代码

Entity.cs

添加攻击检测变量和绘制函数,添加伤害函数。

//Entity:实体类
using System.Collections;
using System.Collections.Generic;
using Unity.IO.LowLevel.Unsafe;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class Entity : MonoBehaviour
{

    [Header("Flip Info")]
    protected bool facingRight = true;
    public int facingDir { get; private set; } = 1;



    [Header("Collision Info")]
    public Transform attackCheck;
    public float attackCheckRadius;
    [SerializeField] protected Transform groundCheck;
    [SerializeField] protected float groundCheckDistance;
    [SerializeField] protected Transform wallCheck;
    [SerializeField] protected float wallCheckDistance;
    [SerializeField] protected LayerMask whatIsGround;


    #region 组件
    public Rigidbody2D rb { get; private set; }
    public Animator anim { get; private set; }
    #endregion

    protected virtual void Awake()
    {

    }

    //获取组件
    protected virtual void Start()
    {
        rb= GetComponent<Rigidbody2D>();
        anim= GetComponentInChildren<Animator>();
    }

    // 更新
    protected virtual void Update()
    {
        
    }

    public virtual void Damage()
    {
        Debug.Log(gameObject.name + " was damaged");
    }

    #region 速度设置
    //速度置零
    public void ZeroVelocity() => rb.velocity = new Vector2(0, 0);

    //设置速度
    public void SetVelocity(float _xVelocity, float _yVelocity)
    {
        rb.velocity = new Vector2(_xVelocity, _yVelocity);
        FlipController(_xVelocity);
    }
    #endregion

    #region 翻转
    //翻转实现
    public virtual void Flip()
    {
        facingDir = -1 * facingDir;
        facingRight = !facingRight;
        transform.Rotate(0, 180, 0);
    }
    //翻转控制
    public virtual void FlipController(float _x)
    {
        if (_x > 0 && !facingRight)
            Flip();
        else if (_x < 0 && facingRight)
            Flip();
    }
    #endregion

    #region 碰撞
    //碰撞检测
    public virtual bool isGroundDetected() => Physics2D.Raycast(groundCheck.position, Vector2.down, groundCheckDistance, whatIsGround);
    public virtual bool isWallDetected() => Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, wallCheckDistance, whatIsGround);


    //绘制碰撞检测
    protected virtual void OnDrawGizmos()
    {
        Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));
        Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x + wallCheckDistance, wallCheck.position.y));
        Gizmos.DrawWireSphere(attackCheck.position, attackCheckRadius);
    }
    #endregion
}


PlayerAnimationTriggers.cs

添加攻击触发器

//PlayerAnimationTriggers:触发器组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnimationTriggers : MonoBehaviour
{
    private Player player => GetComponentInParent<Player>();
    private void AnimationTrigger()
    {
        player.AnimationTrigger();
    }

    private void AttackTrigger()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(player.attackCheck.position, player.attackCheckRadius);

        foreach(var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null)
                hit.GetComponent<Enemy>().Damage();
        }
    }
}

Enemy_SkeletonAnimationTriggers.cs

//Enemy_SkeletonAnimationTriggers:触发器组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy_SkeletonAnimationTriggers : MonoBehaviour
{

    private Enemy_Skeleton enemy => GetComponentInParent<Enemy_Skeleton>();
    private void AnimationTrigger()
    {
        enemy.AnimationTrigger();
    }
    private void AttackTrigger()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(enemy.attackCheck.position, enemy.attackCheckRadius);

        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Player>() != null)
                hit.GetComponent<Player>().Damage();
        }
    }
}

原文地址:https://blog.csdn.net/cyr___/article/details/143315614

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!