lotu 0.1.15 → 0.1.16
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/examples/{hello_world → 01_hello_world}/moving_portraits.rb +5 -3
- data/examples/{screen_cursor → 02_screen_cursor}/mouse_and_keyboard_cursors.rb +6 -26
- data/examples/03_collisions/box.rb +83 -0
- data/examples/{steering_behaviors → 04_steering_behaviors}/pursuit_and_evade.rb +4 -23
- data/examples/{steering_behaviors → 04_steering_behaviors}/pursuit_and_evade_multiple.rb +4 -23
- data/lib/lotu/actor.rb +21 -13
- data/lib/lotu/behavior.rb +19 -0
- data/lib/lotu/behaviors/collidable.rb +28 -7
- data/lib/lotu/behaviors/controllable.rb +1 -1
- data/lib/lotu/behaviors/eventful.rb +2 -5
- data/lib/lotu/behaviors/resource_manager.rb +104 -0
- data/lib/lotu/behaviors/system_user.rb +41 -3
- data/lib/lotu/game.rb +27 -116
- data/lib/lotu/helpers/kernel.rb +8 -0
- data/lib/lotu/{misc → helpers}/string.rb +0 -0
- data/lib/lotu/{misc → helpers}/vector2d.rb +1 -1
- data/lib/lotu/systems/animation_system.rb +3 -3
- data/lib/lotu/{system.rb → systems/base_system.rb} +3 -2
- data/lib/lotu/systems/collision_system.rb +1 -1
- data/lib/lotu/systems/{input_system.rb → input_manager_system.rb} +4 -4
- data/lib/lotu/systems/interpolation_system.rb +1 -1
- data/lib/lotu/systems/stalker_system.rb +1 -1
- data/lib/lotu/systems/steering_system.rb +2 -2
- data/lib/lotu/text_box.rb +8 -3
- data/lib/lotu.rb +6 -4
- data/lotu.gemspec +21 -15
- data/spec/lotu/actor_spec.rb +36 -0
- data/spec/lotu/game_spec.rb +22 -15
- data/spec/lotu/shared_spec.rb +41 -0
- metadata +25 -19
- data/lib/lotu/systems/fps_system.rb +0 -31
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.16
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
2
3
|
|
3
4
|
# Hello world for lotu
|
4
5
|
# Here you will learn about:
|
@@ -17,7 +18,6 @@ include Lotu
|
|
17
18
|
# subclass, set the image for all the instances of that class and
|
18
19
|
# define the movement methods
|
19
20
|
class Portrait < Actor
|
20
|
-
|
21
21
|
def initialize( opts )
|
22
22
|
# It's important to call super so we take advantage of automatic
|
23
23
|
# management for this object (being added to draw and update queues)
|
@@ -32,15 +32,15 @@ class Portrait < Actor
|
|
32
32
|
def move_left; @x -= 1 end
|
33
33
|
def move_up; @y -= 1 end
|
34
34
|
def move_down; @y += 1 end
|
35
|
-
|
36
35
|
end
|
37
36
|
|
38
37
|
# Let's subclass the Game class and write some code!
|
39
38
|
class MyPortraits < Game
|
39
|
+
use StalkerSystem, :stalk => [Actor, TextBox, Portrait, Object]
|
40
40
|
|
41
41
|
def initialize
|
42
42
|
# This will call the hooks:
|
43
|
-
# load_resources,
|
43
|
+
# load_resources, setup_actors, setup_input and setup_events
|
44
44
|
# declared in the parent class
|
45
45
|
super
|
46
46
|
# When the Escape key is pressed, call the close method on our
|
@@ -82,6 +82,8 @@ class MyPortraits < Game
|
|
82
82
|
@info = TextBox.new
|
83
83
|
# Add some text
|
84
84
|
@info.text("Hello world!")
|
85
|
+
@info.watch lambda{ "FPS: #{ fps }" }
|
86
|
+
@info.watch( @systems[StalkerSystem] )
|
85
87
|
# Add more text, but specify the color and size in pixels
|
86
88
|
@info.text("Move the portraits around with arrow keys", :size => 16, :color => 0xff33ccff)
|
87
89
|
end
|
@@ -14,26 +14,19 @@ include Lotu
|
|
14
14
|
|
15
15
|
# Create a class for displaying something on screen
|
16
16
|
class Lobo < Actor
|
17
|
-
def initialize(opts={})
|
17
|
+
def initialize( opts={} )
|
18
18
|
super
|
19
19
|
set_image 'lobo_tuerto.png', :width => 100
|
20
20
|
end
|
21
21
|
|
22
22
|
# Define a method for teleporting our instances around
|
23
|
-
def teleport(x, y)
|
23
|
+
def teleport( x, y )
|
24
24
|
@x, @y = x, y
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
class Cursors < Game
|
29
|
-
|
30
|
-
# This will call the hooks:
|
31
|
-
# load_resources, setup_systems, setup_input and setup_actors
|
32
|
-
# declared in the parent class
|
33
|
-
super
|
34
|
-
# Custom setup methods for this class
|
35
|
-
setup_events
|
36
|
-
end
|
29
|
+
use StalkerSystem, :stalk => [Actor, Cursor, TextBox, Lobo, Object]
|
37
30
|
|
38
31
|
def load_resources
|
39
32
|
with_path_from_file(__FILE__) do
|
@@ -41,19 +34,6 @@ class Cursors < Game
|
|
41
34
|
end
|
42
35
|
end
|
43
36
|
|
44
|
-
def setup_systems
|
45
|
-
# It's important to call super here to setup the InputSystem in
|
46
|
-
# the parent class
|
47
|
-
super
|
48
|
-
# To use the systems lotu provides, you just "use" them
|
49
|
-
# Let's activate the FPS system, so we can track the frames per
|
50
|
-
#second our app is pushing out
|
51
|
-
use(FpsSystem)
|
52
|
-
# Activate the stalker system to track how many objects of these
|
53
|
-
# classes are around
|
54
|
-
use(StalkerSystem, :stalk => [Actor, Cursor, TextBox, Lobo, Object])
|
55
|
-
end
|
56
|
-
|
57
37
|
# Setup some input handling for our Cursors app
|
58
38
|
def setup_input
|
59
39
|
set_keys(KbEscape => :close,
|
@@ -123,10 +103,10 @@ class Cursors < Game
|
|
123
103
|
@info = TextBox.new(:size => 15)
|
124
104
|
@info.text("Press F1 to hide this text", :size => 24)
|
125
105
|
# Watch the FPS, so we get a nice FPS report on the screen
|
126
|
-
@info.watch(
|
106
|
+
@info.watch(lambda{ "FPS: #{ fps }" }, :size => 20)
|
127
107
|
# Watch the Stalker system, so we know how many objects of the
|
128
|
-
# classes we specified up in
|
129
|
-
@info.watch(@systems[StalkerSystem], :color => 0xff3ffccf)
|
108
|
+
# classes we specified up in "use StalkerSystem" are around
|
109
|
+
@info.watch( @systems[StalkerSystem], :color => 0xff3ffccf )
|
130
110
|
# We can change the size for a specific line of text
|
131
111
|
@info.text("@cursor1 data:", :size => 20)
|
132
112
|
@info.text("move with Mouse | click with LeftMouseButton")
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
|
4
|
+
require File.expand_path(LIB_PATH)
|
5
|
+
|
6
|
+
include Lotu
|
7
|
+
include Gosu
|
8
|
+
|
9
|
+
class Box < Actor
|
10
|
+
collides_as :box
|
11
|
+
|
12
|
+
def initialize( opts )
|
13
|
+
# It's important to call super so we take advantage of automatic
|
14
|
+
# management for this object (being added to draw and update queues)
|
15
|
+
super
|
16
|
+
# Use the image which filename is "lobo_tuerto.png", and scale
|
17
|
+
# it's size to half width and half height
|
18
|
+
set_image 'lobo_tuerto.png', :factor_x => 0.5, :factor_y => 0.5
|
19
|
+
calc_radius
|
20
|
+
end
|
21
|
+
|
22
|
+
# Let's define some basic movement methods
|
23
|
+
def move_right; @x += 1 end
|
24
|
+
def move_left; @x -= 1 end
|
25
|
+
def move_up; @y -= 1 end
|
26
|
+
def move_down; @y += 1 end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Example < Game
|
30
|
+
use CollisionSystem
|
31
|
+
use StalkerSystem, :stalk => [Game, Box, Actor, BaseSystem, Object]
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
super
|
35
|
+
set_keys(KbEscape => :close,
|
36
|
+
KbD => [:debug!, false])
|
37
|
+
end
|
38
|
+
|
39
|
+
# This method is called when we call super inside initialize
|
40
|
+
def load_resources
|
41
|
+
# From this file,
|
42
|
+
with_path_from_file(__FILE__) do
|
43
|
+
# go back one dir and search inside media/images
|
44
|
+
load_images '../media/images'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def setup_events
|
49
|
+
when_colliding( :box, :box ) do |b1, b2|
|
50
|
+
b1.color = Gosu::Color.from_hsv(rand(360), 1, 1)
|
51
|
+
b2.color = Gosu::Color.from_hsv(rand(360), 1, 1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# This method is called when we call super inside initialize
|
56
|
+
def setup_actors
|
57
|
+
# Create a portrait in the middle of the screen
|
58
|
+
@lobo1 = Box.new(:x => width/2 - 100, :y => height/2)
|
59
|
+
# Map keys to some methods
|
60
|
+
@lobo1.set_keys(KbRight => :move_right,
|
61
|
+
KbLeft => :move_left,
|
62
|
+
KbUp => :move_up,
|
63
|
+
KbDown => :move_down)
|
64
|
+
|
65
|
+
# Rinse and repeat... but invert some keys
|
66
|
+
@lobo2 = Box.new(:x => width/2 + 100, :y => height/2)
|
67
|
+
@lobo2.set_keys(KbRight => :move_left,
|
68
|
+
KbLeft => :move_right,
|
69
|
+
KbUp => :move_up,
|
70
|
+
KbDown => :move_down)
|
71
|
+
|
72
|
+
# Create a TextBox so we can display a message on screen
|
73
|
+
@info = TextBox.new
|
74
|
+
# Add some text
|
75
|
+
@info.text("Hello world!")
|
76
|
+
@info.watch lambda{ "FPS: #{ fps }" }
|
77
|
+
@info.watch( @systems[StalkerSystem] )
|
78
|
+
# Add more text, but specify the color and size in pixels
|
79
|
+
@info.text("Move the portraits around with arrow keys", :size => 16, :color => 0xff33ccff)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
Example.new.show
|
@@ -14,12 +14,7 @@ include Lotu
|
|
14
14
|
# Let's define a Missile class that will use a Steering system to
|
15
15
|
# control it's movement
|
16
16
|
class Missile < Actor
|
17
|
-
|
18
|
-
super
|
19
|
-
# Activate the steering system and pass the opts, since they might
|
20
|
-
# have some config info for the system
|
21
|
-
use(SteeringSystem, opts)
|
22
|
-
end
|
17
|
+
use SteeringSystem
|
23
18
|
|
24
19
|
def teleport(x, y)
|
25
20
|
@pos.x, @pos.y = x, y
|
@@ -28,14 +23,7 @@ end
|
|
28
23
|
|
29
24
|
# The main app class
|
30
25
|
class SteeringMissiles < Game
|
31
|
-
|
32
|
-
# This will call the hooks:
|
33
|
-
# load_resources, setup_systems, setup_input and setup_actors
|
34
|
-
# declared in the parent class
|
35
|
-
super
|
36
|
-
# Custom setup methods for this class
|
37
|
-
setup_events
|
38
|
-
end
|
26
|
+
use StalkerSystem, :stalk => [Actor, Missile, Vector2d, Object]
|
39
27
|
|
40
28
|
# Let's load some images and animations, check out the animations
|
41
29
|
# directory, the animation there was created with:
|
@@ -54,13 +42,6 @@ class SteeringMissiles < Game
|
|
54
42
|
KbF1 => [:toggle_missile_info, false])
|
55
43
|
end
|
56
44
|
|
57
|
-
def setup_systems
|
58
|
-
# It's important to call super here to setup the InputSystem
|
59
|
-
super
|
60
|
-
use(FpsSystem)
|
61
|
-
use(StalkerSystem, :stalk => [Actor, Missile, Vector2d, Object])
|
62
|
-
end
|
63
|
-
|
64
45
|
def setup_actors
|
65
46
|
@big_missile = Missile.new(:mass => 0.3, :max_speed => 100, :max_turn_rate => 140)
|
66
47
|
@big_missile.teleport(width/2, height/2)
|
@@ -77,8 +58,8 @@ class SteeringMissiles < Game
|
|
77
58
|
|
78
59
|
@window_info = TextBox.new(:size => 15)
|
79
60
|
@window_info.text("Press F1 to hide this text", :size => 24)
|
80
|
-
@window_info.watch(
|
81
|
-
@window_info.watch(@systems[StalkerSystem], :color => 0xff33ccff)
|
61
|
+
@window_info.watch(lambda{ "FPS: #{fps}" }, :size => 20)
|
62
|
+
@window_info.watch( @systems[StalkerSystem], :color => 0xff33ccff)
|
82
63
|
@window_info.watch(@cursor, :color => @cursor.color)
|
83
64
|
@window_info.text("Click to start the simulation", :color => 0xffffff00)
|
84
65
|
@window_info.text("One will pursuit while the other evades, right click to center evader on screen")
|
@@ -14,12 +14,7 @@ include Lotu
|
|
14
14
|
# Let's define a Missile class that will use a Steering system to
|
15
15
|
# control it's movement
|
16
16
|
class Missile < Actor
|
17
|
-
|
18
|
-
super
|
19
|
-
# Activate the steering system and pass the opts, since they might
|
20
|
-
# have some config info for the system
|
21
|
-
use(SteeringSystem, opts)
|
22
|
-
end
|
17
|
+
use SteeringSystem
|
23
18
|
|
24
19
|
def teleport(x, y)
|
25
20
|
@pos.x, @pos.y = x, y
|
@@ -28,14 +23,7 @@ end
|
|
28
23
|
|
29
24
|
# The main app class
|
30
25
|
class EvadeMultiple < Game
|
31
|
-
|
32
|
-
# This will call the hooks:
|
33
|
-
# load_resources, setup_systems, setup_input and setup_actors
|
34
|
-
# declared in the parent class
|
35
|
-
super
|
36
|
-
# Custom setup methods for this class
|
37
|
-
setup_events
|
38
|
-
end
|
26
|
+
use StalkerSystem, :stalk => [Actor, Missile, Vector2d, Object]
|
39
27
|
|
40
28
|
# Let's load some images and animations, check out the animations
|
41
29
|
# directory, the animation there was created with:
|
@@ -55,13 +43,6 @@ class EvadeMultiple < Game
|
|
55
43
|
KbSpace => [:pause!, false])
|
56
44
|
end
|
57
45
|
|
58
|
-
def setup_systems
|
59
|
-
# It's important to call super here to setup the InputSystem
|
60
|
-
super
|
61
|
-
use(FpsSystem)
|
62
|
-
use(StalkerSystem, :stalk => [Actor, Missile, Vector2d, Object])
|
63
|
-
end
|
64
|
-
|
65
46
|
def setup_actors
|
66
47
|
@big_missile = Missile.new(:mass => 0.3, :max_speed => 100, :max_turn_rate => 140)
|
67
48
|
@big_missile.teleport(width/2, height/2)
|
@@ -81,8 +62,8 @@ class EvadeMultiple < Game
|
|
81
62
|
|
82
63
|
@window_info = TextBox.new(:size => 15)
|
83
64
|
@window_info.text("Press F1 to hide this text", :size => 24)
|
84
|
-
@window_info.watch(
|
85
|
-
@window_info.watch(@systems[StalkerSystem], :color => 0xff33ccff)
|
65
|
+
@window_info.watch(lambda{ "FPS: #{fps}" }, :size => 20)
|
66
|
+
@window_info.watch( @systems[StalkerSystem], :color => 0xff33ccff)
|
86
67
|
@window_info.watch(@cursor, :color => @cursor.color)
|
87
68
|
@window_info.text("Click to start the simulation", :color => 0xffffff00)
|
88
69
|
@window_info.text("Little missiles will pursuit while the big one evades, right click to center big one on screen")
|
data/lib/lotu/actor.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
module Lotu
|
2
2
|
class Actor
|
3
|
-
|
3
|
+
extend Behavior
|
4
|
+
|
5
|
+
behave_like SystemUser
|
6
|
+
use AnimationSystem
|
7
|
+
use InterpolationSystem
|
8
|
+
|
9
|
+
behave_like Eventful
|
10
|
+
behave_like Collidable
|
11
|
+
behave_like Controllable
|
12
|
+
|
13
|
+
attr_accessor :parent, :x, :y,
|
4
14
|
:z, :angle, :center_x, :center_y,
|
5
15
|
:factor_x, :factor_y, :color, :mode, :image,
|
6
16
|
:width, :height
|
7
17
|
|
8
|
-
include SystemUser
|
9
|
-
include Controllable
|
10
|
-
|
11
18
|
def initialize(opts={})
|
12
19
|
default_opts = {
|
13
20
|
:x => 0,
|
@@ -22,20 +29,17 @@ module Lotu
|
|
22
29
|
:mode => :default,
|
23
30
|
:parent => $lotu
|
24
31
|
}
|
32
|
+
|
25
33
|
opts = default_opts.merge!(opts)
|
26
34
|
@parent = opts[:parent]
|
27
35
|
@parent.manage_me(self)
|
28
36
|
set_image(opts[:image], opts) if opts[:image]
|
29
37
|
parse_options(opts)
|
30
38
|
@color = rand_color if opts[:rand_color]
|
31
|
-
|
32
39
|
set_keys(opts[:keys]) unless opts[:keys].nil?
|
33
40
|
|
34
|
-
#
|
35
|
-
|
36
|
-
self.extend Collidable
|
37
|
-
use(AnimationSystem)
|
38
|
-
use(InterpolationSystem)
|
41
|
+
# so it can start behaving
|
42
|
+
init_behavior opts
|
39
43
|
end
|
40
44
|
|
41
45
|
# Easy access to delta-time
|
@@ -118,12 +122,16 @@ module Lotu
|
|
118
122
|
end
|
119
123
|
|
120
124
|
def update
|
121
|
-
|
122
|
-
|
123
|
-
|
125
|
+
# to call update on behaviors (that in turn wil call
|
126
|
+
# update on systems, for example)
|
127
|
+
super
|
124
128
|
end
|
125
129
|
|
126
130
|
def draw
|
131
|
+
# to call draw on behaviors (that in turn will call
|
132
|
+
# draw on systems, for example)
|
133
|
+
super
|
134
|
+
|
127
135
|
unless @image.nil?
|
128
136
|
@image.draw_rot(@x, @y, @z, @angle, @center_x, @center_y, @factor_x*@zoom_x, @factor_y*@zoom_y, @color, @mode)
|
129
137
|
draw_debug if $lotu.debug?
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Lotu
|
2
|
+
module Behavior
|
3
|
+
|
4
|
+
def behave_like something
|
5
|
+
class << self
|
6
|
+
attr_accessor :behavior_options
|
7
|
+
end
|
8
|
+
include something
|
9
|
+
|
10
|
+
@behavior_options ||= Hash.new{ |h,k| h[k] = {} }
|
11
|
+
end
|
12
|
+
|
13
|
+
def inherited subclass
|
14
|
+
subclass.behavior_options =
|
15
|
+
behavior_options.inject({}){ |hash, opts| hash[opts[0]] = opts[1].deep_copy; hash }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -1,20 +1,35 @@
|
|
1
1
|
module Lotu
|
2
2
|
module Collidable
|
3
3
|
|
4
|
-
def self.
|
5
|
-
|
4
|
+
def self.included base
|
5
|
+
base.extend ClassMethods
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
@
|
8
|
+
def calc_radius
|
9
|
+
if @width
|
10
|
+
@collision_radius = @width/2.0 * @factor_x
|
11
|
+
elsif @height
|
12
|
+
@collision_radius = @height/2.0 * @factor_y
|
13
|
+
else
|
14
|
+
@collision_radius = 100
|
15
|
+
end
|
10
16
|
end
|
11
17
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
18
|
+
def init_behavior opts
|
19
|
+
super if defined? super
|
20
|
+
|
21
|
+
calc_radius
|
22
|
+
class << self
|
23
|
+
attr_accessor :collision_radius
|
24
|
+
end
|
25
|
+
|
26
|
+
@collision_tag = self.class.behavior_options[Collidable]
|
27
|
+
# TODO: Change @parent for @manager (could be a Game or a Scene)
|
28
|
+
@parent.systems[CollisionSystem].add_entity(self, @collision_tag) if @parent.systems[CollisionSystem]
|
15
29
|
end
|
16
30
|
|
17
31
|
def collides_with(other)
|
32
|
+
return false if self.equal? other
|
18
33
|
Gosu.distance(@x, @y, other.x, other.y) < @collision_radius + other.collision_radius
|
19
34
|
end
|
20
35
|
|
@@ -23,5 +38,11 @@ module Lotu
|
|
23
38
|
@parent.systems[CollisionSystem].remove_entity(self, @collision_tag) if @parent.systems[CollisionSystem]
|
24
39
|
end
|
25
40
|
|
41
|
+
module ClassMethods
|
42
|
+
def collides_as tag
|
43
|
+
behavior_options[Collidable] = tag
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
26
47
|
end
|
27
48
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Lotu
|
2
|
+
module ResourceManager
|
3
|
+
|
4
|
+
attr_accessor :images, :sounds, :songs, :animations, :default_font
|
5
|
+
|
6
|
+
def init_behavior opts
|
7
|
+
super if defined? super
|
8
|
+
@images = {}
|
9
|
+
@sounds = {}
|
10
|
+
@songs = {}
|
11
|
+
@animations = Hash.new{ |h,k| h[k] = [] }
|
12
|
+
@default_font = Hash.new{ |h,k| h[k] = Gosu::Font.new( self, Gosu::default_font_name, k ) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def image( name )
|
16
|
+
@images[name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def sound( name )
|
20
|
+
@sounds[name]
|
21
|
+
end
|
22
|
+
|
23
|
+
def song( name )
|
24
|
+
@songs[name]
|
25
|
+
end
|
26
|
+
|
27
|
+
def animation(name)
|
28
|
+
@animations[name]
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_path_from_file(path, &blk)
|
32
|
+
@path = File.expand_path(File.dirname path)
|
33
|
+
instance_eval &blk
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
def load_images( path )
|
38
|
+
count = 0
|
39
|
+
with_files(/\.png$|\.jpg$|\.bmp$/, path) do |file_name, file_path|
|
40
|
+
@images[file_name] = Gosu::Image.new($lotu, file_path)
|
41
|
+
count += 1
|
42
|
+
end
|
43
|
+
puts "\n#{count} image(s) loaded."
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_sounds(path)
|
47
|
+
count = 0
|
48
|
+
with_files(/\.ogg$|\.mp3$|\.wav$/, path) do |file_name, file_path|
|
49
|
+
@sounds[file_name] = Gosu::Sample.new($lotu, file_path)
|
50
|
+
count += 1
|
51
|
+
end
|
52
|
+
puts "\n#{count} sounds(s) loaded."
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_songs(path)
|
56
|
+
count = 0
|
57
|
+
with_files(/\.ogg$|\.mp3$|\.wav$/, path) do |file_name, file_path|
|
58
|
+
@songs[file_name] = Gosu::Song.new($lotu, file_path)
|
59
|
+
count += 1
|
60
|
+
end
|
61
|
+
puts "\n#{count} song(s) loaded."
|
62
|
+
end
|
63
|
+
|
64
|
+
def load_animations(path)
|
65
|
+
count = 0
|
66
|
+
coords = Hash.new{|h,k| h[k] = []}
|
67
|
+
|
68
|
+
with_files(/\.txt$/, path) do |file_name, file_path|
|
69
|
+
name = File.basename(file_name, '.txt')
|
70
|
+
File.open(file_path) do |file|
|
71
|
+
file.lines.each do |line|
|
72
|
+
coords[name] << line.scan(/\d+/).map!(&:to_i)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
with_files(/\.png$|\.jpg$|\.bmp$/, path) do |file_name, file_path|
|
79
|
+
name, extension = file_name.split('.')
|
80
|
+
coords[name].each do |index, x, y, width, height|
|
81
|
+
@animations[file_name] << Gosu::Image.new($lotu, file_path, true, x, y, width, height)
|
82
|
+
end
|
83
|
+
count += 1 if coords[name]
|
84
|
+
end
|
85
|
+
puts "\n#{count} animation(s) loaded."
|
86
|
+
end
|
87
|
+
|
88
|
+
def with_files(regexp, path)
|
89
|
+
path = File.expand_path(File.join(@path, path))
|
90
|
+
puts "\nLoading from: #{path}".blue if @debug
|
91
|
+
|
92
|
+
Dir.entries(path).grep(regexp).each do |entry|
|
93
|
+
begin
|
94
|
+
report = yield(entry, File.join(path, entry))
|
95
|
+
print '.'.green if report
|
96
|
+
rescue Exception => e
|
97
|
+
print '.'.red
|
98
|
+
puts e, File.join(path, entry) if @debug
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -1,10 +1,48 @@
|
|
1
1
|
module Lotu
|
2
2
|
module SystemUser
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
attr_accessor :systems
|
5
|
+
|
6
|
+
def self.included base
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def init_behavior user_opts
|
11
|
+
super if defined? super
|
6
12
|
@systems ||= Hash.new
|
7
|
-
|
13
|
+
|
14
|
+
options_for_me = self.class.behavior_options[SystemUser]
|
15
|
+
|
16
|
+
options_for_me && options_for_me.each do |klass, options|
|
17
|
+
# add the behavior options to the user_opts hash
|
18
|
+
# in case we need access to some level class config param
|
19
|
+
user_opts.merge!(options)
|
20
|
+
@systems[klass] = klass.new( self, user_opts )
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Need to call this inside update
|
25
|
+
def update
|
26
|
+
super if defined? super
|
27
|
+
@systems.each_value do |system|
|
28
|
+
system.update
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Need to call this inside draw
|
33
|
+
def draw
|
34
|
+
super if defined? super
|
35
|
+
# Systems may report interesting stuff
|
36
|
+
@systems.each_value do |system|
|
37
|
+
system.draw
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Allows to activate a system in the host
|
42
|
+
module ClassMethods
|
43
|
+
def use( klass, opts={} )
|
44
|
+
behavior_options[SystemUser][klass] = opts
|
45
|
+
end
|
8
46
|
end
|
9
47
|
|
10
48
|
end
|