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,111 @@
|
|
|
1
|
+
# A CardinalMovable that interacts with the physics manager.
|
|
2
|
+
# See the API for CardinalMovable for method descriptions.
|
|
3
|
+
# TODO: Allow disabling of diaganol easily
|
|
4
|
+
# TODO: Allow disabling of directions
|
|
5
|
+
# TODO: Allow speed limit per axis
|
|
6
|
+
# TODO: Allow speed limit per direction
|
|
7
|
+
class PhysicalCardinalMovable < 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 :Physical
|
|
21
|
+
depends_on :HandlesEvents
|
|
22
|
+
attr_accessor :facing_direction
|
|
23
|
+
wrap_with_callbacks :facing_direction=, :set_facing_drection
|
|
24
|
+
|
|
25
|
+
def load
|
|
26
|
+
@facing_direction = NORTH
|
|
27
|
+
@allowed_directions = CARDINAL_DIRECTIONS.dup
|
|
28
|
+
@cardinal_speed = 25
|
|
29
|
+
@game_object.on_update do
|
|
30
|
+
@game_object.add_velocity @cardinal_velocity if @moving
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def facing_direction=(direction)
|
|
35
|
+
if @allowed_directions.include? direction
|
|
36
|
+
if @moving && orthogonal_directions?(@facing_direction, direction)
|
|
37
|
+
diagonal_direction = begin
|
|
38
|
+
"#{self.class}::#{@facing_direction.to_s.upcase}_#{direction.to_s.upcase}".constantize
|
|
39
|
+
rescue
|
|
40
|
+
"#{self.class}::#{direction.to_s.upcase}_#{@facing_direction.to_s.upcase}".constantize
|
|
41
|
+
end
|
|
42
|
+
@facing_direction = diagonal_direction
|
|
43
|
+
else
|
|
44
|
+
@facing_direction = direction
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
alias_method :set_facing_direction, :facing_direction=
|
|
49
|
+
|
|
50
|
+
def constrain_direction(directions)
|
|
51
|
+
directions = [directions] unless directions.kind_of? Array
|
|
52
|
+
directions.each
|
|
53
|
+
directions.each { |direction| @allowed_directions.delete direction }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def begin_cardinal_movement(message)
|
|
57
|
+
direction = message.value
|
|
58
|
+
return unless @allowed_directions.include? direction
|
|
59
|
+
set_facing_direction direction
|
|
60
|
+
@moving = true
|
|
61
|
+
@cardinal_velocity = direction_to_polar_vector(@facing_direction)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def end_cardinal_movement(message)
|
|
65
|
+
direction = message.value
|
|
66
|
+
@facing_direction = other_direction(@facing_direction, direction) if diagonal_direction? @facing_direction
|
|
67
|
+
if @facing_direction == direction
|
|
68
|
+
@cardinal_velocity = Vector.new(0,0)
|
|
69
|
+
@moving = false
|
|
70
|
+
else
|
|
71
|
+
@cardinal_velocity = direction_to_polar_vector(@facing_direction)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def direction_to_polar_vector(direction)
|
|
78
|
+
angle = case direction
|
|
79
|
+
when NORTH
|
|
80
|
+
0
|
|
81
|
+
when NORTH_EAST
|
|
82
|
+
45
|
|
83
|
+
when EAST
|
|
84
|
+
90
|
|
85
|
+
when SOUTH_EAST
|
|
86
|
+
135
|
|
87
|
+
when SOUTH
|
|
88
|
+
180
|
|
89
|
+
when SOUTH_WEST
|
|
90
|
+
225
|
|
91
|
+
when WEST
|
|
92
|
+
270
|
|
93
|
+
when NORTH_WEST
|
|
94
|
+
315
|
|
95
|
+
end
|
|
96
|
+
Vector.from_polar_vector(@cardinal_speed, angle)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def diagonal_direction?(direction)
|
|
100
|
+
DIAGONAL_DIRECTIONS.include? direction
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def other_direction(diagonal_direction, direction)
|
|
104
|
+
diagonal_direction.to_s.sub(direction.to_s, '').sub('_', '').to_sym
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def orthogonal_directions?(direction_a, direction_b)
|
|
108
|
+
([NORTH, SOUTH].include?(direction_a) && [EAST, WEST].include?(direction_b)) ||
|
|
109
|
+
([NORTH, SOUTH].include?(direction_b) && [EAST, WEST].include?(direction_a))
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#Gives an object a bitmap that responds appropriately to the physics engine.
|
|
2
|
+
class PhysicalImage < Jemini::Behavior
|
|
3
|
+
depends_on :DrawableImage
|
|
4
|
+
depends_on :Physical
|
|
5
|
+
attr_accessor :tiled_to_bounds
|
|
6
|
+
alias_method :set_tiled_to_bounds, :tiled_to_bounds=
|
|
7
|
+
|
|
8
|
+
def load
|
|
9
|
+
@game_object.on_before_draw :draw_physical_image
|
|
10
|
+
@offset_position = Vector.new
|
|
11
|
+
@offset_rotation = 0.0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def bounded_image=(new_image)
|
|
15
|
+
@game_object.set_image new_image
|
|
16
|
+
@game_object.set_shape(:Box, @game_object.image_size.x, @game_object.image_size.y)
|
|
17
|
+
end
|
|
18
|
+
alias_method :set_bounded_image, :bounded_image=
|
|
19
|
+
|
|
20
|
+
def tiled_to_bounds=(state)
|
|
21
|
+
@tiled_to_bounds = state
|
|
22
|
+
@game_object.image_size = @game_object.box_size
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def physical_image_position_offset=(offset)
|
|
26
|
+
@offset_position = offset.dup
|
|
27
|
+
end
|
|
28
|
+
alias_method :set_physical_image_position_offset, :physical_image_position_offset=
|
|
29
|
+
|
|
30
|
+
def physical_image_rotation_offset=(offset)
|
|
31
|
+
@offset_rotation = offset
|
|
32
|
+
end
|
|
33
|
+
alias_method :set_physical_image_rotation_offset, :physical_image_rotation_offset=
|
|
34
|
+
|
|
35
|
+
def draw_physical_image(graphics)
|
|
36
|
+
@game_object.image_rotation = @game_object.physical_rotation unless @game_object.image.nil?
|
|
37
|
+
#TODO: Only execute this if the shape is bound to the image.
|
|
38
|
+
#TODO: Call raw_move instead of x= and y=
|
|
39
|
+
position = @game_object.body_position
|
|
40
|
+
|
|
41
|
+
offset = Vector::ORIGIN.pivot_around_degrees(@offset_position, @game_object.physical_rotation + @offset_rotation)
|
|
42
|
+
@game_object.x = position.x + offset.x
|
|
43
|
+
@game_object.y = position.y + offset.y
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#Makes an object move with the mouse.
|
|
2
|
+
class Pointer < Jemini::Behavior
|
|
3
|
+
depends_on :DrawableImage
|
|
4
|
+
# depends_on :Movable2d
|
|
5
|
+
# depends_on :CollisionPoolAlgorithmTaggable
|
|
6
|
+
# depends_on :WorldCollidable
|
|
7
|
+
depends_on :HandlesEvents
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load
|
|
11
|
+
# add_tag :ui, :gui, :pointer
|
|
12
|
+
# collides_with_tags :gui, :clickable
|
|
13
|
+
#
|
|
14
|
+
@game_object.handle_event :mouse_move do |message|
|
|
15
|
+
mouse_movement(message)
|
|
16
|
+
end
|
|
17
|
+
# handle_event :start_click, :start_click
|
|
18
|
+
# handle_event :stop_click, :stop_click
|
|
19
|
+
|
|
20
|
+
# listen_for(:collided) do |event, continue|
|
|
21
|
+
# event.collided_object.click if event.collided_object.respond_to? :click
|
|
22
|
+
# end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#Takes a message with a Vector indicating the x/y coordinates to move the object to.
|
|
26
|
+
def mouse_movement(message)
|
|
27
|
+
vector = message.value
|
|
28
|
+
@game_object.move(vector.location.x, vector.location.y)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#Makes an object change appearance when clicked.
|
|
2
|
+
class Pressable < Jemini::Behavior
|
|
3
|
+
depends_on :DrawableImage
|
|
4
|
+
depends_on :Clickable
|
|
5
|
+
|
|
6
|
+
def load
|
|
7
|
+
add_tag :button, :gui, :ui
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
#Takes a hash with the following keys and values:
|
|
11
|
+
#[:normal] The path for the image to display when the object is not pressed.
|
|
12
|
+
#[:pressed] The path for the image to display when the object is pressed.
|
|
13
|
+
def images=(image_path_hash)
|
|
14
|
+
@normal_image = image_path_hash[:normal]
|
|
15
|
+
@pressed_image = image_path_hash[:pressed]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
#Indicates that the receiver has entered/exited an area.
|
|
4
|
+
class RegionalTransitionEvent
|
|
5
|
+
attr_accessor :region, :spatial
|
|
6
|
+
def initialize(region, spatial)
|
|
7
|
+
@region = region
|
|
8
|
+
@spatial = spatial
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#Makes an object receive a RegionalTransitionEvent whenever it enters/exits a given area.
|
|
13
|
+
class Regional < Jemini::Behavior
|
|
14
|
+
depends_on :Spatial
|
|
15
|
+
attr_accessor :dimensions, :region_shape
|
|
16
|
+
alias_method :set_dimensions, :dimensions=
|
|
17
|
+
alias_method :set_region_shape, :region_shape=
|
|
18
|
+
|
|
19
|
+
# This is bad. We need a real collision system
|
|
20
|
+
def load
|
|
21
|
+
@game_object.enable_listeners_for :entered_region, :exited_region
|
|
22
|
+
@game_object.move(0,0)
|
|
23
|
+
@dimensions = Vector.new(1,1)
|
|
24
|
+
@last_spatials_within = []
|
|
25
|
+
@last_spatials_without = nil
|
|
26
|
+
@last_spatials = []
|
|
27
|
+
#TODO: SAVE: This should be turned on when requested.
|
|
28
|
+
# game_state.manager(:update).on_update do
|
|
29
|
+
# spatials = game_state.manager(:game_object).game_objects.select {|game_object| game_object.kind_of? Tangible}.compact
|
|
30
|
+
#
|
|
31
|
+
# spatials_within, spatials_without = spatials.partition {|spatial| within_region?(spatial)}
|
|
32
|
+
# (spatials_within - @last_spatials_within).each do |spatial_within|
|
|
33
|
+
# @game_object.notify :entered_region, RegionalTransitionEvent.new(self, spatial_within) if existed_last_update? spatial_within
|
|
34
|
+
# end
|
|
35
|
+
# @last_spatials_within = spatials_within
|
|
36
|
+
#
|
|
37
|
+
# unless @last_spatials_without.nil?
|
|
38
|
+
# (spatials_without - @last_spatials_without).each do |spatial_without|
|
|
39
|
+
# @game_object.notify :exited_region, RegionalTransitionEvent.new(self, spatial_without) if existed_last_update? spatial_without
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
# @last_spatials_without = spatials_without
|
|
43
|
+
# @last_spatials = spatials
|
|
44
|
+
# end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#Indicates whether the given point is within the region's boundaries.
|
|
48
|
+
def within_region?(spatial)
|
|
49
|
+
half_width = dimensions.x / 2.0
|
|
50
|
+
half_height = dimensions.y / 2.0
|
|
51
|
+
((@game_object.x - half_width) < spatial.x) && ((@game_object.x + half_width) > spatial.x) &&
|
|
52
|
+
((@game_object.y - half_height) < spatial.y) && ((@game_object.y + half_height) > spatial.y)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#Indicates whether the given object existed on the previous world update.
|
|
56
|
+
#If not, it should not be considered for collision events on this update.
|
|
57
|
+
def existed_last_update?(game_object)
|
|
58
|
+
@last_spatials.find {|previous_game_object| game_object == previous_game_object}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def toggle_debug_mode
|
|
62
|
+
@debug_mode = !@debug_mode
|
|
63
|
+
if @debug_mode
|
|
64
|
+
game_state.manager(:render).on_before_render do |graphics|
|
|
65
|
+
old_color = graphics.color
|
|
66
|
+
graphics.color = Color.new(0.0, 1.0, 0.0, 0.3).native_color
|
|
67
|
+
half_width = dimensions.x / 2.0
|
|
68
|
+
half_height = dimensions.y / 2.0
|
|
69
|
+
graphics.fill_rect(@game_object.x - half_width, @game_object.y - half_height, dimensions.x, dimensions.y)
|
|
70
|
+
graphics.color = old_color
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
game_state.manager(:render).remove_before_draw self
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This behavior rotates to face the tracking point or game object.
|
|
2
|
+
class RotatesToPoint < Jemini::Behavior
|
|
3
|
+
#TODO: Add offset rotation
|
|
4
|
+
depends_on :Physical
|
|
5
|
+
attr_accessor :rotation_target
|
|
6
|
+
alias_method :set_rotation_target, :rotation_target=
|
|
7
|
+
|
|
8
|
+
def load
|
|
9
|
+
@game_object.on_update do
|
|
10
|
+
@game_object.set_rotation rotation_to_face_target if @rotation_target
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#The angle that the object must turn to face the rotation_target.
|
|
15
|
+
def rotation_to_face_target
|
|
16
|
+
#TODO: Use vector
|
|
17
|
+
diff_angle = Jemini::Math.radians_to_degrees Math.atan2(@game_object.y - @rotation_target.y, @game_object.x - @rotation_target.x)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#Gives an object x/y coordinates.
|
|
2
|
+
class Spatial < Jemini::Behavior
|
|
3
|
+
wrap_with_callbacks :position=
|
|
4
|
+
attr_accessor :position
|
|
5
|
+
|
|
6
|
+
alias_method :set_position, :position=
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def load
|
|
10
|
+
@position = Vector.new(0,0)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def x
|
|
14
|
+
@position.x
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def y
|
|
18
|
+
@position.y
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def x=(x)
|
|
22
|
+
@position.x = x
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def y=(y)
|
|
26
|
+
@position.y = y
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#Takes a Vector or x/y coordinates to move to.
|
|
30
|
+
# def move(x_or_other, y=nil)
|
|
31
|
+
# if y.nil?
|
|
32
|
+
# #TODO: Determine if Spatial should really suppor this behavior.
|
|
33
|
+
# # use case: Pipe a mouse move event directly to move
|
|
34
|
+
# if x_or_other.kind_of? Jemini::Message
|
|
35
|
+
# @position = Vector.new(x_or_other.value.x, x_or_other.value.y)
|
|
36
|
+
# else
|
|
37
|
+
# @position = Vector.new(x_or_other.x, x_or_other.y)
|
|
38
|
+
# end
|
|
39
|
+
# else
|
|
40
|
+
# @position = Vector.new(x_or_other, y)
|
|
41
|
+
# end
|
|
42
|
+
# end
|
|
43
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
# Makes an object transition between states.
|
|
3
|
+
# Notes from Logan:
|
|
4
|
+
# I started on this behavior, and realized what I needed was multiple axises of states for my behavior
|
|
5
|
+
# that I wanted to use Stateful in. This behavior is simple, and seems like it would be useful for some cases.
|
|
6
|
+
# Thus, the behavior remains, but it is not tested or used at the time of this comment.
|
|
7
|
+
class Stateful < Jemini::Behavior
|
|
8
|
+
class StateTransferEvent
|
|
9
|
+
attr_accessor :before_state, :after_state
|
|
10
|
+
def initialize(before_state, after_state)
|
|
11
|
+
@before_state = before_state
|
|
12
|
+
@after_state = after_state
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
attr_accessor :default_state, :current_state
|
|
16
|
+
wrap_with_callbacks :transfer_state
|
|
17
|
+
|
|
18
|
+
def load
|
|
19
|
+
@state_transitions = {}
|
|
20
|
+
@game_object.enable_listeners_for :state_transfer_accepted
|
|
21
|
+
@game_object.enable_listeners_for :state_transfer_rejected
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def transfer_state(state)
|
|
25
|
+
event = StateTransferEvent.new(@current_state, state)
|
|
26
|
+
if @state_transitions[@current_state].include? state
|
|
27
|
+
@current_state = state
|
|
28
|
+
notify :state_transfer_accepted, event
|
|
29
|
+
else
|
|
30
|
+
notify :state_transfer_rejected, event
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#Allows an object to be categorized.
|
|
2
|
+
class Taggable < Jemini::Behavior
|
|
3
|
+
|
|
4
|
+
def load
|
|
5
|
+
@tags = []
|
|
6
|
+
@game_object.enable_listeners_for :tag_added, :tag_removed
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def add_tag(*tags)
|
|
10
|
+
new_tags = tags - @tags
|
|
11
|
+
@tags.concat new_tags
|
|
12
|
+
new_tags.each { |tag| @game_object.notify :tag_added, tag }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def remove_tag(*tags)
|
|
16
|
+
tags_to_remove = @tags & tags
|
|
17
|
+
@tags -= tags_to_remove
|
|
18
|
+
tags_to_remove.each {|tag| @game_object.notify :tag_removed, tag}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def has_tag?(*tags)
|
|
22
|
+
tags.any? {|tag| @tags.member?(tag) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def tags
|
|
26
|
+
@tags.clone
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#A shape used to determine if one object collides with another.
|
|
2
|
+
class TangibleBox
|
|
3
|
+
attr_accessor :size
|
|
4
|
+
def get_points(top_left_position, rotation)
|
|
5
|
+
top_left = top_left_position
|
|
6
|
+
top_right = Vector.new(top_left_position.x + size.x, top_left_position.y)
|
|
7
|
+
bottom_left = Vector.new(top_left_position.x, top_left_position.y + size.y)
|
|
8
|
+
bottom_right = Vector.new(top_left_position.x + size.x, top_left_position.y + size.y)
|
|
9
|
+
[top_left, top_right, bottom_right, bottom_left]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
#Allows an object to indicate when it collides with another.
|
|
14
|
+
class Tangible < Jemini::Behavior
|
|
15
|
+
depends_on :Spatial
|
|
16
|
+
attr_reader :tangible_shape
|
|
17
|
+
|
|
18
|
+
def load
|
|
19
|
+
@game_object.enable_listeners_for :tangible_collision
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def tangible_debug_mode=(mode)
|
|
23
|
+
if mode
|
|
24
|
+
@game_object.add_behavior :DebugTangible
|
|
25
|
+
else
|
|
26
|
+
@game_object.remove_behavior :DebugTangible
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
alias_method :set_tangible_debug_mode, :tangible_debug_mode=
|
|
30
|
+
|
|
31
|
+
#Set the shape of the object as seen by collision calculations.
|
|
32
|
+
#call-seq:
|
|
33
|
+
#set_shape(:Box, vector)
|
|
34
|
+
#set_shape(:Box, width, height)
|
|
35
|
+
#
|
|
36
|
+
def set_tangible_shape(name, *args)
|
|
37
|
+
@tangible_shape = case name
|
|
38
|
+
when :Box
|
|
39
|
+
box = TangibleBox.new
|
|
40
|
+
if args.size == 1
|
|
41
|
+
box.size = args[0]
|
|
42
|
+
else
|
|
43
|
+
box.size = Vector.new(args[0], args[1])
|
|
44
|
+
end
|
|
45
|
+
box
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#Indicates whether this object collides with the given object.
|
|
50
|
+
def tangibly_collides_with?(other_tangible)
|
|
51
|
+
#TODO: top_left isn't on spatial...
|
|
52
|
+
other_shape = other_tangible.tangible_shape
|
|
53
|
+
|
|
54
|
+
((@game_object.x <= other_tangible.x && (@game_object.x + @tangible_shape.size.x) >= other_tangible.x) ||
|
|
55
|
+
( @game_object.x >= other_tangible.x && @game_object.x <= (other_tangible.x + other_shape.size.x))) &&
|
|
56
|
+
((@game_object.y <= other_tangible.y && (@game_object.y + @tangible_shape.size.y) >= other_tangible.y) ||
|
|
57
|
+
( @game_object.y >= other_tangible.y && @game_object.y <= (other_tangible.y + other_shape.size.y)))
|
|
58
|
+
end
|
|
59
|
+
end
|