I'd like to deflect a ball at an angle depending on where it hits a paddle. Right now, I'm only changing the y coordinate, which results in an uninteresting deflection. It will angle but independent on impact location against the paddle. I'd like something more fun. Speed, momentum, mass and other factors don't need to be taken into consideration. Just angle depending on impact location of paddle. I've read this Not a number error (NAN) doing collision detection in an iphone app but it seems overly complicated for what I'm looking for. Is there a simpler way to calculate the deflection?
The objects are two UIImageViews.
Well, nothing realistic but you could do something so that the outbound angle is only dependent on where on the paddle it hits.
I have never done any iPhone or objective C coding so I'll just write up something in pseudo/C code.
First I'd calculate the speed, which is the length of the speed vector, or:
double speed = sqrt(velX * velX + velY * velY); // trigonometry, a^2 + o^2 = h^2
Then we want to calculate the new angle based on where we hit the paddle. I'm going to assume that you store the X collision in impactX and the length of the paddle in paddleLength. That way we can calculate an outbound angle. First let's figure out how to calculate the range so that we get a value between -1 and 1.
double proportionOfPaddle = impactX / (double) paddleLength; // between 0 and 1
double impactRange = proportionOfPaddle * 2 - 1; // adjust to -1 and 1
Let's assume that we do not want to deflect the ball completely to the side, or 90 degrees, since that would be pretty hard to recover from. Since I'm going to use the impactRange as the new velY, I'm going to scale it down to say -0.9 to 0.9.
impactRange = impactRange * 0.9;
Now we need to calculate the velX so that the speed is constant.
double newVelX = impactRange;
double newVelY = sqrt(speed * speed - newVelX * newVelX); // trigonometry again
Now you return the newVelX and newVelY and you have an impact and speed dependent bounce.
Good luck!
(Might very well be bugs in here, and I might have inverted the X or Y, but I hope you get the general idea).
EDIT: Adding some thoughts about getting the impactX.
Let's assume you have the ball.center.x and the paddle.center.x (don't know what you call it, but let's assume that paddle.center.x will give us the center of the paddle) we should be able to calculate the impactRange from that.
We also need the ball radius (I'll assume ball.width as the diameter) and the paddle size (paddle.width?).
int ballPaddleDiff = paddle.center.x - ball.center.x;
int totalRange = paddle.width + ball.width;
The smallest value for ballPaddleDiff would be when the ball is just touching the side of the paddle. That ballPaddleDiff would then be paddle.width/2 + ball.width/2. So, the new impactRange would therefore be
double impactRange = ballPaddleDiff / (double) totalRange / 2;
You should probably check the impactRange so that it actually is between -1 and 1 so that the ball doesn't shoot off into the stars or something.
You don't necessarily want realistic, you want fun. Those aren't always one and the same. If you wanted realistic, you can't throw out speed, momentum, mass, etc. In a normal game of ping pong, the point where it hits the paddle doesn't really matter, theres not a sweet spot like on a tennis racket.
Develop a mathematical function that will return an output vector, or a velocity and a unit vector, representing the output angle and velocity of the ball, givin an input angle, velocity, impact point on the paddle, and velocity of the paddle.
We expect already that the output angle = -1 * input angle. Output velocity also would be expected to be -1 * the input velocity. So if you want to mix it up, adjust those. You could increase the output angle proportional to the distance from the center of the paddle. You could also increase the angle or the speed proportional to the velocity of the paddle when its hit.
There's a lot of ways you could do that, so I can't really tell you exactly what function you would use, you're going to have to figure that out with testing and playing. If you still need more info add more specifics to your question.
The following code (C++ but easy enough to convert to ObjC), takes an incoming 2D vector and reflects it based on a surface normal (the face of your pong bat).
You could add some random 'fun factor' by randomizing an offset that you'd either apply to 'scalar' - to change velocity, or to the surface normal, to alter the reflection angle.
I'm using this in my iPhone project, and it works fine :)
void vec2ReflectScalar(vec2& vResult, const vec2& v1, const vec2& normal, float scalar)
{
vec2 _2ndotvn;
float dotVal = vec2DotProduct(v1, normal);
vec2Scale(_2ndotvn, normal, scalar * 2.f * dotVal);
vec2Subtract(vResult, v1, _2ndotvn);
}
void vec2Reflect(vec2& vResult, const vec2& v1, const vec2& normal)
{
vec2ReflectScalar(vResult, v1, normal, 1.f);
}
Related
I'm looking to display coordinates on a map. The coordinates are at a relatively fine resolution (3 decimal places), but I need to anonymise and aggregate them to a coarser resolution.
All the approaches I've seen run the risk of the coarse coordinates being the same as, or very close to, the original coordinates, since they rely on rounding or adding random noise to the original.
For example, with rounding:
53.401, -2.899 -> 53.4, -2.9 # less than 100m
With adding 'noise', e.g.:
lat = 53.456
// 'fuzz' in range -0.1 to 0.1
rnd = (Math.random() * 2 - 1) * 0.1
newLat = lat + (Math.random() * 2 - 1) * 0.1
However if rnd is close to 0, then the coordinates don't 'move' much.
Is there a (simple) way to 'move' a coordinate in a random way a certain (minimum) distance from it's original location?
I've looked at other answers here but they don't seem to solve this issue of the new coordinates overlapping with the original coordinates:
Rounding Lat and Long to Show Approximate Location in Google Maps
Is there any easy way to make GPS coordinates coarse?
To add random noise, you could displace every point by a fixed distance in a random direction. On a flat projection, for a radius r:
angle = Math.random() * 2 * PI
newLat = lat + (r * sin(angle))
newLon = lon + (r * cos(angle))
That would guarantee a fixed displacement (r) for every point, in an unpredictable direction.
Alternatively, you could anonymise by joining to a polygon at a coarser grain, and then plot the data by the polygon rather than the points. It could be as simple as a grid on a flat projection. Or something more sophisticated such as the Australian Statistical Geography Standard which offers multiple choices, the most granular being a "mesh block" which they guarantee to always contain 30-60 dwellings.
All the approaches I've seen run the risk of the coarse coordinates
being the same as, or very close to, the original coordinates, since
they rely on rounding or adding random noise to the original.
Could you explain, what's the risk that you are concerned about here? Yes, the coarse coordinate might happen to be the same, but it is still anonymized - whoever sees the coarse data would not know if it is coincidentally close or not. All they know is that the actual location is within some distance R_max from the coarse location.
Re the other solution,
displace every point by a fixed distance in a random direction
I would say it is much worse: here it would be easy to discover the fixed displacement distance by knowing just a single original location. Then, for any "coarse" location, we would know the original is on thin unfilled circle centered on the "coarse" location - much worse than the filled circle or rectangle in the original solution.
At the very least, I would use random radius, maybe don't allow it to be zero, if you are concerned about coincidental collision (but you should not be). E.g. this varies the radius from r_max / 2 to r_max:
r = (Math.random() + 1) * r_max / 2;
and then you can use this random radius with Schepo's solution.
I have a camera (main view, projection). I create it here:
-(void)setupProjection
{
// Generate a perspective matrix with a 60 degree FOV
float aspect = self.frame.size.width / self.frame.size.height;
ksMatrixLoadIdentity(&_projectionMatrix);
ksPerspective(&_projectionMatrix, 60.0, aspect, 0.01f, 50.0f);
ksTranslate(&_projectionMatrix, 0.0, -0.295, 0.0);
// Defaul value
mFloatScale = 0.5;
// Load projection matrix
glUniformMatrix4fv(_projectionSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
}
Also I have gesture recognizer. So I want when my user move finger he will rotate camera like in first person shooters games. How can I update my projection matrix? I think I must create something like lookAt function.
Either use a method to generate the lookAt matrix or create your own. It is an easy equation found on web.
Once you have this what I suggest is you store 3 vectors representing your camera as position, forward, up. These will be inserted into the lookAt method (center = position+forward).
Now at this point you may implement quite a few variations of camera movement. The omni situation would be to create an additional vector right which is a cross product of forward and up. Then:
Turn left/right: forward += right*someRotationSpeedFactor
Turn up/down: forward += up*someRotationSpeedFactor
Tilt left/right: up += right*someRotationSpeedFactor
Move forward/backwards: position += forward*someSpeedFactor
Move up/down: position += up*someSpeedFactor
Move sideways: position += right*someSpeedFactor
Changing the direction means negative factor. The factors are usually received from either the user input (the distance of two touch events) or current speed. After using any of these equations you need to renormalize the changed vectors for forward and up (divide them by their distance). Also you need to recompute the effected vector forward or up if any by again using a cross product. For instance if you turn up you will change the forward vector but the up vector is effected by it as well. That means you need to set the up vector as a cross product of forward and right vectors. It sounds confusing in theory but in practice it looks something like this:
- (void)turnUp:(CGFloat)scale {
vector forward = self.forward;
vector up = self.up;
vector right = cross(self.forward, self.up);
self.forward = normalized(forward + up*scale);
self.up = cross(self.forward, right);
}
Now this procedure is quite good for something like piloting a space craft or a jet for instance. But the first person shooters are usually a bit more restricted as the up vector must always face upwards your display. The tilt is then not implemented and in some games you have a restriction as to maximum upwards angle. This is due to the math issue in this case. Anyway in general if you simply leave the up vector unchanged you should do fine but you might need to normalize the right vector after computing it as it will not have a length of 1 anymore.
I'm trying to move multiple sprites (images) in an elliptical path such that distance (arc distance) remains uniform.
I have tried
Move each sprite angle by angle, however the problem with this is that distance moved while moving unit angle around major axis is different than that while moving unit angle around minor axis - hence different distance moved.
Move sprites with just changing x-axis uniformly, however it again moves more around major axis.
So any ideas how to move sprites uniformly without them catching-up/overlapping each other?
Other info:
it will be called in onMouseMove/onTouchMoved so i guess it shouldn't
be much CPU intensive.
Although its a general algorithm question but
if it helps I'm using cocos2d-x
So this is what i ended up doing (which solved it for me):
I moved it in equation of circle and increased angle by 1 degree. Calculated x and y using sin/cos(angle) * radius. And to make it into an ellipse I multiplied it by a factor.
Factor was yIntercept/xIntercept.
so it looked like this in end
FACTOR = Y_INTERCEPT / X_INTERCEPT;
//calculate previous angle
angle = atan((prev_y/FACTOR)/prev_x);
//increase angle by 1 degree (make sure its not radians in your case)
angle++;
//new x and y
x = cos(newangle) * X_INTERCEPT;
y = sin(newangle) * X_INTERCEPT * FACTOR;
I have written a function named getPointOnEllipse that allows you to move your sprites pixel-by-pixel in an elliptical path. The function determines the coordinates of a particular point in the elliptical path, given the coordinates of the center of the ellipse, the lengths of the semi-major axis and the semi-minor axis, and finally the offset of the point into the elliptical path, all in pixels.
Note: To be honest, unfortunately, the getPointOnEllipse function skips (does not detect) a few of the points in the elliptical path. As a result, the arc distance is not exactly uniform. Sometimes it is one pixel, and sometimes two pixels, but not three or more! In spite of the fault, changes in speed will be really "faint", and IMO, your sprites will move pretty smoothly.
Below is the getPointOnEllipse function, along with another function named getEllipsePerimeter, which is used to determine an ellipse's perimeter through Euler's formula. The code is written in JScript.
function getEllipsePerimeter(rx, ry)
{
with (Math)
{
// You'll need to floor the return value to obtain the ellipse perimeter in pixels.
return PI * sqrt(2 * (rx * rx + ry * ry));
}
}
function getPointOnEllipse(cx, cy, rx, ry, d)
{
with (Math)
{
// Note: theta expresses an angle in radians!
var theta = d * sqrt(2 / (rx * rx + ry * ry));
//var theta = 2 * PI * d / getEllipsePerimeter(rx, ry);
return {x:floor(cx + cos(theta) * rx),
y:floor(cy - sin(theta) * ry)};
}
}
The following figure illustrates the parameters of this function:
cx - the x-coordinate of the center of the ellipse
cy - the y-coordinate of the center of the ellipse
rx - the length of semi-major axis
ry - the length of semi-minor axis
d - the offset of the point into the elliptical path (i.e. the arc length from the vertex to the point)
The unit of all parameters is pixel.
The function returns an object containing the x- and y-coordinate of the point of interest, which is represented by a purple ball in the figure.
d is the most important parameter of the getPointOnEllipse function. You should call this function multiple times. In the first call, set d to 0, and then place the sprite at the point returned, which causes the sprite to be positioned on the vertex. Then wait a short period (e.g. 50 milliseconds), and call the function again, setting d parameter to 1. This time, by placing the sprite at the point returned, it moves 1 pixel forward in the ellipse path. Then repeat doing so (wait a short period, call the function with increased d value, and position the sprite) until the value of d reaches the perimeter of the ellipse. You can also increase d value by more than one, so that the sprite moves more pixels forward in each step, resulting in faster movement.
Moreover, you can modify the getEllipsePerimeter function in the code to use a more precise formula (like Ramanujan's formula) for getting ellipse perimeter. But in that case, be sure to modify the getPointOnEllipse function as well to use the second version of theta variable (which is commented in the code). Note that the first version of theta is just a simplified form of the second version for the sake of optimization.
Alright, so I'm trying to create my own Physics engine for a 3D XNA game, and I'm having troubles calculating how much I should move my object by for gravity.
XNA's game timer occurs every 16 milliseconds, so after some calculations, and using 9.81m/s as my gravitational velocity, you can see that you should increase the velocity of the object that has gravity by:
0.15696 meters/16milliseconds
- basically every update call should increase the object by 0.15696 meters
The questions is, how do I convert 0.15696 meters into pixels. Obviously if I just use a 1:1 relationship the object will only move 9.81 pixels/second. Which does not really simulate gravity :P Does anyone have a good idea on how I can determine how many pixels I should move the object by?
Thanks for all the help!
Although 2d game dev is more pixel-centric, 3d game dev doesn't concern itself with pixels for this kind of stuff, but rather units. Unit size is completely arbitrary.
Typically, you have a velocity vector whose magnitude is equivalent to the meters(or feet or ??) per second that your object is going. That way the position is updated each frame by adding this velocity * the elapsed time since last frame (the 16.6666 ms). The acceleration from gravity is added to the velocity vector in the same way:
Vector3 gravity = Vector3.Down * 9.81f;
//in the update loop
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;//0.01666667 (or 16.67 ms) # 60FPS
velocity += gravity * elapsed;
position += velocity * elapsed;
In this example, I've arbitrarily established that 1 xna unit == 1 meter.
You just have to figure out how large an "area" your screen represents; then its simple scaling. If you have a 2D representation of a satellite orbiting earth, then your "Y" pixels represent ground to satellite (approximately 35,000 meters).
Use your equations from classical physics (http://en.wikipedia.org/wiki/List_of_equations_in_classical_mechanics), and then just scale real dimensions to your screen.
Ive created a small tank-shooter-minigame, and is currently working on cpu control of other tanks.
A cpu tank knows the following:
Its own facing, the direction its facing
Its own position (X and Y)
Its targets position (X and Y)
On top of that ive made it so that positive y is downwards instead of upwards. positive x direction is left to right.
How do i calculate the shortest way the cpu tank need to rotate to point on its target?
Lets say tank is at (3,3), facing 90 degrees (straight left) and Im at (4,7). What would the calucations be?
I'm not sure there isn't an easier way to do this, I tend to revert to 3d vector math often, even if in 2d trigonometric solutions are better suited. Your question implies you are working in 2d, but the 3d math will still work. Hopefully, someone will come up with an easier algorithm for you, but if not, here is something.
I assume you mean the shortest way in an angular measurement. In this code, the result will be a positive angular value if the shortest way is CCW, negative if CW.
Vector2 targetPosition = new Vector2(3, 3);
Vector2 myPosition = new Vector2(4, 7);
Vector2 myFacingDirection2D = new Vector2(-1, 0);//facing straight left
Vector3 directionToTarget3D = Vector3.Normalize(new Vector3(targetPosition - myPosition, 0));
Vector3 myFacingDirection3D = Vector3.Normalize(new Vector3(myFacingDir2D, 0);
Vector3 crossResult = Vector3.Cross(myFacingDirection3D, directionToTarget3d);
float dotFactor = Vector3.Dot(myFacingDirection3D, directionToTarget3D) < 0 ? MathHelper.Pi : 0f;
float angleToTarget = (dotFactor - (float)Math.Sin(crossResult.Length()) ) * Math.Sign(crossResult.Z);
If this turns out backwards (positive/negative wise) then reverse the order of the params in the Cross function.