Skip to content

Making Your First Game

jaymcgavren edited this page Sep 14, 2010 · 1 revision

Make sure you got things running with Getting Started first!

First GameState

Everything starts in the GameState classes your inherit from. Jemini created for you a Hello World game state to ensure your app would be in a runnable state the moment you created the project. However, a ’’’real’’’ game won’t name things Hello World, so let’s rename the class.

mv src/states/hello_world_state.rb src/states/play_state.rb

For Windows users:

move src\states\hello_world_state.rb src\states\play_state.rb

That’s not quite enough. We also have to rename the class itself inside the file:

class HelloWorldState < Jemini::GameState
#becomes
class PlayState < Jemini::GameState

That hello world state was the entry point to our game. Now that it’s gone, we need to change the reference in main.rb to reflect this:

game = Jemini::Game.new :title => 'Jemini Game',
                          :screen_size => Vector.new(800, 600),
                          :initial_state => :HelloWorldState,
                          :fullscreen => false
#becomes
game = Jemini::Game.new :title => 'Jemini Game',
                          :screen_size => Vector.new(800, 600),
                          :initial_state => :PlayState,
                          :fullscreen => false

If you ever want your initial state to be different, you’ll have to change main.rb.

First GameObject

Now we can start writing a real game. Let’s create our first game object. We’ll need to make a new file for this in the game_objects directory. Let’s create src/game_objects/hero.rb:

class Hero < Jemini::GameObject
  has_behavior :DrawableImage
  def load
    self.image = :hero
  end
end

Hero has the DrawableImage behavior, which means we’ll be able to see it represented as an image on the screen. By adding DrawableImage, we also get Spatial, which adds orientation to the game object. This means we can place the image anywhere we want.

Since Hero is a DrawableImage, and we set its image to :hero, we’ll need to give it an image to use. The png format supports lots of color, transparency, and compression, but you can use gif or jpg as well. Once you have an image, drop it into the data directory. This makes the hero.png image available no matter what state we are on.

Now that we have the game object configured, let’s use it! In our PlayState’s load method, we can place the game object.

def load
  hero = create :Hero
  hero.position = screen_size.half
end

If you run the game, you’ll see your hero in the center of the screen.

Input

Our game is pretty boring now. All we see is an image. Interaction is what sets a game apart from other forms of entertainment. We can add input mapping to our hero.

First, let’s configure our hero to handle events. We’ll name these events whatever sounds natural to us, such as walk, run, move, jump, etc. Nevermind which keys and buttons to use for the moment.

class Hero < Jemini::GameObject
  MOVEMENT_RATE = 0.5
  has_behavior :DrawableImage
  has_behavior :HandlesEvents

  def load
    self.image = :hero
    handle_event :move_left do |message|
       position.x -= MOVEMENT_RATE * message.delta
    end
    handle_event :move_right do |message|
       position.x += MOVEMENT_RATE * message.delta
    end
  end
end

MOVEMENT_RATE and other constants we introduce allow us to fine tune the game. We can change MOVEMENT_RATE to 1.0 to double the speed of the character! It’s a good idea to multiply the amount by the delta. Some computers run faster than others, and multiplying by a delta will scale the game’s speed to the computer. This way faster computers don’t actually have faster heroes!

Adding those events isn’t quite enough. We need to add in inputs! Let’s create src/inputs/play_input.rb:

Jemini::InputBuilder.declare do |i|
  i.in_order_to :move_left do
    i.hold :left
  end

  i.in_order_to :move_right do
    i.hold :right
  end
end

Now if you run your game, you should be able to move left and right with the arrow keys on your keyboard!

Clone this wiki locally