module AdventureRL module Modifiers module Velocity DEFAULT_VELOCITY_SETTINGS = Settings.new( # Does NOT use Deltatime max_velocity: { x: 100, y: 100 }, # DOES use Deltatime velocity_decay: { x: 750, y: 750 }, # Does NOT use Deltatime base_velocity: { x: 0, y: 0 }, quick_turn_around: false ) def initialize settings = {} @settings = DEFAULT_VELOCITY_SETTINGS.merge settings @velocity = { x: 0.0, y: 0.0 } @max_velocity_original = @settings.get :max_velocity @max_velocity = @max_velocity_original.dup @velocity_decay = @settings.get :velocity_decay @velocity_quick_turn_around = @settings.get :quick_turn_around @base_velocity = @settings.get :base_velocity @velocity_deltatime = Deltatime.new @has_increased_velocity_for = { x: false, y: false } super @settings end # Returns the velocity. # Pass an optional target argument, # which can be either an axis (:x or :y), # or :all, which will return a Hash with both values. def get_velocity target = :all target = target.to_sym return @velocity if (target == :all) return @velocity[target] if (@velocity.keys.include?(target)) return nil end # Returns the max velocity. # Pass an optional target argument, # which can be either an axis (:x or :y), # or :all, which will return a Hash with both values. def get_max_velocity target = :all target = target.to_sym return @max_velocity if (target == :all) return @max_velocity[target] if (@max_velocity.keys.include?(target)) return nil end def set_velocity *args new_velocity = parse_position *args @velocity[:x] = new_velocity[:x] if (new_velocity.key? :x) @velocity[:y] = new_velocity[:y] if (new_velocity.key? :y) end # Increase the velocity. # args may be: # Two integers, representing the x and y axes, respectively. # A hash containing one or both of the keys :x and :y. def increase_velocity_by *args opts = {} opts = args.last if (args.last.is_a? Hash) quick_turn_around = @velocity_quick_turn_around quick_turn_around = opts[:quick_turn_around] unless (opts[:quick_turn_around].nil?) incremental_velocity = parse_position *args @velocity.keys.each do |axis| next unless (incremental_velocity.key? axis) velocity_sign = @velocity[axis].sign incremental_velocity_sign = incremental_velocity[axis].sign @velocity[axis] = 0 unless (velocity_sign == incremental_velocity_sign) if (quick_turn_around && !opts[:no_quick_turn_around]) @velocity[axis] = @base_velocity[axis] * incremental_velocity_sign if (@velocity[axis] == 0) @velocity[axis] += incremental_velocity[axis] case velocity_sign when 1 @velocity[axis] = get_max_velocity(axis) if (@velocity[axis] > get_max_velocity(axis)) when -1 @velocity[axis] = -get_max_velocity(axis) if (@velocity[axis] < -get_max_velocity(axis)) end @has_increased_velocity_for[axis] = true end end alias_method :add_velocity, :increase_velocity_by def set_max_velocity *args new_max_velocity = parse_position *args @max_velocity_original.keys.each do |axis| @max_velocity_original[axis] = new_max_velocity[axis] if (new_max_velocity.key? axis) end @max_velocity = @max_velocity_original.dup end def set_temporary_max_velocity *args new_max_velocity = parse_position *args @max_velocity.keys.each do |axis| @max_velocity[axis] = new_max_velocity[axis] if (new_max_velocity.key? axis) end end # Resets the max velocity to the original values. def reset_max_velocity @max_velocity = @max_velocity_original.dup end # Call this every frame to move with the stored velocity. def move move_by get_incremental_position_for_velocity if (any_velocity?) decrease_velocity @has_increased_velocity_for = { x: false, y: false } @velocity_deltatime.update end private # Returns true if there is any stored velocity, # for any axis. def any_velocity? return @velocity.values.any? do |velocity| next velocity != 0 end end def get_incremental_position_for_velocity return get_velocity.map do |axis, speed| next [axis, speed * @velocity_deltatime.dt] end .to_h end # Decrease the velocity, based on the decay rate # and deltatime. def decrease_velocity return unless (any_velocity?) @velocity.keys.each do |axis| next if (@velocity[axis] == 0 || @has_increased_velocity_for[axis]) case @velocity[axis].sign when 1 @velocity[axis] -= @velocity_decay[axis] * @velocity_deltatime.dt @velocity[axis] = 0 if (@velocity[axis] < 0) when -1 @velocity[axis] += @velocity_decay[axis] * @velocity_deltatime.dt @velocity[axis] = 0 if (@velocity[axis] > 0) end end end end end end