Class: Metro::EventRelay

Inherits:
Object
  • Object
show all
Defined in:
lib/metro/events/event_relay.rb

Overview

Note:

registering for ‘button_held’ events require that the window be speicfied. As that is the only way to ask if the button is currently pressed.

An EventRelay represents a target’s willingness to respond to events generate from the window. An event relay is generate for every scene but additional relays can be generated to also listen for events.

An event relay can register a target to listen for the following window events: ‘button_down’; ‘button_up’; and ‘button_held’.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target, window = nil) ⇒ EventRelay

An event relay is created a with a target and optionally a window.

Parameters:

  • target (Object)

    the object that will execute the code when the button events have fired have been triggered.

  • window (Window) (defaults to: nil)

    the window of the game. This parameter is optional and only required if the events are interested in buttons being held.



63
64
65
66
67
68
69
70
# File 'lib/metro/events/event_relay.rb', line 63

def initialize(target,window = nil)
  @target = target
  @window = window
  @up_actions ||= {}
  @down_actions ||= {}
  @held_actions ||= {}
  @custom_notifications ||= HashWithIndifferentAccess.new([])
end

Instance Attribute Details

#custom_notificationsObject (readonly)

Returns the value of attribute custom_notifications.



220
221
222
# File 'lib/metro/events/event_relay.rb', line 220

def custom_notifications
  @custom_notifications
end

#down_actionsObject (readonly)

Returns the value of attribute down_actions.



220
221
222
# File 'lib/metro/events/event_relay.rb', line 220

def down_actions
  @down_actions
end

#held_actionsObject (readonly)

Returns the value of attribute held_actions.



220
221
222
# File 'lib/metro/events/event_relay.rb', line 220

def held_actions
  @held_actions
end

#targetObject (readonly)

Returns the value of attribute target.



72
73
74
# File 'lib/metro/events/event_relay.rb', line 72

def target
  @target
end

#up_actionsObject (readonly)

Returns the value of attribute up_actions.



220
221
222
# File 'lib/metro/events/event_relay.rb', line 220

def up_actions
  @up_actions
end

#windowObject (readonly)

Returns the value of attribute window.



72
73
74
# File 'lib/metro/events/event_relay.rb', line 72

def window
  @window
end

Class Method Details

.check_for_already_defined_control!(control) ⇒ Object



48
49
50
51
52
# File 'lib/metro/events/event_relay.rb', line 48

def self.check_for_already_defined_control!(control)
  if instance_methods.include? control.name
    error! "error.reserved_control_name", name: control.name
  end
end

.define_control(control) ⇒ Object

Defines a control from a ControlDefinition for all EventRelays. A control is a way of defining a shortcut for a common event. This could be the use of a common set of keys for confirmation or canceling.



40
41
42
43
44
45
46
# File 'lib/metro/events/event_relay.rb', line 40

def self.define_control(control)
  check_for_already_defined_control!(control)

  define_method control.name do |&block|
    send(control.event,*control.args,&block)
  end
end

.define_controls(controls) ⇒ Object

Defines the provided controls for every EventRelay that is created.

Parameters:

  • controls (Array<ControlDefinition>)

    the definitions of controls that should be added to all EventRelays.

See Also:

  • #define_control


31
32
33
# File 'lib/metro/events/event_relay.rb', line 31

def self.define_controls(controls)
  controls.each { |control| define_control control }
end

Instance Method Details

#_fire_event_for_notification(event, sender, action) ⇒ Object

Fire a single event based on the matched notification.

An action without any parameters is assumed to be executed within the contexxt of the target. If there are two parameters we will simply execute the action and pass it both the target and the sender.



289
290
291
292
293
294
295
296
297
# File 'lib/metro/events/event_relay.rb', line 289

def _fire_event_for_notification(event,sender,action)
  if action.arity == 2
    target.instance_exec(sender,event,&action)
  elsif action.arity == 1
    target.instance_exec(sender,&action)
  else
    target.instance_eval(&action)
  end
end

#_on(hash, args, block) ⇒ Object



222
223
224
225
226
227
228
# File 'lib/metro/events/event_relay.rb', line 222

def _on(hash,args,block)
  options = (args.last.is_a?(Hash) ? args.pop : {})

  args.each do |keystroke|
    hash[keystroke] = block || lambda { |instance| send(options[:do]) }
  end
end

#down_action(id) ⇒ Object

Returns a block of code that is mapped for the ‘button_down’ id.

Returns:

  • a block of code that is mapped for the ‘button_down’ id



268
269
270
# File 'lib/metro/events/event_relay.rb', line 268

def down_action(id)
  down_actions[id] || lambda {|no_op| }
end

#execute_block_for_target(&block) ⇒ Object



257
258
259
260
# File 'lib/metro/events/event_relay.rb', line 257

def execute_block_for_target(&block)
  event_data = EventData.new(window)
  target.instance_exec(event_data,&block)
end

#fire_button_down(id) ⇒ Object

This is called by external or parent source of events, usually a Scene, when a button down event has been triggered.



242
243
244
# File 'lib/metro/events/event_relay.rb', line 242

def fire_button_down(id)
  execute_block_for_target( &down_action(id) )
end

#fire_button_up(id) ⇒ Object

This is called by external or parent source of events, usually a Scene, when a button up event has been triggered.



234
235
236
# File 'lib/metro/events/event_relay.rb', line 234

def fire_button_up(id)
  execute_block_for_target( &up_action(id) )
end

#fire_events_for_held_buttonsObject

Fire the events mapped to the held buttons within the context of the specified target. This method is differently formatted because held buttons are not events but polling to see if the button is still being held.



251
252
253
254
255
# File 'lib/metro/events/event_relay.rb', line 251

def fire_events_for_held_buttons
  held_actions.each do |key,action|
    execute_block_for_target(&action) if window and window.button_down?(key)
  end
end

#fire_events_for_notification(event, sender) ⇒ Object

Fire all events mapped to the matching notification.



275
276
277
278
279
280
# File 'lib/metro/events/event_relay.rb', line 275

def fire_events_for_notification(event,sender)
  notification_actions = custom_notifications[event]
  notification_actions.each do |action|
    _fire_event_for_notification(event,sender,action)
  end
end

#notification(param, &block) ⇒ Object

Register for a custom notification event. These events are fired when another object within the game posts a notification with matching criteria. If there has indeed been a match, then the stored action block will be fired.

When the action block is specified is defined with no parameters it is assumed that that the code should be executed within the context of the object that defined the action, the ‘target’.

The action block can also be specified with two parameters. In this case the code is no longer executed within the context of the object and is instead provided the the action target and the action source.

Examples:

Registering for a save complete event that would re-enable a menu.


class ExampleScene
  event :notification, :save_complete do
    menu.enabled!
  end
end

Registering for a win game event that explicitly states the target and source.


class ExampleScene

  event :notification, :win_game do |target,winner|
    target.declare_winner winner
  end

  def declare_winner(winning_player)
    # ...
  end
end


216
217
218
# File 'lib/metro/events/event_relay.rb', line 216

def notification(param,&block)
  custom_notifications[param.to_sym] = custom_notifications[param.to_sym] + [ block ]
end

#on_down(*args, &block) ⇒ Object Also known as: button_down

Register for a button_down event. These events are fired when the button is pressed down. This event only fires once when the button moves from the not pressed to the down state.

Here in this scene if the GpLeft or GpUp buttons are pressed down the method ‘previous_options` will be executed.

This example uses a block instead of a method name but it is absolultey the same as the last example.

Examples:

Registering for a button down event to call a method named ‘previous_option’


class ExampleScene
  event :on_down, GpLeft, GpUp, do: :previous_option

  def previous_option
    @selected_index = @selected_index - 1
    @selected_index = options.length - 1 if @selected_index <= -1
  end
end

Registering for a button down event with a block of code to execute


class ExampleScene
   event :on_down, GpLeft, GpUp do
    @selected_index = @selected_index - 1
    @selected_index = options.length - 1 if @selected_index <= -1
  end
end


106
107
108
# File 'lib/metro/events/event_relay.rb', line 106

def on_down(*args,&block)
  _on(@down_actions,args,block)
end

#on_hold(*args, &block) ⇒ Object Also known as: button_hold, button_held

Note:

button_held events require that the window be specified during initialization.

Register for a button_held event. These events are fired when the button is currently in the downstate. This event continues to fire at the beginning of every update of a scene until the button is released.

Examples:

Registering for button held events


class ExampleScene
  event :on_hold KbLeft, GpLeft do
    player.turn_left
  end

  event :on_hold, KbRight, GpRight do
    player.turn_right
  end

  event :on_hold, KbUp, Gosu::GpButton0, do: :calculate_accleration

  def calculate_acceleration
    long_complicated_calculated_result = 0
    # ... multi-line calculations to determine the player acceleration ...
    player.accelerate = long_complicated_calculated_result
  end
end


174
175
176
177
# File 'lib/metro/events/event_relay.rb', line 174

def on_hold(*args,&block)
  log.warn "Registering for a on_hold event requires that a window be provided." unless window
  _on(@held_actions,args,block)
end

#on_up(*args, &block) ⇒ Object Also known as: button_up

Register for a button_up event. These events are fired when the button is released (from being pressed down). This event only fires once when the button moves from the pressed state to the up state.

Here in this scene if the Escape Key is pressed and released the example scene will transition to the title scene.

This example uses a block instead of a method name but it is absolultey the same as the last example.

Examples:

Registering for a button down event to call a method named ‘next_option’


class ExampleScene
   event :on_up, KbEscape, do: :leave_scene

  def leave_scene
    transition_to :title
  end
end

Registering for a button up event with a block of code to execute


class ExampleScene
  event :on_up, KbEscape do
   transition_to :title
  end
end


141
142
143
# File 'lib/metro/events/event_relay.rb', line 141

def on_up(*args,&block)
  _on(@up_actions,args,block)
end

#up_action(id) ⇒ Object

Returns a block of code that is mapped for the ‘button_up’ id.

Returns:

  • a block of code that is mapped for the ‘button_up’ id



263
264
265
# File 'lib/metro/events/event_relay.rb', line 263

def up_action(id)
  up_actions[id] || lambda {|no_op| }
end