RMXP - Need some help in moving with acceleration/deceleration

Started by azdesign, May 31, 2013, 04:37:24 am

Previous topic - Next topic

azdesign

Guys, I need some help with acceleration/deceleration script. I made some extension for sprite class to enable it perform various animations such as moving to various direction, darken, lighten, fading, shaking, etc. The script below is just a simplification of the actual script and not tested yet, I'm sorry if I made some errors; The actual script works fine however. I want to modify the linear moving animation with some acceleration/deceleration capabilities but I can't figure out how, I'm suck at math and physics.
FPS = 40
class Animated < Sprite
attr_accessor :in_animation
@in_animation = false

def initialize
#assign some picture for this class
end

def move(distance,duration) #distance = distance to travel in pixels ; #duration = time for travel distance in seconds
#declaration of variables which I think necessary for acceleration/deceleration
@distance_total = distance
@distance_covered = 0
@distance_remaining = @distance_total
@time_total = FPS * duration
@time_spent = 0 #in frames
@time_remaining = @time_total #in frames
@current_speed = 0
@last_speed = 0
@speed_type = 'constant';
@in_animation = true
end

def animate()
#calculate how many pixel to move in a frame
@current_speed = @distance_total/@time_total

#move the thing to left (
$yeah.x -= current_speed

#set some variables
@distance_covered += @current_speed
@time_spent += 1

#ends the animation if the object has reach the destination
if @distance_covered >= @distance_total && @time_spent >= @time_total
@in_animation = false
end
end
end

Now, in the game loop's update function :
if $yeah.in_animation == true
$yeah.animate()
end

Lets start, interact an event with these script :
   
$yeah = Animated.new
$yeah.move(100,1)
   
After that, the picture is moving to left for 100 pixels in 1 second, in the actual script, this works fine. But that's it, linear movement.

The question is how to turns the linear movement into dynamic movement with below scenario
1. After moving for 60% of frames in constant speed, movement start to decelerate slowly (speed dropping from frame to frame) until it stops upon reaching final destination
2. Decelerating must not have any impact to total time and total distance

Any help will be appreciated!  :D thx before.
~ Check out my deviantart http://my-az-design.deviantart.com/ ~

KK20

First Problem: ShowHide
QuoteDecelerating must not have any impact to total time and total distance

That does not make any logical sense according to the way you have it set now:
@current_speed = @distance_total/@time_total

This says that, at @current_speed, you should cover the distance @distance_total in time @time_total. This assumes that no changes in speed are made, making @current_speed constant.
Quote
Assume each dash represents a pixel. X is the current position of sprite after 1 frame.

Task: Reach from start to end in 5 frames.

How it is right now:
Start ---X---X---X---X---X End (5 frames)

What you want:
Start ---X---X---X--X--X-X End (6 frames) --> It is impossible to decelerate and still be within 5 frames.

Thus, what you want to do is make the sprite move faster at start.
@current_speed = (@distance_total/@time_total)*1.5

Quote
Start -----X----X---X--X-X End (5 frames)

The question I propose to you now is "What is the distance traveled after 60% of the total frames required?"

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!

azdesign

What I wrote was the linear equation (zero-acceleration) one. The equation must be changed in order to meet the scenario given. In form of v-t graph, there will be a straight line which indicates the linear movement and then the line dropping after 60% of frame until finally stops. The function in the program should only takes 2 parameter, the distance and time. Which based on that, the only thing that we know is :
1. The combination of distance traveled by both movement is 100 pixels
2. The time needed for both movement to reach 100 pixels in 1 second (40 frame), which is 24 frames for the linear movement, and 16 frames for the deceleration
3. There is no limit of what is the velocity and acceleration is
The question you asked me is what I'm looking for, I hope the above explanation can explain what I really meant.

I was asking around some sites for this (the scenario is a bit different though) :
http://math.stackexchange.com/questions/407786/motion-with-acceleration-and-deceleration
http://stackoverflow.com/questions/16856675/movement-animation-involving-acceleration-decceleration

Now I'll just try to digest those equations they give me and transform them into form of ruby code. :)
:facepalm: I regret underestimating physic and math class when I'm in school.
~ Check out my deviantart http://my-az-design.deviantart.com/ ~

KK20

I'm not asking hypothetically. I'm asking you "How do you want it?" Basically, if you can tell me how far something should move in 60% of the frames required, I can write an equation easy (side-note, distance traveled in these first 60% of frames should be at least 60% of distance traveled--otherwise, your sprite will need to accelerate at some point to cover the rest of the distance in deceleration-mode). I also need to know how severe of a deceleration you want (even, steady slow down (red line); screeching-halt at the final second (green line); or major drop-off at the start and move at a crawl near the end (blue line)).
Spoiler: ShowHide



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!

azdesign

Hmm, Okay, here is what I wanted :
1st phase : constant speed, duration = 60% of time, distance to travel = 70%
2nd phase : decelerating using green curve you mentioned above, duration = 40% of time, distance to travel = 30%
:D
~ Check out my deviantart http://my-az-design.deviantart.com/ ~

KK20

I think spent too much time working on this

class AnimSprite < Sprite
 attr_accessor :stop
 
 # Sprite is just a red pixel. Used for testing purposes.
 def initialize(viewport)
   super
   self.bitmap = Bitmap.new(1,1)
   self.bitmap.set_pixel(0,0,Color.new(255,0,0))
   self.x, self.y = 10, 300
 end
 
 def move(distance, frames)
   # This is where the pixel should be after finished moving; used for corrections
   @final_x = self.x + distance
   # Keeps track of what frame the graphic is on
   @frame = 0
   
   # Distance needed to be covered at constant speed
   @distance_start = distance * 0.7
   # Leftover distance to decelerate
   @distance_end = distance - @distance_start
   
   # Frame when deceleration should occur
   @begin_end_frame = frames * 0.6
   # Remaining frames to cover rest of distance during deceleration
   @remaining_frames = frames - @begin_end_frame
   
   # Constant speed at start (first 60% of the frames in 70% of the distance)
   @speed_start = @distance_start / @begin_end_frame.to_f
   # Used for calculating deceleration
   @amp = (0.3 * distance) / ((0.4 * frames) ** 2)
   
   # Because doing self.x += decimal_number always returns an integer, which would
   # be bad if moving less than 1 space each frame. Thus, this variable was made.
   @theoretical_x = self.x.to_f
   
   # When done moving, set to true
   @stop = false
 end
 
 def calc_move
   # Determines how far the sprite should move during deceleration
   x0 = @amp * (((@frame - @begin_end_frame - 1) - (@remaining_frames)) ** 2)
   x1 = @amp * (((@frame - @begin_end_frame) - (@remaining_frames)) ** 2)
   return x0 - x1
 end
 
 # ===== Main Update Method =====
 def run
   @frame += 1
   # Continue moving at constant speed?
   if @frame < @begin_end_frame
     @theoretical_x += @speed_start
   else # Decelerating
     @theoretical_x += calc_move
   end
   # Move the sprite
   self.x = @theoretical_x.to_i
   # Finished moving
   @stop = true if @frame == @begin_end_frame + @remaining_frames
   # Make sure the sprite moves the correct number of pixels. Calculations may
   # have rounding error so this is quite essential.
   if self.x > @final_x
     self.x = @final_x
   end
   if @stop and self.x < @final_x
     self.x = @final_x
   end
 end

end


#================
# Test Program
#================
begin
 @vp = Viewport.new(0,0,640,480)
 @pix = AnimSprite.new(@vp)
 Graphics.update
 p "Begin run"
 @pix.move(100,80) # Input values here: (distance, frames)
 while !@pix.stop
   @vp.update
   @pix.run
   Graphics.update
 end
 p "End"
 exit
end

I probably could have cleaned this up a bit and removed some variables, now that I am looking at it again...

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!

azdesign

Thank you very much! it worked, now I'll clean it up a bit and insert it into my script.  :haha: :haha: :haha: Thank you really!
~ Check out my deviantart http://my-az-design.deviantart.com/ ~