{"id":30626899,"url":"https://github.com/mysteriousmilk/godot.composition","last_synced_at":"2025-08-30T19:04:03.827Z","repository":{"id":65393339,"uuid":"589400496","full_name":"MysteriousMilk/Godot.Composition","owner":"MysteriousMilk","description":"This library provides an approach for doing composition in Godot.","archived":false,"fork":false,"pushed_at":"2025-02-22T16:43:03.000Z","size":104,"stargazers_count":25,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-30T19:03:05.357Z","etag":null,"topics":["composition","csharp","gamedev","godot","godotengine"],"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/MysteriousMilk.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-16T02:29:09.000Z","updated_at":"2025-05-28T21:59:26.000Z","dependencies_parsed_at":"2023-10-16T09:10:12.799Z","dependency_job_id":"0f59c36a-dc49-4ff7-a38e-13e5b1db90f4","html_url":"https://github.com/MysteriousMilk/Godot.Composition","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/MysteriousMilk/Godot.Composition","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MysteriousMilk%2FGodot.Composition","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MysteriousMilk%2FGodot.Composition/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MysteriousMilk%2FGodot.Composition/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MysteriousMilk%2FGodot.Composition/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MysteriousMilk","download_url":"https://codeload.github.com/MysteriousMilk/Godot.Composition/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MysteriousMilk%2FGodot.Composition/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272892512,"owners_count":25010795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"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":["composition","csharp","gamedev","godot","godotengine"],"created_at":"2025-08-30T19:03:01.264Z","updated_at":"2025-08-30T19:04:03.820Z","avatar_url":"https://github.com/MysteriousMilk.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Godot.Composition\r\n[![NuGet version (Godot.Composition)](https://img.shields.io/badge/nuget-v1.3.1-blue?style=flat-square)](https://www.nuget.org/packages/Godot.Composition/1.3.1)\r\n\r\nThis library provides a solution for building game entities in Godot through composition over inheritance. Godot's node-based architecture requires some level of inheritance. However, minimizing inheritance and refactoring much of your game's logic into components may go a long way towards cleaner, more reusable code.\r\n\r\nThere are several major approaches to managing entities and data in game development such as inheritance, component-based entity (CBE) model, and entity component systems (ECS). Each of theses models have their pros and cons. While an ECS model is essentially impossible to do in (vanilla) Godot, we can achieve pseudo-CBE/composition approach. So, if you are trying to do composition in Godot, this library will provide some tools and boiler-plate code to help.\r\n\r\n## Entities in Godot.Composition\r\nGodot.Composition requires indicating which objects are entities. In Godot.Composition, entities are simply Godot nodes that can have attached components. Entities are indicated through the use of a class attribute, and must be initialized in the **_Ready** method. The class attribute is paired with a source-code generator which generates a lot of the *boiler-plate* code. Because of this, the class must be marked *partial*, which will  likely be the case anyway since Godot C# uses source-code generators as well.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Entity]\r\npublic partial class Player : CharacterBody2D\r\n{\r\n    public override void _Ready()\r\n    {\r\n        InitializeEntity();\r\n    }\r\n}\r\n```\r\nDepending on implementation and composition level desired, you may end up with several entity classes or just one. For example, you may want all kinematic entities your game to by one entity class where the all the logic is separated into components. Or, you may desired to use a little inheritance and make multiple entity classes, such as, *Player* and *NPC*, etc.\r\n\r\n## Components in Godot.Composition\r\nThe ultimate goal of composition is building reusable components. So, if all your entities need to move around the world, it makes sense to abstract this into a *VelocityComponent*. Likewise, if all your entities have health and can be damaged, that code might be abstracted into a *HealthComponent* and a *HitboxComponent*.\r\n\r\nLets take a look at how to specify a component in Godot.Composition. It works similar to entities. Since this is Godot, the components must be nodes as well (this can help with things like node communication via signal, etc.) Mark components with a class attribute and specify the type of entity that the component can be associated with. The component must be initialized in the **_Ready** method.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Component(typeof(CharacterBody2D))]\r\npublic partial class VelocityComponent : Node\r\n{\r\n    public override void _Ready()\r\n    {\r\n        InitializeComponent();\r\n    }\r\n}\r\n```\r\n\r\nComponents do not have to just be the base Node type. They can be whichever node type makes the most sense for the component. Take a *HitboxComponent* for example. This would be best implemented as an *Area* or *Area2D*.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Component(typeof(CharacterBody2D))]\r\npublic partial class HitboxComponent : Area2D\r\n{\r\n    public override void _Ready()\r\n    {\r\n        InitializeComponent();\r\n    }\r\n}\r\n```\r\n\r\nAll components will have a protected reference to the entity that they belong to. This can be useful for encapsulating the logic with a component. For example, below is a partial implementation of a *VelocityComponent*.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Component(typeof(CharacterBody2D))]\r\npublic partial class VelocityComponent : Node\r\n{\r\n    [Export]\r\n    public float Acceleration { get; set; }\r\n\r\n    public Vector2 Velocity { get; private set; }\r\n\r\n    public void AccelerateToVelocity(Vector2 vel)\r\n    {\r\n        Velocity = vel + Acceleration;\r\n    }\r\n\r\n    public override void _Ready()\r\n    {\r\n        InitializeComponent();\r\n    }\r\n\r\n    public void Move()\r\n    {\r\n        // The parent reference here will be a reference to the CharacterBody2D entity.\r\n        parent.Velocity = Velocity;\r\n        parent.MoveAndSlide();\r\n        Velocity = parent.Velocity;\r\n    }\r\n}\r\n```\r\nAll component nodes for an entity should be placed as a direct child of the entity node with the scene in Godot. An example of a Godot scene tree with components can be scene below.\r\n\r\n![component-tree](https://github.com/MysteriousMilk/Godot.Composition/assets/6441268/1c0f10e0-9fe3-4439-b385-412ed979a45f)\r\n\r\n## Accessing Components from an Entity\r\nEven with most logic abstracted into components, there will likely be some glue code required to bring everything together. If access to a specific component is needed in the Entity script, components can be retrieved as seen below.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Entity]\r\npublic partial class Player : CharacterBody2D\r\n{\r\n    ...\r\n\r\n    public override void _PhysicsProcess(double delta)\r\n    {\r\n        var velocityComponent = GetComponent\u003cVelocityComponent\u003e();\r\n        velocityComponent.AccelerateToVelocity(direction * maxSpeed);\r\n        velocityComponent.Move();\r\n    }\r\n}\r\n```\r\n\r\nComponents can also be retrieved using their interface type.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Component(typeof(CharacterBody2D))]\r\npublic partial class NetworkClientComponent : Node, INetworkComponent\r\n{\r\n    public long NetworkId { get; set; }\r\n\r\n    public override void _Ready()\r\n    {\r\n        InitializeComponent();\r\n    }\r\n}\r\n\r\n[Entity]\r\npublic partial class Player : CharacterBody2D\r\n{\r\n    public override void _Ready()\r\n    {\r\n        InitializeEntity();\r\n\r\n        var networkComponent = GetComponent\u003cINetworkComponent\u003e();\r\n        networkComponent.NetworkId = Multiplayer.GetUniqueId();\r\n    }\r\n}\r\n```\r\n\r\n## Adding Component Dependencies\r\nAdding references to other components is easy with the *ComponentDependency* attribute. Adding a *ComponentDependency* attribute to a component will automatically insert a protected reference to the dependent component. See the example below.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Component(typeof(CharacterBody2D))]\r\n[ComponentDependency(typeof(HealthComponent))]\r\npublic partial class HitboxComponent : Area2D\r\n{\r\n    ...\r\n\r\n    public void OnAreaEntered(Area2D area)\r\n    {\r\n        // Area entered, calculated damage\r\n        double damage;\r\n\r\n        healthComponent.ApplyDamage(damage);\r\n    }\r\n}\r\n```\r\n\r\n## Entity Ready Callback\r\nSometimes, its necessary to run code on a component immediately after an Entity node is ready. Godot.Composition allows the developer to setup a special function that will be called immediately after the parent Entity's *_Ready* function is called.\r\n\r\nSimply define a function called *void OnEntityReady()* on your component and it will be called automatically.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Component(typeof(CharacterBody2D))]\r\npublic partial class HealthComponent : Node\r\n{\r\n    ...\r\n\r\n    /// Called directly after the parent entity's\r\n    /// _Ready function.\r\n    public void OnEntityReady()\r\n    {\r\n        ...\r\n    }\r\n}\r\n```\r\n\r\n## Setting Component Values Programmatically\r\nOccationally, Entity nodes will be created or spawned using a C#. When instantiating Entities in this manner, the Entity's Components do not become available until the Entity's *_Ready* function is called when added to the Scene Tree. Instead of deferring a frame (or two) to set values on a component, you can queue up values to set during the *_Ready* function. Consider the following scenario. We are spawning fast moving projectile. We desire to associate some data with a *DamageComponent* on the projectile, but we don't want to wait several frames to set the value since the projectile's lifetime will be so short. Here we can use the OnReadySet method. See below.\r\n\r\n```C#\r\nusing Godot;\r\nusing Godot.Composition;\r\n\r\n[Entity]\r\npublic partial class Gun : Node2D\r\n{\r\n    ...\r\n\r\n    public void Fire()\r\n    {\r\n        // instantiate projectile\r\n        var projectileScn = ResourceLoader.Load\u003cPackedScene\u003e(\"res://Projectile.tscn\");\r\n        var projectile = projectileScn.Instantiate\u003cProjectile\u003e();\r\n\r\n        projectile.OnReadySet\u003cDamageComponent\u003e(DamageComponent.PropertyName.Damage, 20.0);\r\n    }\r\n}\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmysteriousmilk%2Fgodot.composition","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmysteriousmilk%2Fgodot.composition","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmysteriousmilk%2Fgodot.composition/lists"}