{"id":16686968,"url":"https://github.com/paralin/gogame","last_synced_at":"2026-02-09T16:31:41.170Z","repository":{"id":76707770,"uuid":"68608612","full_name":"paralin/gogame","owner":"paralin","description":"Cross-platform games with Go as a transpiled common language.","archived":false,"fork":false,"pushed_at":"2016-11-25T03:53:43.000Z","size":56,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-10T04:50:31.125Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paralin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2016-09-19T13:29:21.000Z","updated_at":"2023-07-18T04:47:23.000Z","dependencies_parsed_at":"2023-03-16T15:30:56.038Z","dependency_job_id":null,"html_url":"https://github.com/paralin/gogame","commit_stats":null,"previous_names":["fuserobotics/gogame"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paralin%2Fgogame","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paralin%2Fgogame/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paralin%2Fgogame/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paralin%2Fgogame/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paralin","download_url":"https://codeload.github.com/paralin/gogame/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paralin%2Fgogame/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259038334,"owners_count":22796602,"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":[],"created_at":"2024-10-12T15:07:23.460Z","updated_at":"2026-02-09T16:31:40.378Z","avatar_url":"https://github.com/paralin.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"GoGame\n======\n\nUsing Golang as a cross-platform common ground for writing games.\n\nThis is intended to be run natively on the server, and transpiled to JavaScript for the browser.\n\nThe primary advantages to this:\n\n - Symmetric server \u003c-\u003e client codebase\n - Golang is fast on both sides\n - Rendering on the client is up to the JavaScript codebase.\n - Renderer agnostic\n - Fast networking + type safety\n\nThis is a base library that your game code should import.\n\nImplementation\n==============\n\nThis implements an Entity-Component model. Each \"entity\" in it's most basic form has nothing attached to it, and is merely an identity. You can then attach \"Components\" to the entity which give it functionality.\n\nSome built in components are:\n\n - Transform (includes Orientation, Scale, Position)\n   - Transform can be relative to parent or global.\n - Basic Physics (Velocity, Acceleration)\n\nSome examples you could make:\n\n - Sprite (rendering information for renderer)\n - Input (controls)\n\nEvery entity has an ID (unsigned integer). This ID increments until int max at which point it wraps back around to 0 again. This means you can have a maximum of int_max entities before things will begin to be overwritten.\n\nAll of the types in GoGame are in Protobuf for fast serialization and transport.\n\nEvery component has an ID (unsigned integer). The first few IDs are reserved for the built in components (transform, for example).\n\nCreating Game Entities\n======================\n\nAn entity is anything in your game. This could be:\n\n - a type of weapon\n   - This would be composed of:\n     - transform component, in parent-relative mode\n     - \"weapon\" component, presumably with some kind of weapon system\n     - parent (player entity)\n - a player\n\nAs an entity needs to be set up by someone, there is a mechanism in\nplace to build entities. This is called the EntityFactory interface.\n\nAn EntityFactory would be the generic prototype that knows how to\nconstruct an instance of your entity. You would have one for each type\nof entity. This could be, for example:\n\n - one for each type of weapon in your game\n - one for the generic \"player\"\n - one for each NPC in your game, or interactable object\n\nAn entity factory knows how to create an entity, by creating a New()\nentity, and then building a tree of children entities using other\nEntityPrototypes, or adding Components to the entity it has just\ncreated.\n\nGame Rules\n=========\n\nIn gogame, a \"Game\" is an instance of the entire game logic tree. You\nneed a object to \"tick\" and decide what to do each frame.\n\nThere are also other events you need to handle, examples include:\n\n - Player connected\n - Player disconnected\n\nYou implement this logic in your own Game Rules type. This is passed to\nGoGame when you construct the Game on the client or server.\n\nA game doesn't have to be networked, you could make a single player game in the browser or just a sim in the server. Thus, the Game Rules and overall game has a concept of \"operating mode\".\n\nHere are the operating modes:\n\n - Local - game is operating in local mode only\n - Remote - game is connected to a server and following sync\n\nNetworking\n==========\n\nIn your game you will have a number of entities in the world at any given time. These entities need to be synced over the network correctly, as well as all of their individual components.\n\nAs the user (you!) will be creating custom components, we can't just write all of the network sync code in this package.\n\nWe can however implement it for the basic built in components.\n\nThere are a few types of things we might want to send:\n\n - Property updates (position, orientation, health)\n - Events (on hit, on shoot, etc).\n\nIf your motion is predictable, there's no sense in streaming constant position updates.\n\nProjectile motion is easily predictable:\n\n - Spawn with a mass, velocity, and time\n - Calculate forward from spawn time to now, continue from now -\u003e onwards.\n - No other updates needed until impact.\n\nSo, it would make sense to somehow calculate when motion is easily predictable and does not need streaming. In this way you can avoid the nastiness of position sync and interpolation.\n\nFor player movement, we might send:\n\n - Started moving left @ time T starting at position (X, Y)\n - Stopped moving left @ time T ending at position (X, Y)\n\nMovement includes acceleration and physics against the terrain. The client has the code required to figure out what happened, so we just simulate it client side, using the start and end positions to account for differences in simulation between the client and server.\n\nImplementation of Networking\n============================\n\nIt is the component's job to implement what is described above. Thus, the networking is purely an RPC mechanism.\n\nThe server-side Component can Emit a message to everyone who can see the Entity or to a specific subset of clients.\n\nNetworking Interface\n====================\n\nGoGame provides a general network interface layer. It is up to the game developer to implement the actual transport, and provide an implementation of this network interface layer to GoGame.\n\nA network interface must implement:\n\n - send\n - receive\n - connection state\n\nIn terms of server sharding, this is transparent to GoGame. GoGame expects to talk to a server and get back entities + entity sync.\n\nSharding can be implemented by a man in the middle proxy. Each shard server can be configured with a shard ID `uchar`, and then the most significant byte of all entity ids on that shard can be set to that id. This gives an even distribution of entity ids between servers.\n\nThe question is how entities transfer between shards. You will want to seamlessly transfer the objects between the shards without changing the entity IDs. This can be accomplished two ways:\n\n - Use the most significant byte rule for spawning only\n - Implement an entity ID rename system.\n\nSecond one will be more likely. Renaming / changing an entity ID should not be too hard.\n\nConnecting shards together / implementing sharding is outside the scope of this repository.\n\nInterest based Networking\n=========================\n\nThe client only need know about what he can see. The logic of what the client can see is up to the game to decide. The game's entity should call `AddClientVis` or `RemoveClientVis` when it comes into a client's visibility or leaves it.\n\nFurthermore, we will want to shard the world into individual pieces.\n\n\nRenderer / Frontend\n===================\n\nThe `gogame` system has no concept of actually displaying the game to the user, or taking input from the user. This must be implemented by something external. In Terram's case, this is done by TypeScript.\n\nGoGame has a generic \"Frontend\" interface. When creating a game, a struct implementing the Frontend interface can be provided. This interface will be called to sync the internal game state with the frontend. Types of functions the frontend will have to implement might include:\n\n - Entity added, can return a FrontendEntity object which takes callbacks for entity events.\n   - When an entity is added, the frontend entity object receives:\n     - Init()\n     - AddComponent() for each component, can return a FrontendComponent\n     - InitLate()\n     - And later: Destroy()\n   - Frontend component receives similarly:\n     - Init()\n     - Destroy()\n   - Frontend components can receive function calls from the Go component code.\n     - Examples: set position, etc.\n\nMain Update Tick\n================\n\nThe physics engine and game logic in general needs to tick at a constant rate. Furthermore, we don't want to waste time iterating over every single component, if some of them don't need an Update() tick call.\n\nGoGame uses a `time.Ticker` from Go to tick a main Update function. This update function calls in order:\n\n - GameRules.Update\n - Update on each entity with at least one update handler\n  - This calls Update() on each component with an update handler.\n\nThis way, we only call Update() if it's going to do something with it. Also, in the frontend, we check if the Update() function exists in the beginning, and don't do the nil check again after. This is to save time.\n\nEntity Lifecycle\n================\n\nAn entity is created by an EntityFactory.\n\n - Entity is created in the factory with `\u0026MyEntity{}`\n - Each component is added with `AddComponent(Component)`\n - Entity is returned from the factory.\n - Caller of factory calls `ent.InitComponents()`\n   - `component.Init()` is called for each component\n - `g.AddEntity` is called\n   - `g.Frontend.AddEntity`, sets frontend entity if any is returned.\n   - `ent.InitFrontendEntity()` is called.\n   - `ent.LateInitComponents` is called.\n   - The value of `ent.HasUpdateTick` is checked.\n\nWhen spawning one over network (remote entity):\n\n - `EntityFromNetInit()`: creates with `\u0026Entity{}`\n  - calls `comp.InitWithData` on each component\n - `g.AddEntity` is called\n   - `g.Frontend.AddEntity`, sets frontend entity if any is returned.\n   - `ent.InitFrontendEntity()` is called.\n   - `ent.LateInitComponents` is called.\n   - The value of `ent.HasUpdateTick` is checked.\n\nEntity / Component API\n======================\n\nComponents need to reference other components. In `initLate()`, they can grab a reference to another component like so:\n\n```go\nif component, ok := entity.GetComponent(componentId).(ComponentType); ok {\n}\n```\nUnit Conversions\n================\n\nThe game itself should internally use a common unit. Positions are doubles in the transform component, so the units could be something like 1 unit = 1 meter.\n\nThe frontend should convert the units to screen pixels.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparalin%2Fgogame","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparalin%2Fgogame","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparalin%2Fgogame/lists"}