{"id":15357673,"url":"https://github.com/nauja/unity3d-meele2d-raycast-sample","last_synced_at":"2026-05-01T10:31:41.315Z","repository":{"id":139652956,"uuid":"397863349","full_name":"Nauja/unity3d-meele2d-raycast-sample","owner":"Nauja","description":"Sample of a meele combat system done with raycasts","archived":false,"fork":false,"pushed_at":"2021-08-19T12:32:54.000Z","size":10907,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-27T19:53:27.363Z","etag":null,"topics":["2d","combat","meele","raycast","raycasting","sample","unity","unity2d","unity3d"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nauja.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-19T07:58:21.000Z","updated_at":"2023-06-07T15:19:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"9f2f3e41-dd2b-4752-96e2-5442d1e0310e","html_url":"https://github.com/Nauja/unity3d-meele2d-raycast-sample","commit_stats":{"total_commits":14,"total_committers":1,"mean_commits":14.0,"dds":0.0,"last_synced_commit":"e8dc6f58519f17876b09cba3b98181ca8c0b24a8"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Nauja/unity3d-meele2d-raycast-sample","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nauja%2Funity3d-meele2d-raycast-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nauja%2Funity3d-meele2d-raycast-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nauja%2Funity3d-meele2d-raycast-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nauja%2Funity3d-meele2d-raycast-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nauja","download_url":"https://codeload.github.com/Nauja/unity3d-meele2d-raycast-sample/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nauja%2Funity3d-meele2d-raycast-sample/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32494270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2d","combat","meele","raycast","raycasting","sample","unity","unity2d","unity3d"],"created_at":"2024-10-01T12:37:56.769Z","updated_at":"2026-05-01T10:31:41.252Z","avatar_url":"https://github.com/Nauja.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# unity3d-meele2d-raycast-sample\n\n![Unity](https://img.shields.io/badge/Unity-2021.1.16+-blue)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Nauja/unity3d-meele2d-raycast-sample/master/LICENSE)\n\nSample of a meele combat system done with raycasts.\n\n![Preview](https://github.com/Nauja/unity3d-meele2d-raycast-sample/raw/media/preview.gif)\n\nThis 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.\n\n## Table of contents:\n\n- [Controls](#controls)\n- [Animation Driven Hitbox and Events](#animation-driven-hitbox-and-events)\n- [AttackPhase](#attackphase)\n\n## Controls\n\nCheck `Assets/Controls.inputactions` for the full list of controls available:\n\n![Controls](https://github.com/Nauja/unity3d-meele2d-raycast-sample/raw/media/controls.png)\n\n  * Left/Right arrow or Left analog stick: Move\n  * Space or Bottom button: Punch, a light attack that hits one time\n  * E or Left button: Kick, a light attack that hits one time\n  * Ctrl or Up button: High punch, an heavy attack that hits three times\n\n## Animation Driven Hitbox and Events\n\nCheck [Assets/Textures/Ryu.png](Assets/Textures/Ryu.png) for the spritesheet containing all of Ryu's animations:\n\n![Ryu](https://github.com/Nauja/unity3d-meele2d-raycast-sample/raw/media/ryu-texture.png)\n\nIn the scene we have two game objects for the player:\n  * `Player`: this is our controllable player with a renderer and a `BoxCollider2D` highlighted in green\n  * `HitBox`: this is the hitbox used to detect attack collisions and it is rendered as a red sphere\n\n![HitBox](https://github.com/Nauja/unity3d-meele2d-raycast-sample/raw/media/hitbox.png)\n\nBoth the position and radius of the hitbox are driven in animation to match Ryu's animation:\n\n![Events](https://github.com/Nauja/unity3d-meele2d-raycast-sample/raw/media/animation-events.gif)\n\nYou can also see that there are multiple events called during the animation. Those are used to notify\nthe `PlayerController` script when:\n  * `OnAttackBegin`: the attack begins and we block the player inputs so he can't move\n  * `OnAttackPhaseBegin`: we enter a new phase of the attack\n  * `OnAttackPhaseEnd`: the current phase of the attack ends\n  * `OnAttackEnd`: the attack ends and we unblock the player inputs so he can move again\n\nThis is how all attack animations are configured.\n\n## AttackPhase\n\nAll attacks are divided in one or multiple phases:\n\n```csharp\n/// \u003csummary\u003eRepresent a phase of the current attack\u003c/summary\u003e\n/// \u003cremarks\u003eAllow to keep track of entities already hit\u003c/remarks\u003e\npublic class AttackPhase\n{\n    /// \u003csummary\u003eEntity who attacked\u003c/summary\u003e\n    public IEntity source;\n    /// \u003csummary\u003eId of the attack\u003c/summarry\u003e\n    public EAttackId attackId;\n    /// \u003csummary\u003eList of entities hit by the attack\u003c/summary\u003e\n    public List\u003cIEntity\u003e targets = new List\u003cIEntity\u003e();\n}\n```\n\nPhases are driven by animation events handled in the `PlayerController` script:\n\n```csharp\n/// \u003csummary\u003ePlayer controller for handling inputs and physics\u003c/summary\u003e\npublic class PlayerController : MonoBehaviour, IEntity\n{\n    ...\n \n    [SerializeField]\n    private AttackHitBox _attackHitBox;\n    /// \u003csummary\u003eCurrent attack phase\u003c/summary\u003e\n    private AttackPhase _attackPhase;\n\n    ...\n\n    /// \u003csummary\u003eCalled by animation when a new phase of attack begins\u003c/summary\u003e\n    private void OnAttackPhaseBegin()\n    {\n        // Create a new phase\n        _attackPhase = new AttackPhase();\n        _attackPhase.source = this;\n\n        // Activate the hitbox\n        _attackHitBox.attackPhase = _attackPhase;\n        _attackHitBox.gameObject.SetActive(true);\n    }\n\n    /// \u003csummary\u003eCalled by animation when the current phase of attack ends\u003c/summary\u003e\n    private void OnAttackPhaseEnd()\n    {\n        CancelAttackPhase();\n    }\n    \n    ...\n}\n```\n\nThis is the hitbox that checks collisions with entities during attack phases:\n\n```csharp\n/// \u003csummary\u003eRepresent an attack hitbox that can hit other entities\u003c/summary\u003e\n/// \u003cremarks\u003eThis is done by using Physics2D.OverlapCircleAll in Update\u003c/remarks\u003e\npublic class AttackHitBox : MonoBehaviour\n{\n    /// \u003csummmary\u003eHitbox radius\u003c/summary\u003e\n    /// \u003cremarks\u003eDriven by animation\u003c/remarks\u003e\n    [SerializeField]\n    private float _radius;\n    /// \u003csummmary\u003eLayer to hit\u003c/summary\u003e\n    [SerializeField]\n    private LayerMask _layerMask;\n    /// \u003csummary\u003eCurrent attack phase\u003c/summary\u003e\n    /// \u003cremarks\u003ePrevent hitting the same entity multiple times\u003c/remarks\u003e\n    [HideInInspector]\n    public AttackPhase attackPhase;\n\n    private void Update()\n    {\n        // Only hit during attack phases\n        if (attackPhase == null)\n        {\n            return;\n        }\n\n        // Search for colliding entities\n        Collider2D[] hitColliders = Physics2D.OverlapCircleAll(transform.position, _radius, _layerMask);\n        foreach (var hitCollider in hitColliders)\n        {\n            // IEntity allows to get any entity\n            var entity = hitCollider.gameObject.GetComponent\u003cIEntity\u003e();\n            if (entity == null || entity == attackPhase.source)\n            {\n                continue;\n            }\n\n            // Entity already hit by this attack\n            if (attackPhase.targets.Contains(entity))\n            {\n                continue;\n            }\n\n            attackPhase.targets.Add(entity);\n\n            // Notify entity\n            var collision = new AttackCollision();\n            collision.position = transform.position;\n            entity.OnHitBy(attackPhase, collision);\n        }\n    }\n\n    ...\n}\n```\n\nEach phase can only hit the same entity once, but a single attack can have multiple phases as demonstrated with the heavy punch.\n\n## Credits\n\nSprites are coming from [The Spriters Resource](https://www.spriters-resource.com/).\n\nFont from [dafont](https://www.dafont.com/fr/great-fighter.font).\n\n## License\n\nLicensed under the [MIT](LICENSE) License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnauja%2Funity3d-meele2d-raycast-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnauja%2Funity3d-meele2d-raycast-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnauja%2Funity3d-meele2d-raycast-sample/lists"}