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.
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/README.md +62 -0
- data/Rakefile +33 -23
- data/VERSION +1 -1
- data/ext/audio.c +473 -0
- data/ext/color.c +4 -4
- data/ext/event.c +25 -3
- data/ext/extconf.rb +35 -22
- data/ext/font.c +287 -0
- data/ext/image.c +682 -33
- data/ext/joystick.c +9 -9
- data/ext/ray.c +166 -55
- data/ext/ray.h +120 -9
- data/ext/ray_osx.m +161 -0
- data/ext/rect.c +31 -4
- data/lib/ray/audio.rb +52 -0
- data/lib/ray/color.rb +16 -0
- data/lib/ray/dsl.rb +1 -3
- data/lib/ray/dsl/event.rb +1 -39
- data/lib/ray/dsl/event_listener.rb +38 -0
- data/lib/ray/dsl/event_runner.rb +3 -1
- data/lib/ray/dsl/event_translator.rb +74 -8
- data/lib/ray/dsl/handler.rb +3 -33
- data/lib/ray/dsl/matcher.rb +129 -23
- data/lib/ray/font.rb +108 -0
- data/lib/ray/font_set.rb +37 -0
- data/lib/ray/game.rb +171 -34
- data/lib/ray/helper.rb +43 -5
- data/lib/ray/image.rb +90 -3
- data/lib/ray/image_set.rb +35 -0
- data/lib/ray/joystick.rb +30 -0
- data/lib/ray/music_set.rb +35 -0
- data/lib/ray/ray.rb +17 -9
- data/lib/ray/rect.rb +51 -0
- data/lib/ray/resource_set.rb +92 -0
- data/lib/ray/scene.rb +220 -51
- data/lib/ray/sound_set.rb +35 -0
- data/lib/ray/sprite.rb +184 -0
- data/psp/ext.c +4 -0
- data/samples/hello_world/hello.rb +35 -0
- data/samples/hello_world/hello_dsl.rb +24 -0
- data/samples/pong/pong.rb +128 -0
- data/samples/sokoban/level_1 +7 -0
- data/samples/sokoban/sokoban.rb +370 -0
- data/spec/ray/audio_spec.rb +146 -0
- data/spec/ray/color_spec.rb +13 -0
- data/spec/ray/event_spec.rb +57 -168
- data/spec/ray/font_spec.rb +93 -0
- data/spec/ray/image_set_spec.rb +48 -0
- data/spec/ray/image_spec.rb +130 -44
- data/spec/ray/joystick_spec.rb +13 -9
- data/spec/ray/matcher_spec.rb +32 -55
- data/spec/ray/ray_spec.rb +33 -31
- data/spec/ray/rect_spec.rb +80 -0
- data/spec/ray/resource_set_spec.rb +105 -0
- data/spec/ray/sprite_spec.rb +163 -0
- data/spec/res/VeraMono.ttf +0 -0
- data/spec/res/aqua2.bmp +0 -0
- data/spec/res/pop.wav +0 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +8 -0
- data/yard_ext.rb +91 -0
- metadata +104 -38
- data/bin/ray +0 -5
- data/bin/ray_irb +0 -4
- data/ext/SDLMain.h +0 -17
- data/ext/SDLMain.m +0 -381
- data/lib/ray/config.rb +0 -84
- data/lib/ray/dsl/converter.rb +0 -65
- data/lib/ray/dsl/listener.rb +0 -30
- data/lib/ray/dsl/type.rb +0 -58
- data/spec/ray/config_spec.rb +0 -90
- data/spec/ray/conversion_spec.rb +0 -43
- data/spec/ray/type_spec.rb +0 -17
- data/spec_runner.rb +0 -27
data/lib/ray/dsl/handler.rb
CHANGED
@@ -1,25 +1,9 @@
|
|
1
1
|
module Ray
|
2
2
|
module DSL
|
3
|
-
#
|
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
|
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
|
data/lib/ray/dsl/matcher.rb
CHANGED
@@ -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
|
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(
|
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
|
-
|
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,
|
43
|
+
def self.describe_matcher(name, &create_block)
|
40
44
|
Matchers.module_eval do
|
41
|
-
define_method(name) do |*args
|
42
|
-
DSL::Matcher.new(
|
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
|
-
#
|
50
|
-
|
51
|
-
|
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 :
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
lambda { |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
|
data/lib/ray/font_set.rb
ADDED
@@ -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
|
-
#
|
3
|
-
#
|
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
|
-
#
|
10
|
-
#
|
11
|
-
#
|
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
|
77
|
+
# If a block is passed, it is instance evaluated, then the game is
|
17
78
|
# directly run.
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
24
|
-
:bpp
|
25
|
-
:hw_surface
|
26
|
-
:sw_surface
|
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
|
-
@
|
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
|
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
|
-
|
65
|
-
|
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
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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 @
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
scene.
|
93
|
-
scene.
|
94
|
-
|
95
|
-
scene.
|
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 = @
|
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
|