summaryrefslogtreecommitdiffhomepage
path: root/dragon
diff options
context:
space:
mode:
authorAmir Rajan <[email protected]>2020-05-03 20:32:11 -0500
committerAmir Rajan <[email protected]>2020-05-03 20:32:11 -0500
commitac6a6d33c4131f649957fcbd01ad4aec2f43455f (patch)
tree73c29d80eb2e73ba12f09ef563f409624e84a74d /dragon
parenta3ba88253fe6140abc8c069898b7c2762dbf79ef (diff)
downloaddragonruby-game-toolkit-contrib-ac6a6d33c4131f649957fcbd01ad4aec2f43455f.tar.gz
dragonruby-game-toolkit-contrib-ac6a6d33c4131f649957fcbd01ad4aec2f43455f.zip
Synced with v1.8
Diffstat (limited to 'dragon')
-rw-r--r--dragon/args.rb64
-rw-r--r--dragon/attr_gtk.rb1
-rw-r--r--dragon/attr_sprite.rb4
-rw-r--r--dragon/config.rb399
-rw-r--r--dragon/console.rb97
-rw-r--r--dragon/controller.rb122
-rw-r--r--dragon/directional_input_helper_methods.rb21
-rw-r--r--dragon/geometry.rb31
-rw-r--r--dragon/grid.rb129
-rw-r--r--dragon/inputs.rb295
-rw-r--r--dragon/keys.rb51
11 files changed, 1011 insertions, 203 deletions
diff --git a/dragon/args.rb b/dragon/args.rb
index e2e8a5c..0e6ff6f 100644
--- a/dragon/args.rb
+++ b/dragon/args.rb
@@ -4,11 +4,50 @@
# args.rb has been released under MIT (*only this file*).
module GTK
+ # This class is the one you'll interact with the most. It's
+ # constructed by the DragonRuby Runtime and is provided to you on
+ # each tick.
class Args
include ArgsDeprecated
-
- attr_accessor :inputs, :outputs, :passes, :runtime,
- :grid, :recording, :geometry
+ include Serialize
+
+ # Contains information related to input devices and input events.
+ #
+ # @return [Inputs]
+ attr_accessor :inputs
+
+ # Contains the means to interact with output devices such as the screen.
+ #
+ # @return [Outputs]
+ attr_accessor :outputs
+
+ # Contains display size information to assist in positioning things on the screen.
+ #
+ # @return [Grid]
+ attr_accessor :grid
+
+ # Provides access to game play recording facilities within Game Toolkit.
+ #
+ # @return [Recording]
+ attr_accessor :recording
+
+ # Gives you access to geometry related functions.
+ #
+ # @return [Geometry]
+ attr_accessor :geometry
+
+ # This is where you'll put state associated with your video game.
+ #
+ # @return [OpenEntity]
+ attr_accessor :state
+
+ # Gives you access to the top level DragonRuby runtime.
+ #
+ # @return [Runtime]
+ attr_accessor :runtime
+ alias_method :gtk, :runtime
+
+ attr_accessor :passes
def initialize runtime, recording
@inputs = Inputs.new
@@ -24,6 +63,9 @@ module GTK
@geometry = GTK::Geometry
end
+ # The number of ticks since the start of the game.
+ #
+ # @return [Integer]
def tick_count
@state.tick_count
end
@@ -32,18 +74,6 @@ module GTK
@state.tick_count = value
end
- def gtk
- @runtime
- end
-
- def state
- @state
- end
-
- def state= value
- @state = value
- end
-
def serialize
{
state: state.as_hash,
@@ -139,10 +169,14 @@ module GTK
@inputs.mouse
end
+ # @see Inputs#controller_one
+ # @return (see Inputs#controller_one)
def controller_one
@inputs.controller_one
end
+ # @see Inputs#controller_two
+ # @return (see Inputs#controller_two)
def controller_two
@inputs.controller_two
end
diff --git a/dragon/attr_gtk.rb b/dragon/attr_gtk.rb
index cf0b9f0..b72f946 100644
--- a/dragon/attr_gtk.rb
+++ b/dragon/attr_gtk.rb
@@ -3,6 +3,7 @@
# MIT License
# attr_gtk.rb has been released under MIT (*only this file*).
+# @private
module AttrGTK
attr_accessor :args
diff --git a/dragon/attr_sprite.rb b/dragon/attr_sprite.rb
index 7865293..e47e051 100644
--- a/dragon/attr_sprite.rb
+++ b/dragon/attr_sprite.rb
@@ -2,12 +2,14 @@
# MIT License
# attr_sprite.rb has been released under MIT (*only this file*).
+# @private
module AttrSprite
include GTK::Geometry
attr_accessor :x, :y, :w, :h, :path, :angle, :a, :r, :g, :b, :tile_x,
:tile_y, :tile_w, :tile_h, :flip_horizontally,
- :flip_vertically, :angle_anchor_x, :angle_anchor_y, :id
+ :flip_vertically, :angle_anchor_x, :angle_anchor_y, :id,
+ :source_x, :source_y, :source_w, :source_h
def primitive_marker
:sprite
diff --git a/dragon/config.rb b/dragon/config.rb
new file mode 100644
index 0000000..de57085
--- /dev/null
+++ b/dragon/config.rb
@@ -0,0 +1,399 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# controller/config.rb has been released under MIT (*only this file*).
+
+# !!! FIXME: add console command to forget custom binding(s)
+# !!! FIXME: add console command to forget replace existing binding(s)
+# !!! FIXME: add console command go into play_around mode to make sure controller isn't wonky.
+
+module GTK
+ class Controller
+ class Config
+ def initialize runtime
+ @runtime = runtime
+ @raw_joysticks = {} # things that aren't game controllers to try to configure.
+ @target = nil
+ @animation_duration = (1.5).seconds
+ @toggled_at = 0
+ @fading = 0
+ @current_part = 0
+ @part_alpha = 0
+ @part_alpha_increment = 10
+ @joystick_state = {}
+ @playing_around = false
+ @used_bindings = {}
+ @bindings = []
+ @parts = [
+ [ 919, 282, 'A button', 'a' ],
+ [ 960, 323, 'B button', 'b' ],
+ [ 878, 323, 'X button', 'x' ],
+ [ 919, 365, 'Y button', 'y' ],
+ [ 433, 246, 'left stick left', '-leftx' ],
+ [ 497, 246, 'left stick right', '+leftx' ],
+ [ 466, 283, 'left stick up', '-lefty' ],
+ [ 466, 218, 'left stick down', '+lefty' ],
+ [ 466, 246, 'left stick button', 'leftstick' ],
+ [ 741, 246, 'right stick left', '-rightx' ],
+ [ 802, 246, 'right stick right', '+rightx' ],
+ [ 773, 283, 'right stick up', '-righty' ],
+ [ 773, 218, 'right stick down', '+righty' ],
+ [ 772, 246, 'right stick button', 'rightstick' ],
+ [ 263, 465, 'left shoulder button', 'leftshoulder' ],
+ [ 263, 503, 'left trigger', 'lefttrigger' ],
+ [ 977, 465, 'right shoulder button', 'rightshoulder' ],
+ [ 977, 503, 'right trigger', 'righttrigger' ],
+ [ 318, 365, 'D-pad up', 'dpup' ],
+ [ 360, 322, 'D-pad right', 'dpright' ],
+ [ 318, 280, 'D-pad down', 'dpdown' ],
+ [ 275, 322, 'D-pad left', 'dpleft' ],
+ [ 570, 402, 'select/back button', 'back'],
+ [ 619, 448, 'guide/home button', 'guide' ],
+ [ 669, 402, 'start button', 'start' ],
+ ]
+ end
+
+ def rawjoystick_connected jid, joystickname, guid
+ return if jid < 0
+ @raw_joysticks[jid] = { name: joystickname, guid: guid }
+ end
+
+ def rawjoystick_disconnected jid
+ return if jid < 0
+ if @raw_joysticks[jid] != nil
+ @raw_joysticks.delete(jid)
+ @runtime.ffi_misc.close_raw_joystick(jid)
+ # Fade out the config screen if we were literally configuring this controller right now.
+ if [email protected]? && @target[0] == jid
+ @target[0] = nil
+ @toggled_at = Kernel.global_tick_count
+ @fading = -1
+ end
+ end
+ end
+
+ def build_binding_string
+ bindingstr = ''
+ skip = false
+
+ if skip ; skip = false ; next ; end
+
+ binding = @bindings[i]
+ next if binding.nil?
+
+ part = @parts[i][3]
+
+ # clean up string:
+ # if axis uses -a0 for negative and +a0 for positive, just make it "leftx:a0" instead of "-leftx:-a0,+leftx:+a0"
+ # if axis uses +a0 for negative and -a0 for positive, just make it "leftx:a0~" instead of "-leftx:+a0,+leftx:-a0"
+ if part == '-leftx' || part == '-lefty' || part == '-rightx' || part == '-righty'
+ nextbinding = @bindings[i+1]
+ if binding.start_with?('-a') && nextbinding.start_with?('+a') && binding[2..-1] == nextbinding[2..-1]
+ skip = true
+ part = part[1..-1]
+ binding = binding[1..-1]
+ elsif binding.start_with?('+a') && nextbinding.start_with?('-a') && binding[2..-1] == nextbinding[2..-1]
+ skip = true
+ part = part[1..-1]
+ binding = "#{binding[1..-1]}~"
+ end
+ end
+
+ bindingstr += "#{!bindingstr.empty? ? ',' : ''}#{part}:#{binding}"
+ end
+
+ details = @target[1]
+
+ # !!! FIXME: no String.delete in mRuby?!?! Maybe so when upgrading.
+ #name = details[:name].delete(',')
+ # !!! FIXME: ...no regexp either... :/
+ #name = details[:name].gsub(/,/, ' ') # !!! FIXME: will SDL let you escape these instead?
+ unescaped = details[:name]
+ name = ''
+ for i in 0..unescaped.length-1
+ ch = unescaped[i]
+ name += (ch == ',') ? ' ' : ch
+ end
+ return "#{details[:guid]},#{name},platform:#{@runtime.platform},#{bindingstr}"
+ end
+
+ def move_to_different_part part
+ if !@joystick_state[:axes].nil?
+ @joystick_state[:axes].each { |i| i[:farthestval] = i[:startingval] if !i.nil? }
+ end
+ @current_part = part
+ end
+
+ def previous_part
+ if @current_part > 0
+ # remove the binding that we previous had here so it can be reused.
+ bindstr = @bindings[@current_part - 1]
+ @bindings[@current_part - 1] = nil
+ @used_bindings[bindstr] = nil
+ move_to_different_part @current_part - 1
+ end
+ end
+
+ def next_part
+ if @current_part < (@parts.length - 1)
+ move_to_different_part @current_part + 1
+ else
+ @playing_around = true
+ end
+ end
+
+ def set_binding bindstr
+ return false if !@used_bindings[bindstr].nil?
+ @used_bindings[bindstr] = @current_part
+ @bindings[@current_part] = bindstr
+ return true
+ end
+
+ # Called when a lowlevel joystick moves an axis.
+ def rawjoystick_axis jid, axis, value
+ return if @target.nil? || jid != @target[0] || @fading != 0 # skip if not currently considering this joystick.
+
+ @joystick_state[:axes] ||= []
+ @joystick_state[:axes][axis] ||= {
+ moving: false,
+ startingval: 0,
+ currentval: 0,
+ farthestval: 0
+ }
+
+ # this is the logic from SDL's controllermap.c, more or less, since this is hard to get right from scratch.
+ state = @joystick_state[:axes][axis]
+ state[:currentval] = value
+ if !state[:moving]
+ state[:moving] = true
+ state[:startingval] = value
+ state[:farthestval] = value
+ end
+
+ current_distance = (value - state[:startingval]).abs
+ farthest_distance = (state[:farthestval] - state[:startingval]).abs
+ if current_distance > farthest_distance
+ state[:farthestval] = value
+ farthest_distance = (state[:farthestval] - state[:startingval]).abs
+ end
+
+ # If we've gone out far enough and started to come back, let's bind this axis
+ if (farthest_distance >= 16000) && (current_distance <= 10000)
+ next_part if set_binding("#{(state[:farthestval] < 0) ? '-' : '+'}a#{axis}")
+ end
+ end
+
+ # Called when a lowlevel joystick moves a hat.
+ def rawjoystick_hat jid, hat, value
+ return if @target.nil? || jid != @target[0] || @fading != 0 # skip if not currently considering this joystick.
+
+ @joystick_state[:hats] ||= []
+ @joystick_state[:hats][hat] = value
+
+ return if value == 0 # 0 == centered, skip it
+ next_part if set_binding("h#{hat}.#{value}")
+ end
+
+ # Called when a lowlevel joystick moves a button.
+ def rawjoystick_button jid, button, pressed
+ return if @target.nil? || jid != @target[0] || @fading != 0 # skip if not currently considering this joystick.
+
+ @joystick_state[:buttons] ||= []
+ @joystick_state[:buttons][button] = pressed
+
+ return if !pressed
+ next_part if set_binding("b#{button}")
+ end
+
+ def calc_fading
+ if @fading == 0
+ return 255
+ elsif @fading > 0 # fading in
+ percent = @toggled_at.global_ease(@animation_duration, :flip, :quint, :flip)
+ if percent >= 1.0
+ percent = 1.0
+ @fading = 0
+ end
+ else # fading out
+ percent = @toggled_at.global_ease(@animation_duration, :flip, :quint)
+ if percent <= 0.0
+ percent = 0.0
+ @fading = 0
+ end
+ end
+
+ return (percent * 255.0).to_i
+ end
+
+ def render_basics args, msg, fade=255
+ joystickname = @target[1][:name]
+ args.outputs.primitives << [0, 0, $gtk.logical_width, $gtk.logical_height, 255, 255, 255, fade].solid
+ args.outputs.primitives << [0, 0, $gtk.logical_width, $gtk.logical_height, 'dragonruby-controller.png', 0, fade, 255, 255, 255].sprite
+ args.outputs.primitives << [$gtk.logical_width / 2, 700, joystickname, 2, 1, 0, 0, 0, fade].label
+ args.outputs.primitives << [$gtk.logical_height / 2, 650, msg, 0, 1, 0, 0, 0, 255].label if !msg.empty?
+ end
+
+ def render_part_highlight args, part, alpha=255
+ partsize = 41
+ args.outputs.primitives << [part[0], part[1], partsize, partsize, 255, 0, 0, alpha].border
+ args.outputs.primitives << [part[0]-1, part[1]-1, partsize+2, partsize+2, 255, 0, 0, alpha].border
+ args.outputs.primitives << [part[0]-2, part[1]-2, partsize+4, partsize+4, 255, 0, 0, alpha].border
+ end
+
+ def choose_target
+ if @target.nil?
+ while !@raw_joysticks.empty?
+ t = @raw_joysticks.shift # see if there's a joystick waiting on us.
+ next if t[0] < 0 # just in case.
+ next if t[1][:guid].nil? # did we already handle this guid? Dump it.
+ @target = t
+ break
+ end
+ return false if @target.nil? # nothing to configure at the moment.
+ @toggled_at = Kernel.global_tick_count
+ @fading = 1
+ @current_part = 0
+ @part_alpha = 0
+ @part_alpha_increment = 10
+ @joystick_state = {}
+ @used_bindings = {}
+ @playing_around = false
+ @bindings = []
+ end
+ return true
+ end
+
+ def render_part_highlight_from_bindstr args, bindstr, alpha=255
+ partidx = @used_bindings[bindstr]
+ return if partidx.nil?
+ render_part_highlight args, @parts[partidx], alpha
+ end
+
+ def play_around args
+ return false if !@playing_around
+
+ if args.inputs.keyboard.key_down.escape
+ @current_part = 0
+ @part_alpha = 0
+ @part_alpha_increment = 10
+ @used_bindings = {}
+ @playing_around = false
+ @bindings = []
+ elsif args.inputs.keyboard.key_down.space
+ jid = @target[0]
+ bindingstr = build_binding_string
+ #puts("new controller binding: '#{bindingstr}'")
+ @runtime.ffi_misc.add_controller_config bindingstr
+ @runtime.ffi_misc.convert_rawjoystick_to_controller jid
+ @target[0] = -1 # Conversion closes the raw joystick.
+
+ # Handle any other pending joysticks that have the same GUID (so if you plug in four of the same model, we're already done!)
+ guid = @target[1][:guid]
+ @raw_joysticks.each { |jid, details|
+ if details[:guid] == guid
+ @runtime.ffi_misc.convert_rawjoystick_to_controller jid
+ details[:guid] = nil
+ end
+ }
+
+ # Done with this guy.
+ @playing_around = false
+ @toggled_at = Kernel.global_tick_count
+ @fading = -1
+ return false
+ end
+
+ render_basics args, 'Now play around with the controller, and make sure it feels right!'
+ args.outputs.primitives << [$gtk.logical_width / 2, 90, '[ESCAPE]: Reconfigure, [SPACE]: Save this configuration', 0, 1, 0, 0, 0, 255].label
+
+ axes = @joystick_state[:axes]
+ if !axes.nil?
+ for i in 0..axes.length-1
+ next if axes[i].nil?
+ value = axes[i][:currentval]
+ next if value.nil? || (value.abs < 16000)
+ render_part_highlight_from_bindstr args, "#{value < 0 ? '-' : '+'}a#{i}"
+ end
+ end
+
+ hats = @joystick_state[:hats]
+ if !hats.nil?
+ for i in 0..hats.length-1
+ value = hats[i]
+ next if value.nil? || (value == 0)
+ render_part_highlight_from_bindstr args, "h#{i}.#{value}"
+ end
+ end
+
+ buttons = @joystick_state[:buttons]
+ if !buttons.nil?
+ for i in 0..buttons.length-1
+ value = buttons[i]
+ next if value.nil? || !value
+ render_part_highlight_from_bindstr args, "b#{i}"
+ end
+ end
+
+ return true
+ end
+
+ def should_tick?
+ return true if @play_around
+ return true if @target
+ return false
+ end
+
+ def tick args
+ return true if play_around args
+ return false if !choose_target
+
+ jid = @target[0]
+
+ if @fading == 0
+ # Cancel config?
+ if args.inputs.keyboard.key_down.escape
+ # !!! FIXME: prompt to ignore this joystick forever or just this run
+ @toggled_at = Kernel.global_tick_count
+ @fading = -1
+ end
+ end
+
+ if @fading == 0
+ if args.inputs.keyboard.key_down.backspace
+ previous_part
+ elsif args.inputs.keyboard.key_down.space
+ next_part
+ end
+ end
+
+ fade = calc_fading
+ if (@fading < 0) && (fade == 0)
+ @runtime.ffi_misc.close_raw_joystick(jid) if jid >= 0
+ @target = nil # done with this controller
+ return false
+ end
+
+ render_basics args, (@fading >= 0) ? "We don't recognize this controller, so tell us about it!" : '', fade
+
+ return true if fade < 255 # all done for now
+
+ part = @parts[@current_part]
+ args.outputs.primitives << [$gtk.logical_width / 2, 575, "Please press the #{part[2]}.", 0, 1, 0, 0, 0, 255].label
+ render_part_highlight args, part, @part_alpha
+ args.outputs.primitives << [$gtk.logical_width / 2, 90, '[ESCAPE]: Ignore controller, [BACKSPACE]: Go back one button, [SPACE]: Skip this button', 0, 1, 0, 0, 0, 255].label
+
+ @part_alpha += @part_alpha_increment
+ if (@part_alpha_increment > 0) && (@part_alpha >= 255)
+ @part_alpha = 255
+ @part_alpha_increment = -10
+ elsif (@part_alpha_increment < 0) && (@part_alpha <= 0)
+ @part_alpha = 0
+ @part_alpha_increment = 10
+ end
+
+ return true
+ end
+ end
+ end
+end
diff --git a/dragon/console.rb b/dragon/console.rb
index 9a8b55f..4f2abab 100644
--- a/dragon/console.rb
+++ b/dragon/console.rb
@@ -2,6 +2,9 @@
# MIT License
# console.rb has been released under MIT (*only this file*).
+# Contributors outside of DragonRuby who also hold Copyright:
+# - Kevin Fischer: https://github.com/kfischer-okarin
+
module GTK
class Console
class Color
@@ -55,14 +58,15 @@ module GTK
end
class Prompt
- attr_accessor :current_input_str, :font_style
+ attr_accessor :current_input_str, :font_style, :console_text_width
- def initialize(font_style:, text_color:)
+ def initialize(font_style:, text_color:, console_text_width:)
@prompt = '-> '
@current_input_str = ''
@font_style = font_style
@text_color = text_color
@cursor_color = Color.new [187, 21, 6]
+ @console_text_width = console_text_width
@last_autocomplete_prefix = nil
@next_candidate_index = 0
@@ -87,7 +91,8 @@ module GTK
if !@last_autocomplete_prefix
@last_autocomplete_prefix = calc_autocomplete_prefix
- puts method_candidates(@last_autocomplete_prefix)
+ puts "* AUTOCOMPLETE CANDIDATES: #{current_input_str}.."
+ pretty_print_strings_as_table method_candidates(@last_autocomplete_prefix)
else
candidates = method_candidates(@last_autocomplete_prefix)
return if candidates.empty?
@@ -100,6 +105,60 @@ module GTK
end
end
+ def pretty_print_strings_as_table items
+ if items.length == 0
+ puts <<-S.strip
++--------+
+| (none) |
++--------+
+S
+ else
+ # figure out the largest string
+ string_width = items.sort_by { |c| -c.to_s.length }.first
+
+ # add spacing to each side of the string which represents the cell width
+ cell_width = string_width.length + 2
+
+ # add spacing to each side of the cell to represent the column width
+ column_width = cell_width + 2
+
+ # determine the max number of columns that can fit on the screen
+ columns = @console_text_width.idiv column_width
+ columns = items.length if items.length < columns
+
+ # partition the original list of items into a string to be printed
+ items.each_slice(columns).each_with_index do |cells, i|
+ pretty_print_row_seperator string_width, cell_width, column_width, columns
+ pretty_print_row cells, string_width, cell_width, column_width, columns
+ end
+
+ pretty_print_row_seperator string_width, cell_width, column_width, columns
+ end
+ end
+
+ def pretty_print_row cells, string_width, cell_width, column_width, columns
+ # if the number of cells doesn't match the number of columns, then pad the array with empty values
+ cells += (columns - cells.length).map { "" }
+
+ # right align each cell value
+ formated_row = "|" + cells.map do |c|
+ "#{" " * (string_width.length - c.length) } #{c} |"
+ end.join
+
+ # remove seperators between empty values
+ formated_row = formated_row.gsub(" | ", " ")
+
+ puts formated_row
+ end
+
+ def pretty_print_row_seperator string_width, cell_width, column_width, columns
+ # this is a joint: +--------
+ column_joint = "+#{"-" * cell_width}"
+
+ # multiple joints create a row seperator: +----+----+
+ puts (column_joint * columns) + "+"
+ end
+
def render(args, x:, y:)
args.outputs.reserved << font_style.label(x: x, y: y, text: "#{@prompt}#{current_input_str}", color: @text_color)
args.outputs.reserved << font_style.label(x: x - 2, y: y + 3, text: (" " * (@prompt.length + current_input_str.length)) + "|", color: @cursor_color)
@@ -128,7 +187,7 @@ module GTK
end
def method_candidates(prefix)
- current_object.methods.map(&:to_s).select { |m| m.start_with? prefix }
+ current_object.autocomplete_methods.map(&:to_s).select { |m| m.start_with? prefix }
end
def display_autocomplete_candidate(candidate)
@@ -179,7 +238,7 @@ module GTK
end
def console_text_width
- @console_text_width ||= (GAME_WIDTH - 20).idiv(font_style.letter_size.x)
+ @console_text_width ||= ($gtk.logical_width - 20).idiv(font_style.letter_size.x)
end
def save_history
@@ -285,12 +344,14 @@ module GTK
@visible
end
+ # @gtk
def show reason = nil
@shown_at = Kernel.global_tick_count
@show_reason = reason
toggle if hidden?
end
+ # @gtk
def hide
if visible?
toggle
@@ -417,6 +478,7 @@ S
Kernel.eval("$results = (#{cmd})")
if $results.nil?
puts "=> nil"
+ elsif $results == :console_silent_eval
else
puts "=> #{$results}"
end
@@ -696,6 +758,7 @@ S
show show_reason
end
+ # @gtk
def set_command command, show_reason = nil
set_command_silent command, show_reason
show show_reason
@@ -708,14 +771,14 @@ S
private
def w
- GAME_WIDTH
+ $gtk.logical_width
end
def h
- GAME_HEIGHT
+ $gtk.logical_height
end
- # def top; def left; def right
+ # methods top; left; right
# Forward to grid
%i[top left right].each do |method|
define_method method do
@@ -735,8 +798,15 @@ S
[left, y, right, y, *color].line
end
+ def include_row_marker? log_entry
+ log_entry[0] == "|"
+ end
+
def color_for_log_entry(log_entry)
- if include_error_marker? log_entry
+
+ if include_row_marker? log_entry
+ @text_color
+ elsif include_error_marker? log_entry
@error_color
elsif include_subdued_markers? log_entry
@text_color.mult_alpha(0.5)
@@ -748,7 +818,7 @@ S
end
def prompt
- @prompt ||= Prompt.new(font_style: font_style, text_color: @text_color)
+ @prompt ||= Prompt.new(font_style: font_style, text_color: @text_color, console_text_width: console_text_width)
end
def current_input_str
@@ -758,5 +828,12 @@ S
def current_input_str=(str)
prompt.current_input_str = str
end
+
+ def clear
+ @archived_log.clear
+ @log.clear
+ @prompt.clear
+ :console_silent_eval
+ end
end
end
diff --git a/dragon/controller.rb b/dragon/controller.rb
new file mode 100644
index 0000000..f67df63
--- /dev/null
+++ b/dragon/controller.rb
@@ -0,0 +1,122 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# controller.rb has been released under MIT (*only this file*).
+
+module GTK
+ # @gtk
+ class Controller
+ # Access to keys that have been pressed down.
+ #
+ # @return [Controller::Keys]
+ # @gtk
+ attr_reader :key_down
+
+ # Access to keys that have been released up.
+ #
+ # @return [Controller::Keys]
+ # @gtk
+ attr_reader :key_up
+
+ # Access to keys that have been held down.
+ #
+ # @return [Controller::Keys]
+ # @gtk
+ attr_reader :key_held
+
+ # @gtk
+ attr_accessor :left_analog_x_raw,
+ :left_analog_y_raw,
+ :left_analog_x_perc,
+ :left_analog_y_perc,
+ :right_analog_x_raw,
+ :right_analog_y_raw,
+ :right_analog_x_perc,
+ :right_analog_y_perc
+
+
+ def initialize
+ @key_down = Controller::Keys.new
+ @key_up = Controller::Keys.new
+ @key_held = Controller::Keys.new
+ @left_analog_x_raw = 0
+ @left_analog_y_raw = 0
+ @left_analog_x_perc = 0
+ @left_analog_y_perc = 0
+ @right_analog_x_raw = 0
+ @right_analog_y_raw = 0
+ @right_analog_x_perc = 0
+ @right_analog_y_perc = 0
+ end
+
+ def serialize
+ {
+ key_down: @key_down.serialize,
+ key_held: @key_held.serialize,
+ key_up: @key_up.serialize
+ }
+ end
+
+ # Clear all current key presses.
+ #
+ # @return [void]
+ def clear
+ @key_down.clear
+ @key_up.clear
+ @key_held.clear
+ end
+
+ def up
+ @key_up.up || @key_held.up
+ end
+
+ def down
+ @key_up.down || @key_held.down
+ end
+
+ def left
+ @key_up.left || @key_held.left
+ end
+
+ def right
+ @key_up.right || @key_held.right
+ end
+
+ # Activates a key into the down position.
+ #
+ # @param key [Symbol] The key to press down.
+ #
+ # @return [void]
+ def activate_down(key)
+ key_down.activate(key)
+ key_held.deactivate(key)
+ key_up.deactivate(key)
+ end
+
+ # Activates a key into the held down position.
+ #
+ # @param key [Symbol] The key to hold down.
+ #
+ # @return [void]
+ def activate_held(key)
+ key_down.deactivate(key)
+ key_held.activate(key) unless key_held.send(key)
+ key_up.deactivate(key)
+ end
+
+
+ # Activates a key release into the up position.
+ #
+ # @param key [Symbol] The key release up.
+ #
+ # @return [void]
+ def activate_up(key)
+ key_down.deactivate(key)
+ key_held.deactivate(key)
+ key_up.activate(key)
+ end
+
+ include DirectionalInputHelperMethods
+ end
+end
+
diff --git a/dragon/directional_input_helper_methods.rb b/dragon/directional_input_helper_methods.rb
index 8550e59..dcf5f07 100644
--- a/dragon/directional_input_helper_methods.rb
+++ b/dragon/directional_input_helper_methods.rb
@@ -4,7 +4,7 @@
# directional_input_helper_methods.rb has been released under MIT (*only this file*).
module GTK
- # normalization of behavior related to up|down|left|right on keyboards and controllers
+ # This is a module that contains normalization of behavior related to `up`|`down`|`left`|`right` on keyboards and controllers.
module DirectionalInputHelperMethods
def self.included klass
key_state_methods = [:key_held, :key_down]
@@ -29,18 +29,35 @@ S
end
end
+ # Returns a signal indicating left (`-1`), right (`1`), or neither ('0').
+ #
+ # @return [Integer]
def left_right
return -1 if self.left
return 1 if self.right
return 0
end
+ # Returns a signal indicating up (`1`), down (`-1`), or neither ('0').
+ #
+ # @return [Integer]
def up_down
return 1 if self.up
return -1 if self.down
return 0
end
+ # Returns a normal vector (in the form of an Array with two values). If no directionals are held/down, the function returns nil.
+ #
+ # The possible results are:
+ #
+ # - `nil` which denotes that no directional input exists.
+ # - `[ 0, 1]` which denotes that only up is being held/pressed.
+ # - `[ 0, -1]` which denotes that only down is being held/pressed.
+ # - `[ 1, 1]` which denotes that right and up are being pressed/held.
+ # - `[-1, -1]` which denotes that left and down are being pressed/held.
+ #
+ # @gtk
def directional_vector
lr, ud = [self.left_right, self.up_down]
@@ -62,8 +79,8 @@ S
end
return send(m)
- # see if the key is either held or down
else
+ # see if the key is either held or down
define_singleton_method(m) do
self.key_down.send(m) || self.key_held.send(m)
end
diff --git a/dragon/geometry.rb b/dragon/geometry.rb
index 777adcd..67e6a08 100644
--- a/dragon/geometry.rb
+++ b/dragon/geometry.rb
@@ -5,6 +5,7 @@
module GTK
module Geometry
+ # Returns f(t) for a cubic Bezier curve.
def self.cubic_bezier t, a, b, c, d
s = 1 - t
s0 = 1
@@ -23,10 +24,14 @@ module GTK
1 * s0 * t3 * d
end
+ # Returns true if a primitive's rectangle is entirely inside another primitive's rectangle.
+ # @gtk
def inside_rect? outer
Geometry.inside_rect? self, outer
end
+ # Returns true if a primitive's rectangle overlaps another primitive's rectangle.
+ # @gtk
def intersect_rect? other, tolerance = 0.1
Geometry.intersect_rect? self, other, tolerance
end
@@ -47,22 +52,32 @@ module GTK
anchor_y: anchor_y
end
+ # Scales a primitive rect by a percentage.
+ # @gtk
def scale_rect percentage, *anchors
Geometry.scale_rect self, percentage, *anchors
end
+ # Returns the angle from one primitive to another primitive.
+ # @gtk
def angle_to other_point
Geometry.angle_to self, other_point
end
+ # Returns the angle to one primitive from another primitive.
+ # @gtk
def angle_from other_point
Geometry.angle_from self, other_point
end
+ # Returns true if a primitive is within a circle specified by the circle's center and radius.
+ # @gtk
def point_inside_circle? circle_center_point, radius
Geometry.point_inside_circle? self, circle_center_point, radius
end
+ # Returns a primitive that is anchored/repositioned based off its retangle.
+ # @gtk
def anchor_rect anchor_x, anchor_y
current_w = self.w
current_h = self.h
@@ -75,6 +90,7 @@ module GTK
raise ":angle_given_point has been deprecated use :angle_from instead."
end
+ # @gtk
def self.shift_line line, x, y
if line.is_a?(Array) || line.is_a?(Hash)
new_line = line.dup
@@ -102,21 +118,25 @@ rule for a long time (and why intersects_rect? has been deprecated).
S
end
+ # @gtk
def self.line_y_intercept line
line.y - line_slope(line) * line.x
end
+ # @gtk
def self.angle_between_lines line_one, line_two, replace_infinity: nil
m_line_one = line_slope line_one, replace_infinity: replace_infinity
m_line_two = line_slope line_two, replace_infinity: replace_infinity
Math.atan((m_line_one - m_line_two) / (1 + m_line_two * m_line_one)).to_degrees
end
+ # @gtk
def self.line_slope line, replace_infinity: nil
(line.y2 - line.y).fdiv(line.x2 - line.x)
.replace_infinity(replace_infinity)
end
+ # @gtk
def self.ray_test point, line
slope = (line.y2 - line.y).fdiv(line.x2 - line.x)
@@ -138,6 +158,7 @@ S
end
end
+ # @gtk
def self.line_rect line
if line.x > line.x2
x = line.x2
@@ -157,6 +178,7 @@ S
{ x: x, y: y, w: w, h: h }
end
+ # @gtk
def self.line_intersect line_one, line_two
m1 = line_slope(line_one)
m2 = line_slope(line_two)
@@ -167,6 +189,7 @@ S
[x, y]
end
+ # @gtk
def self.intersect_rect? rect_one, rect_two, tolerance = 0.1
return false if rect_one.right - tolerance < rect_two.left + tolerance
return false if rect_one.left + tolerance > rect_two.right - tolerance
@@ -177,6 +200,7 @@ S
raise e, ":intersect_rect? failed for rect_one: #{rect_one} rect_two: #{rect_two}."
end
+ # @gtk
def self.to_square size, x, y, anchor_x = 0.5, anchor_y = nil
anchor_y ||= anchor_x
x = x.shift_left(size * anchor_x)
@@ -186,12 +210,14 @@ S
raise e, ":to_square failed for size: #{size} x: #{x} y: #{y} anchor_x: #{anchor_x} anchor_y: #{anchor_y}."
end
+ # @gtk
def self.distance point_one, point_two
Math.sqrt((point_two.x - point_one.x)**2 + (point_two.y - point_one.y)**2)
rescue Exception => e
raise e, ":distance failed for point_one: #{point_one} point_two #{point_two}."
end
+ # @gtk
def self.angle_from start_point, end_point
d_y = end_point.y - start_point.y
d_x = end_point.x - start_point.x
@@ -200,18 +226,21 @@ S
raise e, ":angle_from failed for start_point: #{start_point} end_point: #{end_point}."
end
+ # @gtk
def self.angle_to start_point, end_point
angle_from end_point, start_point
rescue Exception => e
raise e, ":angle_to failed for start_point: #{start_point} end_point: #{end_point}."
end
+ # @gtk
def self.point_inside_circle? point, circle_center_point, radius
(point.x - circle_center_point.x) ** 2 + (point.y - circle_center_point.y) ** 2 < radius ** 2
rescue Exception => e
raise e, ":point_inside_circle? failed for point: #{point} circle_center_point: #{circle_center_point} radius: #{radius}"
end
+ # @gtk
def self.inside_rect? inner_rect, outer_rect
inner_rect.x >= outer_rect.x &&
inner_rect.right <= outer_rect.right &&
@@ -221,6 +250,7 @@ S
raise e, ":inside_rect? failed for inner_rect: #{inner_rect} outer_rect: #{outer_rect}."
end
+ # @gtk
def self.scale_rect_extended rect,
percentage_x: percentage_x,
percentage_y: percentage_y,
@@ -255,6 +285,7 @@ S
raise e, ":scale_rect_extended failed for rect: #{rect} percentage_x: #{percentage_x} percentage_y: #{percentage_y} anchors_x: #{anchor_x} anchor_y: #{anchor_y}."
end
+ # @gtk
def self.scale_rect rect, percentage, *anchors
anchor_x, anchor_y = *anchors.flatten
anchor_x ||= 0
diff --git a/dragon/grid.rb b/dragon/grid.rb
index b794a7d..e5c21a3 100644
--- a/dragon/grid.rb
+++ b/dragon/grid.rb
@@ -7,28 +7,89 @@ module GTK
class Grid
include Serialize
SCREEN_Y_DIRECTION = -1.0
- attr_accessor :bottom, :left, :right, :top,
- :rect, :origin_x, :origin_y, :center_x, :center_y,
- :name
+
+ # The coordinate system currently in use.
+ #
+ # @return [Symbol] `:bottom_left` or `:center`
+ attr_accessor :name
+
+ # Returns the "x" coordinate indicating the bottom of the screen.
+ #
+ # @return [Float]
+ attr_accessor :bottom
+
+ # Returns the "x" coordinate indicating the top of the screen.
+ #
+ # @return [Float]
+ attr_accessor :top
+
+ # Returns the "y" coordinate indicating the left of the screen.
+ #
+ # @return [Float]
+ attr_accessor :left
+
+ # Returns the "y" coordinate indicating the right of the screen.
+ #
+ # @return [Float]
+ attr_accessor :right
+
+ # Returns the "x" coordinate indicating the center of the screen.
+ #
+ # @return [Float]
+ attr_accessor :center_x
+
+ # Returns the "y" coordinate indicating the center of the screen.
+ #
+ # @return [Float]
+ attr_accessor :center_y
+
+ # Returns the bottom left and top right coordinates in a single list.
+ #
+ # @return [[Float, Float, Float, Float]]
+ attr_accessor :rect
+
+ # Returns the "x" coordinate of the origin.
+ #
+ # @return [Float]
+ attr_accessor :origin_x
+
+ # Returns the "y" coordinate of the origin.
+ #
+ # @return [Float]
+ attr_accessor :origin_y
+
+ attr_accessor :left_margin, :bottom_margin
def initialize ffi_draw
@ffi_draw = ffi_draw
origin_bottom_left!
end
+ # Returns `x` plus the origin "x".
+ #
+ # @return [Float]
def transform_x x
@origin_x + x
end
+ # Returns `x` minus the origin "x".
+ #
+ # @return [Float]
def untransform_x x
x - @origin_x
end
- def untransform_y y
+ # Returns `y` plus the origin "y".
+ #
+ # @return [Float]
+ def transform_y y
@origin_y + y * SCREEN_Y_DIRECTION
end
- def transform_y y
+ # Returns `y` minus the origin "y".
+ #
+ # @return [Float]
+ def untransform_y y
@origin_y + y * SCREEN_Y_DIRECTION
end
@@ -40,58 +101,86 @@ module GTK
@ffi_draw = value
end
+ # Sets the rendering coordinate system to have its origin in the bottom left.
+ #
+ # @return [void]
+ # @gtk
def origin_bottom_left!
return if @name == :bottom_left
@name = :bottom_left
@origin_x = 0.0
- @origin_y = GAME_HEIGHT
+ @origin_y = $gtk.logical_height
@left = 0.0
- @right = GAME_WIDTH
- @top = GAME_HEIGHT
+ @right = $gtk.logical_width
+ @top = $gtk.logical_height
@bottom = 0.0
- @center_x = GAME_WIDTH.half
- @center_y = GAME_HEIGHT.half
- @rect = [@left, @bottom, GAME_WIDTH, GAME_HEIGHT].rect
+ @left_margin = 0.0
+ @bottom_margin = 0.0
+ @center_x = $gtk.logical_width.half
+ @center_y = $gtk.logical_height.half
+ @rect = [@left, @bottom, $gtk.logical_width, $gtk.logical_height].rect
@center = [@center_x, @center_y].point
@ffi_draw.set_gtk_grid @origin_x, @origin_y, SCREEN_Y_DIRECTION
end
+ # Sets the rendering coordinate system to have its origin in the center.
+ #
+ # @return [void]
+ # @gtk
def origin_center!
return if @name == :center
@name = :center
- @origin_x = GAME_WIDTH.half
- @origin_y = GAME_HEIGHT.half
- @left = -GAME_WIDTH.half
- @right = GAME_WIDTH.half
- @top = GAME_HEIGHT.half
- @bottom = -GAME_HEIGHT.half
+ @origin_x = $gtk.logical_width.half
+ @origin_y = $gtk.logical_height.half
+ @left = -$gtk.logical_width.half
+ @right = $gtk.logical_width.half
+ @top = $gtk.logical_height.half
+ @bottom = -$gtk.logical_height.half
@center_x = 0.0
@center_y = 0.0
- @rect = [@left, @bottom, GAME_WIDTH, GAME_HEIGHT].rect
+ @rect = [@left, @bottom, $gtk.logical_width, $gtk.logical_height].rect
@center = [@center_x, @center_y].point
@ffi_draw.set_gtk_grid @origin_x, @origin_y, SCREEN_Y_DIRECTION
end
+ # The logical width used for rendering.
+ #
+ # @return [Float]
def w
- GAME_WIDTH
+ $gtk.logical_width
end
+ # Half the logical width used for rendering.
+ #
+ # @return [Float]
def w_half
w.half
end
+ # The logical height used for rendering.
+ #
+ # @return [Float]
def h
- GAME_HEIGHT
+ $gtk.logical_height
end
+ # Half the logical height used for rendering.
+ #
+ # @return [Float]
def h_half
h.half
end
+ # Returns the coordinates indicating the center of the screen.
+ #
+ # @return [[Float, Float]]
def center
@center
end
+ # Returns the coordinates indicating the bottom right of the screen.
+ #
+ # @return [[Float, Float]]
def bottom_right
[@right, @bottom].point
end
diff --git a/dragon/inputs.rb b/dragon/inputs.rb
index 9b8720a..bbf5305 100644
--- a/dragon/inputs.rb
+++ b/dragon/inputs.rb
@@ -4,9 +4,12 @@
# inputs.rb has been released under MIT (*only this file*).
module GTK
+ # Represents all the keys available on the keyboard.
+ # @gtk
class KeyboardKeys
include Serialize
+ # @gtk
attr_accessor :exclamation_point,
:zero, :one, :two, :three, :four,
:five, :six, :seven, :eight, :nine,
@@ -179,23 +182,27 @@ module GTK
@scrubbed_ivars = nil
end
+ # @gtk
def left_right
return -1 if self.left
return 1 if self.right
return 0
end
+ # @gtk
def up_down
return 1 if self.up
return -1 if self.down
return 0
end
+ # @gtk
def truthy_keys
get(all).find_all { |_, v| v }
.map { |k, _| k.to_sym }
end
+ # @gtk
def all? keys
values = get(keys.map { |k| k.without_ending_bang })
all_true = values.all? do |k, v|
@@ -211,6 +218,7 @@ module GTK
all_true
end
+ # @gtk
def any? keys
values = get(keys.map { |k| k.without_ending_bang })
any_true = values.any? do |k, v|
@@ -226,11 +234,13 @@ module GTK
any_true
end
+ # @gtk
def clear_key key
@scrubbed_ivars = nil
self.instance_variable_set("@#{key.without_ending_bang}", false)
end
+ # @gtk
def all
@scrubbed_ivars ||= self.instance_variables
.reject { |i| i == :@all || i == :@scrubbed_ivars }
@@ -239,6 +249,7 @@ module GTK
get(@scrubbed_ivars).map { |k, _| k }
end
+ # @gtk
def get collection
return [] if collection.length == 0
collection.map do |m|
@@ -252,6 +263,7 @@ module GTK
end
end
+ # @gtk
def set collection, value = true
return if collection.length == 0
@scrubbed_ivars = nil
@@ -305,8 +317,24 @@ S
end
module GTK
+ # @gtk
class Keyboard
- attr_accessor :key_up, :key_held, :key_down, :has_focus
+
+ # @return [KeyboardKeys]
+ # @gtk
+ attr_accessor :key_up
+
+ # @return [KeyboardKeys]
+ # @gtk
+ attr_accessor :key_held
+
+ # @return [KeyboardKeys]
+ # @gtk
+ attr_accessor :key_down
+
+ # @return [Boolean]
+ # @gtk
+ attr_accessor :has_focus
def initialize
@key_up = KeyboardKeys.new
@@ -319,22 +347,37 @@ module GTK
@key_down.p || @key_held.p
end
+ # The left arrow or "a" was pressed.
+ #
+ # @return [Boolean]
def left
@key_up.left || @key_held.left || a
end
+ # The right arrow or "d" was pressed.
+ #
+ # @return [Boolean]
def right
@key_up.right || @key_held.right || d
end
+ # The up arrow or "w" was pressed.
+ #
+ # @return [Boolean]
def up
@key_up.up || @key_held.up || w
end
+ # The down arrow or "s" was pressed.
+ #
+ # @return [Boolean]
def down
@key_up.down || @key_held.down || s
end
+ # Clear all current key presses.
+ #
+ # @return [void]
def clear
@key_up.clear
@key_held.clear
@@ -343,25 +386,19 @@ module GTK
def serialize
{
- key_up: @key_up.serialize,
- key_held: @key_held.serialize,
- key_down: @key_down.serialize,
- has_focus: @has_focus
+ key_up: @key_up.serialize,
+ key_held: @key_held.serialize,
+ key_down: @key_down.serialize,
+ has_focus: @has_focus
}
end
+ alias_method :inspect, :serialize
- def inspect
- serialize
- end
-
+ # @return [String]
def to_s
serialize.to_s
end
- def keys
- key
- end
-
def key
{
down: @key_down.truthy_keys,
@@ -370,128 +407,7 @@ module GTK
up: @key_up.truthy_keys,
}
end
-
- include DirectionalInputHelperMethods
- end
-end
-
-
-module GTK
- class ControllerKeys
- include Serialize
- attr_accessor :up, :down, :left, :right,
- :a, :b, :x, :y,
- :l1, :r1,
- :l2, :r2,
- :l3, :r3,
- :start, :select,
- :directional_up,
- :directional_down,
- :directional_left,
- :directional_right
- def clear
- @up = nil
- @down = nil
- @left = nil
- @right = nil
- @a = nil
- @b = nil
- @x = nil
- @y = nil
- @l1 = nil
- @r1 = nil
- @l2 = nil
- @r2 = nil
- @l3 = nil
- @r3 = nil
- @start = nil
- @select = nil
- @directional_up = nil
- @directional_down = nil
- @directional_left = nil
- @directional_right = nil
- end
-
- def truthy_keys
- [
- :up, :down, :left, :right,
- :a, :b, :x, :y,
- :l1, :r1, :l2, :r2, :l3, :r3,
- :start, :select,
- :directional_up, :directional_down, :directional_left, :directional_right,
- ].find_all { |attr| send(attr) }.to_a
- end
- end
-end
-
-module GTK
- class Controller
- attr_accessor :key_down, :key_up, :key_held, :left_right, :up_down,
- :left_analog_x_raw,
- :left_analog_y_raw,
- :left_analog_x_perc,
- :left_analog_y_perc,
- :right_analog_x_raw,
- :right_analog_y_raw,
- :right_analog_x_perc,
- :right_analog_y_perc
-
-
- def initialize
- @key_down = ControllerKeys.new
- @key_up = ControllerKeys.new
- @key_held = ControllerKeys.new
- @left_analog_x_raw = 0
- @left_analog_y_raw = 0
- @left_analog_x_perc = 0
- @left_analog_y_perc = 0
- @right_analog_x_raw = 0
- @right_analog_y_raw = 0
- @right_analog_x_perc = 0
- @right_analog_y_perc = 0
- end
-
- def left_right
- return -1 if self.left
- return 1 if self.right
- return 0
- end
-
- def up_down
- return 1 if self.up
- return -1 if self.down
- return 0
- end
-
- def serialize
- {
- key_down: @key_down.serialize,
- key_held: @key_held.serialize,
- key_up: @key_up.serialize
- }
- end
-
- def clear
- @key_down.clear
- @key_up.clear
- @key_held.clear
- end
-
- def up
- @key_up.up || @key_held.up
- end
-
- def down
- @key_up.down || @key_held.down
- end
-
- def left
- @key_up.left || @key_held.left
- end
-
- def right
- @key_up.right || @key_held.right
- end
+ alias_method :keys, :key
include DirectionalInputHelperMethods
end
@@ -501,6 +417,7 @@ module GTK
class MousePoint
include GTK::Geometry
+ # @gtk
attr_accessor :x, :y, :point, :created_at, :global_created_at
def initialize x, y
@@ -544,18 +461,45 @@ module GTK
end
end
+ # Provides access to the mouse.
+ #
+ # @gtk
class Mouse
- attr_accessor :click,
- :previous_click,
- :moved,
+
+ # @gtk
+ attr_accessor :moved,
:moved_at,
:global_moved_at,
- :x, :y, :up, :has_focus,
+ :up, :has_focus,
:button_bits, :button_left,
:button_middle, :button_right,
:button_x1, :button_x2,
:wheel
+ # The current click.
+ #
+ # @return [MousePoint]
+ # @gtk
+ attr_accessor :click
+
+ # The previous click.
+ #
+ # @return [MousePoint]
+ # @gtk
+ attr_accessor :previous_click
+
+ # The "x" coordinate.
+ #
+ # @return [Integer]
+ # @gtk
+ attr_accessor :x
+
+ # The "y" coordinate.
+ #
+ # @return [Integer]
+ # @gtk
+ attr_accessor :y
+
def initialize
@x = 0
@y = 0
@@ -569,9 +513,14 @@ module GTK
clear
end
+ # The "x" and "y" coordinate pair.
+ #
+ # @return [[Integer, Integer]]
+ # @gtk
def point
[@x, @y].point
end
+ alias_method :position, :point
def clear
if @click
@@ -586,18 +535,19 @@ module GTK
@wheel = nil
end
+ # @return [MousePoint]
+ # @gtk
def up
@up
end
+ # @return [MousePoint]
+ # @gtk
def down
@click
end
- def position
- [@x, @y]
- end
-
+ # @return [Hash]
def serialize
result = {}
@@ -615,12 +565,35 @@ module GTK
result
end
+
+ # @return [String]
+ def to_s
+ serialize.to_s
+ end
+ alias_method :inspect, :to_s
end
end
module GTK
+ # @gtk
class Inputs
- attr_accessor :controllers, :keyboard, :mouse, :text, :history
+
+ # A list of all controllers.
+ #
+ # @return [Controller[]]
+ # @gtk
+ attr_reader :controllers
+
+ # @return [Keyboard]
+ # @gtk
+ attr_reader :keyboard
+
+ # @return [Mouse]
+ # @gtk
+ attr_reader :mouse
+
+ # @gtk
+ attr_accessor :text, :history
def initialize
@controllers = [Controller.new, Controller.new]
@@ -654,44 +627,56 @@ module GTK
(controller_one && controller_one.directional_vector)
end
+ # Returns a signal indicating right (`1`), left (`-1`), or neither ('0').
+ #
+ # @return [Integer]
def left_right
return -1 if self.left
return 1 if self.right
return 0
end
+ # Returns a signal indicating up (`1`), down (`-1`), or neither ('0').
+ #
+ # @return [Integer]
def up_down
return 1 if self.up
return -1 if self.down
return 0
end
+ # Returns the coordinates of the last click.
+ #
+ # @return [Float, Float]
def click
return nil unless @mouse.click
return @mouse.click.point
end
+ # The first controller.
+ #
+ # @return [Controller]
def controller_one
- @controllers.value(0)
+ @controllers[0]
end
+ # The second controller.
+ #
+ # @return [Controller]
def controller_two
- @controllers.value(1)
+ @controllers[1]
end
+ # Clears all inputs.
+ #
+ # @return [void]
def clear
@mouse.clear
- @keyboard.key_down.clear
- @keyboard.key_up.clear
- @keyboard.key_held.clear
- @controllers[0].key_down.clear
- @controllers[0].key_up.clear
- @controllers[0].key_held.clear
- @controllers[1].key_down.clear
- @controllers[1].key_up.clear
- @controllers[1].key_held.clear
+ @keyboard.clear
+ @controllers.each(&:clear)
end
+ # @return [Hash]
def serialize
{
controller_one: controller_one.serialize,
diff --git a/dragon/keys.rb b/dragon/keys.rb
new file mode 100644
index 0000000..9f41fa2
--- /dev/null
+++ b/dragon/keys.rb
@@ -0,0 +1,51 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# controller/keys.rb has been released under MIT (*only this file*).
+
+module GTK
+ class Controller
+ class Keys
+ include Serialize
+
+ LABELS = [
+ :up, :down, :left, :right,
+ :a, :b, :x, :y,
+ :l1, :r1,
+ :l2, :r2,
+ :l3, :r3,
+ :start, :select,
+ :directional_up, :directional_down, :directional_left, :directional_right
+ ].freeze
+
+ LABELS.each do |label|
+ attr_reader label
+ end
+
+ # Activate a key.
+ #
+ # @return [void]
+ def activate key
+ instance_variable_set("@#{key}", Kernel.tick_count + 1)
+ end
+
+ # Deactivate a key.
+ #
+ # @return [void]
+ def deactivate key
+ instance_variable_set("@#{key}", nil)
+ end
+
+ # Clear all key inputs.
+ #
+ # @return [void]
+ def clear
+ LABELS.each { |label| deactivate(label) }
+ end
+
+ def truthy_keys
+ LABELS.select { |label| send(label) }
+ end
+ end
+ end
+end