jemini 2009.10.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.txt +9 -0
- data/bin/jemini +26 -0
- data/lib/ibxm.jar +0 -0
- data/lib/jinput.jar +0 -0
- data/lib/jogg-0.0.7.jar +0 -0
- data/lib/jorbis-0.0.15.jar +0 -0
- data/lib/jruby-complete.jar +0 -0
- data/lib/lwjgl.jar +0 -0
- data/lib/lwjgl_util_applet.jar +0 -0
- data/lib/native_files/OpenAL32.dll +0 -0
- data/lib/native_files/jinput-dx8.dll +0 -0
- data/lib/native_files/jinput-dx8_64.dll +0 -0
- data/lib/native_files/jinput-raw.dll +0 -0
- data/lib/native_files/jinput-raw_64.dll +0 -0
- data/lib/native_files/jinput-wintab.dll +0 -0
- data/lib/native_files/libjinput-linux.so +0 -0
- data/lib/native_files/libjinput-linux64.so +0 -0
- data/lib/native_files/libjinput-osx.jnilib +0 -0
- data/lib/native_files/liblwjgl.jnilib +0 -0
- data/lib/native_files/liblwjgl.so +0 -0
- data/lib/native_files/liblwjgl64.so +0 -0
- data/lib/native_files/libopenal.so +0 -0
- data/lib/native_files/lwjgl.dll +0 -0
- data/lib/native_files/openal.dylib +0 -0
- data/lib/natives-linux.jar +0 -0
- data/lib/natives-mac.jar +0 -0
- data/lib/natives-win32.jar +0 -0
- data/lib/phys2d.jar +0 -0
- data/lib/slick.jar +0 -0
- data/package/jar/jemini.jar +0 -0
- data/src/behavior.rb +248 -0
- data/src/behavior_event.rb +23 -0
- data/src/behaviors/animated_image.rb +88 -0
- data/src/behaviors/audible.rb +16 -0
- data/src/behaviors/axis_stateful.rb +35 -0
- data/src/behaviors/bounding_box_collidable.rb +27 -0
- data/src/behaviors/cardinal_movable.rb +121 -0
- data/src/behaviors/clickable.rb +19 -0
- data/src/behaviors/countable.rb +32 -0
- data/src/behaviors/debug_physical.rb +43 -0
- data/src/behaviors/debug_tangible.rb +31 -0
- data/src/behaviors/drawable.rb +7 -0
- data/src/behaviors/drawable_image.rb +111 -0
- data/src/behaviors/drawable_line.rb +32 -0
- data/src/behaviors/drawable_shape.rb +48 -0
- data/src/behaviors/fading_image_trail_emittable.rb +32 -0
- data/src/behaviors/game_object_emittable.rb +13 -0
- data/src/behaviors/grid_bound.rb +108 -0
- data/src/behaviors/handles_events.rb +33 -0
- data/src/behaviors/inertial.rb +14 -0
- data/src/behaviors/magnetic.rb +34 -0
- data/src/behaviors/metered.rb +3 -0
- data/src/behaviors/movable.rb +81 -0
- data/src/behaviors/particle_emitter.rb +27 -0
- data/src/behaviors/physical.rb +384 -0
- data/src/behaviors/physical_cardinal_movable.rb +111 -0
- data/src/behaviors/physical_image.rb +45 -0
- data/src/behaviors/pointer.rb +30 -0
- data/src/behaviors/pressable.rb +17 -0
- data/src/behaviors/regional.rb +76 -0
- data/src/behaviors/rotates_to_point.rb +19 -0
- data/src/behaviors/spatial.rb +43 -0
- data/src/behaviors/stateful.rb +33 -0
- data/src/behaviors/taggable.rb +28 -0
- data/src/behaviors/tangible.rb +59 -0
- data/src/behaviors/timeable.rb +88 -0
- data/src/behaviors/top_down_vehicle.rb +42 -0
- data/src/behaviors/triangle_trail_emittable.rb +46 -0
- data/src/behaviors/unique.rb +0 -0
- data/src/behaviors/updates.rb +8 -0
- data/src/behaviors/updates_at_consistant_rate.rb +28 -0
- data/src/behaviors/vectored_movement.rb +48 -0
- data/src/behaviors/world_collidable.rb +9 -0
- data/src/color.rb +70 -0
- data/src/events/grid_changed_event.rb +8 -0
- data/src/events/physical_message.rb +9 -0
- data/src/events/tangible_collision_event.rb +8 -0
- data/src/file_system.rb +17 -0
- data/src/game.rb +110 -0
- data/src/game_object.rb +176 -0
- data/src/game_objects/background.rb +10 -0
- data/src/game_objects/fading_image.rb +23 -0
- data/src/game_objects/tangible_object.rb +4 -0
- data/src/game_objects/text.rb +71 -0
- data/src/game_objects/triangle_trail.rb +85 -0
- data/src/game_state.rb +164 -0
- data/src/inflector.rb +68 -0
- data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
- data/src/jemini.rb +31 -0
- data/src/jemini_version.rb +4 -0
- data/src/listenable_mixin.rb +15 -0
- data/src/logger_mixin.rb +11 -0
- data/src/managers/basic_game_object_manager.rb +95 -0
- data/src/managers/basic_physics_manager.rb +95 -0
- data/src/managers/basic_render_manager.rb +49 -0
- data/src/managers/basic_tile_manager.rb +3 -0
- data/src/managers/basic_update_manager.rb +30 -0
- data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
- data/src/managers/input_manager.rb +161 -0
- data/src/managers/input_support/input_binding.rb +77 -0
- data/src/managers/input_support/input_builder.rb +44 -0
- data/src/managers/input_support/input_listener.rb +74 -0
- data/src/managers/input_support/input_message.rb +5 -0
- data/src/managers/input_support/joystick_listener.rb +53 -0
- data/src/managers/input_support/key_listener.rb +27 -0
- data/src/managers/input_support/mouse_listener.rb +38 -0
- data/src/managers/input_support/slick_input_listener.rb +20 -0
- data/src/managers/input_support/slick_input_message.rb +11 -0
- data/src/managers/input_support/slick_input_translator.rb +15 -0
- data/src/managers/message_queue.rb +60 -0
- data/src/managers/network_manager.rb +41 -0
- data/src/managers/render_support/hardware_cursor.rb +13 -0
- data/src/managers/resource_manager.rb +167 -0
- data/src/managers/sound_manager.rb +47 -0
- data/src/managers/tag_manager.rb +47 -0
- data/src/managers/tangible_manager.rb +36 -0
- data/src/math.rb +23 -0
- data/src/org/rubyforge/rawr/Main.java +67 -0
- data/src/platform.rb +28 -0
- data/src/proc_enhancement.rb +5 -0
- data/src/project_generator.rb +138 -0
- data/src/resource.rb +31 -0
- data/src/spline.rb +13 -0
- data/src/states/input_diagnostic_state.rb +53 -0
- data/src/vector.rb +143 -0
- data/test/test_state.rb +3 -0
- metadata +188 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#Makes an object emit sounds.
|
|
2
|
+
class Audible < Jemini::Behavior
|
|
3
|
+
|
|
4
|
+
#Load a sound file and assign a reference to it, which can later be passed to emit_sound.
|
|
5
|
+
def load_sound(reference, path)
|
|
6
|
+
game_state.manager(:sound).add_sound(reference, path)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
#Plays a sound whose reference was assigned via load_sound.
|
|
10
|
+
#Pass in volume to play it back quieter or louder (1.0 is normal).
|
|
11
|
+
#Pass in pitch for a higher or lower tone (1.0 is normal).
|
|
12
|
+
def emit_sound(reference, volume = 1.0, pitch = 1.0)
|
|
13
|
+
game_state.manager(:sound).play_sound(reference, volume, pitch)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#Makes an object transition between several states in succession.
|
|
2
|
+
class AxisStateful < Jemini::Behavior
|
|
3
|
+
#Indicates that an object has transitioned from one state to another along an axis.
|
|
4
|
+
class AxialStateTransferEvent
|
|
5
|
+
attr_accessor :before_state, :after_state, :axis
|
|
6
|
+
def initialize(axis, before_state, after_state)
|
|
7
|
+
@axis = axis
|
|
8
|
+
@before_state = before_state
|
|
9
|
+
@after_state = after_state
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_accessor :default_state_on_axis, :current_state_on_axis
|
|
14
|
+
wrap_with_callbacks :transfer_state_on_axis
|
|
15
|
+
|
|
16
|
+
def load
|
|
17
|
+
@state_transitions = {}
|
|
18
|
+
@game_object.enable_listeners_for :axis_state_transfer_accepted
|
|
19
|
+
@game_object.enable_listeners_for :axis_state_transfer_rejected
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def set_state_transisions_on_axis(axis, transitions)
|
|
23
|
+
@state_transitisions[axis] = transitions
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def transfer_state_on_axis(axis, state)
|
|
27
|
+
event = AxialStateTransferEvent.new(axis, @current_state[axis], state)
|
|
28
|
+
if @state_transitions[axis][@current_state[axis]].include? state
|
|
29
|
+
@current_state = state
|
|
30
|
+
notify :axis_state_transfer_accepted, event
|
|
31
|
+
else
|
|
32
|
+
notify :axis_state_transfer_rejected, event
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# A CardinalMovable can move north, east, south and west.
|
|
2
|
+
# Movement along certain axis can be constrained, for example, pong has horizonal (north/east)
|
|
3
|
+
# TODO: Allow disabling of diagonal easily
|
|
4
|
+
# TODO: Allow disabling of directions
|
|
5
|
+
# TODO: Allow speed limit per axis
|
|
6
|
+
# TODO: Allow speed limit per direction
|
|
7
|
+
class CardinalMovable < Jemini::Behavior
|
|
8
|
+
NORTH = :north
|
|
9
|
+
EAST = :east
|
|
10
|
+
SOUTH = :south
|
|
11
|
+
WEST = :west
|
|
12
|
+
NORTH_EAST = :north_east
|
|
13
|
+
SOUTH_EAST = :south_east
|
|
14
|
+
SOUTH_WEST = :south_west
|
|
15
|
+
NORTH_WEST = :north_west
|
|
16
|
+
DIAGONAL_DIRECTIONS = [NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST]
|
|
17
|
+
CARDINAL_DIRECTIONS = [NORTH, EAST, SOUTH, WEST] + DIAGONAL_DIRECTIONS
|
|
18
|
+
DIRECTION_TRANSLATION_IN_DEGREES = []
|
|
19
|
+
|
|
20
|
+
depends_on :Tangible
|
|
21
|
+
depends_on :HandlesEvents
|
|
22
|
+
attr_accessor :facing_direction
|
|
23
|
+
#TODO: Rename to cardinal facing direction
|
|
24
|
+
wrap_with_callbacks :facing_direction=, :set_facing_drection
|
|
25
|
+
|
|
26
|
+
def load
|
|
27
|
+
@facing_direction = NORTH
|
|
28
|
+
@allowed_directions = CARDINAL_DIRECTIONS.dup
|
|
29
|
+
# @cardinal_speed = 25
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# direct input events here to keep "pushing".
|
|
33
|
+
# TODO: After the update, clear the directions.
|
|
34
|
+
def set_cardinal_movement_for_update(directions)
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def facing_direction=(direction)
|
|
39
|
+
if @allowed_directions.include? direction
|
|
40
|
+
if @moving && orthogonal_directions?(@facing_direction, direction)
|
|
41
|
+
diagonal_direction = begin
|
|
42
|
+
"#{self.class}::#{@facing_direction.to_s.upcase}_#{direction.to_s.upcase}".constantize
|
|
43
|
+
rescue
|
|
44
|
+
"#{self.class}::#{direction.to_s.upcase}_#{@facing_direction.to_s.upcase}".constantize
|
|
45
|
+
end
|
|
46
|
+
@facing_direction = diagonal_direction
|
|
47
|
+
else
|
|
48
|
+
@facing_direction = direction
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
alias_method :set_facing_direction, :facing_direction=
|
|
53
|
+
|
|
54
|
+
#Set direction(s) the object is allowed to move in.
|
|
55
|
+
#Takes either a single directional constant, or an Array of them.
|
|
56
|
+
def constrain_direction(directions)
|
|
57
|
+
directions = [directions] unless directions.kind_of? Array
|
|
58
|
+
directions.each
|
|
59
|
+
directions.each { |direction| @allowed_directions.delete direction }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#Initiate movement in a given direction.
|
|
63
|
+
#Takes a message with a directional constant as its value.
|
|
64
|
+
def begin_cardinal_movement(message)
|
|
65
|
+
direction = message.value
|
|
66
|
+
return unless @allowed_directions.include? direction
|
|
67
|
+
set_facing_direction direction
|
|
68
|
+
@moving = true
|
|
69
|
+
@cardinal_velocity = direction_to_polar_vector(@facing_direction)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#Halt movement in a given direction.
|
|
73
|
+
#Takes a message with a directional constant as its value.
|
|
74
|
+
def end_cardinal_movement(message)
|
|
75
|
+
direction = message.value
|
|
76
|
+
@facing_direction = other_direction(@facing_direction, direction) if diagonal_direction? @facing_direction
|
|
77
|
+
if @facing_direction == direction
|
|
78
|
+
@cardinal_velocity = Vector.new(0,0)
|
|
79
|
+
@moving = false
|
|
80
|
+
else
|
|
81
|
+
@cardinal_velocity = direction_to_polar_vector(@facing_direction)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def direction_to_polar_vector(direction)
|
|
88
|
+
angle = case direction
|
|
89
|
+
when NORTH
|
|
90
|
+
0
|
|
91
|
+
when NORTH_EAST
|
|
92
|
+
45
|
|
93
|
+
when EAST
|
|
94
|
+
90
|
|
95
|
+
when SOUTH_EAST
|
|
96
|
+
135
|
|
97
|
+
when SOUTH
|
|
98
|
+
180
|
|
99
|
+
when SOUTH_WEST
|
|
100
|
+
225
|
|
101
|
+
when WEST
|
|
102
|
+
270
|
|
103
|
+
when NORTH_WEST
|
|
104
|
+
315
|
|
105
|
+
end
|
|
106
|
+
Vector.from_polar_vector(@cardinal_speed, angle)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def diagonal_direction?(direction)
|
|
110
|
+
DIAGONAL_DIRECTIONS.include? direction
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def other_direction(diagonal_direction, direction)
|
|
114
|
+
diagonal_direction.to_s.sub(direction.to_s, '').sub('_', '').to_sym
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def orthogonal_directions?(direction_a, direction_b)
|
|
118
|
+
([NORTH, SOUTH].include?(direction_a) && [EAST, WEST].include?(direction_b)) ||
|
|
119
|
+
([NORTH, SOUTH].include?(direction_b) && [EAST, WEST].include?(direction_a))
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#Makes an object clickable with the mouse.
|
|
2
|
+
class Clickable < Jemini::Behavior
|
|
3
|
+
depends_on :HandlesEvents
|
|
4
|
+
depends_on :Regional
|
|
5
|
+
wrap_with_callbacks :pressed, :released
|
|
6
|
+
|
|
7
|
+
def load
|
|
8
|
+
@game_object.handle_event :mouse_button1_pressed do |mouse_event|
|
|
9
|
+
pressed if @game_object.within_region? mouse_event.value.location
|
|
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
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pressed; end
|
|
18
|
+
def released; end
|
|
19
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#Makes an object receive events when its numbers have changed.
|
|
2
|
+
class Countable < Jemini::Behavior
|
|
3
|
+
attr_accessor :count
|
|
4
|
+
wrap_with_callbacks :count=
|
|
5
|
+
|
|
6
|
+
def load
|
|
7
|
+
@count = 0
|
|
8
|
+
@game_object.enable_listeners_for :incremented
|
|
9
|
+
@game_object.enable_listeners_for :decremented
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def count=(count)
|
|
13
|
+
comparison = @count <=> count
|
|
14
|
+
@count = count
|
|
15
|
+
case comparison
|
|
16
|
+
when -1
|
|
17
|
+
@game_object.notify :decremented
|
|
18
|
+
when 0
|
|
19
|
+
# do nothing
|
|
20
|
+
when 1
|
|
21
|
+
@game_object.notify :incremented
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def decrement
|
|
26
|
+
self.count = count - 1
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def increment
|
|
30
|
+
self.count = count + 1
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#Makes an object draw its interactions with the physics engine on the screen.
|
|
2
|
+
class DebugPhysical < Jemini::Behavior
|
|
3
|
+
|
|
4
|
+
PhysVector = Java::net::phys2d::math::Vector2f
|
|
5
|
+
PhysCircle = Java::net.phys2d.raw.shapes.Circle
|
|
6
|
+
PhysPolygon = Java::net.phys2d.raw.shapes.Polygon
|
|
7
|
+
PhysLine = Java::net.phys2d.raw.shapes.Line
|
|
8
|
+
SlickVector = Java::org::newdawn::slick::geom::Vector2f
|
|
9
|
+
SlickPolygon = Java::org.newdawn.slick.geom.Polygon
|
|
10
|
+
SlickCircle = Java::org.newdawn.slick.geom.Circle
|
|
11
|
+
SlickLine = Java::org.newdawn.slick.geom.Line
|
|
12
|
+
|
|
13
|
+
include_class 'net.phys2d.raw.shapes.Box'
|
|
14
|
+
|
|
15
|
+
def load
|
|
16
|
+
game_state.manager(:render).on_after_render do |graphics|
|
|
17
|
+
draw(graphics)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def unload
|
|
22
|
+
# TODO: Remove listener for after render?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
def draw(graphics)
|
|
27
|
+
#TODO: Support joints and composite bodies(?)
|
|
28
|
+
body = @game_object.instance_variable_get(:@__behaviors)[:Physical].instance_variable_get(:@body)
|
|
29
|
+
physics_shape = body.shape
|
|
30
|
+
graphics_shape = if physics_shape.kind_of? Box
|
|
31
|
+
SlickPolygon.new(physics_shape.get_points(body.position, body.rotation).map{|point| [point.x, point.y]}.flatten.to_java(:float))
|
|
32
|
+
elsif physics_shape.kind_of? PhysPolygon
|
|
33
|
+
SlickPolygon.new(physics_shape.get_vertices(body.position, body.rotation).map{|point| [point.x, point.y]}.flatten.to_java(:float))
|
|
34
|
+
elsif physics_shape.kind_of? PhysCircle
|
|
35
|
+
SlickCircle.new(body.position.x, body.position.y, physics_shape.radius)
|
|
36
|
+
# elsif physics_shape.kind_of? PhysLine
|
|
37
|
+
# SlickLine.new(body_position.x, )
|
|
38
|
+
else
|
|
39
|
+
raise "#{self.class} does not know how to draw the shape #{physics_shape.class}"
|
|
40
|
+
end
|
|
41
|
+
graphics.draw(graphics_shape)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#Makes an object draw its collisions on the screen.
|
|
2
|
+
class DebugTangible < Jemini::Behavior
|
|
3
|
+
#declared_methods :draw
|
|
4
|
+
PhysVector = Java::net::phys2d::math::Vector2f
|
|
5
|
+
SlickVector = Java::org::newdawn::slick::geom::Vector2f
|
|
6
|
+
|
|
7
|
+
def load
|
|
8
|
+
game_state.manager(:render).on_after_render do |graphics|
|
|
9
|
+
draw(graphics)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def unload
|
|
14
|
+
# Remove listener for after render
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def draw(graphics)
|
|
18
|
+
#TODO: Support joints and composite bodies(?)
|
|
19
|
+
tangible_shape = @game_object.instance_variable_get(:@__behaviors)[:Tangible].instance_variable_get(:@tangible_shape)
|
|
20
|
+
graphics_shape = if tangible_shape.kind_of? TangibleBox
|
|
21
|
+
Java::org.newdawn.slick.geom.Polygon.new(tangible_shape.get_points(@game_object.top_left_position, 0).map{|point| [point.x, point.y]}.flatten.to_java(:float))
|
|
22
|
+
# elsif tangible_shape.kind_of?(Java::net.phys2d.raw.shapes.Polygon)
|
|
23
|
+
# Java::org.newdawn.slick.geom.Polygon.new(tangible_shape.get_vertices(body.position, body.rotation).map{|point| [point.x, point.y]}.flatten.to_java(:float))
|
|
24
|
+
# elsif tangible_shape.kind_of? Java::net.phys2d.raw.shapes.Circle
|
|
25
|
+
# Java::org.newdawn.slick.geom.Circle.new(body.position.x, body.position.y, tangible_shape.radius)
|
|
26
|
+
else
|
|
27
|
+
raise "#{self.class} does not know how to draw the shape #{tangible_shape.class}"
|
|
28
|
+
end
|
|
29
|
+
graphics.draw(graphics_shape)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
require 'behaviors/drawable'
|
|
2
|
+
|
|
3
|
+
#Makes an object draw itself as a bitmap image.
|
|
4
|
+
class DrawableImage < Drawable
|
|
5
|
+
include_class 'org.newdawn.slick.Image'
|
|
6
|
+
depends_on :Spatial
|
|
7
|
+
attr_accessor :image, :color, :texture_coords, :image_size
|
|
8
|
+
alias_method :set_image_size, :image_size=
|
|
9
|
+
wrap_with_callbacks :draw
|
|
10
|
+
|
|
11
|
+
def load
|
|
12
|
+
@color = Color.new(1.0, 1.0, 1.0, 1.0)
|
|
13
|
+
@texture_coords = [Vector.new(0.0, 0.0), Vector.new(1.0, 1.0)]
|
|
14
|
+
@rotation = 0.0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#Takes a reference to an image loaded via the resource manager, and sets the bitmap.
|
|
18
|
+
def image=(reference)
|
|
19
|
+
store_image(game_state.manager(:resource).get_image(reference))
|
|
20
|
+
end
|
|
21
|
+
alias_method :set_image, :image=
|
|
22
|
+
|
|
23
|
+
#Assign a Color to the image.
|
|
24
|
+
def color=(color)
|
|
25
|
+
@color = color
|
|
26
|
+
end
|
|
27
|
+
alias_method :set_color, :color=
|
|
28
|
+
|
|
29
|
+
#Increase or decrease horizontal and vertical scale for the image. 1.0 is identical to the current scale. If y_scale is omitted, x_scale is used for both axes.
|
|
30
|
+
#TODO: Take vectors for first args as well
|
|
31
|
+
def image_scaling(x_scale, y_scale = nil)
|
|
32
|
+
y_scale = x_scale if y_scale.nil?
|
|
33
|
+
store_image(@image.get_scaled_copy(x_scale.to_f * image_size.x, y_scale.to_f * image_size.y))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#Set horizontal and vertical scale for the image relative to the original. 1.0 is original scale. If y_scale is omitted, x_scale is used for both axes.
|
|
37
|
+
#TODO: Take vectors for first args as well
|
|
38
|
+
def scale_image_from_original(x_scale, y_scale = nil)
|
|
39
|
+
y_scale = x_scale if y_scale.nil?
|
|
40
|
+
@original_image = @image.copy if @original_image.nil?
|
|
41
|
+
store_image(@original_image.get_scaled_copy(x_scale.to_f * @original_image.width, y_scale.to_f * @original_image.height))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# WARNING: Using Slick's image for rotation can cause some odd quirks with it
|
|
45
|
+
# not quite rotating correctly (especially noticable around 180 degress).
|
|
46
|
+
# @rotation stands alone for this reason, instead of using Slick's rotation
|
|
47
|
+
def image_rotation
|
|
48
|
+
@rotation
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def image_rotation=(rotation)
|
|
52
|
+
@rotation = rotation
|
|
53
|
+
end
|
|
54
|
+
alias_method :set_image_rotation, :image_rotation=
|
|
55
|
+
|
|
56
|
+
#Increment the image rotation.
|
|
57
|
+
def add_rotation(rotation)
|
|
58
|
+
@rotation += rotation
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#Flip the texture horizontally.
|
|
62
|
+
def flip_horizontally
|
|
63
|
+
@texture_coords[1].x, @texture_coords[0].x = @texture_coords[0].x, @texture_coords[1].x
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#Flip the texture vertically.
|
|
67
|
+
def flip_vertically
|
|
68
|
+
@texture_coords[1].y, @texture_coords[0].y = @texture_coords[0].y, @texture_coords[1].y
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#Returns a Vector with the x/y coordinates of the image's top left corner.
|
|
72
|
+
def top_left_position
|
|
73
|
+
#Vector.new(center_position.x - image_size.x / 2.0, center_position.y - image_size.y / 2.0)
|
|
74
|
+
Vector.new(@game_object.x - image_size.x / 2.0, @game_object.y - image_size.y / 2.0)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#Takes either a single Vector or the x/y coordinates to move the image's top left corner to.
|
|
78
|
+
def move_by_top_left(move_x_or_vector, move_y = nil)
|
|
79
|
+
half_width = image_size.x / 2.0
|
|
80
|
+
half_height = image_size.y / 2.0
|
|
81
|
+
if move_y.nil?
|
|
82
|
+
@game_object.move(move_x_or_vector.x + half_width, move_x_or_vector.y + half_height)
|
|
83
|
+
else
|
|
84
|
+
@game_object.move(move_x_or_vector + half_width, move_y + half_height)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#Draw the image to the given graphic context.
|
|
89
|
+
def draw(graphics)
|
|
90
|
+
return if @image.nil? || @image_size.nil?
|
|
91
|
+
half_width = image_size.x / 2.0
|
|
92
|
+
half_height = image_size.y / 2.0
|
|
93
|
+
center_x = @game_object.x - half_width
|
|
94
|
+
center_y = @game_object.y - half_height
|
|
95
|
+
unless 0 == @rotation
|
|
96
|
+
graphics.rotate @game_object.x, @game_object.y, @rotation
|
|
97
|
+
end
|
|
98
|
+
@image.draw(center_x, center_y, @game_object.x + half_width, @game_object.y + half_height,
|
|
99
|
+
@texture_coords[0].x * image_size.x, @texture_coords[0].y * image_size.y, @texture_coords[1].x * image_size.x, @texture_coords[1].y * image_size.y,
|
|
100
|
+
@color.native_color)
|
|
101
|
+
graphics.reset_transform
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
def store_image(value)
|
|
107
|
+
@image = value
|
|
108
|
+
set_image_size(Vector.new(@image.width, @image.height))
|
|
109
|
+
@image
|
|
110
|
+
end
|
|
111
|
+
end
|