flonkerton 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/README.md +115 -0
- data/Rakefile +11 -0
- data/TODO +12 -0
- data/config/defaults.yml +39 -0
- data/examples/clip.rb +16 -0
- data/examples/config/defaults.yml +39 -0
- data/examples/extras/actor.rb +47 -0
- data/examples/extras/fill.rb +5 -0
- data/examples/extras/input_handler.rb +9 -0
- data/examples/extras/mouse_border.rb +21 -0
- data/examples/extras/random_color.rb +27 -0
- data/examples/extras/scrollable.rb +80 -0
- data/examples/font.rb +25 -0
- data/examples/input.rb +63 -0
- data/examples/screen.rb +38 -0
- data/examples/scroll.rb +72 -0
- data/examples/sound.rb +43 -0
- data/examples/tiles.rb +30 -0
- data/flonkerton.gemspec +16 -0
- data/games/gosu_demo/config/defaults.yml +39 -0
- data/games/gosu_demo/media/Space.png +0 -0
- data/games/gosu_demo/media/beep.wav +0 -0
- data/games/gosu_demo/media/star_25x25.png +0 -0
- data/games/gosu_demo/media/starfighter.png +0 -0
- data/games/gosu_demo/original.rb +137 -0
- data/games/gosu_demo/play.rb +135 -0
- data/lib/flonkerton.rb +241 -0
- data/media/ArcadeClassic.ttf +0 -0
- data/media/CREDITS +4 -0
- data/media/background.png +0 -0
- data/media/catch_me_song.ogg +0 -0
- data/media/cursor.png +0 -0
- data/media/gosu_logo.png +0 -0
- data/media/select.wav +0 -0
- data/media/tiles_32x32.png +0 -0
- data/test/integration_test.rb +115 -0
- data/test/test_helper.rb +9 -0
- data/test/unit_tests.rb +386 -0
- data/watchmen.rb +7 -0
- metadata +168 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
require '../../lib/flonkerton'
|
2
|
+
require '../../examples/extras/random_color'
|
3
|
+
include Flonkerton
|
4
|
+
include Gosu
|
5
|
+
|
6
|
+
module GosuTutorial
|
7
|
+
module ZOrder
|
8
|
+
Background, Stars, Player, UI = *0..3
|
9
|
+
end
|
10
|
+
|
11
|
+
class Player
|
12
|
+
attr_reader :score
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@image = Images[:starfighter]
|
16
|
+
@beep = Samples[:beep]
|
17
|
+
@x = @y = @vel_x = @vel_y = @angle = 0.0
|
18
|
+
@score = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def warp(x, y)
|
22
|
+
@x, @y = x, y
|
23
|
+
end
|
24
|
+
|
25
|
+
def turn_left
|
26
|
+
@angle -= 4.5
|
27
|
+
end
|
28
|
+
|
29
|
+
def turn_right
|
30
|
+
@angle += 4.5
|
31
|
+
end
|
32
|
+
|
33
|
+
def accelerate
|
34
|
+
@vel_x += Gosu::offset_x(@angle, 0.5)
|
35
|
+
@vel_y += Gosu::offset_y(@angle, 0.5)
|
36
|
+
end
|
37
|
+
|
38
|
+
def move
|
39
|
+
@x += @vel_x
|
40
|
+
@y += @vel_y
|
41
|
+
@x %= CONFIG[:width]
|
42
|
+
@y %= CONFIG[:height]
|
43
|
+
|
44
|
+
@vel_x *= 0.95
|
45
|
+
@vel_y *= 0.95
|
46
|
+
end
|
47
|
+
|
48
|
+
def draw
|
49
|
+
@image.draw_rot(@x, @y, ZOrder::Player, @angle)
|
50
|
+
end
|
51
|
+
|
52
|
+
def collect_stars(stars)
|
53
|
+
stars.reject! do |star|
|
54
|
+
if Gosu::distance(@x, @y, star.x, star.y) < 35 then
|
55
|
+
@score += 10
|
56
|
+
@beep.play
|
57
|
+
true
|
58
|
+
else
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Star
|
66
|
+
attr_reader :x, :y
|
67
|
+
|
68
|
+
def initialize
|
69
|
+
@animation = Tiles[:star]
|
70
|
+
@offset = @animation.first.width / 2.0
|
71
|
+
@color = Color.random((40..254), (40..254), (40..254))
|
72
|
+
@x = rand * CONFIG[:width]
|
73
|
+
@y = rand * CONFIG[:height]
|
74
|
+
end
|
75
|
+
|
76
|
+
def draw
|
77
|
+
current_frame.draw :x => @x - @offset,
|
78
|
+
:y => @y - @offset,
|
79
|
+
:z => ZOrder::Stars,
|
80
|
+
:color => @color,
|
81
|
+
:mode => :additive
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def current_frame
|
87
|
+
@animation[Gosu::milliseconds / 100 % @animation.size]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class GameScreen < Screen
|
92
|
+
def setup
|
93
|
+
@background = Images[:space]
|
94
|
+
@player = Player.new
|
95
|
+
@player.warp(320, 240)
|
96
|
+
@stars = Array.new
|
97
|
+
@font = Fonts[:default]
|
98
|
+
@input = { :up => [KbUp, GpButton0],
|
99
|
+
:left => [KbLeft, GpLeft],
|
100
|
+
:right => [KbRight, GpRight] }
|
101
|
+
end
|
102
|
+
|
103
|
+
def update
|
104
|
+
@player.turn_left if pressed?(:left)
|
105
|
+
@player.turn_right if pressed?(:right)
|
106
|
+
@player.accelerate if pressed?(:up)
|
107
|
+
@player.move
|
108
|
+
@player.collect_stars(@stars)
|
109
|
+
|
110
|
+
if rand(100) < 4 and @stars.size < 25 then
|
111
|
+
@stars << Star.new
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def draw
|
116
|
+
@background.draw
|
117
|
+
@player.draw
|
118
|
+
@stars.each { |star| star.draw }
|
119
|
+
@font.draw :text => "Score: #{@player.score}",
|
120
|
+
:x => 10,
|
121
|
+
:y => 10,
|
122
|
+
:z => ZOrder::UI,
|
123
|
+
:color => Color::YELLOW
|
124
|
+
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
# Taken from control example.
|
129
|
+
def pressed?(key)
|
130
|
+
@input[key].detect { |k| @game.button_down?(k) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
Game.start
|
data/lib/flonkerton.rb
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class File
|
5
|
+
def self.label(file)
|
6
|
+
self.basename(file)[/^\w+/].scan(/[A-Z]*[a-z0-9]+/).join('_').downcase.intern
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Flonkerton
|
11
|
+
VERSION = '0.0.1'
|
12
|
+
LIB_PATH = File.dirname(File.expand_path(__FILE__))
|
13
|
+
CURRENT_PATH = File.dirname(File.expand_path($0))
|
14
|
+
|
15
|
+
if File.exist?(CURRENT_PATH + '/config/defaults.yml')
|
16
|
+
CONFIG = YAML.load_file(CURRENT_PATH + '/config/defaults.yml')
|
17
|
+
else
|
18
|
+
CONFIG = YAML.load_file(LIB_PATH + '/../config/defaults.yml')
|
19
|
+
end
|
20
|
+
|
21
|
+
module Drawable
|
22
|
+
def draw(options = {})
|
23
|
+
super(*draw_args(defaults.merge(options)))
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def draw_args(options)
|
29
|
+
defaults[:order].map { |arg| options[arg] } # 1.8.6 Patch - defaults.keys.map in 1.9
|
30
|
+
end
|
31
|
+
|
32
|
+
def name
|
33
|
+
self.class.to_s[/\w+$/].downcase
|
34
|
+
end
|
35
|
+
|
36
|
+
def defaults
|
37
|
+
CONFIG[name.intern]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Font < Gosu::Font
|
42
|
+
include Drawable
|
43
|
+
|
44
|
+
def initialize(game, name, height = CONFIG[:font_size])
|
45
|
+
super(game, name, height)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Image < Gosu::Image
|
50
|
+
include Drawable
|
51
|
+
|
52
|
+
def self.load_tiles(game, file, width, height, border = true)
|
53
|
+
super(game, file, width, height, border).each do |image|
|
54
|
+
image.extend(Drawable)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Sample < Gosu::Sample; end
|
60
|
+
|
61
|
+
class Song < Gosu::Song
|
62
|
+
def loop
|
63
|
+
play(true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# This class shouldn't be used directly, it provides behavior for subclasses.
|
68
|
+
#
|
69
|
+
class Resource
|
70
|
+
def self.load(game)
|
71
|
+
Dir[path].each do |file|
|
72
|
+
all[File.label(file)] = klass.new(game, file)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.all
|
77
|
+
@hash ||= Hash.new
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.[](key)
|
81
|
+
all[key]
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def self.name
|
87
|
+
self.to_s[/\w+$/]
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.klass
|
91
|
+
Module.class_eval(name.chop)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.path
|
95
|
+
File.join(CONFIG[:media_path], extension)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.extension
|
99
|
+
CONFIG["#{name.downcase}_ext".intern]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Songs < Resource; end
|
104
|
+
class Images < Resource; end
|
105
|
+
class Samples < Resource; end
|
106
|
+
|
107
|
+
class Fonts < Resource
|
108
|
+
def self.load(game)
|
109
|
+
super(game)
|
110
|
+
all[:default] = Font.new(game, Gosu::default_font_name)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Tiles < Resource
|
115
|
+
def self.load(game)
|
116
|
+
Dir[path].each do |file|
|
117
|
+
if File.basename(file) =~ /(\w+)_(\d+)x(\d+)/
|
118
|
+
all[$1.intern] = Image.load_tiles(game, file, $2.to_i, $3.to_i, true)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Game
|
125
|
+
def self.start screen = nil
|
126
|
+
@window = Window.new(screen)
|
127
|
+
@window.show
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Window < Gosu::Window
|
132
|
+
attr_reader :screen
|
133
|
+
attr_accessor :next_screen
|
134
|
+
|
135
|
+
def initialize initial_screen = nil
|
136
|
+
super(CONFIG[:width], CONFIG[:height], CONFIG[:fullscreen])
|
137
|
+
self.caption = CONFIG[:caption]
|
138
|
+
load_resources
|
139
|
+
create(initial_screen || default_screen)
|
140
|
+
end
|
141
|
+
|
142
|
+
def update
|
143
|
+
@screen.update
|
144
|
+
create(@next_screen) if @next_screen
|
145
|
+
end
|
146
|
+
|
147
|
+
def draw
|
148
|
+
@screen.draw
|
149
|
+
end
|
150
|
+
|
151
|
+
def button_down(id)
|
152
|
+
@screen.button_down(id)
|
153
|
+
end
|
154
|
+
|
155
|
+
def button_up(id)
|
156
|
+
@screen.button_up(id)
|
157
|
+
end
|
158
|
+
|
159
|
+
def params
|
160
|
+
@params ||= Hash.new
|
161
|
+
end
|
162
|
+
|
163
|
+
protected
|
164
|
+
|
165
|
+
def load_resources
|
166
|
+
[Fonts, Songs, Images, Samples, Tiles].each do |resource|
|
167
|
+
resource.load(self)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def default_screen
|
172
|
+
Module.module_eval(CONFIG[:initial_screen])
|
173
|
+
end
|
174
|
+
|
175
|
+
def create(klass)
|
176
|
+
@screen = klass.new(self)
|
177
|
+
@next_screen = nil
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# This class shouldn't be instantiated, it provides behavior for subclasses.
|
182
|
+
#
|
183
|
+
class Screen
|
184
|
+
def initialize game
|
185
|
+
@game = game
|
186
|
+
setup
|
187
|
+
end
|
188
|
+
|
189
|
+
def setup; end
|
190
|
+
def button_up(id); end
|
191
|
+
|
192
|
+
def button_down(id)
|
193
|
+
close if id == Gosu::KbEscape # Don't Panic!
|
194
|
+
end
|
195
|
+
|
196
|
+
def update; end
|
197
|
+
def draw; end
|
198
|
+
|
199
|
+
def width
|
200
|
+
@game.width
|
201
|
+
end
|
202
|
+
|
203
|
+
def height
|
204
|
+
@game.height
|
205
|
+
end
|
206
|
+
|
207
|
+
def mouse_x
|
208
|
+
@game.mouse_x
|
209
|
+
end
|
210
|
+
|
211
|
+
def mouse_y
|
212
|
+
@game.mouse_y
|
213
|
+
end
|
214
|
+
|
215
|
+
def button_down?(id)
|
216
|
+
@game.button_down?(id)
|
217
|
+
end
|
218
|
+
|
219
|
+
def close
|
220
|
+
@game.close
|
221
|
+
end
|
222
|
+
|
223
|
+
def go_to(screen)
|
224
|
+
@game.next_screen = screen
|
225
|
+
end
|
226
|
+
|
227
|
+
def params
|
228
|
+
@game.params
|
229
|
+
end
|
230
|
+
|
231
|
+
def clip_to(x, y, w, h, &block)
|
232
|
+
@game.clip_to(x, y, w, h, &block)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class WelcomeScreen < Screen
|
237
|
+
def draw
|
238
|
+
Fonts[:default].draw :text => 'Welcome'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
Binary file
|
data/media/CREDITS
ADDED
Binary file
|
Binary file
|
data/media/cursor.png
ADDED
Binary file
|
data/media/gosu_logo.png
ADDED
Binary file
|
data/media/select.wav
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
Protest.context('A Game example') do
|
4
|
+
module Example
|
5
|
+
class TextLogo
|
6
|
+
|
7
|
+
SPEED_X = 16
|
8
|
+
SPEED_Y = 10
|
9
|
+
|
10
|
+
def initialize text, limit
|
11
|
+
@text = text
|
12
|
+
@limit = limit
|
13
|
+
@font = Flonkerton::Fonts[:default]
|
14
|
+
@x = 0
|
15
|
+
@y = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def update
|
19
|
+
@x += SPEED_X
|
20
|
+
@y += SPEED_Y
|
21
|
+
end
|
22
|
+
|
23
|
+
def draw
|
24
|
+
@font.draw :text => @text,
|
25
|
+
:x => @x,
|
26
|
+
:y => @y,
|
27
|
+
:factor_x => 4,
|
28
|
+
:factor_y => 4
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_screen?
|
32
|
+
@y < @limit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class LogoScreen < Flonkerton::Screen
|
37
|
+
LOGO_TIME = 1000
|
38
|
+
|
39
|
+
def setup
|
40
|
+
@time = Gosu.milliseconds
|
41
|
+
@font = Flonkerton::Fonts[:default]
|
42
|
+
@image = Flonkerton::Images[:gosu_logo]
|
43
|
+
@sample = Flonkerton::Samples[:select]
|
44
|
+
@x = (width - @image.width) / 2
|
45
|
+
@y = (height - @image.height) / 2
|
46
|
+
@song = Flonkerton::Songs[:catch_me_song]
|
47
|
+
@song.volume = 0.1
|
48
|
+
@song.loop
|
49
|
+
end
|
50
|
+
|
51
|
+
def update
|
52
|
+
if time_elapsed? or button_down?(Gosu::KbReturn)
|
53
|
+
@song.play
|
54
|
+
@sample.play
|
55
|
+
params[:health] = 75
|
56
|
+
go_to(GameScreen)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def draw
|
61
|
+
fill
|
62
|
+
@image.draw :x => @x, :y => @y
|
63
|
+
|
64
|
+
@font.draw :x => 10,
|
65
|
+
:y => height - @font.height,
|
66
|
+
:text => 'Press Enter to continue...',
|
67
|
+
:color => Gosu::Color::BLACK
|
68
|
+
|
69
|
+
@font.draw :text => time_left,
|
70
|
+
:color => Gosu::Color::BLACK
|
71
|
+
end
|
72
|
+
|
73
|
+
def fill(color = 0xffffffff)
|
74
|
+
@game.draw_quad(0, 0, color, width, 0, color, 0, height, color, width, height, color)
|
75
|
+
end
|
76
|
+
|
77
|
+
def time_left
|
78
|
+
Gosu.milliseconds - @time
|
79
|
+
end
|
80
|
+
|
81
|
+
def time_elapsed?
|
82
|
+
time_left >= LOGO_TIME
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class GameScreen < Flonkerton::Screen
|
87
|
+
def setup
|
88
|
+
@logo = TextLogo.new('LOGO', height)
|
89
|
+
@mouse = Flonkerton::Images[:cursor]
|
90
|
+
@tiles = Flonkerton::Tiles[:tiles]
|
91
|
+
@background = Flonkerton::Images[:background]
|
92
|
+
end
|
93
|
+
|
94
|
+
def draw
|
95
|
+
@tiles.first.draw
|
96
|
+
clip_to(40, 40, 640, 480) do
|
97
|
+
@background.draw
|
98
|
+
end
|
99
|
+
@logo.draw
|
100
|
+
@mouse.draw :x => mouse_x, :y => mouse_y
|
101
|
+
end
|
102
|
+
|
103
|
+
def update
|
104
|
+
@logo.update
|
105
|
+
close unless @logo.on_screen?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should work." do
|
111
|
+
assert_nothing_raised do
|
112
|
+
Flonkerton::Game.start(Example::LogoScreen)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|