jemini 2009.10.27

Sign up to get free protection for your applications and to get access to all the features.
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