Class: Ray::Game

Inherits:
Object
  • Object
show all
Includes:
Helper
Defined in:
lib/ray/game.rb

Overview

Games are used to manage different scenes. They also init Ray and create a window.

Creating a Game

There are several ways of doing this. Using a block:

Ray::Game.new("my game") do
  ...
end

Using the instance directly:

game = Ray::Game.new("my game")
...
game.run

Subclassing:

class Game < Ray::Game
  def initialize
    super("my game")
    ...
  end
end

Game.new.run

Registring scenes to a Game

Games need the scenes they use to be registred. The most obvious way to do it is to use scene with a block:

scene :game do
  # See Ray::Scene
end

You may also call it to register a subclass of Ray::Scene

scene(:game, GameScene)

Which is the same as:

GameScene.bind(self) # Assuming GameScene's scene_name is set to :game

Managing the scene stack

You can push a scene to the game:

push_scene :game

When #run will be called, it will show the scene :game. Notice that, if you push more than one scene, only the last one will be seen directly. However, if you remove it later, the previous scene will be shown.

You can thus also remove a scene from your stack:

pop_scene # Removes the last scene

exit is not exactly the same: it will ask the scene to quit before doing this. exit! will do something totally different: completely kill the game.

Handling events

Games can listen to events just like scenes. Since the event runner will change often, it needs to register every time it changes it. You can pass a block to the register method:

register do
  on :some_event do some_stuff end
end

You may also want to override register in suclasses:

def register
  on :some_event do some_stuff end
end

Instance Method Summary collapse

Methods included from Helper

#channel, #create_event_runner, #event_runner, #event_runner=, #font, #image, #music, #sound, #sprite

Methods included from Matchers

#where

Methods included from DSL::EventListener

#add_hook, #listener_runner, #listener_runner=, #on

Methods included from DSL::EventRaiser

#raise_event, #raiser_runner, #raiser_runner=

Constructor Details

#initialize(title, hash = {}, &block) ⇒ Game

Creates a new game.

You can pass all the arguments you would pass to create_window, except width and height which should be given in :video_mode:

Ray::Game.new('hello', :video_modes => %w(480x272 640x480))

It will try to get the biggest resolution available (so it will most likely choose 640x480 in this case).

If a block is passed, it is instance evaluated, then the game is directly run.

This methods creates a new window and inits Ray.

Raises:

  • (ArgumentError)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/ray/game.rb', line 81

def initialize(title, hash = {}, &block)
  @game_registred_scenes = {}
  @game_scenes = []

  defaults = {
    :double_buf  => true,
    :bpp         => 32,
    :hw_surface  => true,
    :sw_surface  => false,
    :video_modes => %w(480x272 640x480)
  }

  options = defaults.merge(hash)

  common_settings = {
    :sw_surface => options[:sw_surface],
    :hw_surface => options[:hw_surface],
    :bpp        => options[:bpp] || options[:bits_per_pixel],
    :async_blit => options[:async_blit],
    :double_buf => options[:double_buf],
    :fullscreen => options[:fullscreen],
    :resizable  => options[:resizable],
    :no_frame   => options[:no_frame]
  }

  modes = options[:video_modes].map { |m| m.split('x').map { |i| i.to_i } }

  # The biggest resolution is privileged
  modes = modes.sort_by { |(w, h)| w * h }.map do |(w, h)|
    common_settings.merge(:w => w, :h => h)
  end

  Ray.init

  last_mode = modes.select { |mode| Ray.can_use_mode? mode }.last
  raise ArgumentError, "No valid mode found" unless last_mode

  if @game_title = title
    Ray.window_title = @game_title
    Ray.text_icon    = @game_title
  end

  if icon = options[:icon]
    Ray.icon = icon.is_a?(Ray::Image) ? icon : icon.to_image
  end

  @game_last_mode = last_mode
  @game_window = Ray.create_window(last_mode)

  if block
    instance_eval(&block)
    run
  end
end

Instance Method Details

#exitObject

Removes the current scene of this game



203
204
205
206
207
208
# File 'lib/ray/game.rb', line 203

def exit
  return if @game_scenes.empty?

  @game_scenes.last.exit
  pop_scene
end

#exit!Object

Kills the game, removing all the scenes it contains.



211
212
213
214
215
216
# File 'lib/ray/game.rb', line 211

def exit!
  return if @game_scenes.empty?

  @game_scenes.last.exit
  @game_scenes.clear
end

#inspectObject



235
236
237
# File 'lib/ray/game.rb', line 235

def inspect
  "game(#{title.inspect})"
end

#pop_sceneObject

Pops the last scene.



154
155
156
# File 'lib/ray/game.rb', line 154

def pop_scene
  @game_scenes.delete_at(-1)
end

#push_scene(scene_name, *args) ⇒ Object

Adds a scene to the stack using its name.

You must call Game#scene before this. If you subclassed scene, then call bind to register it:

scene :something, SomeClass
SomeClass.bind(self)

Parameters:

  • scene_name (Symbol)

    The name of the scene which should be pushed

  • *args

    Arguments passed to the scene

Raises:

  • (ArgumentError)


145
146
147
148
149
150
151
# File 'lib/ray/game.rb', line 145

def push_scene(scene_name, *args)
  scene = @game_registred_scenes[scene_name]
  raise ArgumentError, "Unknown scene #{scene_name}" unless scene

  @game_scenes << scene
  @game_scene_arguments = args
end

#register(&block) ⇒ Object

Registers a block to listen to events Subclasses can also overrid this method to register for events.



194
195
196
197
198
199
200
# File 'lib/ray/game.rb', line 194

def register(&block)
  if block_given?
    @game_register_block = block
  else
    @game_register_block.call if @game_register_block
  end
end

#resize_window(w, h) ⇒ Object

Resizes the window and raises a window_resize event



219
220
221
222
223
224
225
226
227
228
229
# File 'lib/ray/game.rb', line 219

def resize_window(w, h)
  @game_window = Ray.create_window(@game_last_mode.merge!(:w => w,
                                                          :h => h))
  @game_scenes.each do |scene|
    scene.window = @game_window
  end
  
  @game_scenes.last.need_render!
  
  raise_event(:window_resize, Ray::Rect.new(0, 0, w, h))
end

#runObject

Runs the game until the last scene gets popped. Will call Ray.stop.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/ray/game.rb', line 169

def run
  until @game_scenes.empty?
    create_event_runner
    register

    @game_scenes.each do |scene|
      scene.game            = self
      scene.window          = @game_window
      scene.event_runner    = event_runner
      scene.scene_arguments = @game_scene_arguments
    end

    scene = @game_scenes.last

    scene.setup(*@game_scene_arguments)
    scene.register_events
    scene.need_render!
    scene.run
  end

  Ray.stop
end

#scene(name, klass = Scene, &block) ⇒ Object

Registers a new scene with a given name. the block will be passed to klass.new.

Parameters:

  • name (Symobl)

    the name of the new scene

  • klass (Class) (defaults to: Scene)

    the class of the scene.



163
164
165
# File 'lib/ray/game.rb', line 163

def scene(name, klass = Scene, &block)
  @game_registred_scenes[name] = klass.new(&block)
end

#titleObject



231
232
233
# File 'lib/ray/game.rb', line 231

def title
  @game_title
end