rubygame 2.3.0 → 2.4.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/CREDITS +5 -0
- data/NEWS +88 -0
- data/README +8 -4
- data/ROADMAP +19 -43
- data/Rakefile +94 -10
- data/doc/macosx_install.rdoc +2 -2
- data/doc/windows_install.rdoc +2 -2
- data/ext/rubygame/rubygame_event.c +116 -0
- data/ext/rubygame/rubygame_event2.c +661 -0
- data/ext/rubygame/rubygame_event2.h +29 -0
- data/ext/rubygame/rubygame_joystick.c +106 -17
- data/ext/rubygame/rubygame_main.c +3 -0
- data/ext/rubygame/rubygame_shared.c +2 -5
- data/ext/rubygame/rubygame_shared.h +1 -0
- data/ext/rubygame/rubygame_surface.c +11 -9
- data/lib/rubygame.rb +14 -3
- data/lib/rubygame/event_actions.rb +203 -0
- data/lib/rubygame/event_handler.rb +454 -0
- data/lib/rubygame/event_hook.rb +112 -0
- data/lib/rubygame/event_triggers.rb +692 -0
- data/lib/rubygame/events.rb +44 -0
- data/lib/rubygame/events/joystick_events.rb +342 -0
- data/lib/rubygame/events/keyboard_events.rb +132 -0
- data/lib/rubygame/events/misc_events.rb +144 -0
- data/lib/rubygame/events/mouse_events.rb +155 -0
- data/lib/rubygame/ftor.rb +2 -2
- data/lib/rubygame/queue.rb +50 -29
- data/samples/demo_draw.rb +175 -0
- data/samples/demo_rubygame.rb +421 -165
- metadata +18 -5
@@ -0,0 +1,454 @@
|
|
1
|
+
#--
|
2
|
+
# Rubygame -- Ruby code and bindings to SDL to facilitate game creation
|
3
|
+
# Copyright (C) 2004-2008 John Croisant
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'rubygame/event_hook'
|
21
|
+
|
22
|
+
|
23
|
+
# EventHandler provides a simple, extensible system for
|
24
|
+
# hook-based event handling.
|
25
|
+
#
|
26
|
+
# An EventHandler holds a list of EventHook objects. When
|
27
|
+
# the EventHandler receives a new event (passed to #handle),
|
28
|
+
# it tests the event against each EventHook. If the event
|
29
|
+
# matches the EventHook, the EventHandler passes the event to
|
30
|
+
# the EventHook to perform an action (such as calling a
|
31
|
+
# method or executing a block).
|
32
|
+
#
|
33
|
+
# Although the EventHandler and EventHook classes are very
|
34
|
+
# simple in themselves, they can be used as building blocks
|
35
|
+
# to create flexible and complex systems, whatever is needed
|
36
|
+
# by your application.
|
37
|
+
#
|
38
|
+
# Here are a few ways you could use EventHandler:
|
39
|
+
#
|
40
|
+
# * One central EventHandler with EventHooks to perform
|
41
|
+
# all types of actions. This is good for simple apps.
|
42
|
+
#
|
43
|
+
# * Multiple EventHandlers, one for each category of
|
44
|
+
# event. For example, one for keyboard input, one for
|
45
|
+
# mouse input, one for game logic events, etc.
|
46
|
+
#
|
47
|
+
# * An EventHandler in every game object (using the
|
48
|
+
# HasEventHandler mixin module), being fed events from
|
49
|
+
# a central EventHandler.
|
50
|
+
#
|
51
|
+
# You can also extend the possibilities of EventHandler and
|
52
|
+
# EventHook by creating your own event trigger and action
|
53
|
+
# classes. See EventHook for more information.
|
54
|
+
#
|
55
|
+
class Rubygame::EventHandler
|
56
|
+
|
57
|
+
# call-seq:
|
58
|
+
# EventHandler.new { |handler| ... } -> new_handler
|
59
|
+
#
|
60
|
+
# Create a new EventHandler. The optional block can be used
|
61
|
+
# for further initializing the EventHandler.
|
62
|
+
#
|
63
|
+
def initialize(&block)
|
64
|
+
@hooks = []
|
65
|
+
yield self if block_given?
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_accessor :hooks
|
69
|
+
|
70
|
+
# call-seq:
|
71
|
+
# append_hook( hook ) -> hook
|
72
|
+
# append_hook( description ) -> hook
|
73
|
+
#
|
74
|
+
# Puts an EventHook at the bottom of the stack (it will be handled last).
|
75
|
+
# If the EventHandler already has that hook, it is moved to the bottom.
|
76
|
+
# See EventHook and #handle.
|
77
|
+
#
|
78
|
+
# This method has two distinct forms. The first form adds an existing Hook
|
79
|
+
# instance; the second form constructs a new EventHook instance and adds it.
|
80
|
+
#
|
81
|
+
# hook:: the hook to add. (EventHook, for first form only)
|
82
|
+
#
|
83
|
+
# description:: a Hash to initialize a new EventHook.
|
84
|
+
# (Hash, for second form only)
|
85
|
+
#
|
86
|
+
# Returns:: the hook that was added. (EventHook)
|
87
|
+
#
|
88
|
+
# Contrast this method with #prepend, which puts the EventHook at
|
89
|
+
# the top of the stack.
|
90
|
+
#
|
91
|
+
def append_hook( hook )
|
92
|
+
hook = EventHook.new( hook ) if hook.kind_of?( Hash )
|
93
|
+
@hooks = (@hooks - [hook]) | [hook]
|
94
|
+
return hook
|
95
|
+
end
|
96
|
+
|
97
|
+
# call-seq:
|
98
|
+
# prepend_hook( hook ) -> hook
|
99
|
+
# prepend_hook( description ) -> hook
|
100
|
+
#
|
101
|
+
# Exactly like #append_hook, except that the EventHook is put at the
|
102
|
+
# top of the stack (it will be handled first).
|
103
|
+
# If the EventHandler already has that hook, it is moved to the top.
|
104
|
+
#
|
105
|
+
def prepend_hook( hook )
|
106
|
+
hook = EventHook.new( hook ) if hook.kind_of?( Hash )
|
107
|
+
@hooks = [hook] | @hooks
|
108
|
+
return hook
|
109
|
+
end
|
110
|
+
|
111
|
+
# call-seq:
|
112
|
+
# handle( event ) -> nil
|
113
|
+
#
|
114
|
+
# Triggers every hook in the stack which matches the given event.
|
115
|
+
# See EventHook.
|
116
|
+
#
|
117
|
+
# If one of the matching hooks has @consumes enabled, no hooks
|
118
|
+
# after it will receive that event. (Example use: a mouse click that
|
119
|
+
# only affects the top-most object it hits, not any below it.)
|
120
|
+
#
|
121
|
+
# event: the event to handle. (Object, required)
|
122
|
+
#
|
123
|
+
# Returns:: nil.
|
124
|
+
#
|
125
|
+
def handle( event )
|
126
|
+
matching_hooks = @hooks.select { |hook| hook.match?( event ) }
|
127
|
+
|
128
|
+
catch :event_consumed do
|
129
|
+
matching_hooks.each do |hook|
|
130
|
+
hook.perform( event )
|
131
|
+
throw :event_consumed if hook.consumes
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
return nil
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns true if the given EventHook instance is on the stack.
|
139
|
+
def has_hook?( hook )
|
140
|
+
@hooks.include?( hook )
|
141
|
+
end
|
142
|
+
|
143
|
+
# Removes the given EventHook instance from the stack, if it exists
|
144
|
+
# on the stack.
|
145
|
+
#
|
146
|
+
# Returns:: the hook that was removed, or nil if the hook did not
|
147
|
+
# exist on the stack.
|
148
|
+
#
|
149
|
+
# NOTE: You must pass the exact EventHook instance to remove it!
|
150
|
+
# Passing another EventHook that is "similar" will not work.
|
151
|
+
# So, you should store a reference to the hook when it is returned
|
152
|
+
# by #append_hook or #prepend_hook.
|
153
|
+
#
|
154
|
+
def remove_hook( hook )
|
155
|
+
@hooks.delete( hook )
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
|
162
|
+
# HasEventHandler is a mixin module to conveniently integrate
|
163
|
+
# EventHandler into any class, allowing instances of the class
|
164
|
+
# to hold event hooks and handle incoming events.
|
165
|
+
#
|
166
|
+
# To use HasEventHandler, you simply 'include' it in your class:
|
167
|
+
#
|
168
|
+
# class Player
|
169
|
+
# include Rubygame::EventHandler::HasEventHandler
|
170
|
+
#
|
171
|
+
# # ... the rest of your class ...
|
172
|
+
#
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# You can then use all of the functionality of HasEventHandler.
|
176
|
+
#
|
177
|
+
# HasEventHandler provides several methods for adding new
|
178
|
+
# event hooks to the object. The two basic methods for that are
|
179
|
+
# #append_hook and #prepend_hook. The #make_magic_hooks method can
|
180
|
+
# create multiple hooks very simply and conveniently.
|
181
|
+
#
|
182
|
+
# HasEventHandler also defines the #handle method, which accepts
|
183
|
+
# an event and gives it to the object's event handler. This is
|
184
|
+
# the recommended way to make the object process an event.
|
185
|
+
#
|
186
|
+
module Rubygame::EventHandler::HasEventHandler
|
187
|
+
|
188
|
+
# Appends a new hook to the end of the list. If the hook does
|
189
|
+
# not have an owner, the owner is set to this object before
|
190
|
+
# appending.
|
191
|
+
#
|
192
|
+
# hook:: the hook to append.
|
193
|
+
# (EventHook or Hash description, required)
|
194
|
+
#
|
195
|
+
# See also EventHandler#append_hook.
|
196
|
+
#
|
197
|
+
# Example:
|
198
|
+
#
|
199
|
+
# # Create and append new hook from a description:
|
200
|
+
# trigger = KeyPressedTrigger.new(:space)
|
201
|
+
# action = MethodAction.new(:jump)
|
202
|
+
# player.append_hook( :trigger => trigger, :action => action )
|
203
|
+
#
|
204
|
+
# # You can also give it an EventHook instance, if you want.
|
205
|
+
# hook = EventHook.new( :trigger => trigger, :action => action )
|
206
|
+
# player.append_hook( hook )
|
207
|
+
#
|
208
|
+
def append_hook( hook )
|
209
|
+
hook = _prepare_hook( hook )
|
210
|
+
@event_handler.append_hook( hook )
|
211
|
+
rescue NoMethodError
|
212
|
+
_make_event_handler
|
213
|
+
retry
|
214
|
+
end
|
215
|
+
|
216
|
+
# Passes the given event to the object's event handler.
|
217
|
+
def handle( event )
|
218
|
+
@event_handler.handle( event )
|
219
|
+
rescue NoMethodError
|
220
|
+
_make_event_handler
|
221
|
+
retry
|
222
|
+
end
|
223
|
+
|
224
|
+
# Returns true if the object's event handler includes the given
|
225
|
+
# EventHook instance.
|
226
|
+
def has_hook?( hook )
|
227
|
+
@event_handler.has_hook?( hook )
|
228
|
+
rescue NoMethodError
|
229
|
+
_make_event_handler
|
230
|
+
retry
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
# Convenience method for creating and appending hooks easily.
|
235
|
+
# It takes a Hash of {trigger_seed => action_seed} pairs, and
|
236
|
+
# creates and appends a new EventHook for each pair.
|
237
|
+
#
|
238
|
+
# Returns:: an Array of the EventHook instances that were
|
239
|
+
# created and appended.
|
240
|
+
#
|
241
|
+
# May raise:: ArgumentError, if an object doesn't match any
|
242
|
+
# conversion rules.
|
243
|
+
#
|
244
|
+
# Trigger and action can be symbols, classes, or other types of
|
245
|
+
# object. The method uses simple rules to convert the "seed"
|
246
|
+
# objects into appropriate event triggers or event actions.
|
247
|
+
#
|
248
|
+
# By default, triggers are converted according to these rules:
|
249
|
+
#
|
250
|
+
# * Symbols starting with "mouse" become a MouseClickTrigger.
|
251
|
+
# * Keyboard symbols become a KeyPressTrigger.
|
252
|
+
# * Classes become an InstanceOfTrigger.
|
253
|
+
# * Objects with a #match? method are duplicated and used
|
254
|
+
# as the trigger without being converted.
|
255
|
+
#
|
256
|
+
# By default, actions are converted according to these rules:
|
257
|
+
#
|
258
|
+
# * Symbols become a MethodAction.
|
259
|
+
# * Proc and Method instances become a BlockAction.
|
260
|
+
# * Objects with a #perform method are duplicated and used
|
261
|
+
# as the action without being converted.
|
262
|
+
#
|
263
|
+
# This method raises ArgumentError if an object doesn't match
|
264
|
+
# any of the conversion rules.
|
265
|
+
#
|
266
|
+
# You can define your own custom conversion rules by overriding
|
267
|
+
# the private methods #_make_magic_trigger and #make_magic_action
|
268
|
+
# in your class.
|
269
|
+
#
|
270
|
+
# NOTE: Additional default rules may be added in the future, but
|
271
|
+
# objects which match the existing rules will continue to match
|
272
|
+
# them. However, objects which are invalid in one version might
|
273
|
+
# become valid in future versions, if a new rule is added. So, you
|
274
|
+
# should never depend on ArgumentError being raised for a paricular
|
275
|
+
# object!
|
276
|
+
#
|
277
|
+
# Example:
|
278
|
+
#
|
279
|
+
# died_action = proc { |owner, event|
|
280
|
+
# owner.say "Blargh, I'm dead!" if event.who_died == owner
|
281
|
+
# }
|
282
|
+
#
|
283
|
+
# player.make_magic_hooks( :space => :jump,
|
284
|
+
# :left => :move_left,
|
285
|
+
# :right => :move_right,
|
286
|
+
# :mouse_left => :shoot,
|
287
|
+
# DiedEvent => died_action )
|
288
|
+
#
|
289
|
+
def make_magic_hooks( hash )
|
290
|
+
hash.collect do |trigger, action|
|
291
|
+
append_hook( :trigger => _make_magic_trigger( trigger ),
|
292
|
+
:action => _make_magic_action( action ))
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Exactly like #append_hook, except that the hook is put at the
|
297
|
+
# top of the stack (it will be handled first).
|
298
|
+
#
|
299
|
+
# See also EventHandler#prepend_hook.
|
300
|
+
#
|
301
|
+
def prepend_hook( hook )
|
302
|
+
hook = _prepare_hook( hook )
|
303
|
+
@event_handler.prepend_hook( hook )
|
304
|
+
rescue NoMethodError
|
305
|
+
_make_event_handler
|
306
|
+
retry
|
307
|
+
end
|
308
|
+
|
309
|
+
# Remove the given EventHook instance from the stack, if it
|
310
|
+
# exists on the stack.
|
311
|
+
# See EventHandler#remove_hook for details and restrictions.
|
312
|
+
#
|
313
|
+
# Returns:: the hook that was removed, or nil if the hook did not
|
314
|
+
# exist on the stack.
|
315
|
+
#
|
316
|
+
def remove_hook( hook )
|
317
|
+
@event_handler.remove_hook( hook )
|
318
|
+
rescue NoMethodError
|
319
|
+
_make_event_handler
|
320
|
+
retry
|
321
|
+
end
|
322
|
+
|
323
|
+
private
|
324
|
+
|
325
|
+
# Sets @event_handler to a new EventHandler if needed.
|
326
|
+
def _make_event_handler
|
327
|
+
@event_handler = EventHandler.new() if @event_handler.nil?
|
328
|
+
end
|
329
|
+
|
330
|
+
# This method is called by #make_magic_hooks to convert an
|
331
|
+
# object into an event action instance. For example, when
|
332
|
+
# this method is given a Proc, it creates and returns a
|
333
|
+
# BlockAction using that Proc. See #make_magic_hooks for
|
334
|
+
# information about how other objects are converted.
|
335
|
+
#
|
336
|
+
# You can override this method in your own classes to
|
337
|
+
# define your own custom conversion rules. Example:
|
338
|
+
#
|
339
|
+
# class Player
|
340
|
+
# include Rubygame::EventHandler::HasEventHandler
|
341
|
+
#
|
342
|
+
# private
|
343
|
+
#
|
344
|
+
# def _make_magic_action( action )
|
345
|
+
# if( action == :move_left )
|
346
|
+
# return BlockAction.new { |owner, event|
|
347
|
+
# owner.move_by( [-1, 0] )
|
348
|
+
# }
|
349
|
+
# else
|
350
|
+
# super
|
351
|
+
# end
|
352
|
+
# end
|
353
|
+
#
|
354
|
+
# end
|
355
|
+
#
|
356
|
+
#
|
357
|
+
# Returns:: an event action instance
|
358
|
+
#
|
359
|
+
# May raise:: ArgumentError, if the given object does not
|
360
|
+
# match any of the conversion rules.
|
361
|
+
#
|
362
|
+
def _make_magic_action( action )
|
363
|
+
case action
|
364
|
+
|
365
|
+
when Symbol
|
366
|
+
EventActions::MethodAction.new(action)
|
367
|
+
|
368
|
+
when Proc, Method
|
369
|
+
EventActions::BlockAction.new(&action)
|
370
|
+
|
371
|
+
else
|
372
|
+
if action.respond_to? :perform
|
373
|
+
action.dup
|
374
|
+
else
|
375
|
+
raise( ArgumentError,
|
376
|
+
"invalid action '#{action.inspect}'. " +\
|
377
|
+
"See HasEventHandler#make_magic_hooks docs for " +\
|
378
|
+
"allowed action types." )
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
# This method is called by #make_magic_hooks to convert an
|
385
|
+
# object into an event trigger instance. For example, when
|
386
|
+
# this method is given the symbol :mouse_left, it creates
|
387
|
+
# and returns a MousePressTrigger that matches :mouse_left.
|
388
|
+
# See #make_magic_hooks for information about how other objects
|
389
|
+
# are converted.
|
390
|
+
#
|
391
|
+
# You can override this method in your own classes to
|
392
|
+
# define your own custom conversion rules. Example:
|
393
|
+
#
|
394
|
+
# class Player
|
395
|
+
# include Rubygame::EventHandler::HasEventHandler
|
396
|
+
#
|
397
|
+
# private
|
398
|
+
#
|
399
|
+
# def _make_magic_trigger( trigger )
|
400
|
+
# if( trigger == :game_over )
|
401
|
+
# return GameOverTrigger.new()
|
402
|
+
# else
|
403
|
+
# super
|
404
|
+
# end
|
405
|
+
# end
|
406
|
+
#
|
407
|
+
# end
|
408
|
+
#
|
409
|
+
#
|
410
|
+
# Returns:: an event trigger instance
|
411
|
+
#
|
412
|
+
# May raise:: ArgumentError, if the given object does not
|
413
|
+
# match any of the conversion rules.
|
414
|
+
#
|
415
|
+
def _make_magic_trigger( trigger )
|
416
|
+
case trigger
|
417
|
+
|
418
|
+
when Symbol
|
419
|
+
case(trigger.to_s)
|
420
|
+
when /mouse/
|
421
|
+
EventTriggers::MousePressTrigger.new(trigger)
|
422
|
+
else
|
423
|
+
EventTriggers::KeyPressTrigger.new(trigger)
|
424
|
+
end
|
425
|
+
|
426
|
+
when Class
|
427
|
+
EventTriggers::InstanceOfTrigger.new(trigger)
|
428
|
+
|
429
|
+
else
|
430
|
+
if trigger.respond_to? :match?
|
431
|
+
trigger.dup
|
432
|
+
else
|
433
|
+
raise( ArgumentError,
|
434
|
+
"invalid trigger '#{trigger.inspect}'. " +\
|
435
|
+
"See HasEventHandler#make_magic_hooks docs for " +\
|
436
|
+
"allowed trigger types." )
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
|
442
|
+
def _prepare_hook( hook )
|
443
|
+
if( hook.kind_of? Hash )
|
444
|
+
hook = EventHook.new( {:owner => self}.merge(hook) )
|
445
|
+
end
|
446
|
+
|
447
|
+
if( hook.owner == nil )
|
448
|
+
hook = hook.dup
|
449
|
+
hook.owner = self
|
450
|
+
end
|
451
|
+
|
452
|
+
return hook
|
453
|
+
end
|
454
|
+
end
|