{"id":17273551,"url":"https://github.com/markmandel/brute","last_synced_at":"2025-04-09T19:18:54.040Z","repository":{"id":15718879,"uuid":"18456965","full_name":"markmandel/brute","owner":"markmandel","description":"A simple and lightweight Entity Component System library for writing games with Clojure and ClojureScript.","archived":false,"fork":false,"pushed_at":"2016-01-24T00:36:01.000Z","size":162,"stargazers_count":180,"open_issues_count":1,"forks_count":6,"subscribers_count":9,"default_branch":"develop","last_synced_at":"2025-04-09T19:18:49.348Z","etag":null,"topics":["clojure","clojurescript","entity","entity-component","game"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markmandel.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}},"created_at":"2014-04-05T00:57:53.000Z","updated_at":"2024-12-12T08:25:46.000Z","dependencies_parsed_at":"2022-09-06T02:10:50.324Z","dependency_job_id":null,"html_url":"https://github.com/markmandel/brute","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markmandel%2Fbrute","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markmandel%2Fbrute/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markmandel%2Fbrute/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markmandel%2Fbrute/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markmandel","download_url":"https://codeload.github.com/markmandel/brute/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248094990,"owners_count":21046770,"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","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":["clojure","clojurescript","entity","entity-component","game"],"created_at":"2024-10-15T08:51:35.316Z","updated_at":"2025-04-09T19:18:54.019Z","avatar_url":"https://github.com/markmandel.png","language":"Clojure","readme":"# Brute\n\nA simple and lightweight Entity Component System library for writing games with Clojure or ClojureScript.\n\n![Clojars Version](https://clojars.org/brute/latest-version.svg?v=3)\n\n[![wercker status](https://app.wercker.com/status/5f5d692036ee110c41a50ccc7b6f4ae5/m \"wercker status\")](https://app.wercker.com/project/bykey/5f5d692036ee110c41a50ccc7b6f4ae5)\n\nThe aim of this project was to use basic Clojure building blocks to form an Entity System architecture, and get out of the\nauthor's way when deciding exactly what approach would best fit their game when integrating with this library.\n\nTo that end:\n\n- Entities are UUIDs.\n- The Component type system can be easily extended through a multimethod `get-component-type`, but defaults to using the component's instance class as its type.\n- Components can therefore be defrecords or deftypes by default, but could easily be maps or just about anything else.\n- Systems are simply references to functions of the format `(fn [delta])`.\n\nTo learn more about Entity Component Systems, please read the [Entity Systems Wiki](http://entity-systems.wikidot.com/).\nI personally, also found [Adam Martin's Blog Post series](http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/)\nvery useful at giving a step by step explanation of Entity System architecture.\n\n## News\n\nBlog posts and news can be found on the [Compound Theory Blog](http://www.compoundtheory.com/category/brute)\n\n## Usage\n\nSee the [Library API](https://markmandel.github.io/brute/codox/) for all the functionality of this library.\n\n### Quick Start\n\nA quick example based overview of what functionality Brute provides.\n\nI've used fully qualified namespace, *brute.entity* and *brute.system* to be explicit about what is part of Brute in the demo code below, and what denotes custom code.\n\n#### Creating the Basic Entity Component System\n\nBrute doesn't store any data in a ref/atom, but instead provides you with the functions and capabilities for manipulating an immutable data structure that represents this ES system.  This is particularly useful because:\n\n- How the entity data structure is persisted is up to you and the library you are using (although 9/10 times I expect it will end up stored in a single atom, and reset! on each game loop), which gives you complete control over when state mutation occurs – if it occurs at all. This makes concurrent processes much simpler to develop.\n- You get direct access to the ES data structure, in case you want to do something with it that isn’t exposed in the current API.\n- You can easily have multiple ES systems within a single game, e.g. for sub-games.\n- Saving a game becomes simple: Just serialise the ES data structure and store. Deserialise to load.\n- Basically all the good stuff having immutable data structures and pure functions should give you.\n\nTo create the initial system data structure:\n\n```clojure\n(brute.entity/create-system)\n```\n\nThis is actually a map, that lets you access Entities and their Components from a variety of ways, so you can always do it in a performant way.\n\n```clojure\n    {;; Nested Map of Component Types -\u003e Entity -\u003e Component Instance\n        :entity-components      {}\n     ;; Map of Entities -\u003e Set of Component Types\n        :entity-component-types {}}\n```\n\nDo note, that this data structure may be subject to change between releases.\n\n#### Creating a Ball Entity, with corresponding Component instances.\n\n- A `Ball` component instance to know it is a Ball.\n- A `Rectangle` component instance to draw a rectangle in its' place\n- A `Velocity` component instance to know what direction it is travelling in, and how fast.\n\n```clojure\n(defn create-ball\n    \"Creates a ball entity\"\n    [system]\n    (let [ball (brute.entity/create-entity) ;; Returns a UUID for the Entity\n          center-x (-\u003e (graphics! :get-width) (/ 2) (m/round))\n          center-y (-\u003e (graphics! :get-height) (/ 2) (m/round))\n          ball-size 20\n          ball-center-x (- center-x (/ ball-size 2))\n          ball-center-y (- center-y (/ ball-size 2))\n          angle (create-random-angle)]\n        (-\u003e system\n            (brute.entity/add-entity ball) ;; Adds the entity to the ES data structure and returns it\n            (brute.entity/add-component ball (c/-\u003eBall)) ;; Adds the Ball instance to the ES data structure and returns it\n            (brute.entity/add-component ball (c/-\u003eRectangle (rectangle ball-center-x ball-center-y ball-size ball-size) (color :white))) ;; Adds the Rectangle instance to the ES data structure and returns it\n            (brute.entity/add-component ball (c/-\u003eVelocity (vector-2 0 300 :set-angle angle)))))) ;; Adds the Velocity instance to the ES data structure and returns it\n```\n\n#### Render each of the Entities that have a Rectangle Component\n\n```clojure\n(defn- render-rectangles\n    \"Render all the rectangles\"\n    [system]\n    (let [shape-renderer (:shape-renderer (:renderer system))]\n        (.begin shape-renderer ShapeRenderer$ShapeType/Filled)\n        (doseq [entity (brute.entity/get-all-entities-with-component system Rectangle)] ;; loop around all the entities that have a Rectangle Component instance\n            (let [rect (brute.entity/get-component system entity Rectangle) ;; get the Rectangle Component Instance for this entity\n                  geom (:rect rect)] ;; Rectangle component contains a Rectangle geometry shape.\n                (doto shape-renderer ;; Draw the actual rectangle on the screen\n                    (.setColor (:colour rect)) ;; Rectangle component contains the colour\n                    (.rect (rectangle! geom :get-x)\n                           (rectangle! geom :get-y)\n                           (rectangle! geom :get-width)\n                           (rectangle! geom :get-height)))))\n        (.end shape-renderer)))\n```\n\n#### Systems Management\nSystem management is an optional feature for you to use with Brute.\n\nThe following adds each system function to a list contains on the Entity System data structure, maintaining the order in which they were added.\n\n```clojure\n(defn- create-systems\n    \"register all the system functions\"\n    [system]\n    (-\u003e system\n    \t(brute.system/add-system-fn input/process-one-game-tick)\n    \t(brute.system/add-system-fn scoring/process-one-game-tick)\n    \t(brute.system/add-system-fn ai/process-one-game-tick)\n    \t(brute.system/add-system-fn physics/process-one-game-tick)\n    \t(brute.system/add-system-fn rendering/process-one-game-tick)))\n```\n\nFinally call each function in the order added, simply write:\n\n```clojure\n(brute.system/process-one-game-tick system (graphics! :get-delta-time))\n```\n\n\n\n## Game Examples\n\n- [Pong Clone](https://github.com/markmandel/brute-play-pong) written with [play-clj](https://github.com/oakes/play-clj)\n\n## Contributing\n\nPull requests are always welcome!\n\nActive development happens on the `develop` branch. The `master` branch is the source for the current release.\n\n### Reader Conditionals\nThis project uses [Reader Conditionals](http://clojure.org/reader#The%20Reader--Reader%20Conditionals) to support both Clojure and ClojureScript. It should be a seamless experience.\n\n## Testing\n\nTo test under Clojure: `lein test`\n\nTo test under ClojureScript: `lein cljstest`\n\nTo run all tests: `lein alltest`\n\n### Run all tests in the a Docker Container\nYou should be able to run all the tests without having to install anything, except to pull the Docker container.\n\n`make test` will run all the tests in the development Docker container, which should make development easier.\n\n## License\n\nCopyright © 2016 Mark Mandel, Google Inc.\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkmandel%2Fbrute","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkmandel%2Fbrute","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkmandel%2Fbrute/lists"}