I'm trying to figureout how to create parabola/bezier-curve/quadratic (i.e. grenade lobbing) movement based on the player's velocity dx/dy. I'm familiar how to do this for a player's speed, and the cart shows the setup for speed as a functioning baseline. In the cart I defined a player who can move around with the arrow keys. When they hit x they bunny style hop moving to the right using the quad() function. The system freezes the movement of the player while the hop completes, so its always the same movement pattern.
Speed relies on absolute movement and coordinates...with quad() the player will start somewhere defined p0...move along a curve defined by point p1 and endup at p2. The cart math is based on augmenting the x/y player values directly. Velocity is different though, and I can't figureout how to make the same example work for the dx/dy in the cart.
My intent is to make a bunny hop according to the direction of movement defined by dx/dy. So if the player is moving and they press x, the player movement freezes for a time, and the current values of dx/dy will judge the direction and magnitude of movement to be completed according to some general curve outline (bunny hop). And since I'm now dealing with velocity vectors, for this system to allow me to apply other forces onto the movement like gravity etc which should affect the bunny hop movement dynamically rather than scripted like in the cart. Without the quadratic part the effect can be achieved with just straightup multipliers dx*=1.1 (i.e. velocity increases if I press x for a time)..but that's not what I want.
Velocity+quadratics....how to? Would appreciate help with the math here or something to get me started. If there are some search terms of articles to link to, that's good too. I'm having a hard time finding the information online, could use better keywords. I found it hard to create the quad() function to begin with cause I was relying on quadratics tutorials when what I wanted was bezier curves...so I'm hoping I'm just missing a keyword like in that case.
I'm not sure why you're using a bezier curve for this, rather than setting a jump strength, a time for the hop to take, and a gravity for the hop (like in most platformers). However, if you really want to use that quad() function, I would recommend just setting p0 to to the current position, p2 to the position at (x + t * dx, y + t * dy)
where t is how long you want the bunny hop to last, and p1 to a spot halfway between p0 and p2 plus a vector perpendicular to (dx, dy)
with magnitude inversely proportional to (t * dx, t * dy)
.
So from that I have:
x0=self.x; y0=self.y x1=x0+20 +self.dy; y1=y0-20 +self.dx*(-1) x2=self.x+self.t*self.dx; y2=self.y+self.t*self.dy |
For p1:
A vector perpendicular to (dx,dy) is (dy,-dx) or (dy,dx). I don't get what u mean by 'with magnitude inversely proportional to
(t dx, t dy)'.
The magnitude of the vector is mag= sqrt( y^2+(-x)^2 ) inverse is 1/mag. So (1/t)*(dy,-dx)? I don't know what you mean by this, can you elaborate or write some of it out?
The method below gives me the desired look of the jump and uses the velocity for movement, but what I'm looking for is a setup where I have the same control as I would with the bezier function in the OP (choosing general points). Maybe I wanted 4 or 5+ bezier points to my jump (doing spirals in the air)...the bezier function enables that. Below doesn't though, its just me randomly choosing a dy* dx+ until things look right.
if not init then x0=self.x; y0=self.y --initial init=true end self.t+=1/16 if self.t<=.4 then self.dy-=1.2; self.dx*=1.7 --random velocity values method else self.dy+=.6; self.dx*=1.4 if self.y>=y0 then self.y=y0 self.dy=0 self.jump=false self.t=0 init=nil end end |
I guess I'm just confused as to what you're trying to accomplish. From the cart, it looks like the circle is just jumping to the right a bit. Are you trying to figure out a specific curve that looks like a jump but varies depending on velocity, or are you trying to ensure that the circle keeps the same velocity while moving through the curve? Depending on exactly how the starting values are supposed to relate to the curve, there's a huge number of possibilities. Your cart doesn't really help clarify those relations either, as the jump in the cart appears to be the circle dodging with a sudden change in direction.
What I suggested earlier was for getting a curve shape that looks like the one in your cart but with the final distance from the starting point being based on velocity and the time the jump takes always being the same, since that's what it sounded like. Also, since you're including both x and y movement, I assumed you meant a jump that doesn't need to be directly to the left or right. In that case, p0 would be the starting point, p2 would be the end point, and p1 would be what determines the shape. If that is what you're looking for, then x0,y0,x2, and y2 should be calculated first, with x2 being x0 + self.dx * tt
where tt is the total absolute time the jump should take, then y1 would be (y0 + y2)/2 + c * self.dx * 1/tt
where c is just whatever number causes the system of curves to look good (with the option of c being negative if you want the curve to go the other direction). x1 could then be calculated the same way. If you want the time the jump takes to be based on velocity, then this wouldn't apply at all. Also, if you do want the jump to always be directly left or right, then I'm not sure what role the starting dy would have. In that case x1 would instead be (x0 + x2)/2
as the y portion of the vector wouldn't be relevant to the movement in the x axis, while y1 could either be the same formula as above or (y0 + y2)/2 + c * self.dx * 1/tt + self.dy * tt * c2
where c2 is another variable to configure exactly what system of curves you want.
If what you want is the speed that the circle goes through the curve to be the same as the current velocity, then there's several very different ways to accomplish that, each based on what other consequences you want the velocity to have.
I just want a bezier curve like below to move the player using its dx/dy values instead of applying absolute x/y positioning. Cause in the cart its using the below, but if I had a force applying like gravity or the player hitting another player or a high velocity on the player leading into the function, the effects of those forces wouldn't do anything...it would just complete the curve exactly the same regardless like its doing in the cart shown. And yes I'm aware the player arrow keys are intentionally locked when the player jumps (x)...cause contrary to most games you can't move back/forwards/up/down when ur in a midair jump.
The player moves via velocity...but the function moves via speed...I want the function to work via velocity values so other velocity values affect it. These aren't mario controls...this is more like mario's default jump following a bezier curve of any number of points, with the intent being its dynamically affected by other possible forces like the wind. The last code snippet achieved this, but the system isn't like below, there isn't a clear method like quad() provides, I was just randomly inserting values..setting a timer at the peak and then setting more random values. It wouldn't be viable to redo this across 8 points, but I can easily expand quad() to 8 points cause its method is clear. I don't understand the math of the last snippet enough to make it into 'quad() for velocity'...nor what to research to figure it out.
function quad(p0,p1,p2,t) --t from 0->1 x=p0.x*(1-(t))^2+2*(t)*p1.x*(1-(t))+p2.x*(t)^2 y=p0.y*(1-(t))^2+2*(t)*p1.y*(1-(t))+p2.y*(t)^2 return x,y end |
If I'm understanding correctly, the meaning of "speed" that you're using is slightly different than I expected. The code in the cart controls the rate at which the circle goes through the path by setting how the t parameter relates to the updates. However, that's speed in terms of curves traversed per time unit. Velocity is specifically the distance in a particular direction traveled per time unit, and as such I thought you meant "speed" as in the magnitude of a velocity vector (as in, the distance traveled without regard to direction).
The relevant math here is conceptually simple. "Velocity" in the form you're looking at (dx and dy) is the rate of change in position. Getting it exactly would be hard and require complicated math, but wouldn't really make sense anyway, since you're working with discreet time intervals rather than smooth movement. As such, the linear approximation of "slope", difference in position divided by difference in time, is good enough. Conveniently, since the velocity would need to be in frames anyway, the difference can be assumed to be 1.
Try using the quad() function twice. The first time, put in the value for t of the previous update. The second time, put in the value for t of the current update. Then, subtract the first result from the second result. That should give you the velocity.
Note: When I do player.x+=1 the tutorials I learnt from taught me to refer to this as speed. Velocity follows as being speed/time etc...and its setup like in the codes posted to date.
Okay so doing that gives me this. Which is sort of what I want. The outstanding issues are:
- Is there a more effective way to rewrite para_init()? mbe based on dx/dy?
Basically the player's jump direction is based on the last button presses...dx/dy shud also contain this data. - I wanted more slide at the end of the jump. So imagine this is a topdown style game. Player jumps and lands on the same level. In the code from my last post this was achieved (straightup multipliers on dx/dy), here though its sort of there, but not really..if I crank friction down I see more slide, but its too little per player movement (player goes flying).
Is there a way to modify the existing or do I have to add in another point to the bezier curve or some kind of multiplier at the end?
3.The rest jump is sort of weird looking as it drags. If its a topdown style game I want them to land where they started without dragging midair. The only solution I can think of is to take it out of the quad() function and just do its own thing for that instance...or just leave it cause I'd rather have cleaner code and its no big.
--arrow keys move x to jump
If you want to use dx and dy for the angle, then look at the function atan2() in the manual. The documentation even calls the parameters "dx" and "dy". I haven't used it much though, so I don't know if the angle it returns would need adjusting.
For getting more slide, I don't see any problem with just using the multipliers. You have a spot in the code that handles the end of the jump, so you could just apply the multipliers there.
For getting the rest just to linger less, you could detect that when incrementing self.t and do a slightly different expression in that case. This isn't the best formula for it, but after self.t+=1/32
try adding this:
self.t+=(x0==x2 and y0==y2 and self.t >= .4 and self.t <= .6) and 1/32 or 0
That would partially (though in a clunky way) compensate for the appearance of slowing down increasing the circle's progress through the curve only when the jump is straight up and the portion of the curve is the center fifth.
[Please log in to post a comment]