I have two CGPoints A and B. Distance between A and B can be found with ccpDistance(A,B).
With this information, I need to find programmatically CGPoint(x,y) of X by adding small distance into distance of A-B. A-B may can make a connecting line in horizontal, vertical, diagonal or any orientation. Purpose is to extend the imaginary line and find a point at the end of it.
Is it possible in Box2D for iOS? If Yes, then how?
X Y X
/ . \
/ . \
B .B
/ \
/ \
/ \
/ \
A A
Use the following function (put it in one of your .h files):
static inline CGPoint
ccpLineExtend(const CGPoint v1, const CGPoint v2, const CGFloat extension)
{
double angle = atan2(v2.y - v1.y, v2.x - v1.x);
return ccp(v2.x + extension * cos(angle), v2.y + extension * sin(angle));
}
I suggest the following method which doesn't make use of any triangular function. I suppose it's faster than Lukman's suggestion but I didn't measure times.
static inline CGPoint ccpLineExtend(const CGPoint from, const CGPoint to, const CGFloat factor)
{
return CGPointMake(from.x + factor * (to.x - from.x), from.y + factor * (to.y - from.y));
}
factor = 1.0 means that the resulting point is equal to point to. factor = 2.0 means that the resulting point is as twice as far from from as to is.
#Lars's answer was best and simplest for me. Here is the Swift 4 version:
let newPoint = CGPoint(x: origin.x + factor * (end.x - origin.x), y: origin.y + factor * (end.y - origin.y))
If you have the current distance, you can add and subtract from it or change it altogether by calculating:
let factor = newDistance/currentDistance
In my case, I had a distance calculator from CGPoint to CGPoint using an extension:
extension CGPoint {
func distance(to point: CGPoint) -> CGFloat {
let x = self.x - point.x
let y = self.y - point.y
return sqrt(pow(x, 2) + pow(y, 2))
}
}
Related
Some help would be most appreciated. Sprite movement based upon a heading that is given from a touch on the screen. Sprite moves as expected but I am unable to vary the speed, no matter what value I use for currentSpeed. This is in the update method of the sprite. Thanks in advance.
// Distance between two points (Distance formula, Pythagorean Theorem c^2=a^2+b^2, so d=sqrt((x2-x1)^2+(y2-y1)^2)
// Duration (time = distance / rate)
CGPoint adjustedPosition;
adjustedPosition.x = position_.x - sinf(heading);
adjustedPosition.y = position_.y - cosf(heading);
float distance = CGPointDistanceBetweenTwoPoints(adjustedPosition, position_);
float duration = distance / currentSpeed;
position_ = adjustedPosition;
[self runAction:[CCMoveTo actionWithDuration:duration position:position_]];
dont use a moveto or for that matter any action in an update method. Instead, compute the position , something like this:
-(void) update:(ccTime) dt {
// _velocity in points per second.
// heading should be in ccw notation, 0 on x axis, RHS
float deltaX = dt * _velocity * cosf(heading);
float deltaY = dt * _velocity * sinf(heading);
CGPoint adjustedPosition = ccpAdd(self.position, ccp(deltaX,deltaY));
self.position = adjustedPosition;
}
or something similar. This will ease out any variance id dt, for which the only thing you can bet on is that it wont be constant ; but the physics should be right.
Try this for distance:
float distance = ccpLength(ccpSub(adjustedPosition, position_));
Essentially I'm trying to calculate the bisector line between two points. I've got two methods, one works the other doesn't. I can't quite figure out why the other one doesn't work. The one that works is a little more computationally intensive and since this routine is run a lot, I'd like to use the simpler one... except it doesn't work. I'm probably missing something simple but I find this amusing since I seem to have a better grasp of trig than I do of high school algebra.
Note: the function is passed the end points (endPoint1, endPoint2).
Here's the one that works (using trig to calculate the bisector):
CGPoint midPoint = CGPointMake((endPoint1.x + endPoint2.x) / 2, (endPoint1.y + endPoint2.y) / 2);
//Normalize an end point
CGPoint nPoint = CGPointMake(endPoint1.x - endPoint2.x, endPoint1.y - endPoint2.y);
//Find theta and rotate 90°
CGFloat theta = atanf(nPoint.y / nPoint.x);
if (nPoint.x < 0.0f) theta += M_PI;
else if (nPoint.x > 0.0f && nPoint.y < 0.0f) theta += (M_PI * 2);
theta += M_PI_2;
//Calculate another point along new theta and de-normalize the point
CGPoint centerPoint = CGPointMake(cosf(theta) * 10, sinf(theta) * 10);
centerPoint.x += midPoint.x;
centerPoint.y += midPoint.y;
//Create the line definition
LineDef def = LineDefForPoints(midPoint, centerPoint);
Here's the one that doesn't, but I'd like it to:
CGPoint midPoint = CGPointMake((endPoint1.x + endPoint2.x) / 2, (endPoint1.y + endPoint2.y) / 2);
//Calculate the slope and invert
CGFloat m = (endPoint1.y - endPoint2.y) / (endPoint1.x - endPoint2.x);
//Take the negative reciprocal
m = -1/m;
//Calculate another point on the line
CGPoint centerPoint = CGPointMake(midPoint.x + 10, midPoint.y + (m * 10));
//Create the line definition
LineDef def = LineDefForPoints(midPoint, centerPoint);
So I'd swear this should work. The change in Y is equal to m times the change in x. I've calculated the mid point, figured out the slope of the perpendicular line and calculated another point on that line. However the line definitions created aren't equivalent when given the same end points, so I'm missing something.
By the way, LindeDef is a simple struct with three CGFloat variables for the a, b & c components of a straight line. And creating a LineDef from two points is trivial (I happen to be using a block to do this):
LineDef (^LineDefForPoints)(CGPoint, CGPoint) = ^LineDef(CGPoint p1, CGPoint p2){
LineDef line = {0,0,0};
line.a = p2.y - p1.y;
line.b = p1.x - p2.x;
line.c = line.a*p1.x + line.b*p1.y;
return line;
};
Slope-intercept form is fragile for this; use vectors.
〈V〉 = B - A
midpoint = 〈V〉/2 + A
⟂〈V〉 = 〈Vy, -Vx〉
Dammit, it was something simple. I reformatted my actual production code so I could put it on Stack Exchange and in the process edited out my mistake. The code I posted in the question actually works perfectly. Originally the line: m = -1 / m; was folded into the original assignment like so: CGFloat m = -1 / (endPoint1.y - endPoint2.y) / (endPoint1.x - endPoint2.x);. Of course, now the problem is obvious...I forgot parenthesis. I separated the line into two in stack exchange so I could explain my 'reasoning' in the comments, hoping to find the problem.
Sorry, for all the trouble.
I have a grid of images, like a 2D tile set. This method is supposed to give me the image from the tile set when I just give the the tile index.
Can anyone see where my math is screwed up? Currently this function just gives me n and n.(random decimal) for the x and y.
- (CGImageRef)tileFromTileset:(int)gid {
CGImageRef tile;
CGPoint point;
CGFloat fGid = (CGFloat)gid;
point.x = fmodf(fGid, tileSource.size.width);
point.y = (fGid - (fmod(fGid, tileSource.size.width)) / (tileSource.size.width) + 1);
NSLog(#"%#", NSStringFromCGPoint(point));
tile = CGImageCreateWithImageInRect([tileSource CGImage], CGRectMake(point.x, point.y, kTileWidth, kTileHeight));
return tile;
}
I think you have a simple error of units. At the moment, you're dividing a number representing an index by a number representing a coordinate; the unit that you end up with is therefore "index per coordinate".* What you want, though, is just coordinate units.
The assignment to point.x should therefore be:
point.x = fmodf(fGid * kTileWidth, tileSource.size.width);
That is, the tile index (units: "index"), multiplied by the width of one tile (units: "coordinates per index"), gives you its location if this were a single row of tiles (units: "coordinates"). Taking the remainder after dividing by the actual width of a row of tiles gives you the correct x coordinate.
For point.y, you need the quotient of the same calculation:
point.y = trunc(fGid * kTileWidth / tileSouce.size.width) * kTileHeight;
The index, multiplied by the width of a tile, divided by the width of a row, tells you how many rows are completed at that index; multiply by the height of a tile to get the coordinate.
This might be even clearer with one more constant, kNumTilesInRow:
point.x = (gid % kNumTilesInRow) * kTileWidth;
point.y = (gid / kNumTilesInRow) * kTileHeight;
*You keep getting n back because, for abs(n) < abs(m), n % m always equals n.
I think you need to move a parenthesis.
Assuming a 3 x 3 layout as follows:
1 2 3
4 5 6
7 8 9
And you call this passing a 7, here's what I see:
- (CGImageRef)tileFromTileset:(int)gid { // 7
CGImageRef tile;
CGPoint point;
CGFloat fGid = (CGFloat)gid; // 7
point.x = fmodf(fGid, tileSource.size.width); // x= 7 % 3, so x=1
// y= (7 - 1 / 3 + 1), so y= 7.6666666
point.y = (fGid - (fmod(fGid, tileSource.size.width)) / (tileSource.size.width) + 1);
// Try this instead of the above
// y = ((7 - 1) / 3 + 1), so y=3
// point.y = ((fGid - fmod(fGid, tileSource.size.width)) / (tileSource.size.width) + 1);
NSLog(#"%#", NSStringFromCGPoint(point));
tile = CGImageCreateWithImageInRect([tileSource CGImage], CGRectMake(point.x, point.y, kTileWidth, kTileHeight));
return tile;
I'm building a cocos2d iPhone game with lots of bullets and moving enemies and I'm detecting collisions between them. Every sprite can be represented by a circle for collision purposes. I'm considering the following options:
1) Simple Sphere Detection
I detect like this at regular intervals:
-(BOOL) isCollidingSphere:(CCSpriteExt*) obj1 WithSphere:(CCSprite *) obj2
{
float minDistance = obj1.radius + obj2.radius;
float dx = obj2.position.x - obj1.position.x;
float dy = obj2.position.y - obj1.position.y;
if (! (dx > minDistance || dy > minDistance) )
{
float actualDistance = sqrt( dx * dx + dy * dy );
return (actualDistance <= minDistance);
}
return NO;
}
2) Box2d for collision detection only
I create a Box2d body for all sprites as shown in this tutorial: http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
My question is simple: If my priority is optimisation, which approach is faster?
Thanks!
If all you need is distance/radius based collision checks, you don't need a physics engine.
You should get rid of the sqrt though. First of all, you're using the square root function that works on doubles. For the float version use sqrtf.
To get rid entirely of the square root, make sure your objects store their radius squared (radiusSquared = radius * radius). That way you don't have to take the square root anymore:
-(BOOL) isCollidingSphere:(CCSpriteExt*) obj1 WithSphere:(CCSprite *) obj2
{
float r1 = obj1.radius;
float r2 = obj2.radius;
float minDistanceSquared = r1 * r1 + r2 * r2 + 2 * r1 * r2;
float dx = obj2.position.x - obj1.position.x;
float dy = obj2.position.y - obj1.position.y;
float actualDistanceSquared = dx * dx + dy * dy;
return (actualDistanceSquared <= minDistanceSquared);
}
Let me just start with the code.
- (NSPoint*) pointFromPoint:(NSPoint*)point withDistance:(float)distance towardAngle:(float)angle; {
float newX = distance * cos(angle);
float newY = distance * sin(angle);
NSPoint * anNSPoint;
anNSPoint.x = newX;
anNSPoint.y = newY;
return thePoint;
}
This should, based on my knowledge, be perfect. It should return and x value of 0 and a y value of 2 if I call this code.
somePoint = [NSPoint pointFromPoint:somePoint withDistance:2 towardAngle:90];
Instead, I get and x value of 1.05 and a y of 1.70. How can I find the x and y coordinates based on an angle and a distance?
Additional note: I have looked on math.stackexchange.com, but the formulas there led me to this. I need the code, not the normal math because I know I will probably screw this up.
A working version of your function, which accepts values in degrees instead of radians, would look like this:
- (NSPoint)pointFromPoint:(NSPoint)origin withDistance:(float)distance towardAngle:(float)angle
{
double radAngle = angle * M_PI / 180.0;
return NSMakePoint(origin.x + distance * cos(radAngle), point.y + distance * sin(radAngle));
}
Your problem is you're giving the angle in degrees (e.g. 90), but the math is expecting it in radians. Try replacing the 90 with M_PI_2