Skip to content

Macaw basic concepts

Marcus Renno edited this page Aug 21, 2018 · 2 revisions

Creating the game window

To create the game window you will need to Initialize() Macaw first.

Adding your entities to the game

Entities are the objects which will contain an ID, etype (entity type which is a string) and components which will hold the true data of this object.

An Entity must implements an interface (Entitier). You should not be worried with the functions if you are using the EntityManager from Macaw.

To create an entity with the EntityManager all you have to do is the following:

entityManager := &entity.Manager{}
player := em.Create("player")

This will create the "player" entity.

Adding Components to your Entity

Components are the structures that contain the "true" data of the entity. An Entity can have multiple components. Components cannot have any logic.

Take a look at the PositionComponent that comes with Macaw:

type PositionComponent struct {
	Pos *sdl.Point
}

All it has is a *sdl.Point variable. To add or remove components from the entity, use the entity manager. Following the previous example we can add the following components to our player:

// Player component
player.AddComponent(&entity.PositionComponent{&sdl.Point{20, 20}})
player.AddComponent(&entity.CollisionComponent{CollisionAreas: []sdl.Rect{sdl.Rect{0, 0, 10, 80}}})

// Let's also add a camera component that is required to the game engine to be run!
camera := em.Create("camera")
camera.AddComponent(&entity.PositionComponent{&sdl.Point{0, 0}})
camera.AddComponent(&entity.CameraComponent{
	ViewportSize: sdl.Point{800, 600},
	WorldSize:    sdl.Point{1145, 600},
})

Adding your systems to the game

Macaw comes with built-in systems. At this moment we have render*, physics and collision systems.

You can (and should) add systems to your game to implement logic to your game. The recommended way is to create a package with your system.

A system must implement the Systemer interface, which means, have a Init() and Update() function.

Here is an example of a system that will keep moving the player entity we have been using in this wiki page

import (
	"github.com/tubelz/macaw/entity"
)

type MovePlayerSystem struct {
	EntityManager *entity.Manager
	Name          string
}

// Init initialize this system
func (mps *MovePlayerSystem) Init() {}

// Update will move the player to the right
func (mps *MovePlayerSystem) Update() {
	var player *entity.Entity
	// IterAvailable will loop only through the entities that are being used in our array
	it := p.EntityManager.IterAvailable()
	for tmpObj, itok := it(); itok; tmpObj, itok = it() {
		if tmpObj.GetType() == "player" {
			player = tmpObj
			break
		}
	}
	// Get the components we are interested in
	component, _ := ball.GetComponent("position")
	posComponent := component.(*entity.PositionComponent)
	posComponent.X++
} 

Creating our scenes

A Scene is responsible to divide our game logic (systems) and components. You are required to have at least one Scene in your game.

You can move between the scenes using the SceneManager that is embedded in the Gameloop.

It is not required to have a name per Scene, but it is highly recommended. Here is also where you define some options that will impact your Game Window like showing/hiding your cursor, background color, and music.

Example of a Scene in our game

// getting the systems we want to add to our Scene...
render := &system.RenderSystem{Name: "render system", Window: macaw.Window, EntityManager: em}
movePlayer := &customsystem.MovePlayerSystem{Name: "move player system", EntityManager: em}

myInitFunc := func() { log.Print("My Awesome Scene!") }
bgColor := sdl.Color{32, 180, 230, 255}
scene := &macaw.Scene{
	Name:         "SomeName",
	InitFunc:     myInitFunc,
	SceneOptions: macaw.SceneOptions{BgColor: bgColor, HideCursor: true},
}
scene.AddRenderSystem(renderSystem)
scene.AddGameUpdateSystem(movePlayerSystem)

Initializing your game loop

We are almost done!

Our Game loop works in the following way:

It takes care of all of the player's input, it runs all of our game's logic (GameUpdateSystem) and then after we accomplish what we need in the timeframe given by our minimum FPS, it will render as much as possible! That's it.

The game loop requires at least one scene!

// Initialize the game loop
gameLoop := &macaw.GameLoop{}
gameLoop.AddScene(scene)
// Execute the game loop
gameLoop.Run()