Q: Linear Acceleration for Characters (Events and Player)

Started by Heretic86, July 04, 2013, 08:20:12 pm

Previous topic - Next topic

Heretic86

So after racking my brain, I've concluded Im a retard having forgotten everything I learned in high school about how to calculate Linear Acceleration.

First problem: RMXP doest use Linear Acceleration directly.  It uses Exponential Acceleration.  
IE: 2 to the power of @move_speed

Thus, in order to find a Delta (how much to change the speed each frame) one must first get the Velocity.  Simple enough, v1 = 2**@move_speed

Increase the Velocity by Delta

v1 += delta

Pretty easy so far.  Now, to convert that back into a number that XP uses, it has to be an Exponent.  Also fairly simple.  @move_speed = Math.log(v1)

Oh wait, this version of Ruby isnt using a Base 2 Logarithm.  It uses "Natural Logarithm" which is a base of 2.77, whatever the fuck that means.  Newer versions of Ruby do have log2 built in, but not in the current build that XP uses.

Well, alright, guess I'll have to plug in method for calculating a Base 2 Logarythm.

def logBase(n, x)
   return Math.log(x) / Math.log(n)
end


Great.  Now I can get a Log Base of 2 (because XP uses 2 to the power of @move_speed, and LogBase2 should tell us what Exponent 2 needs to be in order to result in X)

What I want to do:

def acceleration(new_speed)
 // Calculate Time and derive Delta with Time
 @acceleration_counter = time
end

alias accelerate_update_move update_move
def update_move
 if @acceleration_counter > 1
   @move_speed = logBaxe(2, 2**@move_speed + @delta)
   @acceleration_counter -= 1
 end
 # Call Original
 accelerate_update_move
end


(Note: Not real code, Im stuck figuring out Time and Delta)

Problem: I dont have a clue how to find Delta with the given information.  I know we have two speeds (using exponents), the current @move_speed, and the new one to be accelerated to.  Distance I am using 128 based on @real_x and @real_y.  Time I think should be half the difference of current speed and new speed, could be wrong on that too.  Hell, I dont even remember how to rearrange simple algebraic formulas to solve for any of this.

Any suggestions from you Math Jeaniuses?
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

KK20

You will have to choose the time yourself. There is no preset formula for calculating how long an object goes from speed A to B--that's your decision. As for your delta, because we are accelerating linearly, it's a matter of finding the difference between A and B and the time it should take to get from A to B.

If A = 4 and B = 5 and it should take 20 frames, then delta can be calculated as (5-4)/20. So each frame, the character's move speed is increasing by 1/20 or 0.05.

I think you should test this out on a sprite object instead of a character first. Like I told you previously, the way how characters move (i.e. the movement methods in Game_Character) rely on integer move_speed values and will probably need to be edited.

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Heretic86

I dont believe it can be an arbitrary number.  After doing some research, I came to the conclusion what I need to use is Kinematic Motion Equations.  Five possible variables.

V0 - Initial Velocity
Vf - Final Velocity
d - Displacement (a.k.a distance or delta distance)
a - acceleration
t - time

Lets see what we have so far.  Vo and Vf are easy.  2**@move_speed and 2**@target_speed, which gives us the REAL speed measured in Pixels per Frame.  Distance for each step is 32 pixels.  I may have to use 128 for @real_x and _y, not sure.

To solve, there are three possible equations.

#1:  Vf = V0 + at
#2:  V2 = Vf2 + 2a(df - d0)
#3:  df - d0 = V0t - ((at2) / 2)

So from those choices, I think we are supposed to pick one that has the variables that we can plug into it.

Looking at #1, we have Vf and Vo, but not a or t, so cant use that equation because it has two unknowns.  Next would be #2, we have the V's, D's and an a, so this should be able to be rearranged to solve for a.

Im pretty sure we need equation #2 to solve for a.

After that, we have a, so we can plug our values into equation #1 to solve for t.  Once I have t, I'll have to either round or ceil it so I have a whole number, then I can figure out how much to adjust the actual speed for each frame (linear), get a logarithm of that, and use that as the new speed.  Pain in the pooper, and probably why no acceleration scripts have been written yet.

Im stuck because I dont remember how to rearrage algebraic formulas.  I dont care about the code, hence why this is in General not Scripts.  I do need a hand rearranging #2 to solve for a and #1 to solve for t.

With me so far?
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

KK20

a = (V2 - Vf2) / 2(df - d0)
t = (Vf - V0) / a

which roughly translates to what I just said.

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Heretic86

Yep, doesnt work.  I plugged the numbers in and while some settings work, the next set of settings are just wonky.  When I do the math, it just makes a big frowny face.  I give up.  And I didnt know it wasnt possible to solve any kinematic equation without a or t.  That blows.
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

winkio

All of these equations work, I don't know what the problem is, but here you go:

you determine beforehand the following variables:
V0 - Initial Velocity
Vf - Final Velocity
d - Displacement (a.k.a distance or delta distance)

you use the equations to solve for these variables:
a - acceleration
t - time

Starting with these 3 equations from the earlier post:
#1:  Vf = V0 + at
#2:  V2 = Vf2 + 2a(df - d0)
#3:  df - d0 = V0t - ((at^2) / 2)

solve #1 for a:
a = (Vf - V0) / t

Substitute into #3
df - d0 = V0t - ((((Vf - V0) / t)t^2) / 2)
df - d0 = V0t - ((Vf - V0)t) / 2)
df - d0 = t(V0 - (Vf - V0)) / 2
2(df - d0) / (2V0 - Vf) = t
t = 2(df - d0) / (2V0 - Vf)

now we have an equation for t, we can go back and solve for a using:
a = (Vf - V0) / t
a = (Vf - V0) / (2(df - d0) / (2V0 - Vf))
a = (Vf - V0) * (2V0 - Vf) / (2(df - d0))

Heretic86

When I plugged in the numbers, what I got back was super screwy.  Like ending up with a total time of 1536.0 frames.  

I'll try some of these that you gave me a bit later...
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

KK20

You wouldn't happen to still be using real_x and real_y for your distances, would you?

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Heretic86

Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

KK20

Dividing 1536 by 128 gave me 12. I don't think you want to use real_x/y.

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Heretic86

I'll let you guys play with the weirdness for a while...

In a move route, run a script "accelerate(new_speed)", where the New Speed is different than the current speed.  New Speed is same thing as the current move speeds, well, thats my intention...

Spoiler: ShowHide
class Game_Character
  alias accelerate_initialize initialize
  def initialize
    # Call Original or other Alias
    accelerate_initialize
    # New Properties
    @accelerate_delta = nil
    @accelerate_speed = nil
    # Frame Counter
    @accelerate_counter = 0
  end
  #--------------------------------------------------------------------------
  # Defines Log Base 2 - Allows Logarithms of ANY Base, not just Natural 2.77
  #--------------------------------------------------------------------------
  def logBaseX(x, n=2)
    # NOTE: x must be a Positive number larger than 0 or this will
    # blow up and give a "Domain Error"
    return Math.log(x) / Math.log(n)
  end
  #--------------------------------------------------------------------------
  # - accelerate(new_speed)
  #--------------------------------------------------------------------------
  def accelerate(speed)
    # New Speed to Accelerate / Decelerate to on the Next Movement
    @accelerate_speed = speed
  end
  #--------------------------------------------------------------------------
  # * Update frame (move)
  #--------------------------------------------------------------------------
  alias accelerate_update_move update_move
  def update_move
    # If a Valid Acceleration is Set
    if @accelerate_speed and @accelerate_counter == 0
       @move_speed * 1.0 != @accelerate_speed * 1.0
      # Kinematic Motion Equations
      #
      # V = Vo + a*t
      # d = Vo * t + 1/2at^2
      # V^2 = Vo^2 + 2*a*d

      # Known Variables
      d = 128.0                           # Distance (even when moving diagonal)
      u = 2**@move_speed * 1.0            # Initial Velocity in Pixels per Frame
      v = 2**@accelerate_speed * 1.0      # Final Velocity in Pixels per Frame
      # Note: d may need to use d1**2 + d2**2 = d3**2 for Jumping

      # Solve for Time - t = 2(df - d0) / (2V0 - Vf)
      t = 2*d / (2*u - v)

      # Solve for Acceleration per Frame
      # a = (Vf - V0) * (2V0 - Vf) / (2(df - d0))
      a = ((v - u) * (2*u - v)) / (2*d)

      # Assign Values
      @accelerate_delta = a
      @accelerate_counter = t
     
      print "Time: ", t,
            "\nAcc:  ", a
    end
    if @accelerate_counter > 0
      # Calculate New Speed as an Exponent of 2 for RMXP Math
      @move_speed = logBaseX(2**@move_speed + @accelerate_delta)
      # Decrement Counter to 0
      @accelerate_counter -= 1
      # If Final Frame of Acceleration
      if @accelerate_counter == 0
        # This is needed to Cleanup leftovers like @move_speed = 4.000000001
        @move_speed = @target_speed
        @target_speed = nil
      end
    end
    # Call Original or other Alias
    accelerate_update_move
  end
end


(May have to move this topic to scripts...)
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

winkio

the acceleration is calculated in pixels/s^2.  If you are running this script each frame, then you will want to increase velocity by a/40, not a, because of the framerate of 40 fps.

Heretic86

Quote from: winkio on July 07, 2013, 03:10:18 am
the acceleration is calculated in pixels/s^2.  If you are running this script each frame, then you will want to increase velocity by a/40, not a, because of the framerate of 40 fps.


That, and in combination with the version of Ruby not supporting Base 2 Logarithms to convert any adjusted speed back into an exponent is partially think why a character acceleration script doesnt exist yet.

Numbers still arent quite working tho, after monkeying with both 1/Graphics.frame_rate, and setting d to not be 128 for real_x, _y...  For now, Im going to bed, and World War Z is NOT as graphic as Walking Dead.  Falling asleep due to popcorn gut.
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

KK20

I'll take a looks at it this week. Like I said, you really should try this with just basic sprites on a black background first.

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!