lotu 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +19 -9
- data/TODO +4 -0
- data/VERSION +1 -1
- data/examples/hello_world/hello_world.rb +3 -8
- data/examples/mouse_pointer/mouse_pointer.rb +14 -9
- data/examples/steering_behaviors/steering.rb +56 -0
- data/lib/lotu/actor.rb +15 -2
- data/lib/lotu/behaviors/drawable.rb +15 -4
- data/lib/lotu/behaviors/resourceful.rb +1 -3
- data/lib/lotu/cursor.rb +4 -0
- data/lib/lotu/{fps.rb → misc/fps.rb} +1 -5
- data/lib/lotu/misc/vector2d.rb +124 -0
- data/lib/lotu/systems/steering.rb +198 -0
- data/lib/lotu/text_box.rb +54 -0
- data/lib/lotu/window.rb +3 -3
- data/lib/lotu.rb +3 -2
- data/lotu.gemspec +11 -5
- metadata +11 -4
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
== Development just started!
|
2
|
-
So bear with me while this framework is in a primordial state. But fear not, it's shaping up pretty nicely! :D
|
3
|
-
|
4
1
|
= lotu
|
5
2
|
A simple, agile Ruby game development framework.
|
6
3
|
|
7
4
|
== Install
|
5
|
+
The preferred way to try it out is cloning from github:
|
6
|
+
|
7
|
+
git clone git://github.com/lobo-tuerto/lotu.git
|
8
|
+
|
9
|
+
The is a gem right now, but while the API stabilizes it is not updated as often as the github repo.
|
10
|
+
|
8
11
|
gem install lotu
|
9
12
|
|
10
13
|
== Description
|
@@ -23,17 +26,24 @@ So, what can you do if you spot some patters here, a few more there? well, you d
|
|
23
26
|
If you have any questions of suggestions don't hesitate and send me a message!
|
24
27
|
|
25
28
|
|
26
|
-
== Features
|
27
|
-
* Easy way to manage input, rendering, updating, etc.
|
28
|
-
*
|
29
|
-
*
|
29
|
+
== Features
|
30
|
+
* Easy way to manage input, rendering, updating, etc.
|
31
|
+
* Simple access to game resources (images, sounds, songs, etc).
|
32
|
+
* Steering behaviors
|
33
|
+
|
34
|
+
|
35
|
+
== Coming features
|
36
|
+
* Utility classes for viewports, game states, etc.
|
37
|
+
* Pathfinding and more AI stuff
|
30
38
|
|
31
39
|
|
32
40
|
== Other frameworks
|
33
|
-
I saw another framework around called Chingu
|
34
|
-
It's been around for a little while and I recommend you take a look at it:
|
41
|
+
I saw another framework around called *Chingu*, It's been around for a little while and I recommend you take a look at it:
|
35
42
|
http://github.com/ippa/chingu
|
36
43
|
|
44
|
+
There is also *gamebox*, it's based on Rubygame though:
|
45
|
+
http://github.com/shawn42/gamebox
|
46
|
+
|
37
47
|
I did find many of the ideas I have for my framework already implemented in it. But be sure I will take inspiration from many others. ;)
|
38
48
|
Nevertheless I'm doing this because I want to become better at architecturing software. And this seems like fitting practice. :D
|
39
49
|
|
data/TODO
ADDED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
@@ -5,7 +5,7 @@ include Gosu::Button
|
|
5
5
|
|
6
6
|
class MovingRuby < Lotu::Actor
|
7
7
|
|
8
|
-
def initialize
|
8
|
+
def initialize(opts={})
|
9
9
|
super
|
10
10
|
set_image 'CptnRuby Gem.png'
|
11
11
|
set_keys(KbRight => :move_right,
|
@@ -36,18 +36,13 @@ class Example < Lotu::Window
|
|
36
36
|
|
37
37
|
def initialize
|
38
38
|
super
|
39
|
-
set_keys
|
39
|
+
set_keys(KbEscape => :close)
|
40
40
|
|
41
41
|
with_path(__FILE__) do
|
42
42
|
load_images '../media'
|
43
43
|
end
|
44
44
|
|
45
|
-
@ruby = MovingRuby.new
|
46
|
-
end
|
47
|
-
|
48
|
-
def draw
|
49
|
-
super
|
50
|
-
@fps_counter.draw
|
45
|
+
@ruby = MovingRuby.new(:x => width/2, :y => height/2)
|
51
46
|
end
|
52
47
|
|
53
48
|
end
|
@@ -25,7 +25,8 @@ class Example < Lotu::Window
|
|
25
25
|
|
26
26
|
@ruby = WarpingRuby.new
|
27
27
|
@cursor1 = Lotu::Cursor.new(:image => 'crosshair.png',
|
28
|
-
:keys => {MsLeft => [:click, false]}
|
28
|
+
:keys => {MsLeft => [:click, false]},
|
29
|
+
:color => 0xff0099ff)
|
29
30
|
@cursor2 = Lotu::Cursor.new(:image => 'crosshair.png',
|
30
31
|
:use_mouse => false,
|
31
32
|
:keys => {
|
@@ -33,8 +34,8 @@ class Example < Lotu::Window
|
|
33
34
|
KbUp => :up,
|
34
35
|
KbDown => :down,
|
35
36
|
KbLeft => :left,
|
36
|
-
KbRight => :right
|
37
|
-
|
37
|
+
KbRight => :right},
|
38
|
+
:color => 0xff99ff00)
|
38
39
|
|
39
40
|
@cursor1.on(:click) do |x,y|
|
40
41
|
@ruby.warp(x,y)
|
@@ -42,14 +43,18 @@ class Example < Lotu::Window
|
|
42
43
|
@cursor2.on(:click) do |x,y|
|
43
44
|
@ruby.warp(x,y)
|
44
45
|
end
|
45
|
-
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@
|
51
|
-
@
|
47
|
+
@cursor2.x = width*3/4
|
48
|
+
@cursor2.y = height/2
|
49
|
+
|
50
|
+
@info = Lotu::TextBox.new
|
51
|
+
@info.watch(@fps_counter)
|
52
|
+
@info.watch("@cursor1 data:")
|
53
|
+
@info.watch(@cursor1, :color => 0xff0099ff, :font_size => 15)
|
54
|
+
@info.watch("@cursor2 data:")
|
55
|
+
@info.watch(@cursor2, :color => 0xff99ff00, :font_size => 15)
|
52
56
|
end
|
57
|
+
|
53
58
|
end
|
54
59
|
|
55
60
|
Example.new.show
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
LIB_PATH = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'lotu.rb')
|
3
|
+
require File.expand_path(LIB_PATH)
|
4
|
+
include Gosu::Button
|
5
|
+
|
6
|
+
class SteeringRuby < Lotu::Actor
|
7
|
+
def initialize(opts={})
|
8
|
+
super
|
9
|
+
set_image 'CptnRuby Gem.png'
|
10
|
+
activate_system(Lotu::Steering, opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def warp(x, y)
|
14
|
+
@pos.x, @pos.y = x, y
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Example < Lotu::Window
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
set_keys(KbEscape => :close,
|
22
|
+
MsRight => :reset_ruby)
|
23
|
+
|
24
|
+
with_path __FILE__ do
|
25
|
+
load_images '../media'
|
26
|
+
end
|
27
|
+
|
28
|
+
@ruby = SteeringRuby.new(:mass => 0.3, :max_speed => 100, :max_turn_rate => 140)
|
29
|
+
@ruby.warp(width/2, height/2)
|
30
|
+
@ruby.activate(:evade)
|
31
|
+
|
32
|
+
@ruby2 = SteeringRuby.new
|
33
|
+
@ruby2.activate(:pursuit)
|
34
|
+
|
35
|
+
@cursor = Lotu::Cursor.new(:image => 'crosshair.png',
|
36
|
+
:keys => {MsLeft => [:click, false]})
|
37
|
+
@cursor.on(:click) do |x,y|
|
38
|
+
@ruby.pursuer = @ruby2#Lotu::Vector2d.new(x, y)
|
39
|
+
@ruby2.evader = @ruby
|
40
|
+
end
|
41
|
+
|
42
|
+
@window_info = Lotu::TextBox.new
|
43
|
+
@window_info.watch(@fps_counter)
|
44
|
+
@window_info.watch(@cursor, :color => 0xffff0000)
|
45
|
+
|
46
|
+
@ruby_info = Lotu::TextBox.new(:attach_to => @ruby, :font_size => 16)
|
47
|
+
@ruby_info.watch(@ruby)
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset_ruby
|
51
|
+
@ruby.pos.x = width/2
|
52
|
+
@ruby.pos.y = height/2
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Example.new.show
|
data/lib/lotu/actor.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Lotu
|
2
2
|
class Actor
|
3
|
-
attr_accessor :parent, :x, :y
|
3
|
+
attr_accessor :parent, :x, :y, :systems
|
4
4
|
|
5
5
|
def initialize(opts={})
|
6
6
|
default_opts = {
|
@@ -20,6 +20,8 @@ module Lotu
|
|
20
20
|
self.extend Controllable
|
21
21
|
self.extend Eventful
|
22
22
|
self.extend Collidable
|
23
|
+
|
24
|
+
@systems = {}
|
23
25
|
end
|
24
26
|
|
25
27
|
# Easy access to delta-time
|
@@ -32,6 +34,17 @@ module Lotu
|
|
32
34
|
@parent.update_queue.delete(self)
|
33
35
|
end
|
34
36
|
|
35
|
-
def
|
37
|
+
def activate_system(klass, opts={})
|
38
|
+
@systems[klass] = klass.new(self, opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
def update
|
42
|
+
@systems.each_pair do |klass, system|
|
43
|
+
system.update
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def draw;end
|
48
|
+
|
36
49
|
end
|
37
50
|
end
|
@@ -6,25 +6,36 @@ module Lotu
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def init_behavior
|
9
|
+
class << self
|
10
|
+
attr_accessor :angle
|
11
|
+
end
|
12
|
+
|
9
13
|
@image = nil
|
10
|
-
@color = 0xffffffff
|
11
14
|
@z = 0
|
12
15
|
@angle = 0.0
|
13
16
|
@center_x = 0.5
|
14
17
|
@center_y = 0.5
|
15
18
|
@factor_x = 1.0
|
16
19
|
@factor_y = 1.0
|
17
|
-
@color = 0xffffffff
|
18
20
|
@mode = :default
|
19
21
|
end
|
20
22
|
|
23
|
+
def draw_me
|
24
|
+
@parent.draw_queue << self unless @parent.draw_queue.include?(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def image
|
28
|
+
@image
|
29
|
+
end
|
30
|
+
|
21
31
|
def set_image(image)
|
22
32
|
@image = @parent.image(image)
|
23
|
-
|
33
|
+
draw_me
|
24
34
|
end
|
25
35
|
|
26
36
|
def draw
|
27
|
-
|
37
|
+
super
|
38
|
+
@image.draw_rot(@x, @y, @z, @angle, @center_x, @center_y, @factor_x, @factor_y, @color, @mode) unless @image.nil?
|
28
39
|
end
|
29
40
|
|
30
41
|
def die
|
@@ -46,9 +46,7 @@ module Lotu
|
|
46
46
|
puts "Loading from: #{path}"
|
47
47
|
|
48
48
|
count = 0
|
49
|
-
Dir.entries(path).
|
50
|
-
entry =~ regexp
|
51
|
-
end.each do |entry|
|
49
|
+
Dir.entries(path).grep(regexp).each do |entry|
|
52
50
|
begin
|
53
51
|
container[entry] = klass.new($window, File.join(path, entry))
|
54
52
|
count += 1
|
data/lib/lotu/cursor.rb
CHANGED
@@ -22,11 +22,7 @@ class FpsCounter
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def draw
|
26
|
-
$window.font.draw("FPS: #{to_s}", 10, 10, 0, 1.0, 1.0, 0xffffff00)
|
27
|
-
end
|
28
|
-
|
29
25
|
def to_s
|
30
|
-
"
|
26
|
+
"@samples(#{@samples}) @fps(#{format("%.2f",@fps)}) @objs(#{@objs}) @actors(#{@actors}) @inputs(#{@inputs})"
|
31
27
|
end
|
32
28
|
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Lotu
|
2
|
+
class Vector2d
|
3
|
+
attr_reader :x, :y
|
4
|
+
|
5
|
+
def self.up
|
6
|
+
new(0, -1)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(x=0, y=0)
|
10
|
+
clear_cache
|
11
|
+
@x = Float(x)
|
12
|
+
@y = Float(y)
|
13
|
+
end
|
14
|
+
|
15
|
+
def clear_cache
|
16
|
+
@length = nil
|
17
|
+
@length_sq = nil
|
18
|
+
@normalized = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def zero!
|
22
|
+
self.x = 0
|
23
|
+
self.y = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def zero?
|
27
|
+
@x == 0 && @y == 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def length
|
31
|
+
@length ||= Math.sqrt(length_sq)
|
32
|
+
end
|
33
|
+
|
34
|
+
def length_sq
|
35
|
+
@length_sq ||= @x*@x + @y*@y
|
36
|
+
end
|
37
|
+
|
38
|
+
def x=(x)
|
39
|
+
clear_cache
|
40
|
+
@x = Float(x)
|
41
|
+
end
|
42
|
+
|
43
|
+
def y=(y)
|
44
|
+
clear_cache
|
45
|
+
@y = Float(y)
|
46
|
+
end
|
47
|
+
|
48
|
+
def normalize
|
49
|
+
if zero?
|
50
|
+
Vector2d.new(0,0)
|
51
|
+
else
|
52
|
+
Vector2d.new(@x/length, @y/length)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def normalize!
|
57
|
+
if zero?
|
58
|
+
@length = 0
|
59
|
+
@length_sq = 0
|
60
|
+
@normalized = true
|
61
|
+
end
|
62
|
+
|
63
|
+
return self if @normalized
|
64
|
+
@x /= length
|
65
|
+
@y /= length
|
66
|
+
clear_cache
|
67
|
+
@normalized = true
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def +(v)
|
72
|
+
Vector2d.new(@x+v.x, @y+v.y)
|
73
|
+
end
|
74
|
+
|
75
|
+
def -(v)
|
76
|
+
Vector2d.new(@x-v.x, @y-v.y)
|
77
|
+
end
|
78
|
+
|
79
|
+
def /(n)
|
80
|
+
Vector2d.new(@x/n, @y/n)
|
81
|
+
end
|
82
|
+
|
83
|
+
def *(n)
|
84
|
+
Vector2d.new(@x*n, @y*n)
|
85
|
+
end
|
86
|
+
|
87
|
+
def truncate!(max_l)
|
88
|
+
return self if length < max_l
|
89
|
+
normalize!
|
90
|
+
self.x *= max_l
|
91
|
+
self.y *= max_l
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def dot(v)
|
96
|
+
@x*v.x + @y*v.y
|
97
|
+
end
|
98
|
+
|
99
|
+
def perp
|
100
|
+
Vector2d.new(@y, -@x)
|
101
|
+
end
|
102
|
+
|
103
|
+
def angle
|
104
|
+
Gosu.angle(0, 0, @x, @y)
|
105
|
+
end
|
106
|
+
|
107
|
+
def angle_to(v)
|
108
|
+
Gosu.angle_diff(angle, v.angle)
|
109
|
+
end
|
110
|
+
|
111
|
+
def sign_to(v)
|
112
|
+
if @y * v.x > @x * v.y
|
113
|
+
return -1
|
114
|
+
else
|
115
|
+
return 1
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_s
|
120
|
+
format('%.2f, %.2f', @x, @y)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Lotu
|
3
|
+
class Steering
|
4
|
+
attr_reader :force
|
5
|
+
|
6
|
+
def initialize(actor, opts={})
|
7
|
+
# Add new functionality to Actor
|
8
|
+
actor.extend ActorMethods
|
9
|
+
|
10
|
+
# Initialize attributes
|
11
|
+
default_opts = {
|
12
|
+
:mass => 1,
|
13
|
+
:max_speed => 350,
|
14
|
+
:max_turn_rate => 180,
|
15
|
+
:max_force => 300,
|
16
|
+
:wander_radius => 120,
|
17
|
+
:wander_distance => 240.0
|
18
|
+
}
|
19
|
+
opts = default_opts.merge!(opts)
|
20
|
+
|
21
|
+
actor.mass = opts[:mass]
|
22
|
+
actor.max_speed = opts[:max_speed]
|
23
|
+
actor.max_turn_rate = opts[:max_turn_rate]
|
24
|
+
actor.max_force = opts[:max_force]
|
25
|
+
actor.wander_radius = opts[:wander_radius]
|
26
|
+
actor.wander_distance = opts[:wander_distance]
|
27
|
+
|
28
|
+
# More attributes
|
29
|
+
@actor = actor
|
30
|
+
@behaviors = {}
|
31
|
+
@force = Vector2d.new
|
32
|
+
@zero = Vector2d.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def update
|
36
|
+
@force.zero!
|
37
|
+
@behaviors.each_pair do |behavior, active|
|
38
|
+
@force += send(behavior) if active
|
39
|
+
end
|
40
|
+
|
41
|
+
@actor.accel = @force / @actor.mass
|
42
|
+
@actor.accel.truncate!(@actor.max_force)
|
43
|
+
|
44
|
+
max_angle = @actor.max_turn_rate * @actor.dt
|
45
|
+
new_velocity = @actor.vel + @actor.accel * @actor.dt
|
46
|
+
angle_to_new_velocity = @actor.heading.angle_to(new_velocity)
|
47
|
+
|
48
|
+
if angle_to_new_velocity.abs > max_angle
|
49
|
+
sign = @actor.heading.sign_to(new_velocity)
|
50
|
+
corrected_angle = @actor.heading.angle + max_angle * sign
|
51
|
+
@actor.vel.x = Gosu.offset_x(corrected_angle, new_velocity.length)
|
52
|
+
@actor.vel.y = Gosu.offset_y(corrected_angle, new_velocity.length)
|
53
|
+
else
|
54
|
+
@actor.vel = new_velocity
|
55
|
+
end
|
56
|
+
|
57
|
+
@actor.vel.truncate!(@actor.max_speed)
|
58
|
+
@actor.pos += @actor.vel * @actor.dt
|
59
|
+
|
60
|
+
if @actor.vel.length > 0.0001
|
61
|
+
@actor.heading = @actor.vel.normalize
|
62
|
+
end
|
63
|
+
|
64
|
+
@actor.x = @actor.pos.x
|
65
|
+
@actor.y = @actor.pos.y
|
66
|
+
@actor.angle = @actor.heading.angle
|
67
|
+
end
|
68
|
+
|
69
|
+
def activate(behavior)
|
70
|
+
@behaviors[behavior] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
def deactivate(behavior)
|
74
|
+
@behaviors[behavior] = false
|
75
|
+
end
|
76
|
+
|
77
|
+
# The steering behaviors themselves
|
78
|
+
def seek
|
79
|
+
return @zero if @actor.target.nil?
|
80
|
+
desired_velocity = (@actor.target - @actor.pos).normalize * @actor.max_speed
|
81
|
+
return desired_velocity - @actor.vel
|
82
|
+
end
|
83
|
+
|
84
|
+
def flee
|
85
|
+
return @zero if @actor.target.nil?
|
86
|
+
desired_velocity = (@actor.pos - @actor.target).normalize * @actor.max_speed
|
87
|
+
return desired_velocity - @actor.vel
|
88
|
+
end
|
89
|
+
|
90
|
+
def arrive(deceleration = :normal)
|
91
|
+
return @zero if @actor.target.nil?
|
92
|
+
deceleration_values = {
|
93
|
+
:fast => 0.5,
|
94
|
+
:normal => 1,
|
95
|
+
:slow => 2
|
96
|
+
}
|
97
|
+
deceleration_tweaker = 1.0
|
98
|
+
to_target = @actor.target - @actor.pos
|
99
|
+
distance_to_target = to_target.length
|
100
|
+
|
101
|
+
if distance_to_target > 10
|
102
|
+
speed = distance_to_target / (deceleration_tweaker * deceleration_values[deceleration])
|
103
|
+
speed = [speed, @actor.max_speed].min
|
104
|
+
desired_velocity = to_target * speed / distance_to_target
|
105
|
+
return desired_velocity - @actor.vel
|
106
|
+
else
|
107
|
+
@actor.vel /= 1.15
|
108
|
+
@actor.accel /= 1.15
|
109
|
+
end
|
110
|
+
return @zero
|
111
|
+
end
|
112
|
+
|
113
|
+
def pursuit
|
114
|
+
return @zero if @actor.evader.nil?
|
115
|
+
to_evader = @actor.evader.pos - @actor.pos
|
116
|
+
relative_heading = @actor.heading.dot(@actor.evader.heading)
|
117
|
+
if to_evader.dot(@actor.heading) > 0 && relative_heading < -0.95
|
118
|
+
@actor.target = @actor.evader.pos
|
119
|
+
return seek
|
120
|
+
end
|
121
|
+
|
122
|
+
look_ahead_time = to_evader.length / (@actor.max_speed + @actor.evader.vel.length)
|
123
|
+
predicted_position = @actor.evader.pos + @actor.evader.vel * look_ahead_time
|
124
|
+
@actor.target = predicted_position
|
125
|
+
return seek
|
126
|
+
end
|
127
|
+
|
128
|
+
def evade
|
129
|
+
return @zero if @actor.pursuer.nil?
|
130
|
+
to_pursuer = @actor.pursuer.pos - @actor.pos
|
131
|
+
look_ahead_time = to_pursuer.length / (@actor.max_speed + @actor.pursuer.vel.length)
|
132
|
+
predicted_position = @actor.pursuer.pos + @actor.pursuer.vel * look_ahead_time
|
133
|
+
@actor.target = @actor.pursuer.pos
|
134
|
+
return flee
|
135
|
+
end
|
136
|
+
|
137
|
+
# TODO: Fix wander
|
138
|
+
def wander
|
139
|
+
wander_jitter = 10
|
140
|
+
|
141
|
+
@actor.wander_target += Vector2d.new(Gosu.random(-1,1), Gosu.random(-1,1))
|
142
|
+
@actor.wander_target.normalize!
|
143
|
+
@actor.wander_target *= @actor.wander_radius
|
144
|
+
target_local = @actor.wander_target + Vector2d.new(0, @actor.wander_distance)
|
145
|
+
target_world = local_to_world(target_local, @actor.heading, @actor.heading.perp, @actor.pos)
|
146
|
+
return target_world - @actor.pos
|
147
|
+
end
|
148
|
+
|
149
|
+
def local_to_world(local_target, heading, side, pos)
|
150
|
+
local_angle = heading.angle_to(local_target)
|
151
|
+
x = Gosu.offset_x(local_angle, local_target.length)
|
152
|
+
y = Gosu.offset_y(local_angle, local_target.length)
|
153
|
+
world_point = Vector2d.new(x, y) + pos
|
154
|
+
end
|
155
|
+
|
156
|
+
module ActorMethods
|
157
|
+
|
158
|
+
def self.extended(instance)
|
159
|
+
instance.steering_setup
|
160
|
+
end
|
161
|
+
|
162
|
+
def steering_setup
|
163
|
+
# Create accessors for the actor
|
164
|
+
class << self
|
165
|
+
attr_accessor :mass, :pos, :heading, :vel, :accel,
|
166
|
+
:max_speed, :max_turn_rate, :max_force,
|
167
|
+
:wander_radius, :wander_distance, :wander_target,
|
168
|
+
:target, :evader, :pursuer
|
169
|
+
end
|
170
|
+
|
171
|
+
# Some defaults
|
172
|
+
@pos = Vector2d.new(@x, @y)
|
173
|
+
offset_x = Gosu.offset_x(@angle, 1)
|
174
|
+
offset_y = Gosu.offset_y(@angle, 1)
|
175
|
+
@heading = Vector2d.new(offset_x, offset_y)
|
176
|
+
@vel = Vector2d.new
|
177
|
+
@accel = Vector2d.new
|
178
|
+
@wander_target = Vector2d.new
|
179
|
+
end
|
180
|
+
|
181
|
+
def activate(behavior)
|
182
|
+
@systems[Steering].activate(behavior)
|
183
|
+
end
|
184
|
+
|
185
|
+
# to_s utility methods
|
186
|
+
def to_s
|
187
|
+
["@angle(#{format('%.2f', @angle)}°)",
|
188
|
+
"@pos(#{@pos})",
|
189
|
+
"@heading(#{@heading})",
|
190
|
+
"@vel |#{format('%.2f', @vel.length)}| (#{@vel})",
|
191
|
+
"@accel |#{format('%.2f', @accel.length)}| (#{@accel})",
|
192
|
+
"@seek_target(#{@seek_target})"]
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Lotu
|
2
|
+
class TextBox < Actor
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
default_opts = {
|
6
|
+
:font_size => 20
|
7
|
+
}
|
8
|
+
opts = default_opts.merge!(opts)
|
9
|
+
super(opts)
|
10
|
+
@watch_list = []
|
11
|
+
@subject_opts = {}
|
12
|
+
@font_size = opts[:font_size]
|
13
|
+
@attached_to = opts[:attach_to]
|
14
|
+
# Since we aren't setting an image for this, we need to specify
|
15
|
+
# this actor needs to be drawed
|
16
|
+
draw_me
|
17
|
+
end
|
18
|
+
|
19
|
+
def watch(subject, opts={})
|
20
|
+
@watch_list << subject
|
21
|
+
@subject_opts[subject] = opts
|
22
|
+
end
|
23
|
+
|
24
|
+
def attach_to(actor)
|
25
|
+
@attached_to = actor
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
unless @attached_to.nil?
|
30
|
+
@x = @attached_to.x + @attached_to.image.width / 2
|
31
|
+
@y = @attached_to.y - @attached_to.image.height / 2
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def draw
|
36
|
+
pos_y = 0
|
37
|
+
@watch_list.each do |watched|
|
38
|
+
my_font_size = @subject_opts[watched][:font_size] || @font_size
|
39
|
+
my_color = @subject_opts[watched][:color] || @color
|
40
|
+
my_text = watched.to_s
|
41
|
+
if my_text.is_a?(String)
|
42
|
+
$window.fonts[my_font_size].draw(my_text, @x, @y + pos_y, @z, @factor_x, @factor_y, my_color)
|
43
|
+
pos_y += my_font_size
|
44
|
+
else
|
45
|
+
my_text.each do |line|
|
46
|
+
$window.fonts[my_font_size].draw(line, @x, @y + pos_y, @z, @factor_x, @factor_y, my_color)
|
47
|
+
pos_y += my_font_size
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
data/lib/lotu/window.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Lotu
|
2
2
|
class Window < Gosu::Window
|
3
3
|
# delta time
|
4
|
-
attr_reader :dt, :systems
|
4
|
+
attr_reader :dt, :systems, :fonts
|
5
5
|
attr_accessor :update_queue, :draw_queue, :input_listeners, :font
|
6
6
|
|
7
7
|
def initialize(params={})
|
8
|
-
super(
|
8
|
+
super(800, 600, false)
|
9
9
|
|
10
10
|
# Handy global window variable
|
11
11
|
$window = self
|
@@ -18,7 +18,7 @@ module Lotu
|
|
18
18
|
|
19
19
|
@fps_counter = FpsCounter.new
|
20
20
|
@last_time = Gosu::milliseconds
|
21
|
-
@
|
21
|
+
@fonts = Hash.new{|h,k| h[k] = Gosu::Font.new(self, Gosu::default_font_name, k)}
|
22
22
|
|
23
23
|
# Add extra functionality
|
24
24
|
extend Controllable
|
data/lib/lotu.rb
CHANGED
@@ -2,6 +2,7 @@ LOTU_ROOT = File.expand_path(File.join(File.dirname(__FILE__), 'lotu'))
|
|
2
2
|
$LOAD_PATH.unshift(LOTU_ROOT)
|
3
3
|
|
4
4
|
require 'gosu'
|
5
|
+
%w{fps vector2d}.each{|file| require "misc/#{file}"}
|
5
6
|
%w{collidable controllable resourceful drawable controllable/input_controller eventful}.each{|file| require "behaviors/#{file}"}
|
6
|
-
%w{collision}.each{|file| require "systems/#{file}"}
|
7
|
-
%w{
|
7
|
+
%w{collision steering}.each{|file| require "systems/#{file}"}
|
8
|
+
%w{window actor cursor text_box}.each{|file| require file}
|
data/lotu.gemspec
CHANGED
@@ -5,16 +5,17 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{lotu}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.4"
|
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-
|
12
|
+
s.date = %q{2010-03-21}
|
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 = [
|
16
16
|
"LICENSE",
|
17
|
-
"README.rdoc"
|
17
|
+
"README.rdoc",
|
18
|
+
"TODO"
|
18
19
|
]
|
19
20
|
s.files = [
|
20
21
|
".document",
|
@@ -43,6 +44,7 @@ Gem::Specification.new do |s|
|
|
43
44
|
"examples/media/lobo_tuerto.png",
|
44
45
|
"examples/media/title.png",
|
45
46
|
"examples/mouse_pointer/mouse_pointer.rb",
|
47
|
+
"examples/steering_behaviors/steering.rb",
|
46
48
|
"lib/lotu.rb",
|
47
49
|
"lib/lotu/actor.rb",
|
48
50
|
"lib/lotu/behaviors/collidable.rb",
|
@@ -52,8 +54,11 @@ Gem::Specification.new do |s|
|
|
52
54
|
"lib/lotu/behaviors/eventful.rb",
|
53
55
|
"lib/lotu/behaviors/resourceful.rb",
|
54
56
|
"lib/lotu/cursor.rb",
|
55
|
-
"lib/lotu/fps.rb",
|
57
|
+
"lib/lotu/misc/fps.rb",
|
58
|
+
"lib/lotu/misc/vector2d.rb",
|
56
59
|
"lib/lotu/systems/collision.rb",
|
60
|
+
"lib/lotu/systems/steering.rb",
|
61
|
+
"lib/lotu/text_box.rb",
|
57
62
|
"lib/lotu/window.rb",
|
58
63
|
"lotu.gemspec"
|
59
64
|
]
|
@@ -63,7 +68,8 @@ Gem::Specification.new do |s|
|
|
63
68
|
s.rubygems_version = %q{1.3.6}
|
64
69
|
s.summary = %q{A simple, agile Ruby game development framework.}
|
65
70
|
s.test_files = [
|
66
|
-
"examples/
|
71
|
+
"examples/steering_behaviors/steering.rb",
|
72
|
+
"examples/hello_world/hello_world.rb",
|
67
73
|
"examples/mouse_pointer/mouse_pointer.rb"
|
68
74
|
]
|
69
75
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 4
|
9
|
+
version: 0.1.4
|
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-
|
17
|
+
date: 2010-03-21 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -40,6 +40,7 @@ extensions: []
|
|
40
40
|
extra_rdoc_files:
|
41
41
|
- LICENSE
|
42
42
|
- README.rdoc
|
43
|
+
- TODO
|
43
44
|
files:
|
44
45
|
- .document
|
45
46
|
- .gitignore
|
@@ -67,6 +68,7 @@ files:
|
|
67
68
|
- examples/media/lobo_tuerto.png
|
68
69
|
- examples/media/title.png
|
69
70
|
- examples/mouse_pointer/mouse_pointer.rb
|
71
|
+
- examples/steering_behaviors/steering.rb
|
70
72
|
- lib/lotu.rb
|
71
73
|
- lib/lotu/actor.rb
|
72
74
|
- lib/lotu/behaviors/collidable.rb
|
@@ -76,10 +78,14 @@ files:
|
|
76
78
|
- lib/lotu/behaviors/eventful.rb
|
77
79
|
- lib/lotu/behaviors/resourceful.rb
|
78
80
|
- lib/lotu/cursor.rb
|
79
|
-
- lib/lotu/fps.rb
|
81
|
+
- lib/lotu/misc/fps.rb
|
82
|
+
- lib/lotu/misc/vector2d.rb
|
80
83
|
- lib/lotu/systems/collision.rb
|
84
|
+
- lib/lotu/systems/steering.rb
|
85
|
+
- lib/lotu/text_box.rb
|
81
86
|
- lib/lotu/window.rb
|
82
87
|
- lotu.gemspec
|
88
|
+
- TODO
|
83
89
|
has_rdoc: true
|
84
90
|
homepage: http://github.com/lobo-tuerto/lotu
|
85
91
|
licenses: []
|
@@ -111,5 +117,6 @@ signing_key:
|
|
111
117
|
specification_version: 3
|
112
118
|
summary: A simple, agile Ruby game development framework.
|
113
119
|
test_files:
|
120
|
+
- examples/steering_behaviors/steering.rb
|
114
121
|
- examples/hello_world/hello_world.rb
|
115
122
|
- examples/mouse_pointer/mouse_pointer.rb
|