ray 0.0.0.pre2 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +3 -0
  3. data/README.md +62 -0
  4. data/Rakefile +33 -23
  5. data/VERSION +1 -1
  6. data/ext/audio.c +473 -0
  7. data/ext/color.c +4 -4
  8. data/ext/event.c +25 -3
  9. data/ext/extconf.rb +35 -22
  10. data/ext/font.c +287 -0
  11. data/ext/image.c +682 -33
  12. data/ext/joystick.c +9 -9
  13. data/ext/ray.c +166 -55
  14. data/ext/ray.h +120 -9
  15. data/ext/ray_osx.m +161 -0
  16. data/ext/rect.c +31 -4
  17. data/lib/ray/audio.rb +52 -0
  18. data/lib/ray/color.rb +16 -0
  19. data/lib/ray/dsl.rb +1 -3
  20. data/lib/ray/dsl/event.rb +1 -39
  21. data/lib/ray/dsl/event_listener.rb +38 -0
  22. data/lib/ray/dsl/event_runner.rb +3 -1
  23. data/lib/ray/dsl/event_translator.rb +74 -8
  24. data/lib/ray/dsl/handler.rb +3 -33
  25. data/lib/ray/dsl/matcher.rb +129 -23
  26. data/lib/ray/font.rb +108 -0
  27. data/lib/ray/font_set.rb +37 -0
  28. data/lib/ray/game.rb +171 -34
  29. data/lib/ray/helper.rb +43 -5
  30. data/lib/ray/image.rb +90 -3
  31. data/lib/ray/image_set.rb +35 -0
  32. data/lib/ray/joystick.rb +30 -0
  33. data/lib/ray/music_set.rb +35 -0
  34. data/lib/ray/ray.rb +17 -9
  35. data/lib/ray/rect.rb +51 -0
  36. data/lib/ray/resource_set.rb +92 -0
  37. data/lib/ray/scene.rb +220 -51
  38. data/lib/ray/sound_set.rb +35 -0
  39. data/lib/ray/sprite.rb +184 -0
  40. data/psp/ext.c +4 -0
  41. data/samples/hello_world/hello.rb +35 -0
  42. data/samples/hello_world/hello_dsl.rb +24 -0
  43. data/samples/pong/pong.rb +128 -0
  44. data/samples/sokoban/level_1 +7 -0
  45. data/samples/sokoban/sokoban.rb +370 -0
  46. data/spec/ray/audio_spec.rb +146 -0
  47. data/spec/ray/color_spec.rb +13 -0
  48. data/spec/ray/event_spec.rb +57 -168
  49. data/spec/ray/font_spec.rb +93 -0
  50. data/spec/ray/image_set_spec.rb +48 -0
  51. data/spec/ray/image_spec.rb +130 -44
  52. data/spec/ray/joystick_spec.rb +13 -9
  53. data/spec/ray/matcher_spec.rb +32 -55
  54. data/spec/ray/ray_spec.rb +33 -31
  55. data/spec/ray/rect_spec.rb +80 -0
  56. data/spec/ray/resource_set_spec.rb +105 -0
  57. data/spec/ray/sprite_spec.rb +163 -0
  58. data/spec/res/VeraMono.ttf +0 -0
  59. data/spec/res/aqua2.bmp +0 -0
  60. data/spec/res/pop.wav +0 -0
  61. data/spec/spec.opts +4 -0
  62. data/spec/spec_helper.rb +8 -0
  63. data/yard_ext.rb +91 -0
  64. metadata +104 -38
  65. data/bin/ray +0 -5
  66. data/bin/ray_irb +0 -4
  67. data/ext/SDLMain.h +0 -17
  68. data/ext/SDLMain.m +0 -381
  69. data/lib/ray/config.rb +0 -84
  70. data/lib/ray/dsl/converter.rb +0 -65
  71. data/lib/ray/dsl/listener.rb +0 -30
  72. data/lib/ray/dsl/type.rb +0 -58
  73. data/spec/ray/config_spec.rb +0 -90
  74. data/spec/ray/conversion_spec.rb +0 -43
  75. data/spec/ray/type_spec.rb +0 -17
  76. data/spec_runner.rb +0 -27
@@ -1,25 +1,9 @@
1
1
  module Ray
2
2
  module DSL
3
- # This is another class kept by your greedy EventRunner. You don't need
4
- # to know it exist. When you say on :foo do something end a handler is
5
- # created, so that your EventRunner can see if you are interested in
6
- # a specific event.
3
+ # Used internally to call blocks registred with Ray::DSL::EventListener#on.
7
4
  class Handler
8
5
  def initialize(type, args, block)
9
6
  @type, @args, @block = type, args, block
10
-
11
- if desc = Ray.description_for_event(@type)
12
- desc.each_with_index do |type, i|
13
- next if @args[i].is_a? Matcher
14
- next if @args[i].is_a? Regexp
15
-
16
- begin
17
- @args[i] = Ray.convert(@args[i], type)
18
- rescue TypeError
19
- return
20
- end
21
- end
22
- end
23
7
  end
24
8
 
25
9
  def match?(event)
@@ -43,25 +27,11 @@ module Ray
43
27
 
44
28
  private
45
29
  def match_args?(args)
46
- return false if @args.size != args.size
30
+ return false if @args.size > args.size
47
31
 
48
32
  @args.each_with_index do |elem, i|
49
33
  other = args[i]
50
-
51
- case elem
52
- when Ray::DSL::Matcher
53
- return false unless elem.match?(other)
54
- when Regexp
55
- if other.is_a? Regexp
56
- return false unless elem == other
57
- elsif other.is_a? String
58
- return false unless elem =~ other
59
- else
60
- return false
61
- end
62
- else
63
- return false unless elem == other
64
- end
34
+ return false unless (elem === args[i]) || (elem == args[i])
65
35
  end
66
36
 
67
37
  return true
@@ -1,24 +1,29 @@
1
1
  module Ray
2
2
  # This is the module including all of your matchers as private methods,
3
3
  # allowing you to use them when you call on.
4
- module Matchers; end
4
+ module Matchers
5
+ # @return [DSL::Matcher] An anonymous matcher, using your block to
6
+ # know if the argument matches.
7
+ #
8
+ # @example
9
+ # on :foo, where { |i| i > 10 } do |i|
10
+ # puts "#{i} is greater than 10!"
11
+ # end
12
+ def where(&block)
13
+ DSL::Matcher.new { |o| block.call(o) }
14
+ end
15
+ end
5
16
 
6
17
  module DSL
7
18
  class Matcher
8
- def initialize(target, &block)
9
- @target = Ray.resolve_type(target)
19
+ def initialize(&block)
10
20
  @block = block
11
21
  end
12
22
 
13
- # @return [true, false] True if we can match on the object of that class
14
- def can_match_on?(klass)
15
- Ray.resolve_type(klass).ancestors.include? @target
16
- end
17
-
18
23
  # @return [true, false] True if the block this object was created with
19
24
  # returns true when called with obj.
20
25
  def match?(obj)
21
- can_match_on?(obj.class) && @block.call(obj)
26
+ @block.call(obj)
22
27
  end
23
28
 
24
29
  alias :=== :match?
@@ -28,7 +33,6 @@ module Ray
28
33
  # Describes a new matcher.
29
34
  #
30
35
  # @param [Symbol] name The name you'll use to call your matcher
31
- # @param [Symbol, Module] target the type on which the matcher operates.
32
36
  # @param [Proc] create_block a block called with the arguments of your matcher
33
37
  # method, and returning the block that will be used
34
38
  # to check if the condition is matched.
@@ -36,25 +40,127 @@ module Ray
36
40
  # Ray.describe_matcher(:match, :string) do |regex|
37
41
  # lambda { |str| str =~ regex }
38
42
  # end
39
- def self.describe_matcher(name, target = :anything, &create_block)
43
+ def self.describe_matcher(name, &create_block)
40
44
  Matchers.module_eval do
41
- define_method(name) do |*args, &block|
42
- DSL::Matcher.new(target, &create_block.call(*args, &block))
45
+ define_method(name) do |*args|
46
+ DSL::Matcher.new(&create_block.call(*args))
43
47
  end
44
-
45
- private name
46
48
  end
47
49
  end
48
50
 
49
- # This is the universal matcher, using a lambda so you can create
50
- # an anonymous matcher if you only need it once, hence you don't want
51
- # to name it.
51
+ # @return [DSL::Matcher] A matcher matching anything (always true)
52
+ describe_matcher(:anything) do
53
+ lambda { |o| true }
54
+ end
55
+
56
+ # @return [DSL::Matcher] A matcher matching anything greater than x
57
+ # (comparaison using >)
58
+ describe_matcher(:more_than) do |x|
59
+ lambda { |o| o > x }
60
+ end
61
+
62
+ # @return [DSL::Matcher] A matcher matching anything that is less than x
63
+ # (comparaison using <)
64
+ describe_matcher(:less_than) do |x|
65
+ lambda { |o| o < x }
66
+ end
67
+
68
+ # @return [DSL::Matcher] A matcher matching a value close of x.
69
+ # @note the maximum and the minimum will only be computed once.
52
70
  #
53
71
  # @example
54
- # on :foo, where { |i| i > 10 } do |i|
55
- # puts "#{i} is greater than 10!"
56
- # end
57
- describe_matcher(:where) do |&block|
58
- lambda { |o| block.call(o) }
72
+ # on :win, almost(10_000, 500) do ... end
73
+ # on :win, where { |x| x <= 10_000 + 500 && x >= 10_000 - 500 } do ... end
74
+ describe_matcher(:almost) do |x, precision|
75
+ min, max = (x - precision), (x + precision)
76
+ lambda { |o| (o <= max) && (o >= min) }
77
+ end
78
+
79
+ # @overload inside(x, y[, w, h])
80
+ # @overload inside(rect)
81
+ # @overload inside(array)
82
+ #
83
+ # @return [DSL::Matcher] A matching matching any rect inside the argument.
84
+ describe_matcher(:inside) do |*args|
85
+ rect = args.size > 1 ? Ray::Rect.new(*args) : args.first.to_rect
86
+ lambda { |o| o.inside? rect }
87
+ end
88
+
89
+ # @overload outside(x, y[, w, h])
90
+ # @overload outside(rect)
91
+ # @overload outside(array)
92
+ #
93
+ # @return [DSL::Matcher] A matching matching any rect outside the argument.
94
+ describe_matcher(:outside) do |*args|
95
+ rect = args.size > 1 ? Ray::Rect.new(*args) : args.first.to_rect
96
+ lambda { |o| o.outside? rect }
97
+ end
98
+
99
+ # @overload colliding_with(x, y[, w, h])
100
+ # @overload colliding_with(rect)
101
+ # @overload colliding_with(array)
102
+ #
103
+ # @return [DSL::Matcher] A matching matching any rect colliding with the
104
+ # argument.
105
+ describe_matcher(:colliding_with) do |*args|
106
+ rect = args.size > 1 ? Ray::Rect.new(*args) : args.first.to_rect
107
+ lambda { |o| o.collide? rect }
108
+ end
109
+
110
+ KEYS = Ray::Event.constants.inject({}) do |hash, const|
111
+ if const =~ /^KEY_(.+)$/
112
+ hash[$1.downcase.to_sym] = [Ray::Event.const_get(const)]
113
+ elsif const =~ /^PSP_BUTTON_(.+)$/
114
+ hash["psp_#{$1.downcase.to_sym}".to_sym] = [Ray::Event.const_get(const)]
115
+ end
116
+
117
+ hash
118
+ end
119
+
120
+ KEYS[:number] = Ray::Event.constants.select { |c| c =~ /^KEY_\d$/ }.map do |c|
121
+ Ray::Event.const_get(c)
122
+ end
123
+
124
+ KEYS[:number] |= Ray::Event.constants.select { |c| c =~ /^KEY_KP\d$/ }.map do |c|
125
+ Ray::Event.const_get(c)
126
+ end
127
+
128
+ KEYS[:letter] = Ray::Event.constants.select { |c| c =~ /^KEY_[a-z]$/ }.map do |c|
129
+ Ray::Event.const_get(c)
130
+ end
131
+
132
+ KEYS[:function] = Ray::Event.constants.select { |c| c =~ /^KEY_F\d$/ }.map do |c|
133
+ Ray::Event.const_get(c)
134
+ end
135
+
136
+ KEYS[:mod] = [Ray::Event::KEY_RSHIFT, Ray::Event::KEY_LSHIFT,
137
+ Ray::Event::KEY_RCTRL, Ray::Event::KEY_LCTRL,
138
+ Ray::Event::KEY_RALT, Ray::Event::KEY_LALT,
139
+ Ray::Event::KEY_RMETA, Ray::Event::KEY_LMETA,
140
+ Ray::Event::KEY_RSUPER, Ray::Event::KEY_LSUPER]
141
+
142
+ KEYS[:arrow] = [Ray::Event::KEY_UP, Ray::Event::KEY_DOWN,
143
+ Ray::Event::KEY_LEFT, Ray::Event::KEY_RIGHT]
144
+
145
+ MOD = Ray::Event.constants.inject({}) do |hash, const|
146
+ if const =~ /^KMOD_(.+)$/
147
+ hash[$1.downcase.to_sym] = [Ray::Event.const_get(const)]
148
+ end
149
+
150
+ hash
151
+ end
152
+
153
+ # @return [DSL::Matcher] A matcher matching the given key, which is a symbol
154
+ # like :space, :a, :b, :number, :letter, :arrow, ...
155
+ describe_matcher(:key) do |sym|
156
+ ary = KEYS[sym.to_sym]
157
+ lambda { |o| ary.include? o }
158
+ end
159
+
160
+ # @return [DSL::Matcher] A matcher matching the given modifier key
161
+ # (:rctrl, :lctrl, :rmeta, :lmeta, ...)
162
+ describe_matcher(:key_mod) do |sym|
163
+ ary = MOD[sym.to_sym]
164
+ lambda { |o| ary.detect { |const| o & const } }
59
165
  end
60
166
  end
data/lib/ray/font.rb ADDED
@@ -0,0 +1,108 @@
1
+ module Ray
2
+ class Font
3
+ extend Ray::ResourceSet
4
+ need_argument_count 1
5
+ add_set(/^(.*)$/) { |filename, size| new(filename, size) }
6
+
7
+ # @return [true, false] True if the font has no style
8
+ def normal?
9
+ style == STYLE_NORMAL
10
+ end
11
+
12
+ # @return [true, false] True if the font is italic
13
+ def italic?
14
+ (style & STYLE_ITALIC) != 0
15
+ end
16
+
17
+ # @return [true, false] True if the font is bold
18
+ def bold?
19
+ (style & STYLE_BOLD) != 0
20
+ end
21
+
22
+ # @return [true, false] True if the font is underlined
23
+ def underlined?
24
+ (style & STYLE_UNDERLINE) != 0
25
+ end
26
+ end
27
+ end
28
+
29
+ class String
30
+ # Draws the receiver.
31
+ #
32
+ # @option opts [Ray::Font] :font The font used to render the string.
33
+ # @option opts [Ray::Image] :on The image to draw on.
34
+ # @option opts [Integer] :w Witdh of the image. Also called :width.
35
+ # @option opts [Integer] ;h height of the image. Also called :height.
36
+ # @option opts [Symbol] The encoding. Can be guessed in Ruby 1.9.
37
+ # @option opts [Ray::Color] :color The color to draw the text in.
38
+ # @option opts [Ray::Color] :background Background color in shaded mode.
39
+ # @option opts [Symbol] :mode The drawing mode.
40
+ # @option opts [Array<Symbol>] :style The different styles to apply.
41
+ # :italic, :bold, and :underlined.
42
+ #
43
+ # @option opts [Array<Integer>] :at Where the image should be drawn.
44
+ # Defaults to (0, 0)
45
+ #
46
+ # @see Ray::Font#draw
47
+ def draw(opts = {})
48
+ font = opts[:font]
49
+
50
+ lines = split(/\r\n|\n|\r/)
51
+ line_skip = font.line_skip
52
+
53
+ target = opts[:on]
54
+
55
+ string_encoding = opts[:encoding]
56
+ string_encoding ||= if respond_to? :encoding # Ruby 1.9
57
+ case encoding.to_s
58
+ when /^utf-?8$/i
59
+ :utf8
60
+ when /^iso-8859-/i
61
+ :latin1
62
+ else
63
+ nil
64
+ end
65
+ else
66
+ nil
67
+ end
68
+
69
+ target ||= Ray::Image.new(:height => opts[:height] || opts[:h] ||
70
+ line_skip * lines.size,
71
+ :width => opts[:width] || opts[:w] ||
72
+ lines.map { |i|
73
+ font.size_of(self, string_encoding).width
74
+ }.max)
75
+
76
+ color = opts[:color]
77
+ background = opts[:background]
78
+
79
+ mode = opts[:mode]
80
+
81
+ if styles = opts[:style]
82
+ font.style = styles.inject(0) do |flags, style|
83
+ flags |= case style
84
+ when :italic
85
+ Ray::Font::STYLE_ITALIC
86
+ when :bold
87
+ Ray::Font::STYLE_BOLD
88
+ when :underlined
89
+ Ray::Font::STYLE_UNDERLINE
90
+ else
91
+ raise "Unknown flag #{style}"
92
+ end
93
+ end
94
+ end
95
+
96
+ x, y = opts[:at]
97
+ x ||= 0
98
+ y ||= 0
99
+
100
+ lines.each do |line|
101
+ font.draw(line, :on => target, :at => [x, y], :encoding => string_encoding,
102
+ :color => color, :background => background, :mode => mode)
103
+ y += line_skip
104
+ end
105
+
106
+ target
107
+ end
108
+ end
@@ -0,0 +1,37 @@
1
+ module Ray
2
+ module FontSet
3
+ extend Ray::ResourceSet
4
+ need_argument_count 1
5
+
6
+ class << self
7
+ def missing_pattern(string, size)
8
+ Ray::Font[string, size]
9
+ end
10
+
11
+ def select!(&block)
12
+ super(&block)
13
+ Ray::Font.select!(&block)
14
+ end
15
+ end
16
+ end
17
+
18
+ # Creates a new font set.
19
+ #
20
+ # @param [Regexp] regex Regular expression used to match file
21
+ # @yield [*args, size] Block returning the font
22
+ #
23
+ # @yieldparam args Regex captures
24
+ # @yieldparam size Size of the font
25
+ def self.font_set(regex, &block)
26
+ Ray::FontSet.add_set(regex, &block)
27
+ end
28
+ end
29
+
30
+ begin
31
+ require 'open-uri'
32
+
33
+ Ray.font_set(/^(http|ftp):\/\/(\S+)$/) do |protocol, address, size|
34
+ open("#{protocol}://#{address}") { |io| Ray::Font.new(io, size) }
35
+ end
36
+ rescue LoadError
37
+ end
data/lib/ray/game.rb CHANGED
@@ -1,29 +1,93 @@
1
1
  module Ray
2
- # a game is represented as a stack of scenes : you register scenes,
3
- # and then you push and pop them until the stack is empty.
2
+ # Games are used to manage different scenes. They also init Ray and create a
3
+ # window.
4
+ #
5
+ # == Creating a Game
6
+ # There are several ways of doing this.
7
+ # Using a block:
8
+ # Ray::Game.new("my game") do
9
+ # ...
10
+ # end
11
+ #
12
+ # Using the instance directly:
13
+ # game = Ray::Game.new("my game")
14
+ # ...
15
+ # game.run
16
+ #
17
+ # Subclassing:
18
+ # class Game < Ray::Game
19
+ # def initialize
20
+ # super("my game")
21
+ # ...
22
+ # end
23
+ # end
24
+ #
25
+ # Game.new.run
26
+ #
27
+ # == Registring scenes to a Game
28
+ # Games need the scenes they use to be registred. The most obvious way to
29
+ # do it is to use scene with a block:
30
+ # scene :game do
31
+ # # See Ray::Scene
32
+ # end
33
+ #
34
+ # You may also call it to register a subclass of Ray::Scene
35
+ # scene(:game, GameScene)
36
+ # Which is the same as:
37
+ # GameScene.bind(self) # Assuming GameScene's scene_name is set to :game
38
+ #
39
+ # == Managing the scene stack
40
+ # You can push a scene to the game:
41
+ # push_scene :game
42
+ # When #run will be called, it will show the scene :game. Notice that, if you
43
+ # push more than one scene, only the last one will be seen directly. However,
44
+ # if you remove it later, the previous scene will be shown.
45
+ #
46
+ # You can thus also remove a scene from your stack:
47
+ # pop_scene # Removes the last scene
48
+ #
49
+ # exit is not exactly the same: it will ask the scene to quit before doing this.
50
+ # exit! will do something totally different: completely kill the game.
51
+ #
52
+ # == Handling events
53
+ # Games can listen to events just like scenes. Since the event runner will change
54
+ # often, it needs to register every time it changes it. You can pass a block to
55
+ # the register method:
56
+ # register do
57
+ # on :some_event do some_stuff end
58
+ # end
59
+ #
60
+ # You may also want to override register in suclasses:
61
+ # def register
62
+ # on :some_event do some_stuff end
63
+ # end
4
64
  #
5
- # The game will run eerything when it is created, and free it when
6
- # it is done running.
7
65
  class Game
66
+ include Ray::Helper
67
+
8
68
  # Creates a new game.
9
- # You can poss all the argument you would pass to create_window,
10
- # except width and height which should be given in :video_mode, like this :
11
- # Ray::Game.new(:video_modes = %w(480x272 640x480))
69
+ #
70
+ # You can pass all the arguments you would pass to create_window,
71
+ # except width and height which should be given in :video_mode:
72
+ # Ray::Game.new('hello', :video_modes => %w(480x272 640x480))
12
73
  #
13
74
  # It will try to get the biggest resolution available (so it will most
14
- # likely choose 640x480).
75
+ # likely choose 640x480 in this case).
15
76
  #
16
- # If a block is passes, it is instance evaluated, and then the game is
77
+ # If a block is passed, it is instance evaluated, then the game is
17
78
  # directly run.
18
- def initialize(hash = {}, &block)
19
- @registred_scenes = {}
20
- @scenes = []
79
+ #
80
+ # This methods creates a new window and inits Ray.
81
+ def initialize(title, hash = {}, &block)
82
+ @game_registred_scenes = {}
83
+ @game_scenes = []
21
84
 
22
85
  defaults = {
23
- :double_buf => true,
24
- :bpp => 32,
25
- :hw_surface => true,
26
- :sw_surface => false
86
+ :double_buf => true,
87
+ :bpp => 32,
88
+ :hw_surface => true,
89
+ :sw_surface => false,
90
+ :video_modes => %w(480x272 640x480)
27
91
  }
28
92
 
29
93
  options = defaults.merge(hash)
@@ -35,6 +99,7 @@ module Ray
35
99
  :async_blit => options[:async_blit],
36
100
  :double_buf => options[:double_buf],
37
101
  :fullscreen => options[:fullscreen],
102
+ :resizable => options[:resizable],
38
103
  :no_frame => options[:no_frame]
39
104
  }
40
105
 
@@ -50,7 +115,17 @@ module Ray
50
115
  last_mode = modes.select { |mode| Ray.can_use_mode? mode }.last
51
116
  raise ArgumentError, "No valid mode found" unless last_mode
52
117
 
53
- @window = Ray.create_window(last_mode)
118
+ if @game_title = title
119
+ Ray.window_title = @game_title
120
+ Ray.text_icon = @game_title
121
+ end
122
+
123
+ if icon = options[:icon]
124
+ Ray.icon = icon.is_a?(Ray::Image) ? icon : icon.to_image
125
+ end
126
+
127
+ @game_last_mode = last_mode
128
+ @game_window = Ray.create_window(last_mode)
54
129
 
55
130
  if block
56
131
  instance_eval(&block)
@@ -58,19 +133,26 @@ module Ray
58
133
  end
59
134
  end
60
135
 
61
- # Adds a scene to the stack by its name.
136
+ # Adds a scene to the stack using its name.
137
+ #
62
138
  # You must call Game#scene before this. If you subclassed scene,
63
- # then call bind to register it.
64
- def push_scene(scene_name)
65
- scene = @registred_scenes[scene_name]
139
+ # then call bind to register it:
140
+ # scene :something, SomeClass
141
+ # SomeClass.bind(self)
142
+ #
143
+ # @param [Symbol] scene_name The name of the scene which should be pushed
144
+ # @param *args Arguments passed to the scene
145
+ def push_scene(scene_name, *args)
146
+ scene = @game_registred_scenes[scene_name]
66
147
  raise ArgumentError, "Unknown scene #{scene_name}" unless scene
67
148
 
68
- @scenes << scene
149
+ @game_scenes << scene
150
+ @game_scene_arguments = args
69
151
  end
70
152
 
71
153
  # Pops the last scene.
72
154
  def pop_scene
73
- @scenes.delete_at(-1)
155
+ @game_scenes.delete_at(-1)
74
156
  end
75
157
 
76
158
  # Registers a new scene with a given name. the block will be passed
@@ -79,29 +161,84 @@ module Ray
79
161
  # @param [Symobl] name the name of the new scene
80
162
  # @param [Class] klass the class of the scene.
81
163
  def scene(name, klass = Scene, &block)
82
- @registred_scenes[name] = klass.new(&block)
164
+ @game_registred_scenes[name] = klass.new(&block)
83
165
  end
84
166
 
85
167
  # Runs the game until the last scene gets popped.
168
+ # Will call Ray.stop.
86
169
  def run
87
- until @scenes.empty?
88
- @runner = Ray::DSL::EventRunner.new
89
-
90
- @scenes.each do |scene|
91
- scene.game = self
92
- scene.window = @window
93
- scene.event_runner = @runner
94
-
95
- scene.register_events
170
+ until @game_scenes.empty?
171
+ create_event_runner
172
+ register
173
+
174
+ @game_scenes.each do |scene|
175
+ scene.game = self
176
+ scene.window = @game_window
177
+ scene.event_runner = event_runner
178
+ scene.scene_arguments = @game_scene_arguments
96
179
  end
97
180
 
98
- scene = @scenes.last
181
+ scene = @game_scenes.last
99
182
 
183
+ scene.setup(*@game_scene_arguments)
184
+ scene.register_events
100
185
  scene.need_render!
101
186
  scene.run
102
187
  end
103
188
 
104
189
  Ray.stop
105
190
  end
191
+
192
+ # Registers a block to listen to events
193
+ # Subclasses can also overrid this method to register for events.
194
+ def register(&block)
195
+ if block_given?
196
+ @game_register_block = block
197
+ else
198
+ @game_register_block.call if @game_register_block
199
+ end
200
+ end
201
+
202
+ # Removes the current scene of this game
203
+ def exit
204
+ return if @game_scenes.empty?
205
+
206
+ @game_scenes.last.exit
207
+ pop_scene
208
+ end
209
+
210
+ # Kills the game, removing all the scenes it contains.
211
+ def exit!
212
+ return if @game_scenes.empty?
213
+
214
+ @game_scenes.last.exit
215
+ @game_scenes.clear
216
+ end
217
+
218
+ # Resizes the window and raises a window_resize event
219
+ def resize_window(w, h)
220
+ @game_window = Ray.create_window(@game_last_mode.merge!(:w => w,
221
+ :h => h))
222
+ @game_scenes.each do |scene|
223
+ scene.window = @game_window
224
+ end
225
+
226
+ @game_scenes.last.need_render!
227
+
228
+ raise_event(:window_resize, Ray::Rect.new(0, 0, w, h))
229
+ end
230
+
231
+ def title
232
+ @game_title
233
+ end
234
+
235
+ def inspect
236
+ "game(#{title.inspect})"
237
+ end
238
+ end
239
+
240
+ # @see Ray::Game#initialize
241
+ def self.game(title, opts = {}, &block)
242
+ Ray::Game.new(title, opts, &block)
106
243
  end
107
244
  end