jemini 2009.10.27

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