Log In  

Hey guys thought I would post this here as I think the answer will help other too:)
Basically I want to make a function that approaches any number in as big chunks as possible. Like this:

Speed = approach (target number, amount to move by)
So speed = approach(0, 0.5)
If speed was 0.4 before I want it to hit 0 and not -0.1

So if speed was a higher number like 7 every frame till it hits the target 0 it would take 0.5

Really useful for making velocity and stuff feel good :)
Any help very much appreciated :)

P#23417 2016-06-21 19:14 ( Edited 2016-07-21 23:13)

:: mrh

If I'm understanding what you want correctly

FUNCTION APPROACH(TARGET, AMOUNT)
IF TARGET>SPEED THEN
RETURN MAX(TARGET, SPEED-AMOUNT)
ELSE
RETURN MIN(TARGET, SPEED+AMOUNT)
END
END

P#23418 2016-06-21 19:28 ( Edited 2016-06-21 23:28)
:: matt

Can you not use mid()?

function _init()
  -- initial values
  MINIMUM = 0
  DELTA = 0.5
  MAXIMUM = 7
  SPEED = MAXIMUM
end

function _update() 
    SPEED = approach(MINIMUM, DELTA)
end

function approach(t,d)
  return mid(t, SPEED-d, MAXIMUM)
end

Only two of the three arguments are used for decreasing speed.
The third would impose a maximum speed limit if required.

P#23419 2016-06-21 20:27 ( Edited 2016-06-22 17:24)
:: Felice

Nice use of MID(). Must remember that.

Edit: Although, now that I look at it, I think you solved a different problem. You're using MID() to clamp a value to a range, and he wants to take a range and direct it towards a target value. Still a spiffy usage of MID(), though.

P#23421 2016-06-21 21:13 ( Edited 2016-06-22 01:22)
:: matt

I've clarified my code to show that if speed is in a loop it would do what he wants?

If not, then I'm not clear and will need more coffee.

P#23428 2016-06-22 05:18 ( Edited 2016-06-22 09:27)

Hey thank you so much for the responses! Matt your function works perfectly when your trying to hit 0 but I've been trying to work out how to make it hit other numbers too, could a similar method be used to include any numbers for example speed = 7 target = 15.2? and also with negatives like speed =-5 target = 2?

I also realized it makes a lot more sense to have the variable represented in the function so you could do this with any numbers so thinking of changing it to:

speed = approach(variable in this case speed,target,max amount to move by)

p.s I didn't know about the MID() function but really smart way to use it :D

P#23433 2016-06-22 07:09 ( Edited 2016-06-22 11:09)
:: matt

mid() just picks the middle value of the three that you pass to it.

i'm not sure it's aligned with that you are doing, is it possible you can post some sample code or a work in progress cart?

@mrh's long form code is probably more what you want, mine was just a nice shortcut for your first use case but may not be suitable for other cases/values.

P#23439 2016-06-22 13:31 ( Edited 2016-06-22 17:31)

Hey thank you for taking the time with this :)

So here is a quick example, I have some code that resembles this:

function _init()
px = 64 py = 64--player x and y
end

function _draw()
cls()
spr(001,px,py)
    if (btn(0)) then hspeed = -1 end
    if (btn(1)) then hspeed = 1 end
    if (btn(0)==false and btn(1)==false) then hspeed = 0 end
    px+=hspeed
end

Now what I want is something like this:

function _init()
px = 64 py = 64
amount_to_jump_by = 0.3
end

function _draw()
cls()
spr(001,px,py)
    if (btn(0)) then hspeed = -1 end
    if (btn(1)) then hspeed = 1 end
    if (btn(0)==false and btn(1)==false) then hspeed = 0 end

    playerhspeed = approach(playerhspeed,hspeed,amount_to_jump_by)
    px+=playerspeed
end

So those last 2 lines have changes with the goal of having a characters whose speed is gradual rather than clunky. So if you let go of left and right the hspeed changes to 0 but the players speed will decrease per frame to give the impression of sliding to a stop. And the same for changing direction mid run they will slide and switch more akin to real life motion :)
I was trying to make the function as broad as possible so I can use it for negative and positive numbers and for vertical speed and stuff too but not sure how realistic that is?

I hope that is better explained but let me know if it is not clear :)

P#23492 2016-06-23 11:50 ( Edited 2016-06-23 15:50)
:: matt

the way I do it in Pico Pang is much simpler.

I go for a very subtle slide to a stop, but it's there.

this way, I do not actually care about the values of how much the thing moves each frame.
i just want it to slow down by 20% (or go 80% as fast) per frame.

this code works, make sure there's a sprite in slot zero.

try changing:
player.momentum
player.minimum
player.speed

try to add:
ability to change player.dx gradually when change of direction happens.

function _init()
  -- lower value for momentum means quicker slide to stop
  -- player properties
  player = {spr=0, x=64,y=64, dx=0, speed=2, momentum=0.8, minimum=0.5}
end

function _update()
  -- player delta slowly decreases
  player.dx = player.dx * player.momentum

  -- clamp to zero if it's within half a pixel
  if (abs(player.dx) < player.minimum) player.dx = 0

  -- override player delta with player speed if keys are bring pressed
  if (btn(0)) player.dx = -player.speed
  if (btn(1)) player.dx = player.speed

  -- change player x position by delta
  player.x = player.x + player.dx
end

function _draw()
  cls()
  spr(0, player.x,player.y)
end
P#23502 2016-06-23 15:47 ( Edited 2016-06-23 20:05)
:: Felice

There's a subtlety in directional movement handling that probably doesn't matter much to most people, but I'll mention it in case it's interesting.

Consider this code:

   if (btn(0)) player.dx = -player.speed
   if (btn(1)) player.dx = player.speed

If your player is someone playing with a keyboard, where left and right are independent buttons that can be pressed simultaneously, there's a chance that a hurried direction-change can result in both buttons being pressed for a few frames. If that happens a lot, this code produces a bias towards rightward movement, since that's the last condition that's checked.

TL;DR: If I have left and right cursor keys pressed at the same time, I will move right.

Something like this eliminates the problem:

   local l = btn(0) and player.speed or 0
   local r = btn(1) and player.speed or 0
   if (l+r > 0) player.dx = r - l

Note that holding both keys cancels existing velocity, since it's assumed that the player is in the process of switching directions.

The other thing you can do is to prioritize the direction opposite the one being traveled, such that holding down right and then pressing both left+right while switching to the left will immediately switch to left, rather than halting movement during the transition. That's a little more involved and left as an exercise to the reader. :)

P#23506 2016-06-23 17:09 ( Edited 2016-06-23 21:10)
:: matt

Oh, nice spot! I'm all about the details, so thanks for that.

P#23508 2016-06-23 18:27 ( Edited 2016-06-23 22:27)

Thank you guys this is all good stuff, ended up using the 80% trick really handy thank you :)

P#23611 2016-06-25 10:33 ( Edited 2016-06-25 14:33)

Hey guys I was just digging through the Celeste cart and I found this!

function appr(val,target,amount)
return val > target
and max(val - amount, target)
or min(val + amount, target)
end

P#25690 2016-07-21 16:10 ( Edited 2016-07-21 20:10)
:: matt

Very close to mrh original solution.

Did you try using it?

P#25693 2016-07-21 19:13 ( Edited 2016-07-21 23:13)

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2020-08-05 12:47 | 0.021s | 2097k | Q:39