ray 0.0.0.pre2 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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