Korok.io

Basics

This page aims at giving a overview of the korok engine.

Scene、Entity and Component

Scene and Entity/Component are fundamental building blocks of a Korok app.

Scene

A scene is the entry point for interacting with the user. For example, a platform game might have one scene shows the main menu, another scene to host the main game. You can create a scene by implementing the Scene interface.

                        
    type Scene interface {
        OnEnter(g *Game)

        Update(dt float32)
        
        OnExit()
    }                       
                        

Most games contain multiple scenes, all these scenes work together to form a completed game. There are usually minimal dependencies among the scenes in a game. SceneManager is used to manage scenes in a game, they are arranged in a FILO stack.

The principal SceneManager method you can use are

  • Push() // Push a scene into stack, it'll fire OnEnter callback.
  • Pop() // Pop a scene from stack, it'll fire OnExit callback.
  • Peek() // Get the scene instance at the top of scene stack.

Over the course of its lifetime, a scene goes through a number of states. You use a series of callbacks to handle transitions between states.

OnEnter()

A callback which fires when the scene is pushed into stack. You can initialize the components of your scene: For example, you game should create Entities and components. When OnEnter() finishes, it's OnUpdate method will be called each frame.

OnUpdate()

The system invokes this callback each frame. Generally, an idea frame rate is 60fps, which means OnUpdate will be called very 16ms. This is where you gameplay code comes in, For example: handle user input and simulate game logic.

OnExit()

The system invokes this callback when another scene is Pushed in, the current scene is stopped and it's OnUpdate method will not be invoked. It's a good place to release the resoruces used by this scene.

Entity/Component

Entity is the game object in Korok(e.g. enemies, bullets, etc.). It's a unique id used to index a collection of different components that represent it(yeah. it's a ECS system). Every Entity consists of one or more components which add additional behavior or functionality, you can also add or remove components at runtime.

To create a new entity, you can use:

                        
    hero := korok.Enity.New()
                        

But, this will not create a real hero. To make the hero live, add a SpriteComp and a Transform:

                        
    // add a sprite component
    spr := korok.Sprite.New(hero)
    spr.SetSprite(texture)

    // add a transform component
    xf  := korok.Transform.New(hero)
    xf.SetPosition(f32.Vec2{100, 100})
                        

Now, the hero can be rendered at location (100, 100) with a texture. That's a common use case of Entity.

Korok has some built-in component types, sunch as:

  • SpriteComp lets you display images as Sprites for use in scene.
  • Transform determines the Position, Rotation and Scale of the Entity in scene.
  • TextComp lets you display text strings in scene.
  • ParticleComp uses a large number of small sprites to simulate fire, snow.. or any "fuzzy" phenomena.

Each component is simple data buckets, they have no dependencies of each other. They can only be indexed by Entity. On other way, entity is nothing without components, it's just an ID. An entity with required components make a real game object.

Table and System

Table is the container of components. It's the same idea as the table in Database. Table provides simple method to Create/Index/Delete component:

  • New(Enity) // Create a component with specified Entity.
  • Comp(Entity) // Find the component belongs to the Entity.
  • Delete(Entity) // Delete the componnet belongs to the Entity.

The data in table is all efficiently organized in tightly packed contiguous array. Always, use Comp(Entity) method to access component, it returns a pointer to the component. But never hold the pointer, it will change from frame to frame(table can layout their data internally and process it as they want).

System performs actions on components, but system don't own components or entity or table. It only keep a ref to interested tables and operate on components. A table can be refed by any system, For example: both move-system and render-system have a ref to TransformTable.

Both table and system are managed by the Game struct. Game is the toppest existence that govern the game world. You can list all the tables by:

                        
    for _, table := range game.DB.Tables {
        // 
    }
                        

or get systems by:

                        
    // get the render system
    render_system := game.RenderSystem

    // get the input system
    input_system := game.InputSystem
                        

Sprite and Texture

In 2D games, sprite is an image that can be positioned in a larger scene. A texture, on the other hand, is the concept of a readable image in modern graphics APIs. Korok use gfx.Tex2D to describe 2D (1D and 3D textures exist) texture, it consists of an ID, size and uv coordinates.

When multiple smaller images are combined into a single images, the resulting image is called a texture atlas(or sprite sheet). The samller images are refered by name(or by index) as gfx.Tex2D with it's size and uv.

Generally, there is no sprite object in Korok, sprite is just a rename of gfx.Tex2D. SpriteComp is used to draw a sprite(Tex2d), it's optimised(by batch) to handle large amount of small images. Graphics components must have a Transform component that used to position/scale/rotate an Entity。