gemini 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/gemini +18 -0
- data/build_configuration.rb +24 -0
- data/lib/ibxm.jar +0 -0
- data/lib/jinput.jar +0 -0
- data/lib/jogg-0.0.7.jar +0 -0
- data/lib/jorbis-0.0.15.jar +0 -0
- data/lib/jruby-complete.jar +0 -0
- data/lib/lwjgl.jar +0 -0
- data/lib/lwjgl_util_applet.jar +0 -0
- data/lib/native_files/OpenAL32.dll +0 -0
- data/lib/native_files/jinput-dx8.dll +0 -0
- data/lib/native_files/jinput-raw.dll +0 -0
- data/lib/native_files/libjinput-linux.so +0 -0
- data/lib/native_files/libjinput-linux64.so +0 -0
- data/lib/native_files/libjinput-osx.jnilib +0 -0
- data/lib/native_files/liblwjgl.jnilib +0 -0
- data/lib/native_files/liblwjgl.so +0 -0
- data/lib/native_files/liblwjgl64.so +0 -0
- data/lib/native_files/libopenal.so +0 -0
- data/lib/native_files/lwjgl.dll +0 -0
- data/lib/native_files/openal.dylib +0 -0
- data/lib/natives-linux.jar +0 -0
- data/lib/natives-mac.jar +0 -0
- data/lib/natives-win32.jar +0 -0
- data/lib/phys2d.jar +0 -0
- data/lib/slick.jar +0 -0
- data/package/jar/gemini.jar +0 -0
- data/src/base_state.rb +112 -0
- data/src/behavior.rb +230 -0
- data/src/behavior_event.rb +23 -0
- data/src/behaviors.txt +5 -0
- data/src/behaviors/animated_sprite.rb +51 -0
- data/src/behaviors/audible.rb +11 -0
- data/src/behaviors/axis_stateful.rb +33 -0
- data/src/behaviors/big_sprite.rb +56 -0
- data/src/behaviors/bounding_box_collidable.rb +25 -0
- data/src/behaviors/camera_anchored_drawable.rb +20 -0
- data/src/behaviors/cardinal_movable.rb +114 -0
- data/src/behaviors/clickable.rb +18 -0
- data/src/behaviors/countable.rb +31 -0
- data/src/behaviors/debug_physical.rb +31 -0
- data/src/behaviors/debug_tangible.rb +30 -0
- data/src/behaviors/drawable.rb +6 -0
- data/src/behaviors/drawable_shape.rb +43 -0
- data/src/behaviors/fading_image_trail_emittable.rb +28 -0
- data/src/behaviors/game_object_emittable.rb +12 -0
- data/src/behaviors/gravity_source.rb +21 -0
- data/src/behaviors/inertial.rb +11 -0
- data/src/behaviors/movable2d.rb +9 -0
- data/src/behaviors/multi_animated_sprite.rb +22 -0
- data/src/behaviors/physical.rb +348 -0
- data/src/behaviors/physical_cardinal_movable.rb +110 -0
- data/src/behaviors/physical_sprite.rb +29 -0
- data/src/behaviors/platformer_controllable.rb +144 -0
- data/src/behaviors/pointer.rb +28 -0
- data/src/behaviors/pressable.rb +13 -0
- data/src/behaviors/receives_events.rb +21 -0
- data/src/behaviors/regional.rb +71 -0
- data/src/behaviors/rotates_to_point.rb +18 -0
- data/src/behaviors/spatial.rb +41 -0
- data/src/behaviors/spline_stretchable_sprite.rb +45 -0
- data/src/behaviors/sprite.rb +99 -0
- data/src/behaviors/stateful.rb +31 -0
- data/src/behaviors/taggable.rb +27 -0
- data/src/behaviors/tangible.rb +51 -0
- data/src/behaviors/timeable.rb +79 -0
- data/src/behaviors/top_down_vehicle.rb +41 -0
- data/src/behaviors/triangle_trail_emittable.rb +41 -0
- data/src/behaviors/updates.rb +10 -0
- data/src/behaviors/updates_at_consistant_rate.rb +27 -0
- data/src/behaviors/vectored_movement.rb +47 -0
- data/src/behaviors/world_collidable.rb +8 -0
- data/src/color.rb +70 -0
- data/src/game_object.rb +174 -0
- data/src/game_objects/background.rb +9 -0
- data/src/game_objects/fading_image.rb +23 -0
- data/src/game_objects/icon_strip_counter_display.rb +58 -0
- data/src/game_objects/static_sprite.rb +18 -0
- data/src/game_objects/tangible_object.rb +4 -0
- data/src/game_objects/text.rb +59 -0
- data/src/game_objects/triangle_trail.rb +85 -0
- data/src/gemini.rb +110 -0
- data/src/gemini_version.rb +3 -0
- data/src/inflector.rb +68 -0
- data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
- data/src/listenable_mixin.rb +15 -0
- data/src/managers/basic_game_object_manager.rb +81 -0
- data/src/managers/basic_physics_manager.rb +97 -0
- data/src/managers/basic_render_manager.rb +48 -0
- data/src/managers/basic_tangible_manager.rb +33 -0
- data/src/managers/basic_update_manager.rb +27 -0
- data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
- data/src/managers/input_manager.rb +229 -0
- data/src/managers/input_support/input_mapping.rb +126 -0
- data/src/managers/input_support/input_message.rb +5 -0
- data/src/managers/input_support/slick_input_listener.rb +19 -0
- data/src/managers/input_support/slick_input_message.rb +11 -0
- data/src/managers/input_support/slick_input_translator.rb +15 -0
- data/src/managers/message_queue.rb +54 -0
- data/src/managers/scrolling_render_manager.rb +44 -0
- data/src/managers/sound_manager.rb +60 -0
- data/src/managers/tag_manager.rb +43 -0
- data/src/math.rb +13 -0
- data/src/music.rb +14 -0
- data/src/org/rubyforge/rawr/Main.java +67 -0
- data/src/platform.rb +28 -0
- data/src/proc_enhancement.rb +5 -0
- data/src/project_generator.rb +122 -0
- data/src/skeleton.txt +10 -0
- data/src/spline.rb +13 -0
- data/src/states/input_diagnostic_state.rb +53 -0
- data/src/vector.rb +99 -0
- data/test/test_state.rb +3 -0
- metadata +181 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
class BasicRenderManager < Gemini::GameObject
|
2
|
+
include_class 'org.newdawn.slick.geom.Circle'
|
3
|
+
|
4
|
+
def load
|
5
|
+
enable_listeners_for :before_render, :after_render
|
6
|
+
@image_cache = {}
|
7
|
+
@debug_queue = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def render(graphics)
|
11
|
+
notify :before_render, graphics
|
12
|
+
#game_state.manager(:game_object).game_objects.each { |game_object| game_object.draw if game_object.respond_to? :draw}
|
13
|
+
game_state.manager(:game_object).layers_by_order.each do |game_objects|
|
14
|
+
game_objects.each { |game_object| game_object.draw(graphics) if game_object.respond_to? :draw}
|
15
|
+
end
|
16
|
+
|
17
|
+
pre_debug_color = graphics.color
|
18
|
+
until @debug_queue.empty?
|
19
|
+
debug_render = @debug_queue.shift
|
20
|
+
color = debug_render[:color]
|
21
|
+
color = Color.new(color) unless color.kind_of? Color
|
22
|
+
graphics.color = color.native_color
|
23
|
+
case debug_render[:type]
|
24
|
+
when :point
|
25
|
+
graphics.fill Circle.new(debug_render[:position].x, debug_render[:position].y, 2)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
graphics.color = pre_debug_color
|
29
|
+
notify :after_render, graphics
|
30
|
+
end
|
31
|
+
|
32
|
+
def debug(type, color, options)
|
33
|
+
@debug_queue << {:type => type, :color => color}.merge(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def cache_image(cache_name, image_name)
|
37
|
+
image_resource = begin
|
38
|
+
Java::org::newdawn::slick::Image.new "data/#{image_name}"
|
39
|
+
rescue java.lang.RuntimeException
|
40
|
+
Java::org::newdawn::slick::Image.new "../data/#{image_name}"
|
41
|
+
end
|
42
|
+
@image_cache[cache_name] = image_resource
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_cached_image(cache_name)
|
46
|
+
@image_cache[cache_name].copy
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'behaviors/tangible'
|
2
|
+
|
3
|
+
class BasicTangibleManager < Gemini::GameObject
|
4
|
+
has_behavior :ReceivesEvents
|
5
|
+
has_behavior :Updates
|
6
|
+
|
7
|
+
def load
|
8
|
+
handle_event :toggle_debug_mode, :toggle_debug_mode
|
9
|
+
on_update do
|
10
|
+
@game_state.manager(:game_object).game_objects.each do |game_object|
|
11
|
+
next unless game_object.kind_of? Tangible
|
12
|
+
@game_state.manager(:game_object).game_objects.each do |other_game_object|
|
13
|
+
next unless other_game_object.kind_of? Tangible
|
14
|
+
next if game_object == other_game_object
|
15
|
+
if game_object.tangibly_collides_with?(other_game_object)
|
16
|
+
game_object.notify :tangible_collision
|
17
|
+
other_game_object.notify :tangible_collision
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def toggle_debug_mode(unused_message=nil)
|
25
|
+
@debug_mode = !@debug_mode
|
26
|
+
@game_state.manager(:game_object).game_objects.each do |game_object|
|
27
|
+
game_object.set_tangible_debug_mode(@debug_mode) if game_object.kind_of? Tangible
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class BasicUpdateManager < Gemini::GameObject
|
2
|
+
def load
|
3
|
+
enable_listeners_for :update, :before_update, :after_update
|
4
|
+
end
|
5
|
+
|
6
|
+
def update(delta)
|
7
|
+
# delta = 20.0
|
8
|
+
return if paused?
|
9
|
+
|
10
|
+
notify :before_update, delta
|
11
|
+
game_state.manager(:game_object).game_objects.each { |game_object| game_object.update(delta) if game_object.respond_to? :update}
|
12
|
+
notify :update, delta
|
13
|
+
notify :after_update, delta
|
14
|
+
end
|
15
|
+
|
16
|
+
def pause
|
17
|
+
@paused = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def resume
|
21
|
+
@paused = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def paused?
|
25
|
+
@paused
|
26
|
+
end
|
27
|
+
end
|
File without changes
|
@@ -0,0 +1,229 @@
|
|
1
|
+
include_class 'org.newdawn.slick.Input'
|
2
|
+
include_class 'org.newdawn.slick.InputListener'
|
3
|
+
require 'message_queue'
|
4
|
+
|
5
|
+
require 'input_support/input_mapping'
|
6
|
+
require 'input_support/input_message'
|
7
|
+
require 'input_support/slick_input_listener'
|
8
|
+
require 'input_support/slick_input_message'
|
9
|
+
|
10
|
+
KEY_PRESSED = {:source_type => :key, :source_state => :pressed}
|
11
|
+
KEY_RELEASED = {:source_type => :key, :source_state => :released}
|
12
|
+
KEY_HELD = {:source_type => :key, :source_state => :held}
|
13
|
+
MOUSE_MOVED = {:source_type => :mouse, :source_state => :moved, :source_value => :any}
|
14
|
+
MOUSE_BUTTON1_PRESSED = {:source_type => :mouse, :source_state => :pressed, :source_value => Input::MOUSE_LEFT_BUTTON }
|
15
|
+
MOUSE_BUTTON1_RELEASED = {:source_type => :mouse, :source_state => :released, :source_value => Input::MOUSE_LEFT_BUTTON}
|
16
|
+
MOUSE_BUTTON2_PRESSED = {:source_type => :mouse, :source_state => :pressed, :source_value => Input::MOUSE_RIGHT_BUTTON}
|
17
|
+
MOUSE_BUTTON2_RELEASED = {:source_type => :mouse, :source_state => :released, :source_value => Input::MOUSE_RIGHT_BUTTON}
|
18
|
+
MOUSE_BUTTON3_PRESSED = {:source_type => :mouse, :source_state => :pressed, :source_value => Input::MOUSE_MIDDLE_BUTTON}
|
19
|
+
MOUSE_BUTTON3_RELEASED = {:source_type => :mouse, :source_state => :released, :source_value => Input::MOUSE_MIDDLE_BUTTON}
|
20
|
+
|
21
|
+
#
|
22
|
+
# XBox 360 controllers use the following axii:
|
23
|
+
# x
|
24
|
+
# y
|
25
|
+
# z
|
26
|
+
# rx
|
27
|
+
# ry
|
28
|
+
# rz
|
29
|
+
#
|
30
|
+
# The 360 controller has two sticks and two triggers
|
31
|
+
#
|
32
|
+
CONTROLLER_AXIS_UPDATE = {:source_type => :controller, :source_state => :axis_update}
|
33
|
+
CONTROLLER_BUTTON_PRESSED = {:source_type => :controller, :source_state => :pressed}
|
34
|
+
CONTROLLER_BUTTON_RELEASED = {:source_type => :controller, :source_state => :released}
|
35
|
+
CONTROLLER_BUTTON_HELD = {:source_type => :controller, :source_state => :held}
|
36
|
+
|
37
|
+
#TODO: Discover Windows mappings
|
38
|
+
if Platform.using_osx?
|
39
|
+
# buttons
|
40
|
+
XBOX_360_DPAD_UP = 0 # No Windows "buttons" for the dpad - it's unusable
|
41
|
+
XBOX_360_DPAD_DOWN = 1
|
42
|
+
XBOX_360_DPAD_LEFT = 2
|
43
|
+
XBOX_360_DPAD_RIGHT = 3
|
44
|
+
XBOX_360_START = 4
|
45
|
+
XBOX_360_BACK = 5
|
46
|
+
XBOX_360_LEFT_STICK = 6
|
47
|
+
XBOX_360_RIGHT_STICK = 7
|
48
|
+
XBOX_360_LEFT_BUMPER = 8
|
49
|
+
XBOX_360_RIGHT_BUMPER = 9
|
50
|
+
XBOX_360_GUIDE_BUTTON = 10
|
51
|
+
XBOX_360_A = 11
|
52
|
+
XBOX_360_B = 12
|
53
|
+
XBOX_360_X = 13
|
54
|
+
XBOX_360_Y = 14
|
55
|
+
# axes
|
56
|
+
XBOX_360_LEFT_X_AXIS = 'x'
|
57
|
+
XBOX_360_LEFT_Y_AXIS = 'y'
|
58
|
+
XBOX_360_LEFT_TRIGGER_AXIS = 'z' # On Windows, both triggers serve as one axis
|
59
|
+
XBOX_360_RIGHT_X_AXIS = 'rx'
|
60
|
+
XBOX_360_RIGHT_Y_AXIS = 'ry'
|
61
|
+
XBOX_360_RIGHT_TRIGGER_AXIS = 'rz' # On Windows, both triggers serve as one axis
|
62
|
+
elsif Platform.using_windows?
|
63
|
+
# buttons
|
64
|
+
XBOX_360_A = 0
|
65
|
+
XBOX_360_B = 1
|
66
|
+
XBOX_360_X = 2
|
67
|
+
XBOX_360_Y = 3
|
68
|
+
XBOX_360_LEFT_BUMPER = 4
|
69
|
+
XBOX_360_RIGHT_BUMPER = 5
|
70
|
+
XBOX_360_BACK = 6
|
71
|
+
XBOX_360_START = 7
|
72
|
+
XBOX_360_LEFT_STICK = 8
|
73
|
+
XBOX_360_RIGHT_STICK = 9
|
74
|
+
#axes
|
75
|
+
XBOX_360_LEFT_X_AXIS = 'X Axis'
|
76
|
+
XBOX_360_LEFT_Y_AXIS = 'Y Axis'
|
77
|
+
XBOX_360_TRIGGER_AXIS = 'Z Axis' # On OSX, both triggers serve as individual axes
|
78
|
+
XBOX_360_RIGHT_X_AXIS = 'X Rotation'
|
79
|
+
XBOX_360_RIGHT_Y_AXIS = 'Y Rotation'
|
80
|
+
end
|
81
|
+
|
82
|
+
# LWJGL can't poll for buttons in the negative range yet. Possible bug to report?
|
83
|
+
# 360 controller provides button presses for analog inputs for convienence
|
84
|
+
XBOX_360_LEFT_STICK_LEFT = -1
|
85
|
+
XBOX_360_LEFT_STICK_RIGHT = -2
|
86
|
+
XBOX_360_LEFT_STICK_UP = -3
|
87
|
+
XBOX_360_LEFT_STICK_DOWN = -4
|
88
|
+
|
89
|
+
class MouseEvent
|
90
|
+
PRESSED = :pressed
|
91
|
+
RELEASED = :released
|
92
|
+
attr_accessor :state, :location
|
93
|
+
def initialize(state, location)
|
94
|
+
@state, @location = state, location
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module Gemini
|
99
|
+
# Consumes raw slick_input events and output events based on
|
100
|
+
# registered key bindings.
|
101
|
+
class InputManager < Gemini::GameObject
|
102
|
+
|
103
|
+
$LOAD_PATH.each do |path|
|
104
|
+
puts path
|
105
|
+
if File.basename(path) == "input_helpers"
|
106
|
+
# could be .class or .rb, we'll just search for *.* and hope nobody is silly (:
|
107
|
+
Dir.glob(File.join(File.expand_path(path), "*.*").gsub('%20', ' ')).each do |input_helper_path|
|
108
|
+
require input_helper_path.sub('.class', '') # .class can't be required directly
|
109
|
+
include File.basename(input_helper_path, '.rb').sub('.class', '').camelize.constantize
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
MAX_CONTROLLERS = 6
|
115
|
+
|
116
|
+
@@loading_input_manager = nil
|
117
|
+
def self.loading_input_manager
|
118
|
+
@@loading_input_manager
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.define_keymap
|
122
|
+
yield loading_input_manager
|
123
|
+
end
|
124
|
+
|
125
|
+
def load(container)
|
126
|
+
@held_keys = []
|
127
|
+
@raw_input = container.input
|
128
|
+
@input_listener = Gemini::SlickInputListener.new(@game_state)
|
129
|
+
@raw_input.add_listener @input_listener
|
130
|
+
@held_buttons = {}
|
131
|
+
end
|
132
|
+
|
133
|
+
def load_keymap(keymap)
|
134
|
+
@keymap = Hash.new{|h,k| h[k] = []}
|
135
|
+
|
136
|
+
@held_buttons = Hash.new {|h,k| h[k] = []}
|
137
|
+
keymap_name = "/keymaps/#{keymap.underscore}"
|
138
|
+
keymap_path = $LOAD_PATH.find do |path|
|
139
|
+
puts "trying path for .rb/.class: #{File.expand_path(path + keymap_name)}"
|
140
|
+
File.exist?(File.expand_path(path + keymap_name + '.rb')) || File.exist?(File.expand_path(path + keymap_name + '.class'))
|
141
|
+
end
|
142
|
+
puts "keymap found: #{keymap_path.inspect}"
|
143
|
+
|
144
|
+
@@loading_input_manager = self
|
145
|
+
keymap_path += '/' unless keymap_path.nil? # was using <<, but that alters the load path in a bad way.
|
146
|
+
begin
|
147
|
+
# the method 'load' already exists on this scope
|
148
|
+
Kernel.load "#{keymap_path}#{keymap_name.sub('/', '')}.class"
|
149
|
+
rescue LoadError
|
150
|
+
# the method 'load' already exists on this scope
|
151
|
+
Kernel.load "#{keymap_path}#{keymap_name.sub('/', '')}.rb"
|
152
|
+
end
|
153
|
+
@@loading_input_manager = nil
|
154
|
+
end
|
155
|
+
|
156
|
+
def poll(screen_width, screen_height, delta)
|
157
|
+
return if @keymap.nil?
|
158
|
+
@input_listener.delta = delta
|
159
|
+
@raw_input.poll(screen_width, screen_height)
|
160
|
+
@keymap.values.map {|keymap_array| keymap_array.map{|keymap| keymap.poll(@raw_input)} }.flatten.compact.each do |game_message|
|
161
|
+
@game_state.manager(:message_queue).post_message game_message
|
162
|
+
end
|
163
|
+
|
164
|
+
# Check for any held keys
|
165
|
+
# @held_buttons.each do |device, button_ids|
|
166
|
+
# button_ids.each do |button_id|
|
167
|
+
# invoke_callbacks_for(device, :held, button_id, nil, delta)
|
168
|
+
# end
|
169
|
+
# end
|
170
|
+
end
|
171
|
+
|
172
|
+
# probably needs deletion
|
173
|
+
def poll_keyboard
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
# probably needs deletion
|
178
|
+
def poll_mouse
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
# probably needs deletion
|
183
|
+
def poll_joystick
|
184
|
+
@raw_input.controller_count.times do |controller_id|
|
185
|
+
@raw_input.get_axis_count(controller_id).times do |axis_id|
|
186
|
+
axis_name = @raw_input.get_axis_name(controller_id, axis_id)
|
187
|
+
axis_value = @raw_input.get_axis_value(controller_id, axis_id)
|
188
|
+
# Do we really want to do this on each poll?
|
189
|
+
# No raw slick event to catch, should be wrapped anyways
|
190
|
+
message = InputMessage.new(:joystick_id => controller_id, :input_name => axis_name, :input_value => axis_value, :raw_input => @raw_input)
|
191
|
+
invoke_callbacks_for(:joystick, :axis_update, axis_name, controller_id, message)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def connected_joystick_size
|
197
|
+
@raw_input.controller_count
|
198
|
+
end
|
199
|
+
|
200
|
+
def map_key(options, &block)
|
201
|
+
map :key, options, &block
|
202
|
+
end
|
203
|
+
|
204
|
+
def map_mouse(options, &block)
|
205
|
+
map :mouse, options, &block
|
206
|
+
end
|
207
|
+
|
208
|
+
def map_joystick(options, &block)
|
209
|
+
map :joystick, options, &block
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
def find_keymaps_for(device, input_button_or_axis, id)
|
214
|
+
@keymap["#{device}_#{input_button_or_axis}_#{id}"]
|
215
|
+
end
|
216
|
+
|
217
|
+
def map(device, options, &block)
|
218
|
+
mapping = InputMapping.create(device, options, &block)
|
219
|
+
@keymap[mapping.key] << mapping
|
220
|
+
end
|
221
|
+
|
222
|
+
def invoke_callbacks_for(device, input_type, input_button_or_axis, id, input_message)
|
223
|
+
key_mappings = find_keymaps_for(device, input_type, input_button_or_axis, id)
|
224
|
+
key_mappings.each do |key_map|
|
225
|
+
@game_state.manager(:message_queue).post_message key_map.to_game_message(input_message)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'managers/input_support/input_message'
|
2
|
+
|
3
|
+
module Gemini
|
4
|
+
class InputMapping
|
5
|
+
attr_accessor :device, :input_type, :input_button_or_axis, :joystick_id, :destination_type, :destination_value, :input_callback
|
6
|
+
|
7
|
+
def self.create(device, options, &callback)
|
8
|
+
options[:input_callback] = callback
|
9
|
+
new(device, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO: Indicate whether or not a joystick mapping is active if a joystick is not installed
|
13
|
+
def initialize(device, options)
|
14
|
+
options = options.dup # we're going to delete some entries, which could have odd side effects without a clone
|
15
|
+
@device = device
|
16
|
+
@input_type = [:held, :released, :pressed, :axis_update].find do |input_event_name|
|
17
|
+
input_event_button_or_axis = options.delete input_event_name
|
18
|
+
if input_event_button_or_axis.nil?
|
19
|
+
false
|
20
|
+
else
|
21
|
+
@input_button_or_axis = input_event_button_or_axis
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@joystick_id = options.delete(:joystick_id)
|
27
|
+
@input_callback = options.delete(:input_callback)
|
28
|
+
@player = options.delete :player
|
29
|
+
# after all the deletes, the game message and value should be only what's left
|
30
|
+
@game_message = options.keys.first
|
31
|
+
@game_value = options.values.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def poll(raw_input)
|
35
|
+
@game_value = case @device
|
36
|
+
when :key
|
37
|
+
poll_key(raw_input)
|
38
|
+
when :mouse
|
39
|
+
when :joystick
|
40
|
+
poll_joystick(raw_input)
|
41
|
+
end
|
42
|
+
if post_canceled?
|
43
|
+
nil
|
44
|
+
else
|
45
|
+
to_game_message(raw_input)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def poll_key(raw_input)
|
50
|
+
case @input_type
|
51
|
+
when :pressed
|
52
|
+
result = raw_input.is_key_pressed(@input_button_or_axis)
|
53
|
+
cancel_post! unless result
|
54
|
+
result
|
55
|
+
when :held
|
56
|
+
result = raw_input.is_key_down(@input_button_or_axis)
|
57
|
+
cancel_post! unless result
|
58
|
+
result
|
59
|
+
when :released
|
60
|
+
key_down = raw_input.is_key_down(@input_button_or_axis)
|
61
|
+
result = (@key_down_on_last_poll && !key_down) ? true : false
|
62
|
+
@key_down_on_last_poll = key_down
|
63
|
+
cancel_post! unless result
|
64
|
+
result
|
65
|
+
else
|
66
|
+
cancel_post!
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def poll_joystick(raw_input)
|
71
|
+
if @joystick_id >= raw_input.controller_count
|
72
|
+
cancel_post!
|
73
|
+
return
|
74
|
+
end
|
75
|
+
|
76
|
+
case @input_type
|
77
|
+
when :axis_update
|
78
|
+
@axis_id ||= find_axis_id_by_axis_name(raw_input, @input_button_or_axis)
|
79
|
+
axis_value = raw_input.get_axis_value(@joystick_id, @axis_id)
|
80
|
+
axis_value
|
81
|
+
when :pressed
|
82
|
+
result = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
83
|
+
cancel_post! unless result
|
84
|
+
result
|
85
|
+
when :held
|
86
|
+
result = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
87
|
+
cancel_post! unless result
|
88
|
+
result
|
89
|
+
when :released
|
90
|
+
button_down = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
91
|
+
result = (@key_down_on_last_poll && !button_down) ? true : false
|
92
|
+
@key_down_on_last_poll = button_down
|
93
|
+
cancel_post! unless result
|
94
|
+
result
|
95
|
+
else
|
96
|
+
cancel_post!
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def cancel_post!
|
101
|
+
@cancel_post = true
|
102
|
+
end
|
103
|
+
|
104
|
+
def post_canceled?
|
105
|
+
result = @cancel_post
|
106
|
+
@cancel_post = false
|
107
|
+
result
|
108
|
+
end
|
109
|
+
|
110
|
+
def find_axis_id_by_axis_name(raw_input, axis_name)
|
111
|
+
(0..raw_input.get_axis_count(@joystick_id)).find {|axis_id| raw_input.get_axis_name(@joystick_id, axis_id) == axis_name}
|
112
|
+
end
|
113
|
+
|
114
|
+
def key
|
115
|
+
"#{@device}_#{@input_type}_#{@input_button_or_axis}_#{@joystick_id}"
|
116
|
+
end
|
117
|
+
|
118
|
+
# eventually, raw_input will need to be wrapped
|
119
|
+
def to_game_message(raw_input)
|
120
|
+
game_message = InputMessage.new(@game_message, @game_value)
|
121
|
+
game_message.player = @player
|
122
|
+
@input_callback.call(game_message, raw_input) unless @input_callback.nil?
|
123
|
+
game_message
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|