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
data/src/game_object.rb
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
require 'behavior'
|
|
2
|
+
require 'listenable_mixin'
|
|
3
|
+
require 'logger_mixin'
|
|
4
|
+
|
|
5
|
+
module Jemini
|
|
6
|
+
class GameObject
|
|
7
|
+
include ListenableMixin
|
|
8
|
+
include LoggerMixin
|
|
9
|
+
attr_reader :game_state
|
|
10
|
+
|
|
11
|
+
@@declared_behaviors = Hash.new{|h,k| h[k] = []}
|
|
12
|
+
def self.has_behavior(behavior)
|
|
13
|
+
require "behaviors/#{behavior.underscore}"
|
|
14
|
+
@@declared_behaviors[self] << behavior
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(state, *args)
|
|
18
|
+
@game_state = state
|
|
19
|
+
@callbacks = Hash.new {|h,k| h[k] = []}
|
|
20
|
+
@__behaviors = {}
|
|
21
|
+
enable_listeners_for :before_remove, :after_remove
|
|
22
|
+
declared_behaviors.each do |behavior|
|
|
23
|
+
add_behavior(behavior)
|
|
24
|
+
end
|
|
25
|
+
validate_dependant_behaviors
|
|
26
|
+
load(*args)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def has_behavior?(behavior_name)
|
|
30
|
+
@__behaviors.has_key? behavior_name
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def add_behavior(behavior_name)
|
|
34
|
+
klass = nil
|
|
35
|
+
retried = false
|
|
36
|
+
begin
|
|
37
|
+
klass = behavior_name.camelize.constantize
|
|
38
|
+
rescue NameError
|
|
39
|
+
raise if retried
|
|
40
|
+
require "behaviors/#{behavior_name.underscore}"
|
|
41
|
+
retried = true
|
|
42
|
+
retry
|
|
43
|
+
end
|
|
44
|
+
@__behaviors[behavior_name] = klass.new(self) if @__behaviors[behavior_name].nil?
|
|
45
|
+
validate_dependant_behaviors
|
|
46
|
+
rescue NameError => e
|
|
47
|
+
raise "Unable to load behavior #{behavior_name}, #{e.message}\n#{e.backtrace.join("\n")}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def __destroy
|
|
51
|
+
notify :before_remove, self
|
|
52
|
+
#TODO: Perhaps expose this as a method on Behavior
|
|
53
|
+
#Jemini::Behavior.send(:class_variable_get, :@@depended_on_by).delete self
|
|
54
|
+
__remove_listeners
|
|
55
|
+
@__behaviors.each do |name, behavior|
|
|
56
|
+
#the list is being modified as we go through it, so check before use.
|
|
57
|
+
next if behavior.nil?
|
|
58
|
+
behavior.send(:delete)
|
|
59
|
+
end
|
|
60
|
+
notify :after_remove, self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def unload; end
|
|
64
|
+
|
|
65
|
+
def remove_behavior(behavior)
|
|
66
|
+
@__behaviors.delete(behavior).send(:delete) unless @__behaviors[behavior].nil?
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Takes a method and adds a corresponding listener registration method. Given
|
|
70
|
+
# the method foo, enable_listeners_for would generate the method on_foo and when
|
|
71
|
+
# notify was called with an event name of :foo, all callback blocks registered
|
|
72
|
+
# with the on_foo method would be called.
|
|
73
|
+
def enable_listeners_for(*methods)
|
|
74
|
+
methods.each do |method|
|
|
75
|
+
code = <<-ENDL
|
|
76
|
+
def on_#{method}(callback_method_name = nil, &callback)
|
|
77
|
+
register_listener(:#{method} , callback_method_name, callback)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def remove_#{method}(object, callback_or_callback_method=nil)
|
|
81
|
+
remove_registered_listener(:#{method}, object, callback_or_callback_method)
|
|
82
|
+
end
|
|
83
|
+
ENDL
|
|
84
|
+
|
|
85
|
+
self.instance_eval code, __FILE__, __LINE__
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def register_listener(listener_method_name, callback_method_name, callback)
|
|
90
|
+
if callback_method_name
|
|
91
|
+
__added_listener_for(self, listener_method_name, callback_method_name)
|
|
92
|
+
@callbacks[listener_method_name] << callback_method_name
|
|
93
|
+
else
|
|
94
|
+
origin = callback.source
|
|
95
|
+
origin.extend Jemini::ListenableMixin unless origin.kind_of? Jemini::ListenableMixin
|
|
96
|
+
origin.__added_listener_for(self, "#{listener_method_name}", callback)
|
|
97
|
+
@callbacks[listener_method_name] << callback
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def remove_registered_listener(listener_method_name, object, callback_or_callback_method)
|
|
102
|
+
if callback_or_callback_method.nil? || callback_or_callback_method.kind_of?(Symbol)
|
|
103
|
+
@callbacks[listener_method_name].delete callback_or_callback_method
|
|
104
|
+
else
|
|
105
|
+
@callbacks[listener_method_name].delete_if {|callback| callback.source == object unless callback.kind_of?(Symbol) }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def notify(event_name, event = nil, callback_status = nil)
|
|
110
|
+
@callbacks[event_name.to_sym].each do |callback|
|
|
111
|
+
if event
|
|
112
|
+
if callback_status
|
|
113
|
+
if callback.kind_of? Symbol
|
|
114
|
+
send(callback, event, callback_status)
|
|
115
|
+
else
|
|
116
|
+
callback.call(event, callback_status)
|
|
117
|
+
end
|
|
118
|
+
break unless callback_status.nil? or callback_status.continue?
|
|
119
|
+
else
|
|
120
|
+
if callback.kind_of? Symbol
|
|
121
|
+
send(callback, event)
|
|
122
|
+
else
|
|
123
|
+
callback.call(event)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
else
|
|
127
|
+
if callback.kind_of? Symbol
|
|
128
|
+
send(callback)
|
|
129
|
+
else
|
|
130
|
+
callback.call
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def listen_for(message, game_object=self, &block)
|
|
137
|
+
game_object.send("on_#{message}", &block)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# def kind_of?(klass)
|
|
141
|
+
# super || @__behaviors.values.inject(false){|result, behavior| result || behavior.class == klass}
|
|
142
|
+
# end
|
|
143
|
+
# alias_method :is_a?, :kind_of?
|
|
144
|
+
|
|
145
|
+
def load(*args)
|
|
146
|
+
args.each do |behavior_name|
|
|
147
|
+
add_behavior behavior_name
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
def behavior_event_alias(behavior_class, aliases, &block)
|
|
153
|
+
if behavior = @__behaviors[behavior_class]
|
|
154
|
+
behavior.set_event_aliases(aliases, block)
|
|
155
|
+
else
|
|
156
|
+
raise "No behavior #{behavior_class} for game object #{self}"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def validate_dependant_behaviors
|
|
161
|
+
declared_behaviors.each do |behavior|
|
|
162
|
+
behavior.constantize.kind_of_dependencies.each do |dependant_behavior|
|
|
163
|
+
dependency = dependant_behavior.constantize
|
|
164
|
+
#TODO: This code cannot work until the game object has a list of behavior objects (behaviors returns names)
|
|
165
|
+
#next if behaviors.find {|behavior| p behavior; behavior.last.kind_of?(dependency)}
|
|
166
|
+
next
|
|
167
|
+
raise "Dependant behavior '#{dependant_behavior}' was not found on class #{self.class}"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def declared_behaviors
|
|
173
|
+
@@declared_behaviors[self.class]
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class Background < Jemini::GameObject
|
|
2
|
+
has_behavior :DrawableImage
|
|
3
|
+
|
|
4
|
+
#Takes a reference to an image loaded via ResourceManager.
|
|
5
|
+
def load(image)
|
|
6
|
+
set_image image
|
|
7
|
+
set_position Vector.new(game_state.screen_width, game_state.screen_height).half
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class FadingImage < Jemini::GameObject
|
|
2
|
+
has_behavior :DrawableImage
|
|
3
|
+
has_behavior :Spatial
|
|
4
|
+
has_behavior :Timeable
|
|
5
|
+
|
|
6
|
+
def load(image, color, seconds_to_fade_away)
|
|
7
|
+
self.image = image
|
|
8
|
+
self.color = color
|
|
9
|
+
add_countdown :fade_timer, seconds_to_fade_away, 1.0 / 30.0
|
|
10
|
+
|
|
11
|
+
on_countdown_complete do
|
|
12
|
+
game_state.remove self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
on_timer_tick do |timer|
|
|
16
|
+
fade(timer.percent_complete)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def fade(percent)
|
|
21
|
+
color.transparency = percent
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'behaviors/drawable'
|
|
2
|
+
|
|
3
|
+
class Text < Jemini::GameObject
|
|
4
|
+
include_class "org.newdawn.slick.TrueTypeFont"
|
|
5
|
+
include_class "java.awt.Font"
|
|
6
|
+
|
|
7
|
+
has_behavior :Spatial
|
|
8
|
+
PLAIN = Font::PLAIN
|
|
9
|
+
ITALIC = Font::ITALIC
|
|
10
|
+
BOLD = Font::BOLD
|
|
11
|
+
|
|
12
|
+
attr_accessor :text, :size, :style, :font_name
|
|
13
|
+
|
|
14
|
+
def load(text, options={})
|
|
15
|
+
@font_name = "Arial"
|
|
16
|
+
@size = 12
|
|
17
|
+
@text = text
|
|
18
|
+
@style = PLAIN
|
|
19
|
+
load_font
|
|
20
|
+
orient_text(options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def text_width
|
|
24
|
+
@font.get_width(@text)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def text_height
|
|
28
|
+
@font.get_height(@text)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def draw(graphics)
|
|
32
|
+
half_width = @font.get_width(@text) / 2
|
|
33
|
+
half_height = @font.get_height(@text) / 2
|
|
34
|
+
@font.draw_string(x - half_width , y - half_height, @text)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def font_name=(name)
|
|
38
|
+
@font_name = name
|
|
39
|
+
load_font
|
|
40
|
+
end
|
|
41
|
+
alias_method :set_font_name, :font_name=
|
|
42
|
+
|
|
43
|
+
def size=(size)
|
|
44
|
+
@size = size
|
|
45
|
+
load_font
|
|
46
|
+
end
|
|
47
|
+
alias_method :set_size, :size=
|
|
48
|
+
|
|
49
|
+
def style=(style)
|
|
50
|
+
raise "Invalid font style, must be PLAIN, ITALIC or BOLD" unless [PLAIN, ITALIC, BOLD].member? style
|
|
51
|
+
@style = style
|
|
52
|
+
load_font
|
|
53
|
+
end
|
|
54
|
+
alias_method :set_style, :style=
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
def orient_text(options)
|
|
58
|
+
case options[:justify]
|
|
59
|
+
when :top_left
|
|
60
|
+
self.position = options[:position] + Vector.new(text_width, text_height).half if options[:position]
|
|
61
|
+
when :bottom_right
|
|
62
|
+
self.position = options[:position] - Vector.new(text_width, text_height).half if options[:position]
|
|
63
|
+
when :center, nil
|
|
64
|
+
self.position = options[:position]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def load_font
|
|
69
|
+
@font = TrueTypeFont.new(Font.new(@font_name, @style, @size), true)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
class TriangleTrail < Jemini::GameObject
|
|
2
|
+
#has_behavior :Movable2d
|
|
3
|
+
has_behavior :Spatial
|
|
4
|
+
attr_accessor :radius, :alpha
|
|
5
|
+
|
|
6
|
+
def load
|
|
7
|
+
@trail = []
|
|
8
|
+
@trail_poly_size = 10
|
|
9
|
+
@trail_size = 50
|
|
10
|
+
@radius = 10
|
|
11
|
+
@alpha = 0.5
|
|
12
|
+
@flip = false
|
|
13
|
+
#TODO: Remove message when the callback stuff is checked in
|
|
14
|
+
@first_move = true
|
|
15
|
+
on_after_position_changes do |message|
|
|
16
|
+
if @first_move
|
|
17
|
+
@first_move = false
|
|
18
|
+
next
|
|
19
|
+
end
|
|
20
|
+
@trail.pop if @trail.size >= @trail_size
|
|
21
|
+
@trail.unshift([x, y])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def draw(graphics)
|
|
26
|
+
if @trail.size > 3
|
|
27
|
+
gl = Java::org::newdawn::slick::opengl::renderer::Renderer.get
|
|
28
|
+
|
|
29
|
+
#Java::org::newdawn::slick::opengl::SlickCallable.new do
|
|
30
|
+
callable_class = Java::org::newdawn::slick::opengl::SlickCallable
|
|
31
|
+
callable_class.enter_safe_block
|
|
32
|
+
# use LWJGL's const directly, Slick's wrapper does not have the triangle strip const
|
|
33
|
+
triangle_strip_enum = Java::org::lwjgl::opengl::GL11::GL_TRIANGLE_STRIP
|
|
34
|
+
gl.gl_begin triangle_strip_enum
|
|
35
|
+
gl.gl_color4f(0.0, 1.0, 1.0, @alpha)
|
|
36
|
+
|
|
37
|
+
origin_x, origin_y = calculate_point_on_trail_edge(@trail[1], @trail[0], @radius, @flip)
|
|
38
|
+
gl.gl_vertex2f(origin_x, origin_y)
|
|
39
|
+
|
|
40
|
+
flipped_origin_x, flipped_origin_y = calculate_point_on_trail_edge(@trail[1], @trail[0], @radius, !@flip)
|
|
41
|
+
gl.gl_vertex2f(flipped_origin_x, flipped_origin_y)
|
|
42
|
+
|
|
43
|
+
last_trail_vector = @trail[1]
|
|
44
|
+
#gl.gl_color4f(0.0, 1.0, 1.0, alpha)
|
|
45
|
+
@trail[2..-1].each_with_index do |trail_vector, index|
|
|
46
|
+
next if trail_vector == last_trail_vector
|
|
47
|
+
actual_trail_size = (@trail.size - 1).to_f
|
|
48
|
+
trail_radius = (@radius) * ((actual_trail_size - (index + 2).to_f) / actual_trail_size)
|
|
49
|
+
|
|
50
|
+
rotated_x, rotated_y = calculate_point_on_trail_edge(trail_vector, last_trail_vector, trail_radius, @flip)
|
|
51
|
+
gl.gl_vertex2f(rotated_x, rotated_y)
|
|
52
|
+
rotated_x, rotated_y = calculate_point_on_trail_edge(trail_vector, last_trail_vector, trail_radius, !@flip)
|
|
53
|
+
gl.gl_vertex2f(rotated_x, rotated_y)
|
|
54
|
+
|
|
55
|
+
last_trail_vector = trail_vector
|
|
56
|
+
end
|
|
57
|
+
gl.gl_end
|
|
58
|
+
callable_class.leave_safe_block
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def calculate_point_on_trail_edge(current_vector, previous_vector, trail_radius, flip)
|
|
63
|
+
trail_diff = [current_vector[0] - previous_vector[0], current_vector[1] - previous_vector[1]]
|
|
64
|
+
diff_angle = Math.atan2(trail_diff[1].to_f, trail_diff[0].to_f)
|
|
65
|
+
|
|
66
|
+
rotation_angle = (Math::PI * 1) / 2
|
|
67
|
+
rotation_angle = -rotation_angle if flip
|
|
68
|
+
|
|
69
|
+
sine = Math.sin(diff_angle + rotation_angle)
|
|
70
|
+
cosine = Math.cos(diff_angle + rotation_angle)
|
|
71
|
+
rotated_weight_x = cosine
|
|
72
|
+
rotated_weight_y = sine
|
|
73
|
+
|
|
74
|
+
rotated_x = (trail_radius * rotated_weight_x) + current_vector[0]
|
|
75
|
+
rotated_y = (trail_radius * rotated_weight_y) + current_vector[1]
|
|
76
|
+
|
|
77
|
+
[rotated_x, rotated_y]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def normalize_vector(vector)
|
|
81
|
+
max_value = vector.map{|value| value.abs}.max
|
|
82
|
+
return Array.new(vector.size, 0) if max_value.zero?
|
|
83
|
+
vector.map {|value| value / max_value}
|
|
84
|
+
end
|
|
85
|
+
end
|
data/src/game_state.rb
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require 'logger_mixin'
|
|
2
|
+
|
|
3
|
+
#All other game states should inherit from this class.
|
|
4
|
+
module Jemini
|
|
5
|
+
class GameState
|
|
6
|
+
|
|
7
|
+
include LoggerMixin
|
|
8
|
+
|
|
9
|
+
attr_reader :container
|
|
10
|
+
|
|
11
|
+
@@active_state = nil
|
|
12
|
+
def self.active_state
|
|
13
|
+
@@active_state
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.active_state=(state)
|
|
17
|
+
@@active_state = state
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
@@inputs = Hash.new {|h,k| h[k] = []}
|
|
21
|
+
def self.use_input(input)
|
|
22
|
+
@@inputs[self] << input
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.inputs
|
|
26
|
+
@@inputs[self]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(container, game)
|
|
30
|
+
@container = container
|
|
31
|
+
@game = game
|
|
32
|
+
|
|
33
|
+
# don't use a hash literal because it messes up the load order and @managers isn't available for the managers to use
|
|
34
|
+
@managers = {}
|
|
35
|
+
@managers[:game_object] = BasicGameObjectManager.new(self)
|
|
36
|
+
@managers[:update] = BasicUpdateManager.new(self)
|
|
37
|
+
@managers[:message_queue] = MessageQueue.new(self)
|
|
38
|
+
@managers[:resource] = ResourceManager.new(self)
|
|
39
|
+
@managers[:input] = InputManager.new(self, container)
|
|
40
|
+
@managers[:render] = BasicRenderManager.new(self)
|
|
41
|
+
|
|
42
|
+
configure_inputs
|
|
43
|
+
load_resources
|
|
44
|
+
@paused = false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def screen_size
|
|
48
|
+
@game.screen_size
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# deprecate
|
|
52
|
+
def screen_width
|
|
53
|
+
@game.screen_width
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
#deprecate
|
|
57
|
+
def screen_height
|
|
58
|
+
@game.screen_height
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#Creates a game object of the given type on the named layer.
|
|
62
|
+
#The given params will be passed to the object's constructor.
|
|
63
|
+
def create_on_layer(type, layer_name, *params)
|
|
64
|
+
game_object_type = if :game_object == type.to_sym || :GameObject == type.to_sym
|
|
65
|
+
Jemini::GameObject
|
|
66
|
+
elsif Module.const_defined?(type.camelize.to_sym)
|
|
67
|
+
log.debug "Creating: #{type.camelize.to_sym}"
|
|
68
|
+
type.constantize
|
|
69
|
+
else
|
|
70
|
+
try_require("game_objects/#{type.underscore}") or try_require("managers/#{type.underscore}")
|
|
71
|
+
type.camelize.constantize
|
|
72
|
+
end
|
|
73
|
+
game_object = game_object_type.new(self, *params)
|
|
74
|
+
add_game_object_to_layer game_object, layer_name
|
|
75
|
+
game_object
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def create(type, *params)
|
|
79
|
+
create_on_layer(type, :default, *params)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def create_game_object(type, *params)
|
|
83
|
+
warn "create_game_object is deprecated, use create instead"
|
|
84
|
+
create(type, *params)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def manager(type)
|
|
88
|
+
@managers[type]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def add_game_object(game_object)
|
|
92
|
+
@managers[:game_object].add_game_object game_object
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def add_game_object_to_layer(game_object, layer_name)
|
|
96
|
+
@managers[:game_object].add_game_object_to_layer game_object, layer_name
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def remove(game_object)
|
|
100
|
+
@managers[:game_object].remove_game_object(game_object)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def remove_game_object(game_object)
|
|
104
|
+
warn "remove_game_object is deprecated, use remove instead"
|
|
105
|
+
remove(game_object)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def switch_state(state_name, *args)
|
|
109
|
+
@game.queue_state state_name, args
|
|
110
|
+
state_name
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def use_input(input)
|
|
114
|
+
@managers[:input].use_input input
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def load(*args); end
|
|
118
|
+
|
|
119
|
+
def quit_game
|
|
120
|
+
java.lang.System.exit 0
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def name
|
|
124
|
+
@name ||= self.class.name.underscore.sub('_state', '')
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def load_resources
|
|
128
|
+
@managers[:resource].load_resources
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
def configure_inputs
|
|
134
|
+
# global - automatic
|
|
135
|
+
begin
|
|
136
|
+
use_input :global
|
|
137
|
+
rescue LoadError
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# class name - automatic
|
|
141
|
+
begin
|
|
142
|
+
use_input self.class.to_s.underscore.sub('_state', '')
|
|
143
|
+
rescue LoadError
|
|
144
|
+
end
|
|
145
|
+
# class declared
|
|
146
|
+
self.class.inputs.each {|input| use_input input}
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def set_manager(type, manager)
|
|
150
|
+
@managers[type] = manager
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def try_require(path)
|
|
154
|
+
begin
|
|
155
|
+
require path
|
|
156
|
+
rescue LoadError => e
|
|
157
|
+
log.warn "Failed to require: #{path}"
|
|
158
|
+
return false
|
|
159
|
+
end
|
|
160
|
+
log.debug "Successful require: #{path}"
|
|
161
|
+
return true
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|