https://github.com/nauja/unity3d-meele2d-raycast-sample
Sample of a meele combat system done with raycasts
https://github.com/nauja/unity3d-meele2d-raycast-sample
2d combat meele raycast raycasting sample unity unity2d unity3d
Last synced: 7 months ago
JSON representation
Sample of a meele combat system done with raycasts
- Host: GitHub
- URL: https://github.com/nauja/unity3d-meele2d-raycast-sample
- Owner: Nauja
- License: mit
- Created: 2021-08-19T07:58:21.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2021-08-19T12:32:54.000Z (about 4 years ago)
- Last Synced: 2025-02-01T22:29:01.994Z (9 months ago)
- Topics: 2d, combat, meele, raycast, raycasting, sample, unity, unity2d, unity3d
- Language: C#
- Homepage:
- Size: 10.4 MB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# unity3d-meele2d-raycast-sample

[](https://raw.githubusercontent.com/Nauja/unity3d-meele2d-raycast-sample/master/LICENSE)Sample of a meele combat system done with raycasts.

This project is an example of how to write a meele combat system by using raycasts such as `Physics2D.OverlapCircle` to detect attack collisions and even allow a single attack to hit multiple times.
## Table of contents:
- [Controls](#controls)
- [Animation Driven Hitbox and Events](#animation-driven-hitbox-and-events)
- [AttackPhase](#attackphase)## Controls
Check `Assets/Controls.inputactions` for the full list of controls available:

* Left/Right arrow or Left analog stick: Move
* Space or Bottom button: Punch, a light attack that hits one time
* E or Left button: Kick, a light attack that hits one time
* Ctrl or Up button: High punch, an heavy attack that hits three times## Animation Driven Hitbox and Events
Check [Assets/Textures/Ryu.png](Assets/Textures/Ryu.png) for the spritesheet containing all of Ryu's animations:

In the scene we have two game objects for the player:
* `Player`: this is our controllable player with a renderer and a `BoxCollider2D` highlighted in green
* `HitBox`: this is the hitbox used to detect attack collisions and it is rendered as a red sphere
Both the position and radius of the hitbox are driven in animation to match Ryu's animation:

You can also see that there are multiple events called during the animation. Those are used to notify
the `PlayerController` script when:
* `OnAttackBegin`: the attack begins and we block the player inputs so he can't move
* `OnAttackPhaseBegin`: we enter a new phase of the attack
* `OnAttackPhaseEnd`: the current phase of the attack ends
* `OnAttackEnd`: the attack ends and we unblock the player inputs so he can move againThis is how all attack animations are configured.
## AttackPhase
All attacks are divided in one or multiple phases:
```csharp
/// Represent a phase of the current attack
/// Allow to keep track of entities already hit
public class AttackPhase
{
/// Entity who attacked
public IEntity source;
/// Id of the attack
public EAttackId attackId;
/// List of entities hit by the attack
public List targets = new List();
}
```Phases are driven by animation events handled in the `PlayerController` script:
```csharp
/// Player controller for handling inputs and physics
public class PlayerController : MonoBehaviour, IEntity
{
...
[SerializeField]
private AttackHitBox _attackHitBox;
/// Current attack phase
private AttackPhase _attackPhase;...
/// Called by animation when a new phase of attack begins
private void OnAttackPhaseBegin()
{
// Create a new phase
_attackPhase = new AttackPhase();
_attackPhase.source = this;// Activate the hitbox
_attackHitBox.attackPhase = _attackPhase;
_attackHitBox.gameObject.SetActive(true);
}/// Called by animation when the current phase of attack ends
private void OnAttackPhaseEnd()
{
CancelAttackPhase();
}
...
}
```This is the hitbox that checks collisions with entities during attack phases:
```csharp
/// Represent an attack hitbox that can hit other entities
/// This is done by using Physics2D.OverlapCircleAll in Update
public class AttackHitBox : MonoBehaviour
{
/// Hitbox radius
/// Driven by animation
[SerializeField]
private float _radius;
/// Layer to hit
[SerializeField]
private LayerMask _layerMask;
/// Current attack phase
/// Prevent hitting the same entity multiple times
[HideInInspector]
public AttackPhase attackPhase;private void Update()
{
// Only hit during attack phases
if (attackPhase == null)
{
return;
}// Search for colliding entities
Collider2D[] hitColliders = Physics2D.OverlapCircleAll(transform.position, _radius, _layerMask);
foreach (var hitCollider in hitColliders)
{
// IEntity allows to get any entity
var entity = hitCollider.gameObject.GetComponent();
if (entity == null || entity == attackPhase.source)
{
continue;
}// Entity already hit by this attack
if (attackPhase.targets.Contains(entity))
{
continue;
}attackPhase.targets.Add(entity);
// Notify entity
var collision = new AttackCollision();
collision.position = transform.position;
entity.OnHitBy(attackPhase, collision);
}
}...
}
```Each phase can only hit the same entity once, but a single attack can have multiple phases as demonstrated with the heavy punch.
## Credits
Sprites are coming from [The Spriters Resource](https://www.spriters-resource.com/).
Font from [dafont](https://www.dafont.com/fr/great-fighter.font).
## License
Licensed under the [MIT](LICENSE) License.