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.
Files changed (127) hide show
  1. data/README.txt +9 -0
  2. data/bin/jemini +26 -0
  3. data/lib/ibxm.jar +0 -0
  4. data/lib/jinput.jar +0 -0
  5. data/lib/jogg-0.0.7.jar +0 -0
  6. data/lib/jorbis-0.0.15.jar +0 -0
  7. data/lib/jruby-complete.jar +0 -0
  8. data/lib/lwjgl.jar +0 -0
  9. data/lib/lwjgl_util_applet.jar +0 -0
  10. data/lib/native_files/OpenAL32.dll +0 -0
  11. data/lib/native_files/jinput-dx8.dll +0 -0
  12. data/lib/native_files/jinput-dx8_64.dll +0 -0
  13. data/lib/native_files/jinput-raw.dll +0 -0
  14. data/lib/native_files/jinput-raw_64.dll +0 -0
  15. data/lib/native_files/jinput-wintab.dll +0 -0
  16. data/lib/native_files/libjinput-linux.so +0 -0
  17. data/lib/native_files/libjinput-linux64.so +0 -0
  18. data/lib/native_files/libjinput-osx.jnilib +0 -0
  19. data/lib/native_files/liblwjgl.jnilib +0 -0
  20. data/lib/native_files/liblwjgl.so +0 -0
  21. data/lib/native_files/liblwjgl64.so +0 -0
  22. data/lib/native_files/libopenal.so +0 -0
  23. data/lib/native_files/lwjgl.dll +0 -0
  24. data/lib/native_files/openal.dylib +0 -0
  25. data/lib/natives-linux.jar +0 -0
  26. data/lib/natives-mac.jar +0 -0
  27. data/lib/natives-win32.jar +0 -0
  28. data/lib/phys2d.jar +0 -0
  29. data/lib/slick.jar +0 -0
  30. data/package/jar/jemini.jar +0 -0
  31. data/src/behavior.rb +248 -0
  32. data/src/behavior_event.rb +23 -0
  33. data/src/behaviors/animated_image.rb +88 -0
  34. data/src/behaviors/audible.rb +16 -0
  35. data/src/behaviors/axis_stateful.rb +35 -0
  36. data/src/behaviors/bounding_box_collidable.rb +27 -0
  37. data/src/behaviors/cardinal_movable.rb +121 -0
  38. data/src/behaviors/clickable.rb +19 -0
  39. data/src/behaviors/countable.rb +32 -0
  40. data/src/behaviors/debug_physical.rb +43 -0
  41. data/src/behaviors/debug_tangible.rb +31 -0
  42. data/src/behaviors/drawable.rb +7 -0
  43. data/src/behaviors/drawable_image.rb +111 -0
  44. data/src/behaviors/drawable_line.rb +32 -0
  45. data/src/behaviors/drawable_shape.rb +48 -0
  46. data/src/behaviors/fading_image_trail_emittable.rb +32 -0
  47. data/src/behaviors/game_object_emittable.rb +13 -0
  48. data/src/behaviors/grid_bound.rb +108 -0
  49. data/src/behaviors/handles_events.rb +33 -0
  50. data/src/behaviors/inertial.rb +14 -0
  51. data/src/behaviors/magnetic.rb +34 -0
  52. data/src/behaviors/metered.rb +3 -0
  53. data/src/behaviors/movable.rb +81 -0
  54. data/src/behaviors/particle_emitter.rb +27 -0
  55. data/src/behaviors/physical.rb +384 -0
  56. data/src/behaviors/physical_cardinal_movable.rb +111 -0
  57. data/src/behaviors/physical_image.rb +45 -0
  58. data/src/behaviors/pointer.rb +30 -0
  59. data/src/behaviors/pressable.rb +17 -0
  60. data/src/behaviors/regional.rb +76 -0
  61. data/src/behaviors/rotates_to_point.rb +19 -0
  62. data/src/behaviors/spatial.rb +43 -0
  63. data/src/behaviors/stateful.rb +33 -0
  64. data/src/behaviors/taggable.rb +28 -0
  65. data/src/behaviors/tangible.rb +59 -0
  66. data/src/behaviors/timeable.rb +88 -0
  67. data/src/behaviors/top_down_vehicle.rb +42 -0
  68. data/src/behaviors/triangle_trail_emittable.rb +46 -0
  69. data/src/behaviors/unique.rb +0 -0
  70. data/src/behaviors/updates.rb +8 -0
  71. data/src/behaviors/updates_at_consistant_rate.rb +28 -0
  72. data/src/behaviors/vectored_movement.rb +48 -0
  73. data/src/behaviors/world_collidable.rb +9 -0
  74. data/src/color.rb +70 -0
  75. data/src/events/grid_changed_event.rb +8 -0
  76. data/src/events/physical_message.rb +9 -0
  77. data/src/events/tangible_collision_event.rb +8 -0
  78. data/src/file_system.rb +17 -0
  79. data/src/game.rb +110 -0
  80. data/src/game_object.rb +176 -0
  81. data/src/game_objects/background.rb +10 -0
  82. data/src/game_objects/fading_image.rb +23 -0
  83. data/src/game_objects/tangible_object.rb +4 -0
  84. data/src/game_objects/text.rb +71 -0
  85. data/src/game_objects/triangle_trail.rb +85 -0
  86. data/src/game_state.rb +164 -0
  87. data/src/inflector.rb +68 -0
  88. data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
  89. data/src/jemini.rb +31 -0
  90. data/src/jemini_version.rb +4 -0
  91. data/src/listenable_mixin.rb +15 -0
  92. data/src/logger_mixin.rb +11 -0
  93. data/src/managers/basic_game_object_manager.rb +95 -0
  94. data/src/managers/basic_physics_manager.rb +95 -0
  95. data/src/managers/basic_render_manager.rb +49 -0
  96. data/src/managers/basic_tile_manager.rb +3 -0
  97. data/src/managers/basic_update_manager.rb +30 -0
  98. data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
  99. data/src/managers/input_manager.rb +161 -0
  100. data/src/managers/input_support/input_binding.rb +77 -0
  101. data/src/managers/input_support/input_builder.rb +44 -0
  102. data/src/managers/input_support/input_listener.rb +74 -0
  103. data/src/managers/input_support/input_message.rb +5 -0
  104. data/src/managers/input_support/joystick_listener.rb +53 -0
  105. data/src/managers/input_support/key_listener.rb +27 -0
  106. data/src/managers/input_support/mouse_listener.rb +38 -0
  107. data/src/managers/input_support/slick_input_listener.rb +20 -0
  108. data/src/managers/input_support/slick_input_message.rb +11 -0
  109. data/src/managers/input_support/slick_input_translator.rb +15 -0
  110. data/src/managers/message_queue.rb +60 -0
  111. data/src/managers/network_manager.rb +41 -0
  112. data/src/managers/render_support/hardware_cursor.rb +13 -0
  113. data/src/managers/resource_manager.rb +167 -0
  114. data/src/managers/sound_manager.rb +47 -0
  115. data/src/managers/tag_manager.rb +47 -0
  116. data/src/managers/tangible_manager.rb +36 -0
  117. data/src/math.rb +23 -0
  118. data/src/org/rubyforge/rawr/Main.java +67 -0
  119. data/src/platform.rb +28 -0
  120. data/src/proc_enhancement.rb +5 -0
  121. data/src/project_generator.rb +138 -0
  122. data/src/resource.rb +31 -0
  123. data/src/spline.rb +13 -0
  124. data/src/states/input_diagnostic_state.rb +53 -0
  125. data/src/vector.rb +143 -0
  126. data/test/test_state.rb +3 -0
  127. 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