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.
- data/bin/gemini +18 -0
- data/build_configuration.rb +24 -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-raw.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/gemini.jar +0 -0
- data/src/base_state.rb +112 -0
- data/src/behavior.rb +230 -0
- data/src/behavior_event.rb +23 -0
- data/src/behaviors.txt +5 -0
- data/src/behaviors/animated_sprite.rb +51 -0
- data/src/behaviors/audible.rb +11 -0
- data/src/behaviors/axis_stateful.rb +33 -0
- data/src/behaviors/big_sprite.rb +56 -0
- data/src/behaviors/bounding_box_collidable.rb +25 -0
- data/src/behaviors/camera_anchored_drawable.rb +20 -0
- data/src/behaviors/cardinal_movable.rb +114 -0
- data/src/behaviors/clickable.rb +18 -0
- data/src/behaviors/countable.rb +31 -0
- data/src/behaviors/debug_physical.rb +31 -0
- data/src/behaviors/debug_tangible.rb +30 -0
- data/src/behaviors/drawable.rb +6 -0
- data/src/behaviors/drawable_shape.rb +43 -0
- data/src/behaviors/fading_image_trail_emittable.rb +28 -0
- data/src/behaviors/game_object_emittable.rb +12 -0
- data/src/behaviors/gravity_source.rb +21 -0
- data/src/behaviors/inertial.rb +11 -0
- data/src/behaviors/movable2d.rb +9 -0
- data/src/behaviors/multi_animated_sprite.rb +22 -0
- data/src/behaviors/physical.rb +348 -0
- data/src/behaviors/physical_cardinal_movable.rb +110 -0
- data/src/behaviors/physical_sprite.rb +29 -0
- data/src/behaviors/platformer_controllable.rb +144 -0
- data/src/behaviors/pointer.rb +28 -0
- data/src/behaviors/pressable.rb +13 -0
- data/src/behaviors/receives_events.rb +21 -0
- data/src/behaviors/regional.rb +71 -0
- data/src/behaviors/rotates_to_point.rb +18 -0
- data/src/behaviors/spatial.rb +41 -0
- data/src/behaviors/spline_stretchable_sprite.rb +45 -0
- data/src/behaviors/sprite.rb +99 -0
- data/src/behaviors/stateful.rb +31 -0
- data/src/behaviors/taggable.rb +27 -0
- data/src/behaviors/tangible.rb +51 -0
- data/src/behaviors/timeable.rb +79 -0
- data/src/behaviors/top_down_vehicle.rb +41 -0
- data/src/behaviors/triangle_trail_emittable.rb +41 -0
- data/src/behaviors/updates.rb +10 -0
- data/src/behaviors/updates_at_consistant_rate.rb +27 -0
- data/src/behaviors/vectored_movement.rb +47 -0
- data/src/behaviors/world_collidable.rb +8 -0
- data/src/color.rb +70 -0
- data/src/game_object.rb +174 -0
- data/src/game_objects/background.rb +9 -0
- data/src/game_objects/fading_image.rb +23 -0
- data/src/game_objects/icon_strip_counter_display.rb +58 -0
- data/src/game_objects/static_sprite.rb +18 -0
- data/src/game_objects/tangible_object.rb +4 -0
- data/src/game_objects/text.rb +59 -0
- data/src/game_objects/triangle_trail.rb +85 -0
- data/src/gemini.rb +110 -0
- data/src/gemini_version.rb +3 -0
- data/src/inflector.rb +68 -0
- data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
- data/src/listenable_mixin.rb +15 -0
- data/src/managers/basic_game_object_manager.rb +81 -0
- data/src/managers/basic_physics_manager.rb +97 -0
- data/src/managers/basic_render_manager.rb +48 -0
- data/src/managers/basic_tangible_manager.rb +33 -0
- data/src/managers/basic_update_manager.rb +27 -0
- data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
- data/src/managers/input_manager.rb +229 -0
- data/src/managers/input_support/input_mapping.rb +126 -0
- data/src/managers/input_support/input_message.rb +5 -0
- data/src/managers/input_support/slick_input_listener.rb +19 -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 +54 -0
- data/src/managers/scrolling_render_manager.rb +44 -0
- data/src/managers/sound_manager.rb +60 -0
- data/src/managers/tag_manager.rb +43 -0
- data/src/math.rb +13 -0
- data/src/music.rb +14 -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 +122 -0
- data/src/skeleton.txt +10 -0
- data/src/spline.rb +13 -0
- data/src/states/input_diagnostic_state.rb +53 -0
- data/src/vector.rb +99 -0
- data/test/test_state.rb +3 -0
- 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
|