jemini 2009.10.27 → 2010.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +9 -1
- data/package/jar/jemini.jar +0 -0
- data/src/behavior.rb +1 -9
- data/src/behaviors/clickable.rb +2 -6
- data/src/behaviors/configurable.rb +51 -0
- data/src/behaviors/debug_physical.rb +4 -3
- data/src/behaviors/drawable_ellipse.rb +53 -0
- data/src/behaviors/drawable_image.rb +1 -3
- data/src/behaviors/drawable_line.rb +6 -2
- data/src/behaviors/drawable_rectangle.rb +53 -0
- data/src/behaviors/drawable_shape.rb +0 -2
- data/src/behaviors/physical.rb +31 -14
- data/src/behaviors/triangle_trail_emittable.rb +4 -2
- data/src/color.rb +9 -8
- data/src/game.rb +2 -1
- data/src/game_object.rb +6 -6
- data/src/game_objects/icon_strip_counter_display.rb +57 -0
- data/src/game_objects/text.rb +20 -14
- data/src/game_objects/triangle_trail.rb +32 -32
- data/src/game_state.rb +5 -4
- data/src/managers/basic_physics_manager.rb +20 -19
- data/src/managers/config_manager.rb +12 -0
- data/src/managers/input_support/input_binding.rb +22 -2
- data/src/managers/input_support/input_listener.rb +7 -1
- data/src/managers/input_support/joystick_listener.rb +33 -12
- data/src/managers/resource_manager.rb +36 -16
- data/src/managers/tag_manager.rb +0 -1
- data/src/project_generator.rb +0 -1
- metadata +8 -8
- data/src/behaviors/bounding_box_collidable.rb +0 -27
- data/src/behaviors/drawable.rb +0 -7
- data/src/behaviors/inertial.rb +0 -14
- data/src/behaviors/unique.rb +0 -0
- data/src/behaviors/world_collidable.rb +0 -9
data/README.txt
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
Jemini
|
1
|
+
Jemini 2010.1.5
|
2
2
|
|
3
3
|
== Description
|
4
4
|
|
5
5
|
Jemini is a game library designed to allow creation of reusable features. How many times has someone implemented the aiming on a first person shooter, or a minimap on a real time strategy? Jemini comes packaged with lots of behaviors out of the box, with the ability to easily author more. Jemini uses Phys2D and Slick for physics and graphics, with 3D on the roadmap.
|
6
6
|
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
At a command line, type:
|
10
|
+
|
11
|
+
sudo gem install jemini
|
12
|
+
|
13
|
+
(Leave off the "sudo" if on Windows.)
|
14
|
+
|
7
15
|
== License
|
8
16
|
|
9
17
|
Jemini is released under the BSD license. See the COPYING file for the full license.
|
data/package/jar/jemini.jar
CHANGED
Binary file
|
data/src/behavior.rb
CHANGED
@@ -42,7 +42,7 @@ module Jemini
|
|
42
42
|
callback_abort = CallbackStatus.new
|
43
43
|
@game_object.notify :before_#{method_name}_changes, event
|
44
44
|
if callback_abort.continue?
|
45
|
-
self.wrapped_#{method}
|
45
|
+
self.wrapped_#{method} event.desired_value
|
46
46
|
@game_object.notify :after_#{method_name}_changes, event
|
47
47
|
end
|
48
48
|
end
|
@@ -228,14 +228,6 @@ module Jemini
|
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
231
|
-
def add_reference_count
|
232
|
-
@reference_count += 1
|
233
|
-
end
|
234
|
-
|
235
|
-
def remove_reference_count
|
236
|
-
@reference_count -= 1
|
237
|
-
end
|
238
|
-
|
239
231
|
def load; end
|
240
232
|
def unload; end
|
241
233
|
end
|
data/src/behaviors/clickable.rb
CHANGED
@@ -5,12 +5,8 @@ class Clickable < Jemini::Behavior
|
|
5
5
|
wrap_with_callbacks :pressed, :released
|
6
6
|
|
7
7
|
def load
|
8
|
-
@game_object.handle_event :
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
@game_object.handle_event :mouse_button1_released do |mouse_event|
|
13
|
-
released if @game_object.within_region? mouse_event.value.location
|
8
|
+
@game_object.handle_event :click do |mouse_event|
|
9
|
+
released if @game_object.within_region? mouse_event.value.screen_position
|
14
10
|
end
|
15
11
|
end
|
16
12
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#Allows an object to load attributes from a file.
|
2
|
+
class Configurable < Jemini::Behavior
|
3
|
+
|
4
|
+
#The loaded configuration for the object.
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
#Loads a configuration with the given name.
|
8
|
+
def configure_as(key)
|
9
|
+
string = game_state.manager(:config).get_config(key)
|
10
|
+
@config = parse(string)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
#Parse the config string, returning a hash of attributes.
|
16
|
+
def parse(string)
|
17
|
+
attributes = {}
|
18
|
+
string.split("\n").each do |line|
|
19
|
+
line.strip!
|
20
|
+
next if line.empty?
|
21
|
+
next if line =~ /^#/
|
22
|
+
if line =~ /^([^=]+)=(.*)$/
|
23
|
+
key = $1.strip.to_sym
|
24
|
+
value = parse_value($2.strip)
|
25
|
+
attributes[key] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
#Treats quoted strings as strings, unquoted numbers as numbers.
|
32
|
+
def parse_value(value)
|
33
|
+
case value
|
34
|
+
when /^"(.*)"$/
|
35
|
+
escape($1)
|
36
|
+
when /^([\-\d]+)$/
|
37
|
+
$1.to_i
|
38
|
+
when /^([\-\d\.]+)$/
|
39
|
+
$1.to_f
|
40
|
+
else
|
41
|
+
escape(value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def escape(string)
|
46
|
+
string.gsub!(/\\\"/, '"')
|
47
|
+
string.gsub!(/\\\\/, '\\')
|
48
|
+
string
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -4,7 +4,7 @@ class DebugPhysical < Jemini::Behavior
|
|
4
4
|
PhysVector = Java::net::phys2d::math::Vector2f
|
5
5
|
PhysCircle = Java::net.phys2d.raw.shapes.Circle
|
6
6
|
PhysPolygon = Java::net.phys2d.raw.shapes.Polygon
|
7
|
-
PhysLine
|
7
|
+
PhysLine = Java::net.phys2d.raw.shapes.Line
|
8
8
|
SlickVector = Java::org::newdawn::slick::geom::Vector2f
|
9
9
|
SlickPolygon = Java::org.newdawn.slick.geom.Polygon
|
10
10
|
SlickCircle = Java::org.newdawn.slick.geom.Circle
|
@@ -33,8 +33,9 @@ private
|
|
33
33
|
SlickPolygon.new(physics_shape.get_vertices(body.position, body.rotation).map{|point| [point.x, point.y]}.flatten.to_java(:float))
|
34
34
|
elsif physics_shape.kind_of? PhysCircle
|
35
35
|
SlickCircle.new(body.position.x, body.position.y, physics_shape.radius)
|
36
|
-
|
37
|
-
# SlickLine.new(
|
36
|
+
elsif physics_shape.kind_of? PhysLine
|
37
|
+
# SlickLine.new(physics_shape.start.x, physics_shape.start.y, physics_shape.end.x, physics_shape.end.y)
|
38
|
+
SlickLine.new(*physics_shape.get_vertices(body.position, body.rotation).map{|point| [point.x, point.y]}.flatten.to_java(:float))
|
38
39
|
else
|
39
40
|
raise "#{self.class} does not know how to draw the shape #{physics_shape.class}"
|
40
41
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# draws a line on the screen
|
2
|
+
class DrawableEllipse < Jemini::Behavior
|
3
|
+
java_import 'org.newdawn.slick.geom.Ellipse'
|
4
|
+
java_import 'org.newdawn.slick.Color'
|
5
|
+
depends_on :Spatial
|
6
|
+
wrap_with_callbacks :draw
|
7
|
+
|
8
|
+
#The Color to draw the ellipse in.
|
9
|
+
attr_accessor :color
|
10
|
+
#If true, the shape will be drawn filled in. If false, only the frame will be drawn.
|
11
|
+
attr_accessor :ellipse_filled
|
12
|
+
|
13
|
+
def load
|
14
|
+
@color = Color.white
|
15
|
+
@ellipse_filled = true
|
16
|
+
@ellipse = Ellipse.new @game_object.position.x, @game_object.position.y, 1.0, 1.0
|
17
|
+
@game_object.on_after_position_changes { set_drawing_location }
|
18
|
+
end
|
19
|
+
|
20
|
+
#The ellipse height.
|
21
|
+
def height=(value)
|
22
|
+
@ellipse.radius2 = value / 2.0
|
23
|
+
set_drawing_location
|
24
|
+
end
|
25
|
+
def height
|
26
|
+
@ellipse.radius2 * 2.0
|
27
|
+
end
|
28
|
+
|
29
|
+
#The ellipse width.
|
30
|
+
def width=(value)
|
31
|
+
@ellipse.radius1 = value / 2.0
|
32
|
+
set_drawing_location
|
33
|
+
end
|
34
|
+
def width
|
35
|
+
@ellipse.radius1 * 2.0
|
36
|
+
end
|
37
|
+
|
38
|
+
#Draw an outline to the given graphics context.
|
39
|
+
def draw(graphics)
|
40
|
+
graphics.set_color @color
|
41
|
+
if @ellipse_filled
|
42
|
+
graphics.fill @ellipse
|
43
|
+
else
|
44
|
+
graphics.draw @ellipse
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def set_drawing_location
|
50
|
+
@ellipse.x = @game_object.position.x - @ellipse.radius1
|
51
|
+
@ellipse.y = @game_object.position.y - @ellipse.radius2
|
52
|
+
end
|
53
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
|
-
require 'behaviors/drawable'
|
2
|
-
|
3
1
|
#Makes an object draw itself as a bitmap image.
|
4
|
-
class DrawableImage <
|
2
|
+
class DrawableImage < Jemini::Behavior
|
5
3
|
include_class 'org.newdawn.slick.Image'
|
6
4
|
depends_on :Spatial
|
7
5
|
attr_accessor :image, :color, :texture_coords, :image_size
|
@@ -1,18 +1,20 @@
|
|
1
1
|
# draws a line on the screen
|
2
|
-
# TODO: Enable color
|
3
2
|
class DrawableLine < Jemini::Behavior
|
4
3
|
java_import 'org.newdawn.slick.geom.Line'
|
4
|
+
java_import 'org.newdawn.slick.Color'
|
5
5
|
depends_on :Spatial
|
6
6
|
wrap_with_callbacks :draw
|
7
7
|
|
8
|
+
#A Vector with the coordinates of the other end of the line.
|
8
9
|
attr_reader :line_end_position
|
10
|
+
#The Color to draw the line in.
|
9
11
|
attr_accessor :color
|
10
12
|
|
11
13
|
def load
|
14
|
+
@color = Color.white
|
12
15
|
@line_end_position = Vector.new(0.0, 0.0)
|
13
16
|
@line = Line.new @game_object.position.to_slick_vector, @line_end_position.to_slick_vector
|
14
17
|
@game_object.on_after_position_changes { set_line }
|
15
|
-
#@color = Color.white
|
16
18
|
end
|
17
19
|
|
18
20
|
def line_end_position=(end_point)
|
@@ -21,7 +23,9 @@ class DrawableLine < Jemini::Behavior
|
|
21
23
|
@line_end_position
|
22
24
|
end
|
23
25
|
|
26
|
+
#Draw the line to the given graphics context.
|
24
27
|
def draw(graphics)
|
28
|
+
graphics.set_color @color
|
25
29
|
graphics.draw @line
|
26
30
|
end
|
27
31
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# draws a line on the screen
|
2
|
+
class DrawableRectangle < Jemini::Behavior
|
3
|
+
java_import 'org.newdawn.slick.geom.Rectangle'
|
4
|
+
java_import 'org.newdawn.slick.Color'
|
5
|
+
depends_on :Spatial
|
6
|
+
wrap_with_callbacks :draw
|
7
|
+
|
8
|
+
#The Color to draw the shape in.
|
9
|
+
attr_accessor :color
|
10
|
+
#If true, the shape will be drawn filled in. If false, only the frame will be drawn.
|
11
|
+
attr_accessor :rectangle_filled
|
12
|
+
|
13
|
+
def load
|
14
|
+
@color = Color.white
|
15
|
+
@rectangle_filled = true
|
16
|
+
@rectangle = Rectangle.new @game_object.position.x, @game_object.position.y, 1.0, 1.0
|
17
|
+
@game_object.on_after_position_changes { set_drawing_location }
|
18
|
+
end
|
19
|
+
|
20
|
+
#The rectangle height.
|
21
|
+
def height=(value)
|
22
|
+
@rectangle.height = value
|
23
|
+
set_drawing_location
|
24
|
+
end
|
25
|
+
def height
|
26
|
+
@rectangle.height
|
27
|
+
end
|
28
|
+
|
29
|
+
#The rectangle width.
|
30
|
+
def width=(value)
|
31
|
+
@rectangle.width = value
|
32
|
+
set_drawing_location
|
33
|
+
end
|
34
|
+
def width
|
35
|
+
@rectangle.width
|
36
|
+
end
|
37
|
+
|
38
|
+
#Draw an outline to the given graphics context.
|
39
|
+
def draw(graphics)
|
40
|
+
graphics.set_color @color
|
41
|
+
if @rectangle_filled
|
42
|
+
graphics.fill @rectangle
|
43
|
+
else
|
44
|
+
graphics.draw @rectangle
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def set_drawing_location
|
50
|
+
@rectangle.x = @game_object.position.x - (@rectangle.width / 2.0)
|
51
|
+
@rectangle.y = @game_object.position.y - (@rectangle.height / 2.0)
|
52
|
+
end
|
53
|
+
end
|
data/src/behaviors/physical.rb
CHANGED
@@ -6,18 +6,19 @@ class Physical < Jemini::Behavior
|
|
6
6
|
|
7
7
|
INFINITE_MASS = Java::net::phys2d::raw::Body::INFINITE_MASS
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
java_import "net.phys2d.raw.Body"
|
10
|
+
java_import "net.phys2d.raw.shapes.Box"
|
11
|
+
java_import "net.phys2d.raw.shapes.Circle"
|
12
|
+
java_import "net.phys2d.raw.shapes.Line"
|
13
|
+
java_import "net.phys2d.raw.shapes.Polygon"
|
14
|
+
java_import "net.phys2d.raw.shapes.ConvexPolygon"
|
15
|
+
java_import "net.phys2d.math.Vector2f"
|
16
|
+
java_import 'net.phys2d.raw.AngleJoint'
|
17
|
+
java_import 'net.phys2d.raw.BasicJoint'
|
18
|
+
java_import 'net.phys2d.raw.SpringJoint'
|
19
|
+
java_import 'net.phys2d.raw.FixedAngleJoint'
|
20
|
+
java_import 'net.phys2d.raw.DistanceJoint'
|
21
|
+
java_import 'net.phys2d.raw.FixedJoint'
|
21
22
|
|
22
23
|
attr_reader :mass, :name, :shape
|
23
24
|
depends_on :Spatial
|
@@ -33,6 +34,8 @@ class Physical < Jemini::Behavior
|
|
33
34
|
@angular_damping = 0.0
|
34
35
|
@game_object.enable_listeners_for :physical_collided
|
35
36
|
@game_object.on_after_position_changes { move_body @game_object.position }
|
37
|
+
@joints = []
|
38
|
+
|
36
39
|
# Manual angular damping. New Phys2D may support this? If not, file a bug.
|
37
40
|
@game_object.on_update do |delta|
|
38
41
|
next if @angular_damping.zero? || angular_velocity.zero?
|
@@ -75,6 +78,9 @@ class Physical < Jemini::Behavior
|
|
75
78
|
end
|
76
79
|
alias_method :set_body_position, :body_position=
|
77
80
|
|
81
|
+
def add_joint(joint)
|
82
|
+
@joints << joint
|
83
|
+
end
|
78
84
|
# See about Phys2D joints here: http://www.cokeandcode.com/phys2d/source/javadoc/net/phys2d/raw/Joint.html
|
79
85
|
# TODO: Make the joint a game object and/or behavior
|
80
86
|
def join_to_physical(physical_game_object, options={})
|
@@ -91,7 +97,9 @@ class Physical < Jemini::Behavior
|
|
91
97
|
AngleJoint.new(@body, other_body, self_body_point, other_body_point, options[:self_body_angle], options[:other_body_angle])
|
92
98
|
when :basic
|
93
99
|
joint = BasicJoint.new(@body, other_body, options[:anchor].to_phys2d_vector)
|
94
|
-
joint
|
100
|
+
joint
|
101
|
+
when :fixed
|
102
|
+
joint = FixedJoint.new(@body, other_body)
|
95
103
|
joint
|
96
104
|
when :spring
|
97
105
|
joint = SpringJoint.new(@body, other_body, options[:self_anchor].to_phys2d_vector, options[:other_anchor].to_phys2d_vector)
|
@@ -99,7 +107,12 @@ class Physical < Jemini::Behavior
|
|
99
107
|
else
|
100
108
|
raise "Joint type #{options[:joint].inspect} not supported."
|
101
109
|
end
|
110
|
+
joint.relaxation = options[:relaxation] if options[:relaxation]
|
111
|
+
|
112
|
+
@joints << joint
|
113
|
+
|
102
114
|
@world.add joint
|
115
|
+
joint
|
103
116
|
end
|
104
117
|
|
105
118
|
#The maximum speed the object is allowed to travel. Takes either a Vector with the x/y limits or the numeric value to assign to both x and y.
|
@@ -198,7 +211,8 @@ class Physical < Jemini::Behavior
|
|
198
211
|
end
|
199
212
|
|
200
213
|
def angular_velocity=(delta)
|
201
|
-
|
214
|
+
velocity = (delta - angular_velocity).to_f
|
215
|
+
@body.adjust_angular_velocity velocity
|
202
216
|
end
|
203
217
|
alias_method :set_angular_velocity, :angular_velocity=
|
204
218
|
|
@@ -254,6 +268,8 @@ class Physical < Jemini::Behavior
|
|
254
268
|
case shape.to_s
|
255
269
|
when 'Polygon', 'ConvexPolygon'
|
256
270
|
params = [params.map {|vector| vector.to_phys2d_vector }.to_java(Vector2f)]
|
271
|
+
when 'Line'
|
272
|
+
params = params.map {|vector| vector.to_phys2d_vector }.to_java(Vector2f)
|
257
273
|
end
|
258
274
|
@shape = ("Physical::" + shape.to_s).constantize.new(*params)
|
259
275
|
else
|
@@ -283,6 +299,7 @@ class Physical < Jemini::Behavior
|
|
283
299
|
#Remove this object from the control of the physics engine.
|
284
300
|
def remove_from_world(world)
|
285
301
|
world.remove @body
|
302
|
+
@joints.each {|j| world.remove j }
|
286
303
|
@world = nil
|
287
304
|
end
|
288
305
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'behaviors/drawable'
|
2
|
-
|
3
1
|
#Makes an object draw a shrinking trail behind itself as it moves.
|
4
2
|
class TriangleTrailEmittable < Jemini::Behavior
|
5
3
|
#depends_on :Movable2d
|
@@ -19,6 +17,10 @@ class TriangleTrailEmittable < Jemini::Behavior
|
|
19
17
|
def unload
|
20
18
|
game_state.remove @emitter
|
21
19
|
end
|
20
|
+
|
21
|
+
def triangle_trail
|
22
|
+
@emitter
|
23
|
+
end
|
22
24
|
|
23
25
|
#Transparency to use. 1.0 is opaque. Default is 0.5.
|
24
26
|
def alpha
|
data/src/color.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
class Color
|
2
|
+
SlickColor = Java::org::newdawn::slick::Color
|
2
3
|
attr_reader :native_color
|
3
4
|
|
4
|
-
def initialize(red_or_other, blue =
|
5
|
+
def initialize(red_or_other, blue = nil, green = nil, alpha = 1.0)
|
5
6
|
if red_or_other.kind_of? Numeric
|
6
|
-
|
7
|
+
if green.nil? && blue.nil? #alpha defaults to 1.0
|
8
|
+
@native_color = SlickColor.new(red_or_other)
|
9
|
+
else
|
10
|
+
@native_color = SlickColor.new(red_or_other, blue, green, alpha)
|
11
|
+
end
|
7
12
|
else
|
8
13
|
# create from predefined Slick colors
|
9
|
-
fixed_color =
|
14
|
+
fixed_color = SlickColor.send(red_or_other.to_s.downcase)
|
10
15
|
# we don't want to change the original, so we copy it
|
11
|
-
@native_color =
|
16
|
+
@native_color = SlickColor.new(fixed_color.r, fixed_color.g, fixed_color.b, fixed_color.a)
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
@@ -63,8 +68,4 @@ class Color
|
|
63
68
|
def fade_by(amount)
|
64
69
|
self.alpha = alpha * (1.0 - amount)
|
65
70
|
end
|
66
|
-
private
|
67
|
-
def new_native_color(red, blue, green, alpha)
|
68
|
-
Java::org::newdawn::slick::Color.new(red, blue, green, alpha)
|
69
|
-
end
|
70
71
|
end
|
data/src/game.rb
CHANGED
@@ -89,7 +89,7 @@ module Jemini
|
|
89
89
|
private
|
90
90
|
def create_app
|
91
91
|
@app = AppGameContainer.new(self, screen_size.x, screen_size.y, fullscreen)
|
92
|
-
@app.vsync =
|
92
|
+
@app.vsync = true
|
93
93
|
@app.maximum_logic_update_interval = 60
|
94
94
|
@app.smooth_deltas = false #true
|
95
95
|
#main.container = container
|
@@ -101,6 +101,7 @@ module Jemini
|
|
101
101
|
@canvas.set_size(screen_size.x, screen_size.y)
|
102
102
|
container = @canvas.container
|
103
103
|
container.vsync = false
|
104
|
+
# container.vsync = true
|
104
105
|
container.maximum_logic_update_interval = 60
|
105
106
|
#container.start
|
106
107
|
@canvas
|
data/src/game_object.rb
CHANGED
@@ -31,29 +31,28 @@ module Jemini
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def add_behavior(behavior_name)
|
34
|
+
underscored_name = behavior_name.underscore
|
34
35
|
klass = nil
|
35
36
|
retried = false
|
36
37
|
begin
|
37
38
|
klass = behavior_name.camelize.constantize
|
38
39
|
rescue NameError
|
39
40
|
raise if retried
|
40
|
-
require "behaviors/#{
|
41
|
+
require "behaviors/#{underscored_name}"
|
41
42
|
retried = true
|
42
43
|
retry
|
43
44
|
end
|
44
|
-
@__behaviors[
|
45
|
+
@__behaviors[underscored_name] = klass.new(self) if @__behaviors[underscored_name].nil?
|
45
46
|
validate_dependant_behaviors
|
46
47
|
rescue NameError => e
|
47
|
-
raise "Unable to load behavior #{
|
48
|
+
raise "Unable to load behavior #{underscored_name}, #{e.message}\n#{e.backtrace.join("\n")}"
|
48
49
|
end
|
49
50
|
|
50
51
|
def __destroy
|
51
52
|
notify :before_remove, self
|
52
|
-
#TODO: Perhaps expose this as a method on Behavior
|
53
|
-
#Jemini::Behavior.send(:class_variable_get, :@@depended_on_by).delete self
|
54
53
|
__remove_listeners
|
55
54
|
@__behaviors.each do |name, behavior|
|
56
|
-
#the list is being modified as we go through it, so check before use.
|
55
|
+
# the list is being modified as we go through it, so check before use.
|
57
56
|
next if behavior.nil?
|
58
57
|
behavior.send(:delete)
|
59
58
|
end
|
@@ -99,6 +98,7 @@ module Jemini
|
|
99
98
|
end
|
100
99
|
|
101
100
|
def remove_registered_listener(listener_method_name, object, callback_or_callback_method)
|
101
|
+
|
102
102
|
if callback_or_callback_method.nil? || callback_or_callback_method.kind_of?(Symbol)
|
103
103
|
@callbacks[listener_method_name].delete callback_or_callback_method
|
104
104
|
else
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class IconStripCounterDisplay < Jemini::GameObject
|
2
|
+
TOP_LEFT_TO_BOTTOM_RIGHT_LAYOUT_MODE = :top_left_to_bottom_right
|
3
|
+
BOTTOM_RIGHT_TO_TOP_LEFT_LAYOUT_MODE = :bottom_right_to_top_left
|
4
|
+
|
5
|
+
has_behavior :Countable
|
6
|
+
has_behavior :Spatial
|
7
|
+
#has_behavior :CameraAnchoredDrawable
|
8
|
+
attr_accessor :icon, :background, :rows, :columns, :layout_mode
|
9
|
+
|
10
|
+
def load
|
11
|
+
@rows = 0
|
12
|
+
@columns = nil
|
13
|
+
@icons = []
|
14
|
+
@old_x = 0
|
15
|
+
@old_y = 0
|
16
|
+
@layout_mode = TOP_LEFT_TO_BOTTOM_RIGHT_LAYOUT_MODE
|
17
|
+
self.x = 0
|
18
|
+
self.y = 0
|
19
|
+
on_after_count_changes do
|
20
|
+
icon_count = count < 0 ? 0 : count
|
21
|
+
diff = @icons.size - icon_count
|
22
|
+
if diff > 0
|
23
|
+
1.upto diff do
|
24
|
+
last_icon = @icons.pop
|
25
|
+
game_state.remove_game_object last_icon
|
26
|
+
end
|
27
|
+
elsif diff < 0
|
28
|
+
1.upto diff.abs do
|
29
|
+
sprite = game_state.create_game_object :GameObject
|
30
|
+
sprite.add_behavior :Sprite
|
31
|
+
sprite.add_behavior :CameraAnchoredDrawable
|
32
|
+
sprite.image = @icon
|
33
|
+
position_sprite(x, y, @icons.size, sprite)
|
34
|
+
@icons << sprite
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
on_after_move do
|
39
|
+
@icons.each_with_index do |sprite, index|
|
40
|
+
position_sprite(x, y, index, sprite)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def position_sprite(offset_x, offset_y, sprite_index, sprite)
|
46
|
+
row_number = @rows.nil? ? sprite_index : (sprite_index % @rows)
|
47
|
+
column_number = @columns.nil? ? sprite_index : (sprite_index % @columns)
|
48
|
+
if TOP_LEFT_TO_BOTTOM_RIGHT_LAYOUT_MODE == @layout_mode
|
49
|
+
sprite_x = offset_x + (@icon.width * column_number)
|
50
|
+
sprite_y = offset_y + (@icon.height * row_number)
|
51
|
+
elsif BOTTOM_RIGHT_TO_TOP_LEFT_LAYOUT_MODE == @layout_mode
|
52
|
+
sprite_x = offset_x - (@icon.width * column_number)
|
53
|
+
sprite_y = offset_y - (@icon.height * row_number)
|
54
|
+
end
|
55
|
+
sprite.move(sprite_x, sprite_y)
|
56
|
+
end
|
57
|
+
end
|
data/src/game_objects/text.rb
CHANGED
@@ -1,21 +1,16 @@
|
|
1
|
-
require 'behaviors/drawable'
|
2
|
-
|
3
1
|
class Text < Jemini::GameObject
|
4
|
-
|
5
|
-
|
2
|
+
java_import "org.newdawn.slick.TrueTypeFont"
|
3
|
+
java_import "java.awt.Font"
|
6
4
|
|
7
5
|
has_behavior :Spatial
|
8
|
-
PLAIN = Font::PLAIN
|
9
|
-
ITALIC = Font::ITALIC
|
10
|
-
BOLD = Font::BOLD
|
11
6
|
|
12
7
|
attr_accessor :text, :size, :style, :font_name
|
13
8
|
|
14
9
|
def load(text, options={})
|
15
|
-
@font_name = "Arial"
|
16
|
-
@size
|
17
|
-
@text
|
18
|
-
@style
|
10
|
+
@font_name = options[:name] || "Arial"
|
11
|
+
@size = options[:size] || 12
|
12
|
+
@text = text
|
13
|
+
@style = get_style(options[:style])
|
19
14
|
load_font
|
20
15
|
orient_text(options)
|
21
16
|
end
|
@@ -47,8 +42,8 @@ class Text < Jemini::GameObject
|
|
47
42
|
alias_method :set_size, :size=
|
48
43
|
|
49
44
|
def style=(style)
|
50
|
-
raise "Invalid font style, must be
|
51
|
-
@style = style
|
45
|
+
raise "Invalid font style #{style.inspect}, must be :bold, :italic or :plain" unless [:bold, :italic, :plain].member? style
|
46
|
+
@style = get_style(style)
|
52
47
|
load_font
|
53
48
|
end
|
54
49
|
alias_method :set_style, :style=
|
@@ -61,11 +56,22 @@ private
|
|
61
56
|
when :bottom_right
|
62
57
|
self.position = options[:position] - Vector.new(text_width, text_height).half if options[:position]
|
63
58
|
when :center, nil
|
64
|
-
self.position = options[:position]
|
59
|
+
self.position = options[:position] if options[:position]
|
65
60
|
end
|
66
61
|
end
|
67
62
|
|
68
63
|
def load_font
|
69
64
|
@font = TrueTypeFont.new(Font.new(@font_name, @style, @size), true)
|
70
65
|
end
|
66
|
+
|
67
|
+
def get_style(style)
|
68
|
+
case style
|
69
|
+
when :bold
|
70
|
+
Font::BOLD
|
71
|
+
when :italic
|
72
|
+
Font::ITALIC
|
73
|
+
when :plain, nil
|
74
|
+
Font::PLAIN
|
75
|
+
end
|
76
|
+
end
|
71
77
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TriangleTrail < Jemini::GameObject
|
2
2
|
#has_behavior :Movable2d
|
3
3
|
has_behavior :Spatial
|
4
|
-
attr_accessor :radius, :alpha
|
4
|
+
attr_accessor :radius, :alpha, :color
|
5
5
|
|
6
6
|
def load
|
7
7
|
@trail = []
|
@@ -9,6 +9,7 @@ class TriangleTrail < Jemini::GameObject
|
|
9
9
|
@trail_size = 50
|
10
10
|
@radius = 10
|
11
11
|
@alpha = 0.5
|
12
|
+
@color = Color.new(0.0, 1.0, 1.0)
|
12
13
|
@flip = false
|
13
14
|
#TODO: Remove message when the callback stuff is checked in
|
14
15
|
@first_move = true
|
@@ -23,40 +24,39 @@ class TriangleTrail < Jemini::GameObject
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def draw(graphics)
|
26
|
-
|
27
|
-
|
27
|
+
return unless @trail.size > 3
|
28
|
+
gl = Java::org::newdawn::slick::opengl::renderer::Renderer.get
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
#Java::org::newdawn::slick::opengl::SlickCallable.new do
|
31
|
+
callable_class = Java::org::newdawn::slick::opengl::SlickCallable
|
32
|
+
callable_class.enter_safe_block
|
33
|
+
# use LWJGL's const directly, Slick's wrapper does not have the triangle strip const
|
34
|
+
triangle_strip_enum = Java::org::lwjgl::opengl::GL11::GL_TRIANGLE_STRIP
|
35
|
+
gl.gl_begin triangle_strip_enum
|
36
|
+
gl.gl_color4f(@color.red, @color.green, @color.blue, @alpha)
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
origin_x, origin_y = calculate_point_on_trail_edge(@trail[1], @trail[0], @radius, @flip)
|
39
|
+
gl.gl_vertex2f(origin_x, origin_y)
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
41
|
+
flipped_origin_x, flipped_origin_y = calculate_point_on_trail_edge(@trail[1], @trail[0], @radius, !@flip)
|
42
|
+
gl.gl_vertex2f(flipped_origin_x, flipped_origin_y)
|
43
|
+
|
44
|
+
last_trail_vector = @trail[1]
|
45
|
+
#gl.gl_color4f(0.0, 1.0, 1.0, alpha)
|
46
|
+
@trail[2..-1].each_with_index do |trail_vector, index|
|
47
|
+
next if trail_vector == last_trail_vector
|
48
|
+
actual_trail_size = (@trail.size - 1).to_f
|
49
|
+
trail_radius = (@radius) * ((actual_trail_size - (index + 2).to_f) / actual_trail_size)
|
50
|
+
|
51
|
+
rotated_x, rotated_y = calculate_point_on_trail_edge(trail_vector, last_trail_vector, trail_radius, @flip)
|
52
|
+
gl.gl_vertex2f(rotated_x, rotated_y)
|
53
|
+
rotated_x, rotated_y = calculate_point_on_trail_edge(trail_vector, last_trail_vector, trail_radius, !@flip)
|
54
|
+
gl.gl_vertex2f(rotated_x, rotated_y)
|
55
|
+
|
56
|
+
last_trail_vector = trail_vector
|
57
|
+
end
|
58
|
+
gl.gl_end
|
59
|
+
callable_class.leave_safe_block
|
60
60
|
end
|
61
61
|
|
62
62
|
def calculate_point_on_trail_edge(current_vector, previous_vector, trail_radius, flip)
|
data/src/game_state.rb
CHANGED
@@ -67,7 +67,8 @@ module Jemini
|
|
67
67
|
log.debug "Creating: #{type.camelize.to_sym}"
|
68
68
|
type.constantize
|
69
69
|
else
|
70
|
-
try_require("game_objects/#{type.underscore}")
|
70
|
+
successful_require = try_require("game_objects/#{type.underscore}") || try_require("managers/#{type.underscore}")
|
71
|
+
raise "Could not find the game object #{type.inspect}." unless successful_require
|
71
72
|
type.camelize.constantize
|
72
73
|
end
|
73
74
|
game_object = game_object_type.new(self, *params)
|
@@ -153,12 +154,12 @@ module Jemini
|
|
153
154
|
def try_require(path)
|
154
155
|
begin
|
155
156
|
require path
|
157
|
+
log.debug "Successful require: #{path}"
|
158
|
+
true
|
156
159
|
rescue LoadError => e
|
157
160
|
log.warn "Failed to require: #{path}"
|
158
|
-
|
161
|
+
false
|
159
162
|
end
|
160
|
-
log.debug "Successful require: #{path}"
|
161
|
-
return true
|
162
163
|
end
|
163
164
|
end
|
164
165
|
end
|
@@ -14,7 +14,7 @@ class BasicPhysicsManager < Jemini::GameObject
|
|
14
14
|
has_behavior :HandlesEvents
|
15
15
|
|
16
16
|
def load
|
17
|
-
@delta_debt = 0
|
17
|
+
# @delta_debt = 0
|
18
18
|
@world = World.new(Vector2f.new(0, 0), 5, QuadSpaceStrategy.new(20, 5))
|
19
19
|
# @world = World.new(Vector2f.new(0, 0), 10, BruteCollisionStrategy.new)
|
20
20
|
@world.add_listener self
|
@@ -34,24 +34,25 @@ class BasicPhysicsManager < Jemini::GameObject
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def update(delta)
|
37
|
-
|
38
|
-
@delta_debt
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
37
|
+
step
|
38
|
+
# delta += @delta_debt
|
39
|
+
# @delta_debt = 0
|
40
|
+
# if delta == MILLISECONDS_PER_UPDATE
|
41
|
+
# sleep PHYS2D_UPDATE_DIFF / 1000.0
|
42
|
+
# step
|
43
|
+
# else
|
44
|
+
# temp_delta = delta
|
45
|
+
# until temp_delta <= 0
|
46
|
+
# new_delta = temp_delta > MILLISECONDS_PER_UPDATE ? MILLISECONDS_PER_UPDATE : temp_delta
|
47
|
+
# if new_delta < MILLISECONDS_PER_UPDATE
|
48
|
+
# @delta_debt = new_delta
|
49
|
+
# return #don't step, we'll try again next update
|
50
|
+
# else
|
51
|
+
# step
|
52
|
+
# temp_delta -= new_delta
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# end
|
55
56
|
end
|
56
57
|
|
57
58
|
# there's a typo in the API, I swears it.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class ConfigManager < Jemini::GameObject
|
2
|
+
|
3
|
+
def load
|
4
|
+
@configs = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
#Takes a reference to a config loaded via the resource manager, and returns it.
|
8
|
+
def get_config(reference)
|
9
|
+
game_state.manager(:resource).get_config(reference)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -13,27 +13,35 @@ module Jemini
|
|
13
13
|
# type can be one of :hold, :release, :press, and :move
|
14
14
|
def add_input_listener(type, button_id, options={})
|
15
15
|
device = detect_device(button_id, type)
|
16
|
-
real_button = detect_button(button_id, device)
|
16
|
+
real_button = detect_button(button_id, options, device)
|
17
17
|
value = options[:value]
|
18
18
|
to = options[:to]
|
19
|
+
id = options[:id]
|
19
20
|
listener = InputListener.create(action_name, type, device, real_button)
|
20
21
|
listener.default_value = value
|
21
22
|
listener.message_to = to
|
23
|
+
listener.joystick_id = id
|
24
|
+
listener.axis_inverted = options[:invert]
|
25
|
+
listener.deadzone = options[:deadzone]
|
22
26
|
InputManager.loading_input_manager.listeners << listener
|
23
27
|
end
|
24
28
|
|
25
29
|
def detect_device(button_id, type)
|
26
30
|
if mouse_button?(button_id, type)
|
27
31
|
:mouse
|
32
|
+
elsif joystick_button?(button_id, type)
|
33
|
+
:joystick
|
28
34
|
else
|
29
35
|
:key
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
33
|
-
def detect_button(button_id, device)
|
39
|
+
def detect_button(button_id, options, device)
|
34
40
|
case device
|
35
41
|
when :mouse
|
36
42
|
detect_mouse_button(button_id)
|
43
|
+
when :joystick
|
44
|
+
detect_joystick_button(button_id, options)
|
37
45
|
when :key
|
38
46
|
case button_id.to_s
|
39
47
|
when /(left|right)_alt/
|
@@ -59,6 +67,18 @@ module Jemini
|
|
59
67
|
return true if button_id.has_key? :mouse_button
|
60
68
|
end
|
61
69
|
|
70
|
+
def joystick_button?(button_id, type)
|
71
|
+
return true if button_id == :joystick
|
72
|
+
# return true if type == :move && button_id == :joystick
|
73
|
+
# return false unless button_id.respond_to? :has_key?
|
74
|
+
# return true if button_id.has_key? :joystick_button
|
75
|
+
# return true if button_id.has_key? :joystick_button
|
76
|
+
end
|
77
|
+
|
78
|
+
def detect_joystick_button(button_id, options)
|
79
|
+
options[:button] || options[:axis]
|
80
|
+
end
|
81
|
+
|
62
82
|
def detect_mouse_button(button_id)
|
63
83
|
case button_id
|
64
84
|
when :mouse_left
|
@@ -11,7 +11,9 @@ module Jemini
|
|
11
11
|
:input_callback,
|
12
12
|
:game_state,
|
13
13
|
:default_value,
|
14
|
-
:message_to
|
14
|
+
:message_to,
|
15
|
+
:axis_inverted,
|
16
|
+
:deadzone
|
15
17
|
|
16
18
|
def self.create(message, type, device, button_id, options={}, &callback)
|
17
19
|
options[:input_callback] = callback
|
@@ -54,6 +56,10 @@ module Jemini
|
|
54
56
|
@cancel_post
|
55
57
|
end
|
56
58
|
|
59
|
+
def axis_inverted?
|
60
|
+
@axis_inverted
|
61
|
+
end
|
62
|
+
|
57
63
|
def key
|
58
64
|
"#{@device}_#{@input_type}_#{@input_button_or_axis}_#{@joystick_id || 'any'}"
|
59
65
|
end
|
@@ -6,9 +6,7 @@ module Jemini
|
|
6
6
|
:joystick
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
(0..raw_input.get_axis_count(@joystick_id)).find {|axis_id| raw_input.get_axis_name(@joystick_id, axis_id) == axis_name}
|
11
|
-
end
|
9
|
+
|
12
10
|
|
13
11
|
def poll_value(raw_input)
|
14
12
|
if @joystick_id && @joystick_id >= raw_input.controller_count
|
@@ -17,29 +15,35 @@ module Jemini
|
|
17
15
|
end
|
18
16
|
|
19
17
|
case @input_type
|
20
|
-
when :axis_update
|
18
|
+
when :move, :axis_update
|
21
19
|
@axis_id ||= find_axis_id_by_axis_name(raw_input, @input_button_or_axis)
|
22
|
-
axis_value = raw_input.get_axis_value(@joystick_id, @axis_id)
|
23
|
-
axis_value
|
24
|
-
when :pressed
|
25
20
|
if @joystick_id.nil?
|
26
|
-
|
21
|
+
nil # how do we send back multiple axis values?
|
22
|
+
else
|
23
|
+
axis_value = raw_input.get_axis_value(@joystick_id, @axis_id)
|
24
|
+
axis_value = 0.0 if deadzone && (deadzone > axis_value.abs)
|
25
|
+
axis_value *= -1 if axis_inverted?
|
26
|
+
axis_value
|
27
|
+
end
|
28
|
+
when :press
|
29
|
+
if @joystick_id.nil?
|
30
|
+
result = (0...raw_input.controller_count).any? {|i| raw_input.is_button_pressed(@input_button_or_axis, i)}
|
27
31
|
else
|
28
32
|
result = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
29
33
|
end
|
30
34
|
pressed = !@key_down_on_last_poll && result
|
31
|
-
@key_down_on_last_poll = result
|
35
|
+
@key_down_on_last_poll = result
|
32
36
|
cancel_post! unless pressed
|
33
37
|
pressed
|
34
|
-
when :
|
38
|
+
when :hold
|
35
39
|
if @joystick_id.nil?
|
36
|
-
result = (0
|
40
|
+
result = (0...raw_input.controller_count).any? {|i| raw_input.is_button_pressed(@input_button_or_axis, i)}
|
37
41
|
else
|
38
42
|
result = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
39
43
|
end
|
40
44
|
cancel_post! unless result
|
41
45
|
result
|
42
|
-
when :
|
46
|
+
when :release
|
43
47
|
button_down = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
44
48
|
result = (@key_down_on_last_poll && !button_down) ? true : false
|
45
49
|
@key_down_on_last_poll = button_down
|
@@ -49,5 +53,22 @@ module Jemini
|
|
49
53
|
cancel_post!
|
50
54
|
end
|
51
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def find_axis_id_by_axis_name(raw_input, axis_name)
|
59
|
+
if @joystick_id
|
60
|
+
find_axis_id_by_joystick_id_and_axis_name(raw_input, @joystick_id, axis_name)
|
61
|
+
else
|
62
|
+
(0...raw_input.controller_count).each do |joystick_id|
|
63
|
+
axis_id = find_axis_id_by_joystick_id_and_axis_name(raw_input, joystick_id, axis_name)
|
64
|
+
return axis_id if axis_id
|
65
|
+
end
|
66
|
+
raise "Could not find axis '#{axis_name}' for any connected joystick"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_axis_id_by_joystick_id_and_axis_name(raw_input, joystick_id, axis_name)
|
71
|
+
(0..raw_input.get_axis_count(joystick_id)).find {|axis_id| raw_input.get_axis_name(joystick_id, axis_id) == axis_name}
|
72
|
+
end
|
52
73
|
end
|
53
74
|
end
|
@@ -8,6 +8,7 @@ class ResourceManager < Jemini::GameObject
|
|
8
8
|
#Sets a default data directory path of "data".
|
9
9
|
def load
|
10
10
|
enable_listeners_for :resources_loaded
|
11
|
+
@configs = {}
|
11
12
|
@images = {}
|
12
13
|
@sounds = {}
|
13
14
|
@songs = {}
|
@@ -25,6 +26,13 @@ class ResourceManager < Jemini::GameObject
|
|
25
26
|
notify :resources_loaded
|
26
27
|
end
|
27
28
|
|
29
|
+
#Load the config at the given path, and make it accessible via the given key.
|
30
|
+
def cache_config(key, path)
|
31
|
+
log.debug "Caching config for #{key} with path: #{path}"
|
32
|
+
log.warn "Skipping duplicate config for #{key} with path: #{path}" and return if @configs[key]
|
33
|
+
@configs[key] = load_resource(path, :config)
|
34
|
+
end
|
35
|
+
|
28
36
|
#Load the image at the given path, and make it accessible via the given key.
|
29
37
|
def cache_image(key, path)
|
30
38
|
log.debug "Caching image for #{key} with path: #{path}"
|
@@ -46,6 +54,22 @@ class ResourceManager < Jemini::GameObject
|
|
46
54
|
@songs[key] = load_resource(path, :music)
|
47
55
|
end
|
48
56
|
|
57
|
+
#Get a config stored previously with cache_config.
|
58
|
+
def get_config(key)
|
59
|
+
@configs[key] or raise "Could not find config: #{key} - cached configs: #{@configs.keys}"
|
60
|
+
end
|
61
|
+
alias_method :config, :get_config
|
62
|
+
|
63
|
+
#Get all configs stored previously with cache_config.
|
64
|
+
def get_all_configs
|
65
|
+
@configs.values
|
66
|
+
end
|
67
|
+
alias_method :configs, :get_all_configs
|
68
|
+
|
69
|
+
def config_names
|
70
|
+
@configs.keys
|
71
|
+
end
|
72
|
+
|
49
73
|
#Get an image stored previously with cache_image.
|
50
74
|
def get_image(key)
|
51
75
|
@images[key] or raise "Could not find image: #{key} - cached images: #{@images.keys}"
|
@@ -90,30 +114,27 @@ private
|
|
90
114
|
|
91
115
|
def load_resource(path, type_name)
|
92
116
|
# due to some JRuby trickery involved with java_import, we can't use metaprogramming tricks here.
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
117
|
+
case type_name
|
118
|
+
when :config
|
119
|
+
File.read(Jemini::Resource.path_of(path))
|
120
|
+
when :image
|
121
|
+
Image.new(Jemini::Resource.path_of(path))
|
122
|
+
when :sound
|
123
|
+
Sound.new(Jemini::Resource.path_of(path))
|
124
|
+
when :music
|
125
|
+
Music.new(Jemini::Resource.path_of(path))
|
126
|
+
end
|
102
127
|
end
|
103
128
|
|
104
129
|
# root dirs can't be skipped
|
105
130
|
def load_directory(directory, root = false)
|
106
131
|
log.debug "Loading contents of #{directory}"
|
107
132
|
begin
|
108
|
-
#Dir.open(directory).each do |file|
|
109
133
|
resources_for(directory).each do |file|
|
110
134
|
next if file =~ /^\./
|
111
|
-
# path = File.join(directory, file)
|
112
135
|
path = File.in_jar?(directory) ? file : File.join(directory, file)
|
113
136
|
log.debug "Dir in jar? #{File.in_jar?(directory)}"
|
114
137
|
log.debug "Using path #{path} for #{file}"
|
115
|
-
# File.file? doesn't work in a jar.
|
116
|
-
# next unless File.file?(path)
|
117
138
|
extension = File.extname(file).downcase
|
118
139
|
key = File.basename(file, extension).downcase.to_sym
|
119
140
|
log.debug "Extension: #{extension}"
|
@@ -124,6 +145,8 @@ private
|
|
124
145
|
cache_sound(key, path)
|
125
146
|
when '.ogg'
|
126
147
|
cache_song(key, path)
|
148
|
+
when '.ini'
|
149
|
+
cache_config(key, path)
|
127
150
|
else
|
128
151
|
log.warn "Skipping unknown file: #{path}"
|
129
152
|
end
|
@@ -159,9 +182,6 @@ private
|
|
159
182
|
entries_under_directory = all_entries.select {|e| e =~ dir_regex }
|
160
183
|
# need a shallow resultset
|
161
184
|
entries_directly_under_directory = entries_under_directory.reject {|e| e =~ /#{just_dir}\/.*\//}
|
162
|
-
# log.debug "entries directly under dir"
|
163
|
-
# log.debug entries_directly_under_directory
|
164
|
-
# log.debug "------------"
|
165
185
|
entries_directly_under_directory
|
166
186
|
end
|
167
187
|
end
|
data/src/managers/tag_manager.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#Tracks tags applied to objects.
|
2
2
|
class TagManager < Jemini::GameObject
|
3
3
|
def load
|
4
|
-
require 'behaviors/taggable'
|
5
4
|
@tagged_objects = Hash.new { |h,k| h[k] = [] }
|
6
5
|
listen_for(:after_add_game_object, game_state.manager(:game_object)) do |game_object|
|
7
6
|
if game_object.has_behavior? :Taggable
|
data/src/project_generator.rb
CHANGED
@@ -29,7 +29,6 @@ module Jemini
|
|
29
29
|
f << <<-ENDL
|
30
30
|
require 'java'
|
31
31
|
|
32
|
-
$LOAD_PATH.clear
|
33
32
|
$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
|
34
33
|
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), 'game_objects'))
|
35
34
|
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), 'managers'))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jemini
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2010.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Logan Barnett, David Koontz, Jay McGavren
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-05 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 1.3.
|
23
|
+
version: 1.3.8
|
24
24
|
version:
|
25
25
|
description: Jemini is a game library designed to allow creation of reusable features. How many times has someone implemented the aiming on a first person shooter, or a minimap on a real time strategy? Jemini comes packaged with lots of behaviors out of the box, with the ability to easily author more. Jemini uses Phys2D and Slick for physics and graphics, with 3D on the roadmap.
|
26
26
|
email: logustus@gmail.com
|
@@ -53,21 +53,21 @@ files:
|
|
53
53
|
- src/behaviors/animated_image.rb
|
54
54
|
- src/behaviors/audible.rb
|
55
55
|
- src/behaviors/axis_stateful.rb
|
56
|
-
- src/behaviors/bounding_box_collidable.rb
|
57
56
|
- src/behaviors/cardinal_movable.rb
|
58
57
|
- src/behaviors/clickable.rb
|
58
|
+
- src/behaviors/configurable.rb
|
59
59
|
- src/behaviors/countable.rb
|
60
60
|
- src/behaviors/debug_physical.rb
|
61
61
|
- src/behaviors/debug_tangible.rb
|
62
|
-
- src/behaviors/
|
62
|
+
- src/behaviors/drawable_ellipse.rb
|
63
63
|
- src/behaviors/drawable_image.rb
|
64
64
|
- src/behaviors/drawable_line.rb
|
65
|
+
- src/behaviors/drawable_rectangle.rb
|
65
66
|
- src/behaviors/drawable_shape.rb
|
66
67
|
- src/behaviors/fading_image_trail_emittable.rb
|
67
68
|
- src/behaviors/game_object_emittable.rb
|
68
69
|
- src/behaviors/grid_bound.rb
|
69
70
|
- src/behaviors/handles_events.rb
|
70
|
-
- src/behaviors/inertial.rb
|
71
71
|
- src/behaviors/magnetic.rb
|
72
72
|
- src/behaviors/metered.rb
|
73
73
|
- src/behaviors/movable.rb
|
@@ -86,16 +86,15 @@ files:
|
|
86
86
|
- src/behaviors/timeable.rb
|
87
87
|
- src/behaviors/top_down_vehicle.rb
|
88
88
|
- src/behaviors/triangle_trail_emittable.rb
|
89
|
-
- src/behaviors/unique.rb
|
90
89
|
- src/behaviors/updates.rb
|
91
90
|
- src/behaviors/updates_at_consistant_rate.rb
|
92
91
|
- src/behaviors/vectored_movement.rb
|
93
|
-
- src/behaviors/world_collidable.rb
|
94
92
|
- src/events/grid_changed_event.rb
|
95
93
|
- src/events/physical_message.rb
|
96
94
|
- src/events/tangible_collision_event.rb
|
97
95
|
- src/game_objects/background.rb
|
98
96
|
- src/game_objects/fading_image.rb
|
97
|
+
- src/game_objects/icon_strip_counter_display.rb
|
99
98
|
- src/game_objects/tangible_object.rb
|
100
99
|
- src/game_objects/text.rb
|
101
100
|
- src/game_objects/triangle_trail.rb
|
@@ -105,6 +104,7 @@ files:
|
|
105
104
|
- src/managers/basic_render_manager.rb
|
106
105
|
- src/managers/basic_tile_manager.rb
|
107
106
|
- src/managers/basic_update_manager.rb
|
107
|
+
- src/managers/config_manager.rb
|
108
108
|
- src/managers/input_manager.rb
|
109
109
|
- src/managers/message_queue.rb
|
110
110
|
- src/managers/network_manager.rb
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'behavior_event'
|
2
|
-
include_class 'org.newdawn.slick.geom.Rectangle'
|
3
|
-
|
4
|
-
#Makes an object generate a BoundingBoxCollisionEvent if its bounding box intersects another's.
|
5
|
-
class BoundingBoxCollidable < Jemini::Behavior
|
6
|
-
depends_on :Spatial2d
|
7
|
-
|
8
|
-
def load
|
9
|
-
@game_object.enable_listeners_for :collided
|
10
|
-
end
|
11
|
-
|
12
|
-
def collision_check(collidable)
|
13
|
-
return if self == collidable || @game_object == collidable
|
14
|
-
|
15
|
-
notify :collided, BoundingBoxCollisionEvent.new(@game_object, collidable) if bounds.intersects(collidable.bounds)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
#Indicates that one object has collided with another.
|
20
|
-
class BoundingBoxCollisionEvent < Jemini::BehaviorEvent
|
21
|
-
attr_accessor :colliding_object, :collided_object
|
22
|
-
|
23
|
-
def load(source, other)
|
24
|
-
@colliding_object = source
|
25
|
-
@collided_object = other
|
26
|
-
end
|
27
|
-
end
|
data/src/behaviors/drawable.rb
DELETED
data/src/behaviors/inertial.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# deprecated
|
2
|
-
class Inertial < Jemini::Behavior
|
3
|
-
depends_on :UpdatesAtConsistantRate
|
4
|
-
|
5
|
-
#A 2-element array with x/y inertial values. 0 means no resistance to acceleration.
|
6
|
-
attr_accessor :inertia
|
7
|
-
|
8
|
-
def load
|
9
|
-
@inertia = [0,0]
|
10
|
-
@game_object.on_update do
|
11
|
-
move(@inertia[0] + x, @inertia[1] + y)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/src/behaviors/unique.rb
DELETED
File without changes
|
@@ -1,9 +0,0 @@
|
|
1
|
-
#Makes an object generate an event if it collides with another.
|
2
|
-
class WorldCollidable < Jemini::Behavior
|
3
|
-
depends_on :BoundingBoxCollidable
|
4
|
-
depends_on_kind_of :CollisionPoolAlgorithm
|
5
|
-
|
6
|
-
def world_collision_check
|
7
|
-
get_collision_candidates.each {|candidate| collision_check candidate}
|
8
|
-
end
|
9
|
-
end
|