I am currently working with painting and displaying on a Cartesian coordinate system. In my game, I have fast moving objects, bullets, for which I use the following formula to determine position:
x += speed * Cos(theta);
y += speed * Sin(theta);
where theta is a radian measure and speed modifies the speed at the cost of overall continuity. [lim speed → ∞] then x and y = larger "jump" between the starting and next calculated x,y point.
I had to use this formula with a 'high speed' object, so instead of using a timer, which is limited to milisecond .001, I utilized a while loop:
while(true) {
if(currentTime - oldTime > setInterval) //x,y and intersection operations {
//operations
} if(currentTime - oldTime > setInterval) //paint operations {
//operations
}
sleep(0,nanoseconds);//sleeps thread or if you're a C kind of guy, "task"
}
I want x,y and intersection operations to happen at a much faster rate than the paint event, which I plan to have occur at 30-125 times a second (basically the hertage of a monitor).
Actual Questions:
What would be the most efficient rate for the x,y and intersection operations, so that they would perform at a rate consistent across different CPUs (from a dusty single core # 1.6 ghz to a fancy shmancy hex-core # 4.0 ghz)?
Is there a better angle position formula than mine for these operations?
*note my method of painting the object has nothing to do with my problems, in case you were wondering.
Have a timer fire every time the screen refreshes (60Hz?). In that time you calculate where the object is at this point in time. You draw the object at the determined location.
Whenever you want to find out where the object currently is, you run the physics simulation until time has caught up with the point in time you want to render. This way you get the object being animated in exactly the point in time it should be in.
Define the frequency at which the physics simulation runs. You can pick 60Hz as well or any integer multiple of it. Run the physics engine with the same time increment (which is 1/Frequency). When you want to render, find out how many physics ticks are missing and run them one by one.
This scheme is completely robust against missing or superfluous timer ticks. CPU clock rate does not matter either. The object is always rendered at the price position it should be in.
Related
I am currently programming the controller for a CNC machine, and therefore I need to get the amount of stepper motor steps in each direction when I get from point A to B.
For example point A's coordinates are x=0 and y=0 and B's coordinates are x=15 and y=3. So I have to go 15 steps on the x axis and 3 und the y axis.
But how do I get those two values mixed up in a way that is smooth (aka not first x and then y, this results in really ugly lines)?
In my example with x=15 and y=3 I want it arranged like that:
for 3 times do:
x:4 steps y:0 steps
x:1 steps y:1 step
But how can I get these numbers from an algorithm?
I hope you get what my problem is, thanks for your time,
Luca
there are 2 major issues in here:
trajectory
this can be handled by any interpolation/rasterization like:
DDA
Bresenham
the DDA is your best option as it can handle any number of dimensions easily and can be computed on both integer and floating arithmetics. Its also faster (was not true in the x386 days but nowadays CPU architecture changed all)
and even if you got just 2D machine the interpolation itself will be most likely multidimensional as you will probably add another stuff like: holding force, tool rpm, preasures for what ever, etc... That has to be interpolated along your line in the same way.
speed
This one is much much more complicated. You need to drive your motors smoothly from start position to the end concerning with these:
line start/end speeds so you can smoothly connect more lines together
top speed (dependent on the manufactoring process usually constant for each tool)
motor/mechanics resonance
motor speed limits: start/stop and top
When writing about speed I mean frequency [Hz] for the steps of the motor or physical speed of the tool [m/s] or [mm/2].
Linear interpolation is not good for this I am using cubics instead as they can be smoothly connected and provide good shape for the speed change. See:
How can i produce multi point linear interpolation?
The interpolation cubic (form of CATMUL ROM) is exactly what I use for tasks like this (and I derived it for this very purpose)
The main problem is the startup of the motor. You need to drive from 0 Hz to some frequency but usual stepping motor has resonance in the lower frequencies and as they can not be avoided for multidimensional machines you need to spend as small time in such frequencies as possible. There are also another means of handling this shifting resonance of kinematics by adding weights or change of shape, and adding inertial dampeners on the motors itself (rotary motors only)
So usual speed control for single start/stop line looks like this:
So you should have 2 cubics one per start up and one per stopping dividing your line into 2 joined ones. You have to do it so start and stop frequency is configurable ...
Now how to merge speed and time? I am using discrete non linear time for this:
Find start point (time) of each cycle in a sine wave
its the same process but instead of time there is angle. The frequency of sinwave is changing linearly so that part you need to change with the cubic. Also You have not a sinwave so instead of that use the resulting time as interpolation parameter for DDA ... or compare it with time of next step and if bigger or equal do step and compute the next one ...
Here another example of this technique:
how to control the speed of animation, using a Bezier curve?
This one actually does exactly what you should be doing ... interpolate DDA with Speed controled by cubic curve.
When done you need to build another layer on top of this which will configure the speeds for each line of trajectory so the result is as fast as possible and matching your machine speed limits and also matching tool speed if possible. This part is the most complicated one...
In order to show you what is ahead of you when I put all this together mine CNC interpolator has ~166KByte of pure C++ code not counting depending libs like vector math, dynamic lists, communication etc... The whole control code is ~2.2 MByte
If your controller can issue commands faster than the steppers can actually turn, you probably want to use some kind of event-driven timer-based system. You need to calculate when you trigger each of the motors so that the motion is distributed evenly on both axes.
The longer motion should be programmed as fast as it can go (that is, if the motor can do 100 steps per second, pulse it every 1/100th of a second) and the other motion at longer intervals.
Edit: the paragraph above assumes that you want to move the tool as fast as possible. This is not normally the case. Usually, the tool speed is given, so you need to calculate the speed along X and Y (and maybe also Z) axes separately from that. You also should know what tool travel distance corresponds to one step of the motor. So you can calculate the number of steps you need to do per time unit, and also duration of the entire movement, and thus time intervals between successive stepper pulses along each axis.
So you program your timer to fire after the smallest of the calculated time intervals, pulse the corresponding motor, program the timer for the next pulse, and so on.
This is a simplification because motors, like all physical objects, have inertia and need time to accelerate/decelerate. So you need to take this into account if you want to produce smooth movement. There are more considerations to be taken into account. But this is more about physics than programming. The programming model stays the same. You model your machine as a physical object that reacts to known stimuli (stepper pulses) in some known way. Your program calculates timings for stepper pulses from the model, and sits in an event loop, waiting for the next time event to occur.
Consider Bresenham's line drawing algorithm - he invented it for plotters many years ago. (Also DDA one)
In your case X/Y displacements have common divisor GCD=3 > 1, so steps should change evenly, but in general case they won't distributed so uniformly.
You should take the ratio between the distance on each of the coordinates, and then alternate between steps along the coordinate that has the longest distance with steps that do a single unit step on both coordinates.
Here is an implementation in JavaScript -- using only the simplest of its syntax:
function steps(a, b) {
const dx = Math.abs(b.x - a.x);
const dy = Math.abs(b.y - a.y);
const sx = Math.sign(b.x - a.x); // sign = -1, 0, or 1
const sy = Math.sign(b.y - a.y);
const longest = Math.max(dx, dy);
const shortest = Math.min(dx, dy);
const ratio = shortest / longest;
const series = [];
let longDone = 0;
let remainder = 0;
for (let shortStep = 0; shortStep < shortest; shortStep++) {
const steps = Math.ceil((0.5 - remainder) / ratio);
if (steps > 1) {
if (dy === longest) {
series.push( {x: 0, y: (steps-1)*sy} );
} else {
series.push( {x: (steps-1)*sx, y: 0} );
}
}
series.push( {x: sx, y: sy} );
longDone += steps;
remainder += steps*ratio-1;
}
if (longest > longDone) {
if (dy === longest) {
series.push( {x: 0, y: longest-longDone} );
} else {
series.push( {x: longest-longDone, y: 0} );
}
}
return series;
}
// Demo
console.log(steps({x: 0, y: 0}, {x: 3, y: 15}));
Note that the first segment is shorter than all the others, so that it is more symmetrical with how the sequence ends near the second point. If you don't like that, then replace the occurrence of 0.5 in the code with either 0 or 1.
I'm trying to set a slider (actually a kitchen timer) using a pan gesture in ionic2 see: http://ionicframework.com/docs/v2/components/#gestures
The slider/timer has an open upper-bound that could be set by a panright, but go down to zero on a panleft.
How can I best translate the pan event to be speed-sensitive to allow an upper bounds near 36000 but sensitive enough to set increments as small as 10? The max deltaX would be around 400px, but I suppose the user could use a few pan gestures to reach a large value.
Is there some ready-built easing function that I can use to achieve this?
Just thinking abstractly:
You could detect the magnitude between 2 consecutive pan events. If its small enough, then you can allow the smaller granularity of incrementation. On the other hand, if you decide its big enough, then you can allow for larger increments. In theory you can do this check continuously during the pan event(s), even affecting the upper-bound dynamically (though not sure why this is relevant).
I don't see why you need to worry about the upper bound in this case. Can you explainwhy?
Using Riron's comment, you can just multiply the velocityX by the deltaX. I saw in a quick test that the speed can easily get higher than 8 and lower than 1 (0.5 for example). The delta can be in the tens or in the hundreds so it allows for both required sensitivities.
Here's a code for that:
hammerObj.on("panright panleft",
function(ev){
if(ev.type == "panright"){
timer += ev.speedX * ev.deltaX;
//timer = Math.min(36000, ev.speedX*ev.deltaX+timer); for an upper bound of 36000 instead of unbound
} else if (ev.type == "panleft"){
timer = Math.max(0, timer - (ev.speedX * ev.deltaX));
}
}
Currently I'm using Math.cos and Math.sin to move objects in a circle in my game, however I suspect it's slow (didn't make proper tests yet though) after reading a bit about it.
Are there any ways to calculate this in a faster way?. Been reading that one alternative could be to have a sort of hash table with stored pre-calculated results, like old people used it in the old times before the computer age.
Any input is appreciated.
Expanding on my comment, if you don't have any angular acceleration (the angular velocity stays constant -- this is a requirement for the object to remain traveling in a circle with constant radius without changing the center-pointing force, e.g. via tension in a string), then you can use the following strategy:
1) Compute B = angular_velocity * time_step_size. This is how much angle change the object needs to go through in a single time step.
2) Compute sinb = sin(B) and cosb = cos(B).
3)
Note that we want to change the angle from A to A+B (the object is going counterclockwise). In this derivation, the center of the circle we're orbiting is given by the origin.
Since the radius of the circle is constant, we know r*sin(A+B) = y_new = r*sin(A)cos(B) + r*cos(A)sin(B) = y_old * cos(B) + x_old*sin(B) and r*cos(A+B) = x_new = r*cos(A)*cos(B) - r*sin(A)sin(B) = x_old*cos(B) - y_old*sin(B).
We've removed the cosine and sine of anything we don't already know, so the Cartesian coordinates can be written as
x_new = x_old*cosb - y_old*sinb
y_new = x_old*sinb + y_old*cosb
No more cos or sin calls except in an initialization step which is called once. Obviously, this won't save you anything if B keeps changing for whatever reason (either angular velocity or time step size changes).
You'll notice this is the same as multiplying the position vector by a fixed rotation matrix. You can translate by the circle center and translate back if you don't want to only consider circles with a center at the origin.
First Edit
As #user5428643 mentions, this method is numerically unstable over time due to drift in the radius. You can probably correct this by periodically renormalizing x and y (x_new = x_old * r_const / sqrt(x_old^2 + y_old^2) and similarly for y every few thousand steps -- if you implement this, save the factor r_const / sqrt(x_old^2 + y_old^2) since it is the same for both x and y). I'll think about it some more and edit this answer if I come up with a better fix.
Second Edit
Some more comments on the numerical drift over time:
I did a couple of tests in C++ and python. In C++ using single precision floats, there is sizable drift even after 1 million time steps when B = 0.1. I used a circle with radius 1. In double precision, I didn't notice any drift visually after 100 million steps, but checking the radius shows that it is contaminated in the lower few digits. Doing the renormalization on every step (which is unnecessary if you're just doing visualization) results in an approximately 4 times slower running time versus the drifty version. However, even this version is about 2-3 times faster than using sin and cos on every iteration. I used full optimization (-O3) in g++. In python (using the math package) I only got a speed up of 2 between the drifty and normalized versions, however the sin and cos version actually slots in between these two -- it's almost exactly halfway between these two in terms of run time. Renormalizing every once in a few thousand steps would still make this faster, but it's not nearly as big a difference as my C++ version would indicate.
I didn't do too much scientific testing to get the timings, just a few tests with 1 million to 1 billion steps in increments of 10.
Sorry, not enough rep to comment.
The answers by #neocpp and #oliveryas01 would both be perfectly correct without roundoff error.
The answer by #oliveryas01, just using sine and cosine directly, and precalculating and storing many values if necessary, will work fine.
However, #neocpp's answer, repeatedly rotating by small angles using a rotation matrix, is numerically unstable; over time, the roundoff error in the radius will tend to grow exponentially, so if you run your programme for a long time the objects will slowly move off the circle, spiralling either inwards or outwards.
You can see this mathematically with a little numerical analysis: at each stage, the squared radius is approximately multiplied by a number which is approximately constant and approximately equal to 1, but almost certainly not exactly equal to 1 due to inexactness of floating point representations.
If course, if you're using double precision numbers and only trying to achieve a simple visual effect, this error may not be large enough to matter to you.
I would stick with sine and cosine if I were you. They're the most efficient way to do what you're trying to do. If you really want maximum performance then you should generate an array of x and y values from the sine and cosine values, then plug that array's values into the circle's position. This way, you aren't running sine and cosine repeatedly, instead only for one cycle.
Another possibility completely avoiding the trig functions would be use a polar-coordinate model, where you set the distance and angle. For example, you could set the x coordinate to be the distance, and the rotation to be the angle, as in...
var gameBoardPin:Sprite = new Sprite();
var gameEntity:Sprite = new YourGameEntityHere();
gameBoardPin.addChild( gameEntity );
...and in your loop...
// move gameEntity relative to the center of gameBoardPin
gameEntity.x = circleRadius;
// rotate gameBoardPin from its center causes gameEntity to rotate at the circleRadius
gameBoardPin.rotation = desiredAngleForMovingObject
gameBoardPin's x,y coordinates would be set to the center of rotation for gameEntity. So, if you wanted the gameEntity to rotate with a 100 pixel tether around the center of the stage, you might...
gameBoardPin.x = stage.stageWidth / 2;
gameBoardPin.y = stage.stageHeight / 2;
gameEntity.x = 100;
...and then in the loop you might...
desiredAngleForMovingObject += 2;
gameBoardPin.rotation = desiredAngleForMovingObject
With this method you're using degrees instead of radians.
Say like it took a whole second for a character to jump in a game, how would a game developer go about keeping that jump time to 1 second if the FPS is either 10fps, 30fps, 100fps etc? - If you get me, how would you stop a game's fps affecting the gameplay speed basically.
I presume there's a certain method of doing this, so I was wondering what exactly it is?
Thankssss,
Alex!
Normally by using a timer to record how much time has passed since the last frame was rendered. There are many articles and samples on the subject available via Google:
Achieving Frame Rate Independent Game Movement
Constant game speed independent of variable FPS in OpenGL with GLUT?
Fixed time step vs Variable time step
Fix Your Timestep!
Of course if your FPS is allowed to be anything then you will end up with unrealistic simulations. For this reason there is the concept of a "fixed time step".
The "Fix Your Timestep!" (and the previous articles linked on that page) in particular is a good read on this subject.
Short answer of a large subject
I guess your game should place "animation" not determine by its frame sequences number but by the time delay from a reference...
1)example : 1 second jump with only 3 drawing ... should be considere draw#1 a t0 draw#2 if between t+0.25 and t+0.75 and draw#3 if between t+0.75 and t+1
2) example : if your move/animation is determined by a formula like positionX(int RelativeFrameNumber) your should consider change your fonction by using time like positionX(long relativeTimeInMillisecond)
or with small change in your gameloop
3) place a "wait" code in your loop that is calibrate depending a continuously/fixed computed framerate performance
Hope that help
Many physics engines pass around a delta time in an update() method of some kind.
void update(float dt)
This delta value represents the current frame step proportional to a fixed frame rate (say, 60fps). For example, if dt is 1.0, then we're at 60fps, if dt is 2.0, then we're 30fps and if dt is 0.5 then we are at 120fps.. etc..
To move (in your case, jump) a character at the same speed for any frame rate, multiply dt by the object's velocity vector to keep the character jumping at the same speed.
void update(float dt)
{
myChar.Vel += myChar.Direction.Normalized() * myChar.Speed * dt;
//myChar.Speed is in meters per second
}
Note: Different calculation is required for quadratic physics.
Say I want to animate a ball rolling 1000 pixels to the right, specifying a timing function in the process – something like this:
UIView *ball = [[UIView alloc] initWithFrame:CGRectMake(0,0,30,30)];
CABasicAnimation* anim =
[CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
anim.toValue = [NSNumber numberWithFloat:ball.frame.origin.x + 1000.0];
// move 1000 pixels to the right
anim.duration = 10.0;
anim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:
0.1 :0.0 :0.3 :1.0]; // accelerate fast, decelerate slowly
[ball.layer addAnimation:anim forKey:#"myMoveRightAnim"];
What I ultimately want is to have a method, say -(void)animationProgressCallback:(float)progress, be called during the animation, in regular intervals of the animation's progress in terms of the absolute "distance" between start and end values, i.e. ignoring the timing function.
I'll try to explain with the above example with the ball rolling 1000px to the right (charted by the y axis, in our case 100%=1000px):
I want my callback method to be invoked whenever the ball has progressed 250 pixels. Because of the timing function, the first 250 pixels might be reached in ti0=2 seconds, half the total distance reached just ti1= 0.7 seconds later (fast acceleration kicks in), the 750px mark another ti2= 1.1 seconds later, and needing the remaining ti3= 5.2 seconds to reach the 100% (1000px) mark.
What would be great, but isn't provided:
If the animation called a delegate method in animation-progress intervals as described, I wouldn't need to ask this question… ;-)
Ideas how to solve the problem:
One solution I can think of is to calculate the bezier curve's values, map that to the tik values (we know the total animation duration), and when the animation is started, we sequentially perform our animationProgresssCallback: selector with those delays manually.
Obviously, this is insane (calculating bezier curves manually??) and, more importantly, unreliable (we can't rely on the animation thread and the main thread to be in sync – or can we?).
Any ideas??
Looking forward to your ideas!
Ideas how to solve the problem:
One solution I can think of is to
calculate the bezier curve's values,
map that to the tik values (we know
the total animation duration), and
when the animation is started, we
sequentially perform our
animationProgresssCallback: selector
with those delays manually.
Obviously, this is insane (calculating
bezier curves manually??) and, more
importantly, unreliable (we can't rely
on the animation thread and the main
thread to be in sync – or can we?).
Actually this is reliable. CoreAnimation is time based, so you could use the delegate to be notified when the animation really starts.
And about calculating the bezier path... well look it this way: It could be worse if you would want to implement a surface in OpenGLES you would have to calculate a Cubic Bezier!. lol. Your case is only one dimension, is not that hard if you know the maths.