gemini 1.0.0

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 (114) hide show
  1. data/bin/gemini +18 -0
  2. data/build_configuration.rb +24 -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-raw.dll +0 -0
  13. data/lib/native_files/libjinput-linux.so +0 -0
  14. data/lib/native_files/libjinput-linux64.so +0 -0
  15. data/lib/native_files/libjinput-osx.jnilib +0 -0
  16. data/lib/native_files/liblwjgl.jnilib +0 -0
  17. data/lib/native_files/liblwjgl.so +0 -0
  18. data/lib/native_files/liblwjgl64.so +0 -0
  19. data/lib/native_files/libopenal.so +0 -0
  20. data/lib/native_files/lwjgl.dll +0 -0
  21. data/lib/native_files/openal.dylib +0 -0
  22. data/lib/natives-linux.jar +0 -0
  23. data/lib/natives-mac.jar +0 -0
  24. data/lib/natives-win32.jar +0 -0
  25. data/lib/phys2d.jar +0 -0
  26. data/lib/slick.jar +0 -0
  27. data/package/jar/gemini.jar +0 -0
  28. data/src/base_state.rb +112 -0
  29. data/src/behavior.rb +230 -0
  30. data/src/behavior_event.rb +23 -0
  31. data/src/behaviors.txt +5 -0
  32. data/src/behaviors/animated_sprite.rb +51 -0
  33. data/src/behaviors/audible.rb +11 -0
  34. data/src/behaviors/axis_stateful.rb +33 -0
  35. data/src/behaviors/big_sprite.rb +56 -0
  36. data/src/behaviors/bounding_box_collidable.rb +25 -0
  37. data/src/behaviors/camera_anchored_drawable.rb +20 -0
  38. data/src/behaviors/cardinal_movable.rb +114 -0
  39. data/src/behaviors/clickable.rb +18 -0
  40. data/src/behaviors/countable.rb +31 -0
  41. data/src/behaviors/debug_physical.rb +31 -0
  42. data/src/behaviors/debug_tangible.rb +30 -0
  43. data/src/behaviors/drawable.rb +6 -0
  44. data/src/behaviors/drawable_shape.rb +43 -0
  45. data/src/behaviors/fading_image_trail_emittable.rb +28 -0
  46. data/src/behaviors/game_object_emittable.rb +12 -0
  47. data/src/behaviors/gravity_source.rb +21 -0
  48. data/src/behaviors/inertial.rb +11 -0
  49. data/src/behaviors/movable2d.rb +9 -0
  50. data/src/behaviors/multi_animated_sprite.rb +22 -0
  51. data/src/behaviors/physical.rb +348 -0
  52. data/src/behaviors/physical_cardinal_movable.rb +110 -0
  53. data/src/behaviors/physical_sprite.rb +29 -0
  54. data/src/behaviors/platformer_controllable.rb +144 -0
  55. data/src/behaviors/pointer.rb +28 -0
  56. data/src/behaviors/pressable.rb +13 -0
  57. data/src/behaviors/receives_events.rb +21 -0
  58. data/src/behaviors/regional.rb +71 -0
  59. data/src/behaviors/rotates_to_point.rb +18 -0
  60. data/src/behaviors/spatial.rb +41 -0
  61. data/src/behaviors/spline_stretchable_sprite.rb +45 -0
  62. data/src/behaviors/sprite.rb +99 -0
  63. data/src/behaviors/stateful.rb +31 -0
  64. data/src/behaviors/taggable.rb +27 -0
  65. data/src/behaviors/tangible.rb +51 -0
  66. data/src/behaviors/timeable.rb +79 -0
  67. data/src/behaviors/top_down_vehicle.rb +41 -0
  68. data/src/behaviors/triangle_trail_emittable.rb +41 -0
  69. data/src/behaviors/updates.rb +10 -0
  70. data/src/behaviors/updates_at_consistant_rate.rb +27 -0
  71. data/src/behaviors/vectored_movement.rb +47 -0
  72. data/src/behaviors/world_collidable.rb +8 -0
  73. data/src/color.rb +70 -0
  74. data/src/game_object.rb +174 -0
  75. data/src/game_objects/background.rb +9 -0
  76. data/src/game_objects/fading_image.rb +23 -0
  77. data/src/game_objects/icon_strip_counter_display.rb +58 -0
  78. data/src/game_objects/static_sprite.rb +18 -0
  79. data/src/game_objects/tangible_object.rb +4 -0
  80. data/src/game_objects/text.rb +59 -0
  81. data/src/game_objects/triangle_trail.rb +85 -0
  82. data/src/gemini.rb +110 -0
  83. data/src/gemini_version.rb +3 -0
  84. data/src/inflector.rb +68 -0
  85. data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
  86. data/src/listenable_mixin.rb +15 -0
  87. data/src/managers/basic_game_object_manager.rb +81 -0
  88. data/src/managers/basic_physics_manager.rb +97 -0
  89. data/src/managers/basic_render_manager.rb +48 -0
  90. data/src/managers/basic_tangible_manager.rb +33 -0
  91. data/src/managers/basic_update_manager.rb +27 -0
  92. data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
  93. data/src/managers/input_manager.rb +229 -0
  94. data/src/managers/input_support/input_mapping.rb +126 -0
  95. data/src/managers/input_support/input_message.rb +5 -0
  96. data/src/managers/input_support/slick_input_listener.rb +19 -0
  97. data/src/managers/input_support/slick_input_message.rb +11 -0
  98. data/src/managers/input_support/slick_input_translator.rb +15 -0
  99. data/src/managers/message_queue.rb +54 -0
  100. data/src/managers/scrolling_render_manager.rb +44 -0
  101. data/src/managers/sound_manager.rb +60 -0
  102. data/src/managers/tag_manager.rb +43 -0
  103. data/src/math.rb +13 -0
  104. data/src/music.rb +14 -0
  105. data/src/org/rubyforge/rawr/Main.java +67 -0
  106. data/src/platform.rb +28 -0
  107. data/src/proc_enhancement.rb +5 -0
  108. data/src/project_generator.rb +122 -0
  109. data/src/skeleton.txt +10 -0
  110. data/src/spline.rb +13 -0
  111. data/src/states/input_diagnostic_state.rb +53 -0
  112. data/src/vector.rb +99 -0
  113. data/test/test_state.rb +3 -0
  114. metadata +181 -0
@@ -0,0 +1,110 @@
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
+ # movement constrained
4
+ # TODO: Allow disabling of diaganol easily
5
+ # TODO: Allow disabling of directions
6
+ # TODO: Allow speed limit per axis
7
+ # TODO: Allow speed limit per direction
8
+ class PhysicalCardinalMovable < Gemini::Behavior
9
+ NORTH = :north
10
+ EAST = :east
11
+ SOUTH = :south
12
+ WEST = :west
13
+ NORTH_EAST = :north_east
14
+ SOUTH_EAST = :south_east
15
+ SOUTH_WEST = :south_west
16
+ NORTH_WEST = :north_west
17
+ DIAGONOL_DIRECTIONS = [NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST]
18
+ CARDINAL_DIRECTIONS = [NORTH, EAST, SOUTH, WEST] + DIAGONOL_DIRECTIONS
19
+ DIRECTION_TRANSLATION_IN_DEGREES = []
20
+
21
+ depends_on :Physical
22
+ depends_on :ReceivesEvents
23
+ attr_accessor :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
+ @target.on_update do
31
+ @target.add_velocity @cardinal_velocity if @moving
32
+ end
33
+ end
34
+
35
+ def facing_direction=(direction)
36
+ if @allowed_directions.include? direction
37
+ if @moving && orthogonal_directions?(@facing_direction, direction)
38
+ diagonol_direction = begin
39
+ "#{self.class}::#{@facing_direction.to_s.upcase}_#{direction.to_s.upcase}".constantize
40
+ rescue
41
+ "#{self.class}::#{direction.to_s.upcase}_#{@facing_direction.to_s.upcase}".constantize
42
+ end
43
+ @facing_direction = diagonol_direction
44
+ else
45
+ @facing_direction = direction
46
+ end
47
+ end
48
+ end
49
+ alias_method :set_facing_direction, :facing_direction=
50
+
51
+ def constrain_direction(directions)
52
+ directions = [directions] unless directions.kind_of? Array
53
+ directions.each
54
+ directions.each { |direction| @allowed_directions.delete direction }
55
+ end
56
+
57
+ def begin_cardinal_movement(message)
58
+ direction = message.value
59
+ return unless @allowed_directions.include? direction
60
+ set_facing_direction direction
61
+ @moving = true
62
+ @cardinal_velocity = direction_to_polar_vector(@facing_direction)
63
+ end
64
+
65
+ def end_cardinal_movement(message)
66
+ direction = message.value
67
+ @facing_direction = other_direction(@facing_direction, direction) if diagonol_direction? @facing_direction
68
+ if @facing_direction == direction
69
+ @cardinal_velocity = Vector.new(0,0)
70
+ @moving = false
71
+ else
72
+ @cardinal_velocity = direction_to_polar_vector(@facing_direction)
73
+ end
74
+ end
75
+
76
+ def direction_to_polar_vector(direction)
77
+ angle = case direction
78
+ when NORTH
79
+ 0
80
+ when NORTH_EAST
81
+ 45
82
+ when EAST
83
+ 90
84
+ when SOUTH_EAST
85
+ 135
86
+ when SOUTH
87
+ 180
88
+ when SOUTH_WEST
89
+ 225
90
+ when WEST
91
+ 270
92
+ when NORTH_WEST
93
+ 315
94
+ end
95
+ Vector.from_polar_vector(@cardinal_speed, angle)
96
+ end
97
+
98
+ def diagonol_direction?(direction)
99
+ DIAGONOL_DIRECTIONS.include? direction
100
+ end
101
+
102
+ def other_direction(diagonol_direction, direction)
103
+ diagonol_direction.to_s.sub(direction.to_s, '').sub('_', '').to_sym
104
+ end
105
+
106
+ def orthogonal_directions?(direction_a, direction_b)
107
+ ([NORTH, SOUTH].include?(direction_a) && [EAST, WEST].include?(direction_b)) ||
108
+ ([NORTH, SOUTH].include?(direction_b) && [EAST, WEST].include?(direction_a))
109
+ end
110
+ end
@@ -0,0 +1,29 @@
1
+ class PhysicalSprite < Gemini::Behavior
2
+ depends_on :Sprite
3
+ depends_on :Physical
4
+ attr_accessor :tiled_to_bounds
5
+ alias_method :set_tiled_to_bounds, :tiled_to_bounds=
6
+
7
+ def load
8
+ #TODO: This should call a method that does the same thing for performance
9
+ @target.on_before_draw do
10
+ @target.image_rotation = @target.physical_rotation unless @target.image.nil?
11
+ #TODO: Only execute this if the shape is bound to the image.
12
+ #TODO: Call raw_move instead of x= and y=
13
+ position = @target.body_position
14
+ @target.x = position.x
15
+ @target.y = position.y
16
+ end
17
+ end
18
+
19
+ def bounded_image=(new_image)
20
+ @target.set_image new_image
21
+ @target.set_shape(:Box, @target.image_size.x, @target.image_size.y)
22
+ end
23
+ alias_method :set_bounded_image, :bounded_image=
24
+
25
+ def tiled_to_bounds=(state)
26
+ @tiled_to_bounds = state
27
+ @target.image_size = @target.box_size
28
+ end
29
+ end
@@ -0,0 +1,144 @@
1
+ # Allows control of a PhysicalSprite in a platformer environment.
2
+ # TODO: Consider moving some of this to a general platformer behavior
3
+ # This behavior will know if it is on the ground
4
+ # TODO: Make a CardinalMovable, for moving N E S W
5
+ # TODO: Allow Walljumping?
6
+ # TODO: Jump-platform exclusion list
7
+ # TODO: Stateful behavior to know when we're jumping, walking, jumping + shooting, walking + shooting, etc
8
+ class PlatformerControllable < Gemini::Behavior
9
+ depends_on :ReceivesEvents
10
+ depends_on :MultiAnimatedSprite
11
+ depends_on :PhysicalSprite
12
+ depends_on :Timeable
13
+ # depends_on :AxisStateful
14
+
15
+ def load
16
+ # @target.set_state_transitions_on_axis[:vertical_platform] = [:grounded, :jumping, :falling]
17
+ # @target.set_state_transitions_on_axis[:horizontal_platform] = [:walking, :standing]
18
+ @target.set_mass 1
19
+ #set_damping 0.1
20
+ @target.set_friction 0
21
+ @target.set_speed_limit(Vector.new(20, 50))
22
+ @target.set_rotatable false
23
+ @horizontal_speed = 100
24
+ @jump_force = 20000
25
+ @facing_right = true
26
+ @target.on_update do
27
+ detect_grounded
28
+ if @moving && grounded?
29
+ @target.animate :walk
30
+ elsif !@moving && grounded?
31
+ @target.animate :stand
32
+ else
33
+ @target.animate :jump
34
+ end
35
+
36
+ if @moving
37
+ # causes smooth movement
38
+ velocity = @target.velocity
39
+ # Another shameless rip of Kevin Glass's code
40
+ # if we've been pushed back from a collision horizontally
41
+ # then kill the velocity - don't want to keep pushing during
42
+ # this frame
43
+ if (velocity.x > 0 && !@facing_right) || (velocity.x < 0 && @facing_right)
44
+ #puts "pushing back"
45
+ velocity.x = 0
46
+ else
47
+ velocity.x = @facing_right ? @horizontal_speed : -@horizontal_speed
48
+ end
49
+
50
+ @target.set_velocity(velocity)
51
+ else
52
+ # comment out to allow for momentum?
53
+ @target.add_velocity(-@target.velocity.x, 0)
54
+ end
55
+ end
56
+ # @target.on_collided do |message|
57
+ # # The collision event hasn't been resolved yet, so we can't check all of our collisions yet
58
+ # # Queue up the collision check for the next update.
59
+ # @check_grounded_on_next_update = true
60
+ # #@target.gravity_effected = false
61
+ # end
62
+ end
63
+
64
+ def grounded?
65
+ @grounded
66
+ end
67
+
68
+ def facing_direction
69
+ @facing_right ? :east : :west
70
+ end
71
+
72
+ def start_move(message)
73
+ @moving = true
74
+ if grounded?
75
+ @target.animate :walk
76
+ else
77
+ @target.animate :jump
78
+ end
79
+ case message.value
80
+ #TODO: Up and down for ladders (aka PlatformerClimbables)
81
+ when :left
82
+ @target.flip_horizontally if @facing_right
83
+ @facing_right = false
84
+ @target.add_force(-@horizontal_speed, 0)
85
+ when :right
86
+ @target.flip_horizontally unless @facing_right
87
+ @facing_right = true
88
+ @target.add_force( @horizontal_speed, 0)
89
+ end
90
+ end
91
+
92
+ def stop_move(message)
93
+ if grounded?
94
+ @target.animate :stand
95
+ else
96
+ @target.animate :jump
97
+ end
98
+ case message.value
99
+ when :left
100
+ @moving = false unless @facing_right
101
+ when :right
102
+ @moving = false if @facing_right
103
+ end
104
+ end
105
+
106
+ def jump(message)
107
+ detect_grounded
108
+ if grounded?
109
+ puts "jump!"
110
+ @target.animate :jump
111
+ # This should help us get the object unstuck if it's sunk a little into another body
112
+ # Although, this might also get us stuck too
113
+ # TODO: Test to see if super low cielings cause PlatformerControllable to get stuck.
114
+ @target.move(@target.x, @target.y - 10)
115
+ #@target.add_force(0, -@jump_force)
116
+ # addForce doesn't always get added. Perhaps a Phys2D bug?
117
+ @target.add_velocity(0, -@jump_force)
118
+ @grounded = false
119
+ end
120
+ end
121
+
122
+ def detect_grounded
123
+ @target.get_collision_events.each do |collision_event|
124
+ # shameless rip/port from Kevin Glass's platformer example, with his comments
125
+ # if the point of collision was below the centre of the actor
126
+ # i.e. near the feet
127
+ if collision_event.point.y > (@target.y + (@target.height / 4))
128
+ # check the normal to work out which body we care about
129
+ # if the right body is involved and a collision has happened
130
+ # below it then we're on the ground
131
+ if (collision_event.normal.y < 0) && (collision_event.body_b.user_data == @target) ||
132
+ (collision_event.normal.y > 0) && (collision_event.body_a.user_data == @target)
133
+ @grounded = true
134
+ #@target.transfer_state_on_axis :grounded, :grounded
135
+ return true
136
+ end
137
+ end
138
+ end
139
+ # jumping_or_falling = @target.velocity.y > 0 ? :jumping : :falling
140
+ # @target.transfer_state_on_axis :grounded, jumping_or_falling
141
+ @grounded = false
142
+ false
143
+ end
144
+ end
@@ -0,0 +1,28 @@
1
+ class Pointer < Gemini::Behavior
2
+ depends_on :Sprite
3
+ # depends_on :Movable2d
4
+ # depends_on :CollisionPoolAlgorithmTaggable
5
+ # depends_on :WorldCollidable
6
+ depends_on :ReceivesEvents
7
+
8
+
9
+ def load
10
+ # add_tag :ui, :gui, :pointer
11
+ # collides_with_tags :gui, :clickable
12
+ #
13
+ @target.handle_event :mouse_move do |message|
14
+ mouse_movement(message)
15
+ end
16
+ # handle_event :start_click, :start_click
17
+ # handle_event :stop_click, :stop_click
18
+
19
+ # listen_for(:collided) do |event, continue|
20
+ # event.collided_object.click if event.collided_object.respond_to? :click
21
+ # end
22
+ end
23
+
24
+ def mouse_movement(message)
25
+ vector = message.value
26
+ @target.move(vector.location.x, vector.location.y)
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ class Pressable < Gemini::Behavior
2
+ depends_on :Sprite
3
+ depends_on :Clickable
4
+
5
+ def load
6
+ add_tag :button, :gui, :ui
7
+ end
8
+
9
+ def images=(image_path_hash)
10
+ @normal_image = image_path_hash[:normal]
11
+ @pressed_image = image_path_hash[:pressed]
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ class ReceivesEvents < Gemini::Behavior
2
+
3
+ def load
4
+ @handled_events = []
5
+ end
6
+
7
+ def handle_event(type, method_name=nil, &block)
8
+ if !method_name.nil?
9
+ @target.game_state.manager(:message_queue).add_listener(type, self, @target.send(:method, method_name).to_proc)
10
+ elsif block_given?
11
+ @target.game_state.manager(:message_queue).add_listener(type, self, &block)
12
+ else
13
+ raise "Either a method name or a block must be provided"
14
+ end
15
+ @handled_events << type
16
+ end
17
+
18
+ def unload
19
+ @handled_events.each {|e| @target.game_state.manager(:message_queue).remove_listener(e, self)}
20
+ end
21
+ end
@@ -0,0 +1,71 @@
1
+ require 'set'
2
+
3
+ class RegionalTransitionEvent
4
+ attr_accessor :region, :spatial
5
+ def initialize(region, spatial)
6
+ @region = region
7
+ @spatial = spatial
8
+ end
9
+ end
10
+
11
+ class Regional < Gemini::Behavior
12
+ depends_on :Spatial
13
+ attr_accessor :dimensions, :region_shape
14
+ alias_method :set_dimensions, :dimensions=
15
+ alias_method :set_region_shape, :region_shape=
16
+
17
+ # This is bad. We need a real collision system
18
+ def load
19
+ @target.enable_listeners_for :entered_region, :exited_region
20
+ @target.move(0,0)
21
+ @dimensions = Vector.new(1,1)
22
+ @last_spatials_within = []
23
+ @last_spatials_without = nil
24
+ @last_spatials = []
25
+ #TODO: SAVE: This should be turned on when requested.
26
+ # @target.game_state.manager(:update).on_update do
27
+ # spatials = @target.game_state.manager(:game_object).game_objects.select {|game_object| game_object.kind_of? Tangible}.compact
28
+ #
29
+ # spatials_within, spatials_without = spatials.partition {|spatial| within_region?(spatial)}
30
+ # (spatials_within - @last_spatials_within).each do |spatial_within|
31
+ # @target.notify :entered_region, RegionalTransitionEvent.new(self, spatial_within) if existed_last_update? spatial_within
32
+ # end
33
+ # @last_spatials_within = spatials_within
34
+ #
35
+ # unless @last_spatials_without.nil?
36
+ # (spatials_without - @last_spatials_without).each do |spatial_without|
37
+ # @target.notify :exited_region, RegionalTransitionEvent.new(self, spatial_without) if existed_last_update? spatial_without
38
+ # end
39
+ # end
40
+ # @last_spatials_without = spatials_without
41
+ # @last_spatials = spatials
42
+ # end
43
+ end
44
+
45
+ def within_region?(spatial)
46
+ half_width = dimensions.x / 2.0
47
+ half_height = dimensions.y / 2.0
48
+ ((@target.x - half_width) < spatial.x) && ((@target.x + half_width) > spatial.x) &&
49
+ ((@target.y - half_height) < spatial.y) && ((@target.y + half_height) > spatial.y)
50
+ end
51
+
52
+ def existed_last_update?(game_object)
53
+ @last_spatials.find {|previous_game_object| game_object == previous_game_object}
54
+ end
55
+
56
+ def toggle_debug_mode
57
+ @debug_mode = !@debug_mode
58
+ if @debug_mode
59
+ @target.game_state.manager(:render).on_before_render do |graphics|
60
+ old_color = graphics.color
61
+ graphics.color = Color.new(0.0, 1.0, 0.0, 0.3).native_color
62
+ half_width = dimensions.x / 2.0
63
+ half_height = dimensions.y / 2.0
64
+ graphics.fill_rect(@target.x - half_width, @target.y - half_height, dimensions.x, dimensions.y)
65
+ graphics.color = old_color
66
+ end
67
+ else
68
+ @target.game_state.manager(:render).remove_before_draw self
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,18 @@
1
+ # This behavior rotates to face the tracking point or game object
2
+ class RotatesToPoint < Gemini::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
+ @target.on_update do
10
+ @target.set_rotation rotation_to_face_target if @rotation_target
11
+ end
12
+ end
13
+
14
+ def rotation_to_face_target
15
+ #TODO: Use vector
16
+ diff_angle = Gemini::Math.radians_to_degrees Math.atan2(@target.y - @rotation_target.y, @target.x - @rotation_target.x)
17
+ end
18
+ end
@@ -0,0 +1,41 @@
1
+ class Spatial < Gemini::Behavior
2
+ attr_accessor :position
3
+ alias_method :set_position, :position=
4
+ wrap_with_callbacks :move
5
+
6
+ def load
7
+ @position = Vector.new(0,0)
8
+ end
9
+
10
+ def x
11
+ @position.x
12
+ end
13
+
14
+ def y
15
+ @position.y
16
+ end
17
+
18
+ def x=(x)
19
+ @position.x = x
20
+ end
21
+
22
+ def y=(y)
23
+ @position.y = y
24
+ end
25
+
26
+ def move(x_or_other, y=nil)
27
+ if y.nil?
28
+ if x_or_other.kind_of? Vector
29
+ @position = Vector.new(x_or_other.x, x_or_other.y)
30
+ #TODO: Determine if Spatial should really suppor this behavior.
31
+ # use case: Pipe a mouse move event directly to move
32
+ elsif x_or_other.kind_of? Gemini::Message
33
+ @position = Vector.new(x_or_other.value.x, x_or_other.value.y)
34
+ else
35
+ raise "move does not support #{x_or_other.class}"
36
+ end
37
+ else
38
+ @position = Vector.new(x_or_other, y)
39
+ end
40
+ end
41
+ end