Skip to content

Instantly share code, notes, and snippets.

@ReiiSky
Forked from JAForbes/readme.md
Created June 11, 2019 11:01
Show Gist options
  • Select an option

  • Save ReiiSky/d05d20475782774a0b38ba287c0a61b9 to your computer and use it in GitHub Desktop.

Select an option

Save ReiiSky/d05d20475782774a0b38ba287c0a61b9 to your computer and use it in GitHub Desktop.

Revisions

  1. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 18 additions and 0 deletions.
    18 changes: 18 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -118,3 +118,21 @@ unlike class/prototype based approaches.

    Also notice how focused each system is. You could easily imaginee reusing any of these systems across many applications. But you get the banana without the gorilla and the rest of the jungle.

    #### State Graph

    Because all your state is stored in one place, you can easily implement quicksave/quickload functionality.

    ```
    QuickSave(quicksave, entity){
    components.SaveState[entity] = JSON.stringify(components)
    }
    QuickLoad(quickload, entity){
    components = JSON.parse(components.SaveSate[entity])
    }
    ```

    #### Live programming

    You can also interact with your game live in a REPL with ease. By modifiying the state you can test elaborate scenarios.
    It's trivial to clone an entity `n` times, or adjust the strength of a particular force and see the results immediately.
  2. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    #### Entities and Components

    An entity is just a number.

    There is a graph of components, indexed by the entity id.
    @@ -42,6 +44,8 @@ Also notice the `game` entity has no `Position` or `Sprite`. It is just an iden
    components.Timer[6] = { count: 0, interval: 1000, on: { ScreenShake: { x: 1, y: 0 } } }
    ```

    #### Systems

    ```js
    //gameloop systems

  3. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -37,7 +37,7 @@ A `potplant` never moves, so it just has a `Position` and a `Sprite`. Because i

    Also notice the `game` entity has no `Position` or `Sprite`. It is just an identifier with some associated data. In this case it has a Timer component that will make the screen shake every 1000 milliseconds. There are no callbacks, or event listeners, it is just an object literal with some numbers in it.

    ```
    ```js
    //look ma, no callbacks
    components.Timer[6] = { count: 0, interval: 1000, on: { ScreenShake: { x: 1, y: 0 } } }
    ```
  4. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -37,6 +37,10 @@ A `potplant` never moves, so it just has a `Position` and a `Sprite`. Because i

    Also notice the `game` entity has no `Position` or `Sprite`. It is just an identifier with some associated data. In this case it has a Timer component that will make the screen shake every 1000 milliseconds. There are no callbacks, or event listeners, it is just an object literal with some numbers in it.

    ```
    //look ma, no callbacks
    components.Timer[6] = { count: 0, interval: 1000, on: { ScreenShake: { x: 1, y: 0 } } }
    ```

    ```js
    //gameloop systems
  5. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -33,6 +33,11 @@ Systems iterate over a specific component type. If that component type is empty
    This is very different to the traditional iteration over all entities, which is wasteful and grounded in thinking every entity
    is an object instead of just an identifier.

    A `potplant` never moves, so it just has a `Position` and a `Sprite`. Because it has no `Velocity` component the code that handles Movement will never be activated for those entities.

    Also notice the `game` entity has no `Position` or `Sprite`. It is just an identifier with some associated data. In this case it has a Timer component that will make the screen shake every 1000 milliseconds. There are no callbacks, or event listeners, it is just an object literal with some numbers in it.


    ```js
    //gameloop systems

    @@ -103,3 +108,5 @@ See how the Move system pulls in the position data by accessing the component gr
    Because all references are local to a function call, deleting a component from the graph will immediately release it into memory
    unlike class/prototype based approaches.

    Also notice how focused each system is. You could easily imaginee reusing any of these systems across many applications. But you get the banana without the gorilla and the rest of the jungle.

  6. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 28 additions and 1 deletion.
    29 changes: 28 additions & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,9 @@
    An entity is just a number.

    There is a graph of components, indexed by the entity id.

    All state is stored in one place.

    ```js
    var components = { Position: {}, Velocity:{}, Spite: {}, Timer: {}, ScreenShake: {}, RemoveComponents: {} }

    @@ -22,6 +28,11 @@ potplants.forEach(function(potplant, i){
    components.Timer[6] = { count: 0, interval: 1000, on: { ScreenShake: { x: 1, y: 0 } } }
    ```

    Systems iterate over a specific component type. If that component type is empty for that game loop, those systems do not run.

    This is very different to the traditional iteration over all entities, which is wasteful and grounded in thinking every entity
    is an object instead of just an identifier.

    ```js
    //gameloop systems

    @@ -75,4 +86,20 @@ function RemoveComponents(remove, entity){
    delete components.ScreenShake[entity]
    })
    }
    ```
    ```

    Each system accepts a single component and the entity id for that component. The id allows the system to pull in other components
    for that entity.

    ```js
    function Move(velocity, entity){
    var p = component.Position[entity]
    p.x += velocity.x
    p.y += velocity.y
    }
    ```

    See how the Move system pulls in the position data by accessing the component graph directly.
    Because all references are local to a function call, deleting a component from the graph will immediately release it into memory
    unlike class/prototype based approaches.

  7. @JAForbes JAForbes revised this gist Mar 11, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -71,7 +71,7 @@ function ScreenShake(screenshake, entity){
    }

    function RemoveComponents(remove, entity){
    remove.forEach(function(){
    remove.components.forEach(function(){
    delete components.ScreenShake[entity]
    })
    }
  8. @JAForbes JAForbes created this gist Mar 11, 2016.
    78 changes: 78 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,78 @@
    ```js
    var components = { Position: {}, Velocity:{}, Spite: {}, Timer: {}, ScreenShake: {}, RemoveComponents: {} }

    var player = 1
    var enemy = 2
    var potplants = [3,4,5]
    var game = 6

    components.Position[player] = { x:100, y: 100 }
    components.Velocity[player] = { x: 0.5, y: 0 }
    components.Sprite[player] = sprites.player

    components.Position[enemy] = { x: 0, y: 100}
    components.Velocity[enemy] = { x: 1, y: 0}
    components.Sprite[enemy] = sprites.enemy

    potplants.forEach(function(potplant, i){
    components.Position[potplant] = { x: i * 100, y: 200 }
    components.Sprite[potplant] = sprites.potplant
    })

    components.Timer[6] = { count: 0, interval: 1000, on: { ScreenShake: { x: 1, y: 0 } } }
    ```

    ```js
    //gameloop systems

    [
    [Move, components.Velocity]
    [Timer, components.Timer],
    [Screenshake, components.Screenshake],
    [Render, components.Sprite],
    [RemoveComponents, components.RemoveComponents],
    ].forEach(callSystem)

    function callSystem([system, components]){
    _.each(components, system)
    }

    function Move(velocity, entity){
    var p = component.Position[entity]
    p.x += velocity.x
    p.y += velocity.y
    }

    function Render(sprite, entity){
    var p = component.Position[entity]
    context.drawImage(p.x, p.y, ..., sprite.img )
    }

    function Timer(timer, entity){
    if(timer.count > timer.timer){
    if(timer.repeat){
    timer.count = 0
    } else {
    components.RemoveComponents[entity] = { components: ['Timer'] }
    }


    _.each(components.on, function(data, name){
    components[name] = data
    })

    }
    timer.count ++
    }

    function ScreenShake(screenshake, entity){
    //shake the screen
    components.RemoveComponents[entity] = { components: ['ScreenShake']}
    }

    function RemoveComponents(remove, entity){
    remove.forEach(function(){
    delete components.ScreenShake[entity]
    })
    }
    ```