jemini 2009.10.27
Sign up to get free protection for your applications and to get access to all the features.
- 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/inflector.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# This code is a modified version of the Inflector class
|
2
|
+
# from the Ruby on Rails project (http://www.rubyonrails.com)
|
3
|
+
|
4
|
+
module Monkeybars
|
5
|
+
module Inflector
|
6
|
+
# The reverse of +camelize+. Makes an underscored form from the expression in the string.
|
7
|
+
#
|
8
|
+
# Changes '::' to '/' to convert namespaces to paths.
|
9
|
+
#
|
10
|
+
# Examples
|
11
|
+
# "ActiveRecord".underscore #=> "active_record"
|
12
|
+
# "ActiveRecord::Errors".underscore #=> active_record/errors
|
13
|
+
def underscore()
|
14
|
+
self.to_s.gsub(/::/, '/').
|
15
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
16
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
17
|
+
tr("-", "_").
|
18
|
+
downcase
|
19
|
+
end
|
20
|
+
|
21
|
+
# Constantize tries to find a declared constant with the name specified
|
22
|
+
# in the string. It raises a NameError when the name is not in CamelCase
|
23
|
+
# or is not initialized.
|
24
|
+
#
|
25
|
+
# Examples
|
26
|
+
# "Module".constantize #=> Module
|
27
|
+
# "Class".constantize #=> Class
|
28
|
+
def constantize()
|
29
|
+
# unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self.to_s
|
30
|
+
# raise NameError, "#{self.inspect} is not a valid constant name!"
|
31
|
+
# end
|
32
|
+
|
33
|
+
Object.module_eval("::#{to_s}", __FILE__, __LINE__)
|
34
|
+
end
|
35
|
+
|
36
|
+
# By default, camelize converts strings to UpperCamelCase. If the argument to camelize
|
37
|
+
# is set to ":lower" then camelize produces lowerCamelCase.
|
38
|
+
#
|
39
|
+
# camelize will also convert '/' to '::' which is useful for converting paths to namespaces
|
40
|
+
#
|
41
|
+
# Examples
|
42
|
+
# "active_record".camelize #=> "ActiveRecord"
|
43
|
+
# "active_record".camelize(:lower) #=> "activeRecord"
|
44
|
+
# "active_record/errors".camelize #=> "ActiveRecord::Errors"
|
45
|
+
# "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
|
46
|
+
def camelize(first_letter_in_uppercase = true)
|
47
|
+
if first_letter_in_uppercase
|
48
|
+
self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
49
|
+
else
|
50
|
+
self.to_s[0..0] + camelize(self.to_s)[1..-1]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class String
|
57
|
+
include Monkeybars::Inflector
|
58
|
+
end
|
59
|
+
|
60
|
+
class Symbol
|
61
|
+
include Monkeybars::Inflector
|
62
|
+
end
|
63
|
+
|
64
|
+
class Class
|
65
|
+
def constantize
|
66
|
+
self
|
67
|
+
end
|
68
|
+
end
|
data/src/jemini.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + '/managers').gsub('%20', ' ')
|
2
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + '/game_objects').gsub('%20', ' ')
|
3
|
+
#$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + '/states')
|
4
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + '/input_helpers').gsub('%20', ' ')
|
5
|
+
|
6
|
+
# Because Windows isn't friendly with JRuby
|
7
|
+
$LOAD_PATH << 'managers'
|
8
|
+
$LOAD_PATH << 'game_objects'
|
9
|
+
#$LOAD_PATH << 'states'
|
10
|
+
$LOAD_PATH << 'input_helpers'
|
11
|
+
|
12
|
+
require 'file_system'
|
13
|
+
require 'platform'
|
14
|
+
require 'color'
|
15
|
+
require 'vector'
|
16
|
+
require 'spline'
|
17
|
+
require 'inflector'
|
18
|
+
|
19
|
+
require 'math'
|
20
|
+
require 'proc_enhancement'
|
21
|
+
require 'resource'
|
22
|
+
require 'game_object'
|
23
|
+
require 'message_queue'
|
24
|
+
require 'managers/input_manager'
|
25
|
+
require 'resource_manager'
|
26
|
+
require 'game_state'
|
27
|
+
require 'inflector'
|
28
|
+
require 'basic_game_object_manager'
|
29
|
+
require 'basic_update_manager'
|
30
|
+
require 'basic_render_manager'
|
31
|
+
require 'game'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Jemini
|
2
|
+
module ListenableMixin
|
3
|
+
def __added_listener_for(game_object, method_name, callback)
|
4
|
+
@__methods_registered ||= {}
|
5
|
+
@__methods_registered[game_object] = [method_name, callback]
|
6
|
+
end
|
7
|
+
|
8
|
+
def __remove_listeners
|
9
|
+
return if @__methods_registered.nil?
|
10
|
+
@__methods_registered.each do |game_object, listener_method_name_and_callback|
|
11
|
+
game_object.send("remove_#{listener_method_name_and_callback.first}", self, listener_method_name_and_callback.last)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/src/logger_mixin.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module LoggerMixin
|
4
|
+
|
5
|
+
#Get the Logger object (see the Ruby standard library documentation).
|
6
|
+
#The log level is set to match the $LOG_LEVEL environment variable, or Logger::ERROR by default.
|
7
|
+
def log
|
8
|
+
@log ||= Logger.new(STDOUT, ENV['LOG_LEVEL'] || Logger::ERROR)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#Controls the objects in the game world.
|
2
|
+
class BasicGameObjectManager < Jemini::GameObject
|
3
|
+
attr_reader :layers
|
4
|
+
FRONT_LAYER = 'front'
|
5
|
+
BACK_LAYER = 'back'
|
6
|
+
|
7
|
+
def load
|
8
|
+
enable_listeners_for :before_add_game_object, :after_add_game_object, :before_remove_game_object, :after_remove_game_object
|
9
|
+
#@layers = Hash.new{|h,k| h[k] = []}
|
10
|
+
@layer_order = [:default]
|
11
|
+
@layers = {:default => []}
|
12
|
+
@game_objects_to_remove = []
|
13
|
+
@game_objects_to_add = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def __process_pending_game_objects
|
17
|
+
@game_objects_to_remove.pop.__destroy until @game_objects_to_remove.empty?
|
18
|
+
until @game_objects_to_add.empty?
|
19
|
+
layer, game_object = @game_objects_to_add.pop
|
20
|
+
@layers[layer] << game_object
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#Called when GameState#create is called.
|
25
|
+
#Triggers :before_add_game_object, :after_add_game_object callbacks.
|
26
|
+
def add_game_object(game_object)
|
27
|
+
notify :before_add_game_object, game_object, :default
|
28
|
+
@layers[:default] << game_object
|
29
|
+
notify :after_add_game_object, game_object, :default
|
30
|
+
end
|
31
|
+
|
32
|
+
#Called when GameState#remove is called.
|
33
|
+
#Triggers :before_remove_game_object, :after_remove_game_object callbacks.
|
34
|
+
def remove_game_object(game_object)
|
35
|
+
owning_layer = @layers.values.find {|layer| layer.include? game_object}
|
36
|
+
return if owning_layer.nil? #NOTE: Not sure if this is the right thing to do, but at least no exception is thrown
|
37
|
+
notify :before_remove_game_object, game_object
|
38
|
+
owning_layer.delete game_object
|
39
|
+
game_object.unload
|
40
|
+
notify :after_remove_game_object, game_object
|
41
|
+
@game_objects_to_remove.push game_object
|
42
|
+
#game_object.unload
|
43
|
+
end
|
44
|
+
|
45
|
+
#Adds game object to named layer.
|
46
|
+
#Triggers :before_add_game_object, :after_add_game_object callbacks.
|
47
|
+
#TODO: If layers are desired for the add game object call, then include them in the notify.
|
48
|
+
# This cannot be as an extra param
|
49
|
+
def add_game_object_to_layer(game_object, layer_name)
|
50
|
+
notify :before_add_game_object, game_object
|
51
|
+
@layers[layer_name] << game_object
|
52
|
+
#@game_objects_to_add.push [layer_name, game_object]
|
53
|
+
notify :after_add_game_object, game_object
|
54
|
+
end
|
55
|
+
|
56
|
+
#Moves given object from one layer to another.
|
57
|
+
def move_game_object_to_layer(game_object, layer_name)
|
58
|
+
owning_layer = @layers.values.find {|layer| layer.include? game_object}
|
59
|
+
owning_layer.delete game_object
|
60
|
+
@layers[layer_name] << game_object
|
61
|
+
end
|
62
|
+
|
63
|
+
#Returns Array of all game objects.
|
64
|
+
def game_objects
|
65
|
+
game_objects = []
|
66
|
+
@layers.values.each do |layer|
|
67
|
+
layer.each do |game_object|
|
68
|
+
game_objects << game_object
|
69
|
+
end
|
70
|
+
end
|
71
|
+
game_objects
|
72
|
+
end
|
73
|
+
|
74
|
+
#Returns Array of all layers by drawing order.
|
75
|
+
def layers_by_order
|
76
|
+
@layer_order.map {|layer_name| @layers[layer_name]}.compact
|
77
|
+
end
|
78
|
+
|
79
|
+
#Add the named layer at the given drawing order position.
|
80
|
+
#Position can be a number or one of the constants FRONT_LAYER or BACK_LAYER.
|
81
|
+
def add_layer_at(layer_name, location)
|
82
|
+
if location.kind_of? Numeric
|
83
|
+
@layer_order.delete_at(location) if @layer_order[location].nil?
|
84
|
+
@layer_order.insert(location, layer_name)
|
85
|
+
else # string/symbol
|
86
|
+
case location.to_s
|
87
|
+
when FRONT_LAYER
|
88
|
+
@layer_order << layer_name
|
89
|
+
when BACK_LAYER
|
90
|
+
@layer_order.unshift(layer_name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@layers[layer_name] = []
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'behaviors/physical'
|
2
|
+
require 'events/physical_message'
|
3
|
+
|
4
|
+
#Controls objects that collide, fall with gravity, roll, etc.
|
5
|
+
class BasicPhysicsManager < Jemini::GameObject
|
6
|
+
INTERPOLATION_THESHOLD = 6.0
|
7
|
+
MILLISECONDS_PER_UPDATE = 1000 / 60
|
8
|
+
PHYS2D_UPDATE_DIFF = (1000.to_f / 60.to_f) - MILLISECONDS_PER_UPDATE.to_f
|
9
|
+
DELTA_FACTOR = 0.01
|
10
|
+
include_class 'net.phys2d.math.Vector2f'
|
11
|
+
include_class 'net.phys2d.raw.World'
|
12
|
+
include_class 'net.phys2d.raw.strategies.QuadSpaceStrategy'
|
13
|
+
include_class 'net.phys2d.raw.strategies.BruteCollisionStrategy'
|
14
|
+
has_behavior :HandlesEvents
|
15
|
+
|
16
|
+
def load
|
17
|
+
@delta_debt = 0
|
18
|
+
@world = World.new(Vector2f.new(0, 0), 5, QuadSpaceStrategy.new(20, 5))
|
19
|
+
# @world = World.new(Vector2f.new(0, 0), 10, BruteCollisionStrategy.new)
|
20
|
+
@world.add_listener self
|
21
|
+
game_state.manager(:update).on_update do |delta|
|
22
|
+
update delta
|
23
|
+
end
|
24
|
+
|
25
|
+
game_state.manager(:game_object).on_after_add_game_object do |game_object|
|
26
|
+
add_to_world game_object if game_object.has_behavior? :Physical
|
27
|
+
end
|
28
|
+
|
29
|
+
game_state.manager(:game_object).on_after_remove_game_object do |game_object|
|
30
|
+
game_object.remove_from_world(@world) if game_object.has_behavior? :Physical
|
31
|
+
end
|
32
|
+
|
33
|
+
handle_event :toggle_debug_mode, :toggle_debug_mode
|
34
|
+
end
|
35
|
+
|
36
|
+
def update(delta)
|
37
|
+
delta += @delta_debt
|
38
|
+
@delta_debt = 0
|
39
|
+
if delta == MILLISECONDS_PER_UPDATE
|
40
|
+
sleep PHYS2D_UPDATE_DIFF / 1000.0
|
41
|
+
step
|
42
|
+
else
|
43
|
+
temp_delta = delta
|
44
|
+
until temp_delta <= 0
|
45
|
+
new_delta = temp_delta > MILLISECONDS_PER_UPDATE ? MILLISECONDS_PER_UPDATE : temp_delta
|
46
|
+
if new_delta < MILLISECONDS_PER_UPDATE
|
47
|
+
@delta_debt = new_delta
|
48
|
+
return #don't step, we'll try again next update
|
49
|
+
else
|
50
|
+
step
|
51
|
+
temp_delta -= new_delta
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# there's a typo in the API, I swears it.
|
58
|
+
def collision_occured(event)
|
59
|
+
event.body_a.user_data.notify :physical_collided, PhysicsMessage.new(event, event.body_b.user_data)
|
60
|
+
event.body_b.user_data.notify :physical_collided, PhysicsMessage.new(event, event.body_a.user_data)
|
61
|
+
end
|
62
|
+
|
63
|
+
#Turns drawing of physical bodies on/off.
|
64
|
+
def toggle_debug_mode(message)
|
65
|
+
@debug_mode = !@debug_mode
|
66
|
+
@game_state.manager(:game_object).game_objects.each do |game_object|
|
67
|
+
game_object.set_physical_debug_mode(@debug_mode) if game_object.has_behavior? :Physical
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#Takes a number representing the downward force to apply to physical objects.
|
72
|
+
def gravity=(gravity_or_x)
|
73
|
+
if gravity_or_x.kind_of? Numeric
|
74
|
+
@world.set_gravity(0, gravity_or_x)
|
75
|
+
else
|
76
|
+
raise "Not implemented yet"
|
77
|
+
# @world.set_gravity(gravity_or_x)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def step
|
83
|
+
@world.step # must step at fixed rate (1/60f) or results are unpredictable
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_to_world(game_object)
|
87
|
+
game_object.add_to_world(@world)
|
88
|
+
game_object.set_physical_debug_mode(true) if @debug_mode
|
89
|
+
end
|
90
|
+
# def colliding?(body)
|
91
|
+
# 0 < @world.get_contacts(body).size
|
92
|
+
# end
|
93
|
+
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'managers/render_support/hardware_cursor'
|
2
|
+
|
3
|
+
class BasicRenderManager < Jemini::GameObject
|
4
|
+
java_import 'org.newdawn.slick.geom.Circle'
|
5
|
+
|
6
|
+
include HardwareCursor
|
7
|
+
|
8
|
+
def load
|
9
|
+
enable_listeners_for :before_render, :after_render
|
10
|
+
@debug_queue = []
|
11
|
+
use_available_hardware_cursor
|
12
|
+
end
|
13
|
+
|
14
|
+
def unload
|
15
|
+
revert_hardware_cursor
|
16
|
+
end
|
17
|
+
|
18
|
+
#Render all game objects to the given graphics context.
|
19
|
+
#Triggers :before_render, :after_render callbacks.
|
20
|
+
def render(graphics)
|
21
|
+
notify :before_render, graphics
|
22
|
+
#game_state.manager(:game_object).game_objects.each { |game_object| game_object.draw if game_object.respond_to? :draw}
|
23
|
+
game_state.manager(:game_object).layers_by_order.each do |game_objects|
|
24
|
+
game_objects.each { |game_object| game_object.draw(graphics) if game_object.respond_to? :draw}
|
25
|
+
end
|
26
|
+
|
27
|
+
render_debug_overlay(graphics)
|
28
|
+
notify :after_render, graphics
|
29
|
+
end
|
30
|
+
|
31
|
+
def debug(type, color, options)
|
32
|
+
@debug_queue << {:type => type, :color => color}.merge(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_debug_overlay(graphics)
|
36
|
+
pre_debug_color = graphics.color
|
37
|
+
until @debug_queue.empty?
|
38
|
+
debug_render = @debug_queue.shift
|
39
|
+
color = debug_render[:color]
|
40
|
+
color = Color.new(color) unless color.kind_of? Color
|
41
|
+
graphics.color = color.native_color
|
42
|
+
case debug_render[:type]
|
43
|
+
when :point
|
44
|
+
graphics.fill Circle.new(debug_render[:position].x, debug_render[:position].y, 2)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
graphics.color = pre_debug_color
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#Updates all game objects.
|
2
|
+
class BasicUpdateManager < Jemini::GameObject
|
3
|
+
def load
|
4
|
+
enable_listeners_for :update, :before_update, :after_update
|
5
|
+
end
|
6
|
+
|
7
|
+
#Call update method on all game objects that support it.
|
8
|
+
#Triggers :before_update, :after_update callbacks.
|
9
|
+
def update(delta)
|
10
|
+
# delta = 20.0
|
11
|
+
return if paused?
|
12
|
+
|
13
|
+
notify :before_update, delta
|
14
|
+
game_state.manager(:game_object).game_objects.each { |game_object| game_object.update(delta) if game_object.respond_to? :update}
|
15
|
+
notify :update, delta
|
16
|
+
notify :after_update, delta
|
17
|
+
end
|
18
|
+
|
19
|
+
def pause
|
20
|
+
@paused = true
|
21
|
+
end
|
22
|
+
|
23
|
+
def resume
|
24
|
+
@paused = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def paused?
|
28
|
+
@paused
|
29
|
+
end
|
30
|
+
end
|
File without changes
|
@@ -0,0 +1,161 @@
|
|
1
|
+
java_import 'org.newdawn.slick.Input'
|
2
|
+
|
3
|
+
require 'message_queue'
|
4
|
+
|
5
|
+
require 'managers/input_support/input_listener'
|
6
|
+
require 'managers/input_support/mouse_listener'
|
7
|
+
require 'managers/input_support/key_listener'
|
8
|
+
require 'managers/input_support/joystick_listener'
|
9
|
+
require 'managers/input_support/input_builder'
|
10
|
+
|
11
|
+
require 'managers/input_support/input_message'
|
12
|
+
require 'managers/input_support/slick_input_listener'
|
13
|
+
require 'managers/input_support/slick_input_message'
|
14
|
+
|
15
|
+
if Platform.using_osx?
|
16
|
+
# buttons
|
17
|
+
XBOX_360_DPAD_UP = 0
|
18
|
+
XBOX_360_DPAD_DOWN = 1
|
19
|
+
XBOX_360_DPAD_LEFT = 2
|
20
|
+
XBOX_360_DPAD_RIGHT = 3
|
21
|
+
XBOX_360_START = 4
|
22
|
+
XBOX_360_BACK = 5
|
23
|
+
XBOX_360_LEFT_STICK = 6
|
24
|
+
XBOX_360_RIGHT_STICK = 7
|
25
|
+
XBOX_360_LEFT_BUMPER = 8
|
26
|
+
XBOX_360_RIGHT_BUMPER = 9
|
27
|
+
XBOX_360_GUIDE_BUTTON = 10
|
28
|
+
XBOX_360_A = 11
|
29
|
+
XBOX_360_B = 12
|
30
|
+
XBOX_360_X = 13
|
31
|
+
XBOX_360_Y = 14
|
32
|
+
# axes
|
33
|
+
XBOX_360_LEFT_X_AXIS = 'x'
|
34
|
+
XBOX_360_LEFT_Y_AXIS = 'y'
|
35
|
+
XBOX_360_LEFT_TRIGGER_AXIS = 'z' # On Windows, both triggers serve as one axis
|
36
|
+
XBOX_360_RIGHT_X_AXIS = 'rx'
|
37
|
+
XBOX_360_RIGHT_Y_AXIS = 'ry'
|
38
|
+
XBOX_360_RIGHT_TRIGGER_AXIS = 'rz' # On Windows, both triggers serve as one axis
|
39
|
+
elsif Platform.using_windows?
|
40
|
+
# buttons
|
41
|
+
XBOX_360_A = 0
|
42
|
+
XBOX_360_B = 1
|
43
|
+
XBOX_360_X = 2
|
44
|
+
XBOX_360_Y = 3
|
45
|
+
XBOX_360_LEFT_BUMPER = 4
|
46
|
+
XBOX_360_RIGHT_BUMPER = 5
|
47
|
+
XBOX_360_BACK = 6
|
48
|
+
XBOX_360_START = 7
|
49
|
+
XBOX_360_LEFT_STICK = 8
|
50
|
+
XBOX_360_RIGHT_STICK = 9
|
51
|
+
#axes
|
52
|
+
XBOX_360_LEFT_X_AXIS = 'X Axis'
|
53
|
+
XBOX_360_LEFT_Y_AXIS = 'Y Axis'
|
54
|
+
XBOX_360_TRIGGER_AXIS = 'Z Axis' # On OSX, both triggers serve as individual axes
|
55
|
+
XBOX_360_RIGHT_X_AXIS = 'X Rotation'
|
56
|
+
XBOX_360_RIGHT_Y_AXIS = 'Y Rotation'
|
57
|
+
elsif Platform.using_linux?
|
58
|
+
XBOX_360_A = 0
|
59
|
+
XBOX_360_B = 1
|
60
|
+
XBOX_360_X = 2
|
61
|
+
XBOX_360_Y = 3
|
62
|
+
XBOX_360_LEFT_BUMPER = 4
|
63
|
+
XBOX_360_RIGHT_BUMPER = 5
|
64
|
+
XBOX_360_BACK = 6
|
65
|
+
XBOX_360_START = 7
|
66
|
+
XBOX_360_GUIDE = 8
|
67
|
+
XBOX_360_LEFT_STICK = 9
|
68
|
+
XBOX_360_RIGHT_STICK = 10
|
69
|
+
XBOX_360_LEFT_X_AXIS = 'x'
|
70
|
+
XBOX_360_LEFT_Y_AXIS = 'y'
|
71
|
+
XBOX_360_LEFT_TRIGGER_AXIS = 'z'
|
72
|
+
XBOX_360_RIGHT_X_AXIS = 'rx'
|
73
|
+
XBOX_360_RIGHT_Y_AXIS = 'ry'
|
74
|
+
XBOX_360_RIGHT_TRIGGER_AXIS = 'rz'
|
75
|
+
end
|
76
|
+
|
77
|
+
# LWJGL can't poll for buttons in the negative range yet. Possible bug to report?
|
78
|
+
# 360 controller provides button presses for analog in for convienence
|
79
|
+
XBOX_360_LEFT_STICK_LEFT = -1
|
80
|
+
XBOX_360_LEFT_STICK_RIGHT = -2
|
81
|
+
XBOX_360_LEFT_STICK_UP = -3
|
82
|
+
XBOX_360_LEFT_STICK_DOWN = -4
|
83
|
+
|
84
|
+
class MouseEvent
|
85
|
+
PRESSED = :pressed
|
86
|
+
RELEASED = :released
|
87
|
+
attr_accessor :state, :location
|
88
|
+
def initialize(state, location)
|
89
|
+
@state, @location = state, location
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module Jemini
|
94
|
+
# Consumes raw slick_input events and outputs events based on
|
95
|
+
# registered key bindings.
|
96
|
+
class InputManager < Jemini::GameObject
|
97
|
+
attr_reader :listeners
|
98
|
+
|
99
|
+
@@loading_input_manager = nil
|
100
|
+
def self.loading_input_manager
|
101
|
+
@@loading_input_manager
|
102
|
+
end
|
103
|
+
|
104
|
+
def load(container)
|
105
|
+
@listeners = []
|
106
|
+
@held_keys = []
|
107
|
+
@raw_input = container.input
|
108
|
+
@input_listener = SlickInputListener.new(@game_state)
|
109
|
+
@raw_input.add_listener @input_listener
|
110
|
+
@held_buttons = {}
|
111
|
+
end
|
112
|
+
|
113
|
+
def use_input(input)
|
114
|
+
@@loading_input_manager = self
|
115
|
+
file_name = File.join('inputs', "#{input}_input")
|
116
|
+
log.debug "Using input mapping: #{file_name}"
|
117
|
+
require file_name
|
118
|
+
@@loading_input_manager = nil
|
119
|
+
$".pop # remove the entry so we can require it again
|
120
|
+
end
|
121
|
+
|
122
|
+
#Check for keypresses and send messages to message queue accordingly.
|
123
|
+
def poll(screen_width, screen_height, delta)
|
124
|
+
@keymap ||= {}
|
125
|
+
# return if @keymap.nil?
|
126
|
+
@input_listener.delta = delta
|
127
|
+
@raw_input.poll(screen_width, screen_height)
|
128
|
+
all_keymappings_to_game_messages.each do |game_message|
|
129
|
+
@game_state.manager(:message_queue).post_message game_message
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#The number of connected game controllers.
|
134
|
+
def connected_joystick_size
|
135
|
+
@raw_input.controller_count
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def all_keymappings_to_game_messages
|
141
|
+
# @keymap.values.map {|keymap_array| poll_to_game_messages(keymap_array)}.flatten.compact
|
142
|
+
poll_to_game_messages(listeners).compact
|
143
|
+
end
|
144
|
+
|
145
|
+
def poll_to_game_messages(keymaps)
|
146
|
+
messages = []
|
147
|
+
keymaps.reject! do |keymap|
|
148
|
+
begin
|
149
|
+
messages << keymap.poll(@raw_input)
|
150
|
+
false # don't delete me
|
151
|
+
rescue => e
|
152
|
+
# TODO: puts in test, warn in production. Is there a better way?
|
153
|
+
puts "error in poll: #{e}"
|
154
|
+
puts "removing keymap #{keymap}"
|
155
|
+
true # I've been bad, delete me
|
156
|
+
end
|
157
|
+
end
|
158
|
+
messages
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|