lotu 0.1.11 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.11
1
+ 0.1.12
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Hello world for lotu
4
+ # Here you will learn about:
5
+ # * Loading image resources
6
+ # * Binding keys to window and actors
7
+ # * How to display text on screen using a text box
8
+
9
+
10
+ LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
11
+ require File.expand_path(LIB_PATH)
12
+
13
+ include Gosu
14
+ include Lotu
15
+
16
+ # We want to move something around the screen so we create a new Actor
17
+ # subclass, set the image all instances of it are going to use and
18
+ # define the movement methods
19
+ class Lobo < Actor
20
+
21
+ def initialize(opts={})
22
+ # It's important to call super so we take advantage of automatic
23
+ # management for this object (being added to draw and update queue)
24
+ super
25
+ # Use the image which filename is "lobo_tuerto.png", and scale
26
+ # it's appearance to half width and half height
27
+ set_image 'lobo_tuerto.png', :factor_x => 0.5, :factor_y => 0.5
28
+ end
29
+
30
+ # Let's define some basic movement methods
31
+ def move_right; @x += 1 end
32
+ def move_left; @x -= 1 end
33
+ def move_up; @y -= 1 end
34
+ def move_down; @y += 1 end
35
+
36
+ end
37
+
38
+ # Let's subclass the Game class and write some code!
39
+ class Portraits < Game
40
+
41
+ def initialize
42
+ # This will call the hooks:
43
+ # load_resources, setup_systems, setup_input and setup_actors
44
+ # declared in the parent class
45
+ super
46
+ # When the Escape key is pressed, call the close method on
47
+ # instance of class Portraits, when D key is pressed turn on
48
+ # debug, we pass false into the array to tell the input system we
49
+ # don't want autofire on, else pass the number of milliseconds
50
+ # (zero and no array is the same)
51
+ set_keys(KbEscape => :close,
52
+ KbD => [:debug!, false])
53
+ end
54
+
55
+ # This method is called when we call super inside initialize
56
+ def load_resources
57
+ # From this file,
58
+ with_path_from_file(__FILE__) do
59
+ # go back one dir and search inside media/images
60
+ load_images '../media/images'
61
+ end
62
+ end
63
+
64
+ # This method is called when we call super inside initialize
65
+ def setup_actors
66
+ # Create a lobo in the middle of the screen
67
+ @lobo1 = Lobo.new(:x => width/2, :y => height/2)
68
+ # Map keys to some methods
69
+ @lobo1.set_keys(KbRight => :move_right,
70
+ KbLeft => :move_left,
71
+ KbUp => :move_up,
72
+ KbDown => :move_down)
73
+
74
+ # Rinse and repeat... but invert some keys
75
+ @lobo2 = Lobo.new(:x => width/2, :y => height/2)
76
+ @lobo2.set_keys(KbRight => :move_left,
77
+ KbLeft => :move_right,
78
+ KbUp => :move_up,
79
+ KbDown => :move_down)
80
+
81
+ # Create a TextBox so we can display a message on screen
82
+ @info = TextBox.new
83
+ # Add some text
84
+ @info.text("Hello world!")
85
+ # Add more text, but specify the color and size in pixels
86
+ @info.text("Move the portraits around with arrow keys", :size => 16, :color => 0xff33ccff)
87
+ end
88
+
89
+ end
90
+
91
+ # Create and show the app
92
+ Portraits.new.show
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # lotu's cursors
4
+ # Here you will learn about:
5
+ # * The Cursor class included in lotu
6
+ # * How to register events
7
+ # * How to use the systems provided by lotu
8
+
9
+ LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
10
+ require File.expand_path(LIB_PATH)
11
+
12
+ include Gosu
13
+ include Lotu
14
+
15
+ # Create a class for displaying something on screen
16
+ class Lobo < Actor
17
+ def initialize(opts={})
18
+ super
19
+ set_image 'lobo_tuerto.png', :width => 100
20
+ end
21
+
22
+ # Define a method for teleporting our instances around
23
+ def teleport(x, y)
24
+ @x, @y = x, y
25
+ end
26
+ end
27
+
28
+ class Cursors < Game
29
+ def initialize
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
37
+
38
+ def load_resources
39
+ with_path_from_file(__FILE__) do
40
+ load_images '../media/images'
41
+ end
42
+ end
43
+
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
+ # Setup some input handling for our Cursors app
58
+ def setup_input
59
+ set_keys(KbEscape => :close,
60
+ KbD => [:debug!, false],
61
+ KbT => [:toggle_text, false])
62
+ end
63
+
64
+ # Now onto define some events
65
+ def setup_events
66
+ # When the left mouse button is clicked (as defined below in
67
+ # setup_actors) call the teleport method in @lobo
68
+ @cursor1.on(:click) do |x,y|
69
+ @lobo.teleport(x,y)
70
+ end
71
+ # When the space bar is pressed (see below in setup_actors) call
72
+ # the teleport method in @lobo
73
+ @cursor2.on(:click) do |x,y|
74
+ @lobo.teleport(x,y)
75
+ end
76
+ end
77
+
78
+ def setup_actors
79
+ # Create a portrait to teleport around with "clicks"
80
+ @lobo = Lobo.new(:x => width/2, :y => height/2)
81
+
82
+ # The cursor class defines a method named (you guessed) "click",
83
+ # when this method is called, it fires an event named (again)
84
+ # "click", that's why we attached some code to that event in
85
+ # setup_events
86
+ @cursor1 = Cursor.new(:image => 'crosshair-1.png',
87
+ :keys => {MsLeft => [:click, false]},
88
+ :width => 100,
89
+ :rand_color => true,
90
+ :mode => :additive)
91
+ @cursor1.transform_angle(:init => 0, :end => 359, :duration => 10, :loop => true)
92
+
93
+ @cursor2 = Cursor.new(:image => 'crosshair-2.png',
94
+ :use_mouse => false,
95
+ :keys => {
96
+ KbSpace => [:click, false],
97
+ KbUp => :up,
98
+ KbDown => :down,
99
+ KbLeft => :left,
100
+ KbRight => :right},
101
+ :width => 100,
102
+ :rand_color => true,
103
+ :mode => :additive)
104
+ @cursor2.transform_angle(:init => 359, :end => 0, :duration => 1, :loop => true)
105
+
106
+ # Center @cursor2 vertically and move it to the right 3/4 of the
107
+ # screen
108
+ @cursor2.x = width*3/4
109
+ @cursor2.y = height/2
110
+
111
+ # Here we tell the TextBox to watch some objects, the TextBox will
112
+ # call the to_s method on the objects it's watching
113
+ # Create a TextBox with default option :size => 15
114
+ @info = TextBox.new(:size => 15)
115
+ @info.text("Press T to hide this text", :size => 24)
116
+ # Watch the FPS, so we get a nice FPS report on the screen
117
+ @info.watch(@systems[FpsSystem], :size => 20)
118
+ # Watch the Stalker system, so we know how many objects of the
119
+ # classes we specified up in setup_systems are around
120
+ @info.watch(@systems[StalkerSystem], :color => 0xff3ffccf)
121
+ # We can change the size for a specific line of text
122
+ @info.text("@cursor1 data:", :size => 20)
123
+ @info.text("move with Mouse | click with LeftMouseButton")
124
+ # And color
125
+ @info.watch(@cursor1, :color => @cursor1.color)
126
+
127
+ # Lets watch @cursor2 too
128
+ @info.text("@cursor2 data:", :size => 20)
129
+ @info.text("move with Arrow keys | click with Space")
130
+ @info.watch(@cursor2, :color => @cursor2.color)
131
+ @info.text("click to teleport the portrait!")
132
+ end
133
+
134
+ def toggle_text
135
+ @info.toggle!
136
+ end
137
+
138
+ end
139
+
140
+ # Create and start the game loop by showing the app
141
+ Cursors.new.show
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Here you will learn about:
4
+ # * The steering system
5
+ # * How to play animations
6
+ # * How to attach a text box to an actor
7
+
8
+ LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
9
+ require File.expand_path(LIB_PATH)
10
+
11
+ include Gosu
12
+ include Lotu
13
+
14
+ # Let's define a Missile class that will use a Steering system to
15
+ # control it's movement
16
+ class Missile < Actor
17
+ def initialize(opts={})
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
23
+
24
+ def teleport(x, y)
25
+ @pos.x, @pos.y = x, y
26
+ end
27
+ end
28
+
29
+ # The main app class
30
+ class SteeringMissiles < Game
31
+ def initialize
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
39
+
40
+ # Let's load some images and animations, check out the animations
41
+ # directory, the animation there was created with:
42
+ # {Sprite Sheet Packer}[http://spritesheetpacker.codeplex.com/]
43
+ def load_resources
44
+ with_path_from_file(__FILE__) do
45
+ load_images '../media/images'
46
+ load_animations '../media/animations'
47
+ end
48
+ end
49
+
50
+ def setup_input
51
+ set_keys(KbEscape => :close,
52
+ MsRight => :teleport_big_missile_to_midscreen,
53
+ KbD => [:debug!, false],
54
+ KbT => [:toggle_missile_info, false])
55
+ end
56
+
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
+ def setup_actors
65
+ @big_missile = Missile.new(:mass => 0.3, :max_speed => 100, :max_turn_rate => 140)
66
+ @big_missile.teleport(width/2, height/2)
67
+ @big_missile.activate(:evade)
68
+ @big_missile.play_animation('missile.png')
69
+
70
+ @little_missile = Missile.new
71
+ @little_missile.activate(:pursuit)
72
+ @little_missile.play_animation('missile.png', :fps => 60, :height => 20)
73
+
74
+ @cursor = Cursor.new(:image => 'crosshair-3.png',
75
+ :keys => {MsLeft => [:click, false]},
76
+ :rand_color => true)
77
+
78
+ @window_info = TextBox.new(:size => 15)
79
+ @window_info.text("Press T to hide this text", :size => 24)
80
+ @window_info.watch(@systems[FpsSystem], :size => 20)
81
+ @window_info.watch(@systems[StalkerSystem], :color => 0xff33ccff)
82
+ @window_info.watch(@cursor, :color => @cursor.color)
83
+ @window_info.text("Click to start the simulation", :color => 0xffffff00)
84
+ @window_info.text("One will pursuit while the other evades, right click to center evader on screen")
85
+
86
+ @missile_info = TextBox.new(:attach_to => @big_missile, :size => 14)
87
+ @missile_info.watch(@big_missile)
88
+ end
89
+
90
+ def setup_events
91
+ @cursor.on(:click) do |x,y|
92
+ @big_missile.pursuer = @little_missile
93
+ @little_missile.evader = @big_missile
94
+ end
95
+ end
96
+
97
+ def teleport_big_missile_to_midscreen
98
+ @big_missile.pos.x = width/2
99
+ @big_missile.pos.y = height/2
100
+ end
101
+
102
+ def toggle_missile_info
103
+ @missile_info.toggle!
104
+ @window_info.toggle!
105
+ end
106
+ end
107
+
108
+ # Create and start the application
109
+ SteeringMissiles.new.show
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Here you will learn about:
4
+ # * The steering system pursuit, and evade_multiple behaviors
5
+ # * How to play animations
6
+ # * How to attach a text box to an actor
7
+
8
+ LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
9
+ require File.expand_path(LIB_PATH)
10
+
11
+ include Gosu
12
+ include Lotu
13
+
14
+ # Let's define a Missile class that will use a Steering system to
15
+ # control it's movement
16
+ class Missile < Actor
17
+ def initialize(opts={})
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
23
+
24
+ def teleport(x, y)
25
+ @pos.x, @pos.y = x, y
26
+ end
27
+ end
28
+
29
+ # The main app class
30
+ class EvadeMultiple < Game
31
+ def initialize
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
39
+
40
+ # Let's load some images and animations, check out the animations
41
+ # directory, the animation there was created with:
42
+ # {Sprite Sheet Packer}[http://spritesheetpacker.codeplex.com/]
43
+ def load_resources
44
+ with_path_from_file(__FILE__) do
45
+ load_images '../media/images'
46
+ load_animations '../media/animations'
47
+ end
48
+ end
49
+
50
+ def setup_input
51
+ set_keys(KbEscape => :close,
52
+ MsRight => :teleport_big_missile_to_midscreen,
53
+ KbD => [:debug!, false],
54
+ KbT => [:toggle_info, false],
55
+ KbSpace => [:pause!, false])
56
+ end
57
+
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
+ def setup_actors
66
+ @big_missile = Missile.new(:mass => 0.3, :max_speed => 100, :max_turn_rate => 140)
67
+ @big_missile.teleport(width/2, height/2)
68
+ @big_missile.activate(:evade_multiple)
69
+ @big_missile.play_animation('missile.png')
70
+
71
+ @little_missiles = []
72
+ 5.times do |i|
73
+ @little_missiles << Missile.new(:x => 200 - rand(400), :y => 200 - rand(400), :rand_color => true)
74
+ @little_missiles[i].activate(:pursuit)
75
+ @little_missiles[i].play_animation('missile.png', :fps => 60+rand(60), :height => 10+rand(30))
76
+ end
77
+
78
+ @cursor = Cursor.new(:image => 'crosshair-3.png',
79
+ :keys => {MsLeft => [:click, false]},
80
+ :rand_color => true)
81
+
82
+ @window_info = TextBox.new(:size => 15)
83
+ @window_info.text("Press T to hide this text", :size => 24)
84
+ @window_info.watch(@systems[FpsSystem], :size => 20)
85
+ @window_info.watch(@systems[StalkerSystem], :color => 0xff33ccff)
86
+ @window_info.watch(@cursor, :color => @cursor.color)
87
+ @window_info.text("Click to start the simulation", :color => 0xffffff00)
88
+ @window_info.text("Little missiles will pursuit while the big one evades, right click to center big one on screen")
89
+
90
+ @missile_info = TextBox.new(:attach_to => @big_missile, :size => 14)
91
+ @missile_info.watch(@big_missile)
92
+ end
93
+
94
+ def setup_events
95
+ @cursor.on(:click) do |x,y|
96
+ @big_missile.pursuers = @little_missiles
97
+ @little_missiles.each do |lil_missile|
98
+ lil_missile.evader = @big_missile
99
+ end
100
+ end
101
+ end
102
+
103
+ def teleport_big_missile_to_midscreen
104
+ @big_missile.pos.x = width/2
105
+ @big_missile.pos.y = height/2
106
+ end
107
+
108
+ def toggle_info
109
+ @missile_info.toggle!
110
+ @window_info.toggle!
111
+ end
112
+
113
+ end
114
+
115
+ # Create and start the application
116
+ EvadeMultiple.new.show
data/lib/lotu/actor.rb CHANGED
@@ -27,12 +27,16 @@ module Lotu
27
27
  @parent.manage_me(self)
28
28
  set_image(opts[:image], opts) if opts[:image]
29
29
  parse_options(opts)
30
+ @color = rand_color if opts[:rand_color]
30
31
  @systems = {}
31
32
 
33
+ set_keys(opts[:keys]) unless opts[:keys].nil?
34
+
32
35
  # Add extra functionality
33
36
  self.extend Eventful
34
37
  self.extend Collidable
35
38
  use(AnimationSystem)
39
+ use(TransformationSystem)
36
40
  end
37
41
 
38
42
  # Easy access to delta-time
@@ -50,36 +54,60 @@ module Lotu
50
54
  @factor_x = opts[:factor_x] || @factor_x
51
55
  @factor_y = opts[:factor_y] || @factor_y
52
56
  @color = opts[:color] || @color
57
+ if @color.kind_of?(Integer)
58
+ @color = Gosu::Color.new(opts[:color])
59
+ end
53
60
  @mode = opts[:mode] || @mode
54
61
  end
55
62
 
63
+ def rand_color
64
+ Gosu::Color.from_hsv(rand(360), 1, 1)
65
+ end
66
+
56
67
  def set_image(image, opts={})
57
68
  @image = @parent.image(image)
58
- puts "Image \"#{image}\" not found".red if @image.nil?
69
+ if @image.nil?
70
+ puts "Image \"#{image}\" not found".red
71
+ return
72
+ end
59
73
  parse_options(opts)
60
- @width = opts[:width] || @image.width
61
- @height = opts[:height] || @image.height
74
+ adjust_width_and_height(opts)
62
75
  calc_zoom
63
76
  end
64
77
 
65
78
  def set_gosu_image(image, opts={})
66
79
  @image = image
67
80
  parse_options(opts)
68
- @width = opts[:width] || @image.width
69
- @height = opts[:height] || @image.height
81
+ adjust_width_and_height(opts)
70
82
  calc_zoom
71
83
  end
72
84
 
73
85
  def width=(width)
74
- @width = width
86
+ @width = Float(width)
75
87
  calc_zoom
76
88
  end
77
89
 
78
90
  def height=(height)
79
- @height = height
91
+ @height = Float(height)
80
92
  calc_zoom
81
93
  end
82
94
 
95
+ def adjust_width_and_height(opts)
96
+ if(opts[:width] && opts[:height])
97
+ @width = Float(opts[:width])
98
+ @height = Float(opts[:height])
99
+ elsif(opts[:width])
100
+ @width = Float(opts[:width])
101
+ @height = @width * @image.height / @image.width
102
+ elsif(opts[:height])
103
+ @height = Float(opts[:height])
104
+ @width = @height * @image.width / @image.height
105
+ else
106
+ @width = Float(@image.width)
107
+ @height = Float(@image.height)
108
+ end
109
+ end
110
+
83
111
  def calc_zoom
84
112
  @zoom_x = Float(@width)/@image.width
85
113
  @zoom_y = Float(@height)/@image.height
@@ -97,8 +125,10 @@ module Lotu
97
125
  end
98
126
 
99
127
  def draw
100
- @image.draw_rot(@x, @y, @z, @angle, @center_x, @center_y, @factor_x*@zoom_x, @factor_y*@zoom_y, @color, @mode) unless @image.nil?
101
- draw_debug if $lotu.debug? unless @image.nil?
128
+ unless @image.nil?
129
+ @image.draw_rot(@x, @y, @z, @angle, @center_x, @center_y, @factor_x*@zoom_x, @factor_y*@zoom_y, @color, @mode)
130
+ draw_debug if $lotu.debug?
131
+ end
102
132
  end
103
133
 
104
134
  def draw_debug
data/lib/lotu/cursor.rb CHANGED
@@ -7,7 +7,7 @@ module Lotu
7
7
  def initialize(opts={})
8
8
  default_opts = {
9
9
  :use_mouse => true,
10
- :speed => 100,
10
+ :speed => 300,
11
11
  :x => $lotu.width/2,
12
12
  :y => $lotu.height/2
13
13
  }
@@ -18,10 +18,10 @@ module Lotu
18
18
  @clicked_x = @clicked_y = 0
19
19
  @speed = opts[:speed]
20
20
  @use_mouse = opts[:use_mouse]
21
- set_keys(opts[:keys]) unless opts[:keys].nil?
22
21
  end
23
22
 
24
23
  def update
24
+ super
25
25
  if @use_mouse
26
26
  @x = $lotu.mouse_x
27
27
  @y = $lotu.mouse_y
data/lib/lotu/game.rb CHANGED
@@ -7,12 +7,18 @@ module Lotu
7
7
 
8
8
  include SystemUser
9
9
 
10
- def initialize(params={})
11
- super(800, 600, false)
10
+ def initialize(opts={})
11
+ default_opts = {
12
+ :width => 1024,
13
+ :height => 768,
14
+ :fullscreen => false
15
+ }
16
+ opts = default_opts.merge!(opts)
17
+ super(opts[:width], opts[:height], opts[:fullscreen])
12
18
 
13
19
  # Handy global window variable
14
20
  $lotu = self
15
- @debug = false
21
+ @debug = opts[:debug] || false
16
22
  setup_containers
17
23
 
18
24
  # For timer initialization
@@ -27,6 +33,14 @@ module Lotu
27
33
  setup_input
28
34
  end
29
35
 
36
+ def pause!
37
+ @pause = !@pause
38
+ end
39
+
40
+ def paused?
41
+ @pause
42
+ end
43
+
30
44
  def debug!
31
45
  @debug = !@debug
32
46
  end
@@ -75,7 +89,7 @@ module Lotu
75
89
  # Update each actor
76
90
  @update_queue.each do |actor|
77
91
  actor.update
78
- end
92
+ end unless paused?
79
93
  end
80
94
 
81
95
  # Main draw loop
@@ -140,24 +154,34 @@ module Lotu
140
154
  end
141
155
 
142
156
  def load_images(path)
157
+ count = 0
143
158
  with_files(/\.png|\.jpg|\.bmp/, path) do |file_name, file_path|
159
+ count += 1
144
160
  @images[file_name] = Gosu::Image.new($lotu, file_path)
145
161
  end
162
+ puts "\n#{count} image(s) loaded."
146
163
  end
147
164
 
148
165
  def load_sounds(path)
166
+ count = 0
149
167
  with_files(/\.ogg|\.mp3|\.wav/, path) do |file_name, file_path|
168
+ count += 1
150
169
  @sounds[file_name] = Gosu::Sample.new($lotu, file_path)
151
170
  end
171
+ puts "\n#{count} sounds(s) loaded."
152
172
  end
153
173
 
154
174
  def load_songs(path)
175
+ count = 0
155
176
  with_files(/\.ogg|\.mp3|\.wav/, path) do |file_name, file_path|
177
+ count += 1
156
178
  @songs[file_name] = Gosu::Song.new($lotu, file_path)
157
179
  end
180
+ puts "\n#{count} song(s) loaded."
158
181
  end
159
182
 
160
183
  def load_animations(path)
184
+ count = 0
161
185
  coords = Hash.new{|h,k| h[k] = []}
162
186
 
163
187
  with_files(/\.txt/, path) do |file_name, file_path|
@@ -167,14 +191,17 @@ module Lotu
167
191
  coords[name] << line.scan(/\d+/).map!(&:to_i)
168
192
  end
169
193
  end
194
+ false
170
195
  end
171
196
 
172
197
  with_files(/\.png|\.jpg|\.bmp/, path) do |file_name, file_path|
173
198
  name, extension = file_name.split('.')
199
+ count += 1 if coords[name]
174
200
  coords[name].each do |index, x, y, width, height|
175
201
  @animations[file_name] << Gosu::Image.new($lotu, file_path, true, x, y, width, height)
176
202
  end
177
203
  end
204
+ puts "\n#{count} animation(s) loaded."
178
205
  end
179
206
 
180
207
  def with_path_from_file(path, &blk)
@@ -184,20 +211,17 @@ module Lotu
184
211
 
185
212
  def with_files(regexp, path)
186
213
  path = File.expand_path(File.join(@path, path))
187
- puts "\nLoading from: #{path}"
214
+ puts "\nLoading from: #{path}".blue if @debug
188
215
 
189
- count = 0
190
216
  Dir.entries(path).grep(regexp).each do |entry|
191
217
  begin
192
- yield(entry, File.join(path, entry))
193
- count += 1
194
- print '.'.green
218
+ report = yield(entry, File.join(path, entry))
219
+ print '.'.green if report
195
220
  rescue Exception => e
196
221
  print '.'.red
197
222
  puts e, File.join(path, entry) if @debug
198
223
  end
199
224
  end
200
- puts "\n#{count} file(s) loaded."
201
225
  end
202
226
 
203
227
  end
@@ -135,6 +135,23 @@ module Lotu
135
135
  return flee
136
136
  end
137
137
 
138
+ def evade_multiple
139
+ return @zero if @user.pursuers.empty?
140
+ combined_velocities = Vector2d.new
141
+ combined_positions = Vector2d.new
142
+ @user.pursuers.each do |p|
143
+ combined_velocities += p.vel
144
+ combined_positions += p.pos
145
+ end
146
+ combined_velocities /= @user.pursuers.length
147
+ combined_positions /= @user.pursuers.length
148
+ to_pursuers = combined_positions - @user.pos
149
+ look_ahead_time = to_pursuers.length / (@user.max_speed + combined_velocities.length)
150
+ predicted_position = combined_positions + combined_velocities * look_ahead_time
151
+ @user.target = combined_positions
152
+ return flee
153
+ end
154
+
138
155
  # TODO: Fix wander
139
156
  def wander
140
157
  wander_jitter = 10
@@ -166,9 +183,11 @@ module Lotu
166
183
  attr_accessor :mass, :pos, :heading, :vel, :accel,
167
184
  :max_speed, :max_turn_rate, :max_force,
168
185
  :wander_radius, :wander_distance, :wander_target,
169
- :target, :evader, :pursuer
186
+ :target, :evader, :pursuer, :pursuers
170
187
  end
171
188
 
189
+ # TODO: move these inside the SteeringSystem?
190
+ # and just delegate with accessors?
172
191
  # Some defaults
173
192
  @pos = Vector2d.new(@x, @y)
174
193
  offset_x = Gosu.offset_x(@angle, 1)
@@ -177,6 +196,13 @@ module Lotu
177
196
  @vel = Vector2d.new
178
197
  @accel = Vector2d.new
179
198
  @wander_target = Vector2d.new
199
+ @pursuers = []
200
+
201
+ @colors = {
202
+ :position => 0xff666666,
203
+ :heading => 0xffff0000,
204
+ :target => rand_color
205
+ }
180
206
  end
181
207
 
182
208
  def activate(behavior)
@@ -191,15 +217,11 @@ module Lotu
191
217
  @heading.facing_to?(@target - @pos)
192
218
  end
193
219
 
194
- def draw
195
- super
196
- draw_debug if $lotu.debug?
197
- end
198
-
199
220
  def draw_debug
200
- $lotu.draw_line(0, 0, 0xff999999, @pos.x, @pos.y, 0xff333333)
201
- $lotu.draw_line(@pos.x, @pos.y, 0xffffffff, (@pos + @heading*50).x, (@pos+@heading*50).y, 0xffff0000)
202
- $lotu.draw_line(@pos.x, @pos.y, 0xffffffff, @target.x, @target.y, 0xff00ff00) if @target
221
+ super
222
+ $lotu.draw_line(0, 0, @colors[:position], @pos.x, @pos.y, @colors[:position])
223
+ $lotu.draw_line(@pos.x, @pos.y, @colors[:heading], (@pos + @heading*50).x, (@pos+@heading*50).y, @colors[:heading])
224
+ $lotu.draw_line(@pos.x, @pos.y, @colors[:target], @target.x, @target.y, @colors[:target]) if @target
203
225
  end
204
226
 
205
227
  # to_s utility methods
@@ -0,0 +1,122 @@
1
+ module Lotu
2
+ class TransformationSystem < System
3
+
4
+ def initialize(user, opts={})
5
+ super
6
+ user.extend(UserMethods)
7
+ @transformations = []
8
+ @tagged_for_deletion = []
9
+ end
10
+
11
+ def transform(object, property, opts)
12
+ transformation = {
13
+ :object => object,
14
+ :property_getter => property,
15
+ :property_setter => "#{property}=",
16
+ :accum_time => 0,
17
+ :calc => 0,
18
+ :init => opts[:init],
19
+ :end => opts[:end],
20
+ :duration => opts[:duration] || 1,
21
+ :start_in => opts[:start_in] || 0,
22
+ :on_result => opts[:on_result],
23
+ :loop => opts[:loop]
24
+ }
25
+ @transformations << transformation
26
+ end
27
+
28
+ def update
29
+ @transformations.each do |t|
30
+ t[:accum_time] += dt
31
+ if t[:accum_time] > t[:start_in]
32
+ step = (t[:end] - t[:init])/t[:duration] * dt
33
+ t[:calc] += step
34
+ if step > 0
35
+ if t[:init] + t[:calc] > t[:end]
36
+ if t[:loop]
37
+ t[:calc] = 0
38
+ else
39
+ t[:calc] = t[:end] - t[:init]
40
+ tag_for_deletion(t)
41
+ end
42
+ end
43
+ else
44
+ if t[:init] + t[:calc] < t[:end]
45
+ if t[:loop]
46
+ t[:calc] = 0
47
+ else
48
+ t[:calc] = t[:end] - t[:init]
49
+ tag_for_deletion(t)
50
+ end
51
+ end
52
+ end
53
+ value = t[:init] + t[:calc]
54
+ value = value.send(t[:on_result]) if t[:on_result]
55
+ t[:object].send(t[:property_setter], value)
56
+ end
57
+ end
58
+
59
+ @tagged_for_deletion.each do |to_delete|
60
+ @transformations.delete(to_delete)
61
+ end.clear
62
+ end
63
+
64
+ def tag_for_deletion(transform)
65
+ @tagged_for_deletion << transform
66
+ end
67
+
68
+ def to_s
69
+ ["@transformations.length #{@transformations.length}",
70
+ "@tagged_for_deletion.length #{@tagged_for_deletion.length}"]
71
+ end
72
+
73
+ module UserMethods
74
+ def transform(object, property, opts)
75
+ @systems[TransformationSystem].transform(object, property, opts)
76
+ end
77
+
78
+ # Image helpers
79
+ def transform_angle(opts)
80
+ transform(self, :angle, opts)
81
+ end
82
+
83
+ def transform_width(opts)
84
+ transform(self, :width, opts)
85
+ end
86
+
87
+ def transform_height(opts)
88
+ transform(self, :height, opts)
89
+ end
90
+
91
+ # Color helpers
92
+ def transform_alpha(opts)
93
+ transform(@color, :alpha, opts.merge!(:on_result => :to_i))
94
+ end
95
+
96
+ def transform_red(opts)
97
+ transform(@color, :red, opts.merge!(:on_result => :to_i))
98
+ end
99
+
100
+ def transform_green(opts)
101
+ transform(@color, :green, opts.merge!(:on_result => :to_i))
102
+ end
103
+
104
+ def transform_blue(opts)
105
+ transform(@color, :blue, opts.merge!(:on_result => :to_i))
106
+ end
107
+
108
+ def transform_hue(opts)
109
+ transform(@color, :hue, opts)
110
+ end
111
+
112
+ def transform_saturation(opts)
113
+ transform(@color, :saturation, opts)
114
+ end
115
+
116
+ def transform_value(opts)
117
+ transform(@color, :value, opts)
118
+ end
119
+ end
120
+
121
+ end
122
+ end
data/lib/lotu/text_box.rb CHANGED
@@ -13,21 +13,32 @@ module Lotu
13
13
  @watch_list = []
14
14
  @size = opts[:size]
15
15
  @attached_to = opts[:attach_to]
16
+ @hiding = false
16
17
  end
17
18
 
18
- def text(text, opts={})
19
- watch(text, opts)
19
+ def hide!
20
+ @hiding = true
21
+ end
22
+
23
+ def show!
24
+ @hiding = false
25
+ end
26
+
27
+ def toggle!
28
+ @hiding = !@hiding
20
29
  end
21
30
 
22
31
  def watch(subject, opts={})
23
32
  @watch_list << [subject, opts]
24
33
  end
34
+ alias :text :watch
25
35
 
26
36
  def attach_to(actor)
27
37
  @attached_to = actor
28
38
  end
29
39
 
30
40
  def update
41
+ return if @hiding
31
42
  unless @attached_to.nil?
32
43
  @x = @attached_to.x + @attached_to.image.width / 2
33
44
  @y = @attached_to.y - @attached_to.image.height / 2
@@ -35,6 +46,7 @@ module Lotu
35
46
  end
36
47
 
37
48
  def draw
49
+ return if @hiding
38
50
  pos_y = 0
39
51
  @watch_list.each do |watched, opts|
40
52
  my_size = opts[:size] || @size
data/lib/lotu.rb CHANGED
@@ -5,4 +5,4 @@ require 'gosu'
5
5
  %w{vector2d string}.each{|file| require "misc/#{file}"}
6
6
  %w{system_user collidable controllable eventful}.each{|file| require "behaviors/#{file}"}
7
7
  %w{game system actor cursor text_box}.each{|file| require file}
8
- %w{animation_system input_system stalker_system fps_system collision_system steering_system}.each{|file| require "systems/#{file}"}
8
+ %w{transformation_system animation_system input_system stalker_system fps_system collision_system steering_system}.each{|file| require "systems/#{file}"}
data/lotu.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{lotu}
8
- s.version = "0.1.11"
8
+ s.version = "0.1.12"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["lobo_tuerto"]
12
- s.date = %q{2010-03-27}
12
+ s.date = %q{2010-03-28}
13
13
  s.description = %q{lotu aims to bring an agile and simple game development framework to life. It provides useful abstractions so you can concentrate on developing your game.}
14
14
  s.email = %q{dev@lobotuerto.com}
15
15
  s.extra_rdoc_files = [
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
  "README.rdoc",
25
25
  "Rakefile",
26
26
  "VERSION",
27
- "examples/hello_world/hello_world.rb",
27
+ "examples/hello_world/moving_portraits.rb",
28
28
  "examples/media/animations/missile.png",
29
29
  "examples/media/animations/missile.txt",
30
30
  "examples/media/images/cohete-big.png",
@@ -36,8 +36,9 @@ Gem::Specification.new do |s|
36
36
  "examples/media/images/lobo_tuerto.png",
37
37
  "examples/media/images/missile-med.png",
38
38
  "examples/media/images/silo.png",
39
- "examples/mouse_pointer/mouse_pointer.rb",
40
- "examples/steering_behaviors/steering.rb",
39
+ "examples/screen_cursor/mouse_and_keyboard_cursors.rb",
40
+ "examples/steering_behaviors/pursuit_and_evade.rb",
41
+ "examples/steering_behaviors/pursuit_and_evade_multiple.rb",
41
42
  "lib/lotu.rb",
42
43
  "lib/lotu/actor.rb",
43
44
  "lib/lotu/behaviors/collidable.rb",
@@ -55,6 +56,7 @@ Gem::Specification.new do |s|
55
56
  "lib/lotu/systems/input_system.rb",
56
57
  "lib/lotu/systems/stalker_system.rb",
57
58
  "lib/lotu/systems/steering_system.rb",
59
+ "lib/lotu/systems/transformation_system.rb",
58
60
  "lib/lotu/text_box.rb",
59
61
  "lotu.gemspec",
60
62
  "test/actor_test.rb"
@@ -66,9 +68,10 @@ Gem::Specification.new do |s|
66
68
  s.summary = %q{A simple, agile Ruby game development framework.}
67
69
  s.test_files = [
68
70
  "test/actor_test.rb",
69
- "examples/steering_behaviors/steering.rb",
70
- "examples/hello_world/hello_world.rb",
71
- "examples/mouse_pointer/mouse_pointer.rb"
71
+ "examples/steering_behaviors/pursuit_and_evade.rb",
72
+ "examples/steering_behaviors/pursuit_and_evade_multiple.rb",
73
+ "examples/hello_world/moving_portraits.rb",
74
+ "examples/screen_cursor/mouse_and_keyboard_cursors.rb"
72
75
  ]
73
76
 
74
77
  if s.respond_to? :specification_version then
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 11
9
- version: 0.1.11
8
+ - 12
9
+ version: 0.1.12
10
10
  platform: ruby
11
11
  authors:
12
12
  - lobo_tuerto
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-27 00:00:00 -06:00
17
+ date: 2010-03-28 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -48,7 +48,7 @@ files:
48
48
  - README.rdoc
49
49
  - Rakefile
50
50
  - VERSION
51
- - examples/hello_world/hello_world.rb
51
+ - examples/hello_world/moving_portraits.rb
52
52
  - examples/media/animations/missile.png
53
53
  - examples/media/animations/missile.txt
54
54
  - examples/media/images/cohete-big.png
@@ -60,8 +60,9 @@ files:
60
60
  - examples/media/images/lobo_tuerto.png
61
61
  - examples/media/images/missile-med.png
62
62
  - examples/media/images/silo.png
63
- - examples/mouse_pointer/mouse_pointer.rb
64
- - examples/steering_behaviors/steering.rb
63
+ - examples/screen_cursor/mouse_and_keyboard_cursors.rb
64
+ - examples/steering_behaviors/pursuit_and_evade.rb
65
+ - examples/steering_behaviors/pursuit_and_evade_multiple.rb
65
66
  - lib/lotu.rb
66
67
  - lib/lotu/actor.rb
67
68
  - lib/lotu/behaviors/collidable.rb
@@ -79,6 +80,7 @@ files:
79
80
  - lib/lotu/systems/input_system.rb
80
81
  - lib/lotu/systems/stalker_system.rb
81
82
  - lib/lotu/systems/steering_system.rb
83
+ - lib/lotu/systems/transformation_system.rb
82
84
  - lib/lotu/text_box.rb
83
85
  - lotu.gemspec
84
86
  - test/actor_test.rb
@@ -115,6 +117,7 @@ specification_version: 3
115
117
  summary: A simple, agile Ruby game development framework.
116
118
  test_files:
117
119
  - test/actor_test.rb
118
- - examples/steering_behaviors/steering.rb
119
- - examples/hello_world/hello_world.rb
120
- - examples/mouse_pointer/mouse_pointer.rb
120
+ - examples/steering_behaviors/pursuit_and_evade.rb
121
+ - examples/steering_behaviors/pursuit_and_evade_multiple.rb
122
+ - examples/hello_world/moving_portraits.rb
123
+ - examples/screen_cursor/mouse_and_keyboard_cursors.rb
@@ -1,77 +0,0 @@
1
- #!/usr/bin/env ruby
2
- LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
3
- require File.expand_path(LIB_PATH)
4
-
5
- include Gosu::Button
6
- include Lotu
7
-
8
- class MovingRuby < Actor
9
-
10
- def initialize(opts={})
11
- super
12
- # Use the image which filename is CptnRuby Gem.png
13
- set_image 'lobo_tuerto.png', :factor_x => 0.5, :factor_y => 0.5
14
- end
15
-
16
- # Let's define some basic movement methods
17
- def move_right
18
- @x += 1
19
- end
20
-
21
- def move_left
22
- @x -= 1
23
- end
24
-
25
- def move_up
26
- @y -= 1
27
- end
28
-
29
- def move_down
30
- @y += 1
31
- end
32
-
33
- end
34
-
35
- class Example < Game
36
-
37
- def initialize
38
- # This will call the hooks:
39
- # load_resources, setup_systems and setup_actors
40
- # declared in the parent class
41
- super
42
- # When the Escape key is pressed, call the close method on class Example
43
- set_keys(KbEscape => :close,
44
- KbD => [:debug!, false])
45
- end
46
-
47
- def load_resources
48
- # From this file,
49
- with_path_from_file(__FILE__) do
50
- # go back one dir and search inside media/
51
- load_images '../media/images'
52
- end
53
- end
54
-
55
- def setup_actors
56
- # Create a ruby in the middle of the screen
57
- @ruby = MovingRuby.new(:x => width/2, :y => height/2)
58
- # Map keys to some methods
59
- @ruby.set_keys(KbRight => :move_right,
60
- KbLeft => :move_left,
61
- KbUp => :move_up,
62
- KbDown => :move_down)
63
- @ruby2 = MovingRuby.new(:x => width/2, :y => height/2)
64
- # Map keys to some methods
65
- @ruby2.set_keys(KbRight => :move_left,
66
- KbLeft => :move_right,
67
- KbUp => :move_up,
68
- KbDown => :move_down)
69
- # Create a TextBox so we can display a message on screen
70
- @info = TextBox.new
71
- @info.text("Hello world!")
72
- @info.text("Move around with arrow keys", :size => 16, :color => 0xff33ccff)
73
- end
74
-
75
- end
76
-
77
- Example.new.show
@@ -1,92 +0,0 @@
1
- #!/usr/bin/env ruby
2
- LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
3
- require File.expand_path(LIB_PATH)
4
-
5
- include Gosu::Button
6
- include Lotu
7
-
8
- class WarpingRuby < Actor
9
- def initialize(opts={})
10
- super
11
- set_image 'lobo_tuerto.png', :factor_x => 0.3, :factor_y => 0.3
12
- end
13
-
14
- def warp(x, y)
15
- @x, @y = x, y
16
- end
17
- end
18
-
19
- class Example < Game
20
- def initialize
21
- # This will call the hooks:
22
- # load_resources, setup_systems and setup_actors
23
- # declared in the parent class
24
- super
25
- # Custom setup methods for this class
26
- setup_events
27
- end
28
-
29
- def load_resources
30
- with_path_from_file(__FILE__) do
31
- load_images '../media/images'
32
- end
33
- end
34
-
35
- def setup_systems
36
- # It's important to call super here to setup the InputSystem
37
- super
38
- use(FpsSystem)
39
- use(StalkerSystem, :stalk => [Actor, Cursor, TextBox, WarpingRuby, Object])
40
- end
41
-
42
- def setup_input
43
- set_keys(KbEscape => :close,
44
- KbD => [:debug!, false])
45
- end
46
-
47
- def setup_events
48
- @cursor1.on(:click) do |x,y|
49
- @ruby.warp(x,y)
50
- end
51
- @cursor2.on(:click) do |x,y|
52
- @ruby.warp(x,y)
53
- end
54
- end
55
-
56
- def setup_actors
57
- @ruby = WarpingRuby.new(:x => width/2, :y => height/2)
58
- @cursor1 = Cursor.new(:image => 'crosshair-1.png',
59
- :keys => {MsLeft => [:click, false]},
60
- :color => 0xff0099ff,
61
- :width => 100,
62
- :height => 100)
63
- @cursor2 = Cursor.new(:image => 'crosshair-2.png',
64
- :use_mouse => false,
65
- :keys => {
66
- KbSpace => [:click, false],
67
- KbUp => :up,
68
- KbDown => :down,
69
- KbLeft => :left,
70
- KbRight => :right},
71
- :color => 0xff99ff00,
72
- :factor_x => 0.5,
73
- :factor_y => 0.5)
74
- @cursor2.x = width*3/4
75
- @cursor2.y = height/2
76
-
77
- # Create a TextBox with default option :size => 15
78
- @info = TextBox.new(:size => 15)
79
- @info.watch(@systems[FpsSystem])
80
- @info.watch(@systems[StalkerSystem], :color => 0xff3ffccf)
81
- # We can change the size for a specific line of text
82
- @info.watch("@cursor1 data:", :size => 20)
83
- # Color too
84
- @info.watch(@cursor1, :color => 0xff0099ff)
85
- @info.watch("@cursor2 data:", :size => 20)
86
- @info.watch(@cursor2, :color => 0xff99ff00)
87
- @info.text("Move @cursor1 with mouse and @cursor2 with arrow keys (click with space!)")
88
- end
89
-
90
- end
91
-
92
- Example.new.show
@@ -1,86 +0,0 @@
1
- #!/usr/bin/env ruby
2
- LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
3
- require File.expand_path(LIB_PATH)
4
-
5
- include Gosu::Button
6
- include Lotu
7
-
8
- class SteeringRuby < Actor
9
- def initialize(opts={})
10
- super
11
- use(SteeringSystem, opts)
12
- end
13
-
14
- def warp(x, y)
15
- @pos.x, @pos.y = x, y
16
- end
17
- end
18
-
19
- class Example < Game
20
- def initialize
21
- # This will call the hooks:
22
- # load_resources, setup_systems and setup_actors
23
- # declared in the parent class
24
- super
25
- # Custom setup methods for this class
26
- setup_events
27
- end
28
-
29
- def load_resources
30
- with_path_from_file(__FILE__) do
31
- load_images '../media/images'
32
- load_animations '../media/animations'
33
- end
34
- end
35
-
36
- def setup_input
37
- set_keys(KbEscape => :close,
38
- MsRight => :reset_ruby,
39
- KbD => [:debug!, false])
40
- end
41
-
42
- def setup_systems
43
- # It's important to call super here to setup the InputSystem
44
- super
45
- use(FpsSystem)
46
- use(StalkerSystem, :stalk => [Actor, Vector2d, Object])
47
- end
48
-
49
- def setup_actors
50
- @ruby = SteeringRuby.new(:mass => 0.3, :max_speed => 100, :max_turn_rate => 140)
51
- @ruby.warp(width/2, height/2)
52
- @ruby.activate(:evade)
53
- @ruby.play_animation('missile.png')
54
-
55
- @ruby2 = SteeringRuby.new
56
- @ruby2.activate(:pursuit)
57
- @ruby2.play_animation('missile.png', :factor_x => 0.5, :factor_y => 0.5, :fps => 60)
58
-
59
- @cursor = Cursor.new(:image => 'crosshair-1.png',
60
- :keys => {MsLeft => [:click, false]})
61
-
62
- @window_info = TextBox.new(:size => 15)
63
- @window_info.watch(@systems[FpsSystem])
64
- @window_info.watch(@systems[StalkerSystem])
65
- @window_info.watch(@cursor, :color => 0xffff0000)
66
- @window_info.text("Click to start the simulation")
67
- @window_info.text("One will pursuit while the other evades, right click to center evader on screen")
68
-
69
- @ruby_info = TextBox.new(:attach_to => @ruby, :size => 14)
70
- @ruby_info.watch(@ruby)
71
- end
72
-
73
- def setup_events
74
- @cursor.on(:click) do |x,y|
75
- @ruby.pursuer = @ruby2
76
- @ruby2.evader = @ruby
77
- end
78
- end
79
-
80
- def reset_ruby
81
- @ruby.pos.x = width/2
82
- @ruby.pos.y = height/2
83
- end
84
- end
85
-
86
- Example.new.show