Skip to content

Tutorial

John Tuttle edited this page Jan 2, 2021 · 3 revisions

This tutorial walks you through creating a simple Gosu game window with a single Entity that has a sprite that is drawn to the screen and can be moved with the keyboard.

Installing Gosu and Baku

If you haven't already, you can install Gosu and Baku with bundler by adding them both to your Gemfile and running bundle or by simply running:

$ gem install gosu
$ gem install baku

Create the Game Window

Create an empty Gosu game window in a file called quick_start.rb by extending Gosu::Window and overriding the #initialize, #update, and #draw methods:

require 'gosu'
require 'baku'

class QuickStart < Gosu::Window
  def initialize
    super(640, 480)
    self.caption = "Quick Start"
    
  end
  
  def update

  end
  
  def draw

  end
end

QuickStart.new.show

Before continuing, open your terminal and make sure your empty game window runs by navigating to the folder with quick_start.rb and running:

$ ruby quick_start.rb

You should see a black 640 x 480 window pop up with the title "Quick Start". If not, make sure you included the require statements at the top of quick_start.rb and don't forget to call QuickStart.new.show at the bottom.

Creating the World

In your game window's #initialize method, create a Baku::World instance.

def initialize
  ...

  @world = Baku::World.new
end

Now call @world.update in your #update method and @world.draw in your draw method:

def update
  @world.update(0)
end

def draw
  @world.draw
end

Note that normally you would pass the milliseconds that have elapsed since the last frame into World#update but we don't need to worry about that for now so just pass it 0. These changes will cause our World to run the Systems we're going to create on every iteration of the #update and #draw methods in our game loop.

Creating an Entity

Now that we have a World object, we can use it to create our first Entity by calling World#create_entity:

def initialize
  ...

  @world = Baku::World.new
  entity = @world.create_entity
end

This is a completely empty Entity object. Right now it has no Components and we have not yet created any Systems to process it. Let's create our Components first.

Creating Components

Components store the data that defines the behavior of an Entity and can be created by extending Baku::Component. First, create transform_component.rb to store the position of your Entity in 2D space:

class TransformComponent < Baku::Component
  attr_accessor :x, :y

  def initialize(x, y)
    super()

    @x = x
    @y = y
  end
end

Next, create sprite_component.rb to store a sprite texture for your Entity so that it can be drawn to the screen:

class SpriteComponent < Baku::Component
  attr_accessor :texture

  def initialize(texture)
    super()

    @texture = texture
  end
end

Let's go back and add these components to our Entity. Make sure you first require them at the top of quick_start.rb:

require_relative 'transform_component.rb'
require_relative 'sprite_component.rb'

Use Entity#add_component to add the TransformComponent and give our Entity x and y coordinates of (100, 100):

def initialize
  ...
  entity = @world.create_entity
  entity.add_component(TransformComponent.new(100, 100))
end

We'll need an image to use as our Entity's sprite. Do a quick Google search or find something on OpenGameArt if you don't have anything handy. Once you've found an image, put it in the same folder as quick_start.rb, then load it with Gosu and use it to create the SpriteComponent for our Entity. Make sure you update the image filename in the code below to point to your image:

def initialize
  ...
  entity = @world.create_entity
  entity.add_component(TransformComponent.new(100, 100))

  texture = Gosu::Image.new("my_sprite.png")
  entity.add_component(SpriteComponent.new(texture))
end

Now we have an Entity with two components. Instead of being an empty shell, it now represents an object in our game that has a position in 2D space and can be drawn to the screen. Neat!

Next, let's make some Systems that will move our sprite around and draw it to the screen.

Create Systems

Systems contain the logic of our game. Usually you will be creating systems that process entities by extending Baku::ComponentSystem. On each iteration of the game loop, a ComponentSystem will process any Entities that contain the Components specified in the ComponentSystem constructor.

Let's first create input_system.rb to move our Entity in response to keyboard input:

class InputSystem < Baku::ComponentSystem
  def initialize
    super([TransformComponent], :update)
  end

  def process_entity(entity, transform)
    speed = 5

    if Gosu.button_down?(Gosu::KB_UP)
      transform.y -= speed
    elsif Gosu.button_down?(Gosu::KB_DOWN)
      transform.y += speed
    elsif Gosu.button_down?(Gosu::KB_LEFT)
      transform.x -= speed
    elsif Gosu.button_down?(Gosu::KB_RIGHT)
      transform.x += speed
    end
  end
end

Note that we must call super in the constructor and pass it a list of the components that an Entity must possess in order to be processed by this system and also a symbol that specifies to run this system during the update step of the game loop.

We must also override the System#process_entity method with entity as the first parameter and then one parameter for each Component specified in the constructor.

Now let's create a second system that will be responsible for drawing our Entity's sprite to the screen. It will require an Entity to have both a SpriteComponent and a TransformComponent and should be run during the draw step:

class SpriteRenderSystem < Baku::ComponentSystem
  def initialize
    super([SpriteComponent, TransformComponent], :draw)
  end
  
  def process_entity(entity, sprite, transform)
    sprite.texture.draw(transform.x, transform.y, 0)
  end
end

Now let's add these Systems to our World. Back in quick_start.rb, require both of the Systems at the top:

require_relative 'input_system.rb'
require_relative 'sprite_render_system.rb'

Then add both Systems to the World just after creating it:

def initialize
  ...
  @world = Baku::World.new
  @world.add_system(InputSystem.new)
  @world.add_system(SpriteRenderSystem.new)
  ...
end

These Systems will now be run during the update and draw steps of our game.

Start the game again by switching to your terminal and running:

$ ruby quick_start.rb

You should now see your sprite being drawn to the screen and you should be able to move it around with the arrow keys on your keyboard.

Next Steps

That concludes our quick start tutorial. If you would like to see a more complete example, check out this example implementation of Asteroids. Or you can read more about Entity Component System frameworks in the Intro to ECS section.

Otherwise, happy Baku-ing!