Find the closest CCSprite - objective-c

I am trying to find the closest "player" to a "ball" and each of these objects are CCSprite Objects. This is my first app, so if there's a better way to do this, feel free to suggest it :)
Here's my code so far:
for(CCSprite *currentPlayer in players) {
// distance formula
CGFloat dx = ball.position.x - currentPlayer.position.x;
CGFloat dy = ball.position.y - currentPlayer.position.y;
CGFloat distance = sqrt(dx*dx + dy*dy);
// add the distance to the distances array
[distances addObject:[NSNumber numberWithFloat:distance]];
NSLog(#"This happen be 5 times before the breakpoint");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
So this seems to work well; it logs each distance of the player from the ball. But then when I loop through my "distances" array, like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
And this is logging a huge number each time, like 220255312. I declare my distances array like this:
// setting the distance array
NSMutableArray *distances = [[NSMutableArray alloc] init];
What am I doing wrong?
Thanks for your time!

Use distance for the #"%#" like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", distance);
}
[NSNumber numberWithInt:distance]
In your first part distance is a CGFloat.
In the second part distance is a NSNumber.
numberWithInt can't take a NSNumber as its argument.
Hope this helps!

CCSprite *nearestPlayer;
for(CCSprite *currentPlayer in players) {
if(nearestPlayer == nil){
nearestPlayer = currentPlayer;
}
if(ccpDistance(ball.position, currentPlayer.position) < ccpDistance(ball.position, nearestPlayer.position)){
nearestPlayer = currentPlayer;
}
}

Related

AnyObject To CGPoint

I cant seem to figure this out, I have a Objective-C function that returns an NSArray, I know for sure that data inside the NSArray contains CGPoint objects How in the world do I cast this to an Array
Here is the function
+(NSArray *)translatePoints:(NSArray *)points fromView:(UIView *)fromView toView:(UIView *)toView
{
NSMutableArray *translatedPoints = [NSMutableArray new];
// The points are provided in a dictionary with keys X and Y
for (NSDictionary *point in points) {
// Let's turn them into CGPoints
CGPoint pointValue = CGPointMake([point[#"X"] floatValue], [point[#"Y"] floatValue]);
// Now translate from one view to the other
CGPoint translatedPoint = [fromView convertPoint:pointValue toView:toView];
// Box them up and add to the array
[translatedPoints addObject:[NSValue valueWithCGPoint:translatedPoint]];
}
return [translatedPoints copy];
}
Your translatesPoints method returns an NSArray that contains NSValues that wrap CGPoints. Let's create such an array:
let arr:NSArray = [NSValue(CGPoint: CGPointMake(1,2)), NSValue(CGPoint: CGPointMake(3,4))]
You can get the values from this array and call CGPointValue() on them:
for val in arr as [NSValue] {
let point = val.CGPointValue()
println("CGPoint = (\(point.x), \(point.y))")
}
If you want, you can convert the entire NSArray to a Swift array of CGPoints like this:
let points = (arr as [NSValue]).map({$0.CGPointValue()})
Now points has the type [CGPoint].

Sort Array of CGPoints

I am trying to figure out what the fastest/cleanest way to sort an array of CGPoints would be. I think I could achieve this using loops but that might not be the fastest and I hope it isn't the cleanest way. I would like to take an array of random CGPoints and sort them say by smallest x coordinate to largest, or smallest x and y coordinate to largest.
After the correct comment by Chuck, I've updated the answer using the sortUsingComparator method:
Here is the complete code with sample data:
First we generate 100 random values that we enter to the Array:
NSMutableArray *testArray = [[NSMutableArray alloc] initWithCapacity:100];
for (int i=0; i<100; i++) {
CGPoint testPoint = CGPointMake(arc4random()%100, arc4random()%100);
[testArray addObject:[NSValue valueWithCGPoint:testPoint]];
}
and here is the actual code to sort the array:
[testArray sortUsingComparator:^(id firstObject, id secondObject) {
CGPoint firstPoint = [firstObject CGPointValue];
CGPoint secondPoint = [secondObject CGPointValue];
return firstPoint.x>secondPoint.x;
}];
finally we can verify that the array was sorted, by printing it:
NSLog(#"%#",testArray);
The C qsort() function is probably your best bet if you just have a plain array of CGPoints. Something like this:
int compareXCoords(CGPoint *a, CGPoint *b) {
return b->x - a->x;
}
// Later:
CGPoint points[100];
// initialize points somehow
qsort(points, 100, sizeof(CGPoint), compareXCoords);
// points is now sorted by the points' x coordinates
According to my comment, it's a good solution insert them on a NSMutableArray keeping the sort you decide.
You have to do something like this:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];
CGPoint candidate;
// Look for the position it has to be
int 0;
for (CGPoint point in array) {
i++;
// Compare candidate with current point
// You have to define this condition, when point is greater than candidate
if (point > candidate) {
break;
}
}
[array insertObjectAtIndex:i-1];
Maybe my code has some errors, I can't check if it's correct now.

float [] array problem in objective c

I am coding in xcode by objective c. I came up with a problem.
I want to try like
declare float[] weights;
results looks like this
weight[0] = 0.5
weight[1] = 0.4
weight[2] = 0.9
A.h
NSMutableArray *weight;
A.m
weights = [NSMutableArray array];
for(int i=0; i < 4; i++) {
float randomNumber = arc4random() % 11;
[weights addObject:[[NSNumber alloc] initWithFloat:randomNumber]];
NSLog(#" for loops color prob weghts=%f",[weights objectAtIndex:i] );
}
I don't know what is wrong with this code. Please help me to find out?
When I print it by NSLOG " all [weight = 0.000] and also How do I access like [weight floatvalue].
secondly, when I create this class to another class there are weight [0],[1],[2],[3] and no values
It should be [[weights objectAtIndex:i] floatValue] when you print it in your NSLog
NSNumber is a class, not a integral type.
Therefore, you must use %#, not %f.
NSLog(#" for loops color prob weghts=%#",[weights objectAtIndex:i] );
Alternatively, use floatValue, like you said. You may need to cast the object into NSNumber first (for type safety)
NSNumber *number = (NSNumber *)[weights objectAtIndex:i];
NSLog(#" for loops color prob weghts=%f", [number floatValue]);
Also, you are leaking objects here, because you did not release them after putting them in the array. Either release after placing them in array, or use [NSNumber numberWithFloat:]

Am I using Objective-C collections properly here?

I'm attempting to write an iPhone game. This function is intended to apply gravitational force to several objects. I'm porting it from Python and I'm wondering if my use of dictionaries and arrays as tuples makes sense and is typical/idiomatic in Objective C. Any comments on the code appreciated.
+ (void)updateBodies:(NSMutableArray*)bodies {
NSMutableDictionary* totals = [NSMutableDictionary dictionaryWithCapacity:[bodies count]];
for (Body* body in bodies) {
if (body.fixed) {
continue;
}
float tx;
float ty;
for (Body* other in bodies) {
if (other == body) {
continue;
}
float dx = other.x - body.x;
float dy = other.y - body.y;
float dist2 = pow(dx, 2) + pow(dy, 2);
float dist = sqrt(dist2);
float mass = pow(other.radius, 3);
float magnitude = G * mass / dist2;
float ux = dx / dist;
float uy = dy / dist;
tx += ux * magnitude;
ty += uy * magnitude;
}
NSNumber* ntx = [NSNumber numberWithFloat:tx];
NSNumber* nty = [NSNumber numberWithFloat:ty];
NSArray* tuple = [NSArray arrayWithObjects:ntx, nty, nil];
[totals setObject:tuple forKey:body];
}
for (Body* body in [totals allKeys]) {
NSArray* tuple = [totals objectForKey:body];
float tx = [[tuple objectAtIndex:0] floatValue];
float ty = [[tuple objectAtIndex:1] floatValue];
body.dx += tx;
body.dy += ty;
}
}
The only problem you should be aware of is that NSDictionary copies its keys. So Body needs to implement NSCopying and the instances of Body in totals are not necessarily the same instances in the passed in bodies array depending on how you implement NSCopying.
The approach I would use would be to consider velocity as a property of the body. That way you don't need a dictionary to associate the body to its velocity, you can just iterate through the array itself.
Talking of iterating. You can halve the number of iterations and some calculations by calculating the velocity of the other body at the same time as the first body. i.e. your inner loop would only iterate through the bodies that come after the outer loop body in the array.
It would mean you can't use fast iteration, so you'd have to profile to figure out which approach is faster.
On a minor note, I think
for ....
{
if (!condition)
{
continue;
}
// do stuff
}
is really ugly. What's wrong with:
for ....
{
if (condition)
{
// do stuff
}
}
You could used block enumeration for final update:
[totals enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
Body* body = key;
NSArray* tuple = key;
body.dx += [[tuple objectAtIndex:0] floatValue];
body.dy += [[tuple objectAtIndex:1] floatValue];
}];
An other solution could be to not used NSDictionary and NSArray and use a C array. It should be faster than using (and create) objects.

Comparing Touch Coordinates

Is it possible to compare touch coordinates made by the users on the UIView to the one store in a plist or txt format? The argument looks like this;
if (user touch coordinate == touch coordinate stored in plist or text)
then
(do something)
else
(do something)
If possible in what format should i write the coordinates in the list and how to associate it inside the program?
thanks in advance and sorry if you find my question a bit noobie.
Not sure if there's a one-liner solution.
On a UITouch instance, the locationInView: method returns a CGPoint struct (x and y coordinates, both of type float). So you can store the x and y coordinates in your plist, then compare them with your current touch's x and y coordinates.
EDIT:
Also, when comparing the coordinates, you probably want to use the distance between the two points to determine when you have a "hit".
EDIT:
Below is sample code for loading and writing to a property list, where the values are based on a NSDictionary:
- (NSMutableDictionary *)loadDictionaryFromPList: (NSString *)plistName
{
NSString *plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:#"plist"];
NSDictionary *immutableDictionary = [NSDictionary dictionaryWithContentsOfFile: plistPath];
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary: immutableDictionary];
return mutableDictionary;
}
- (void)saveDictionary: (NSDictionary *)mySettings toPList: (NSString *)plistName
{
NSString *plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:#"plist"];
[mySettings writeToFile: plistPath atomically: YES];
}
The method to calculate the distance between the two locations of the UITouches:
-(CGFloat) distanceBetween: (CGPoint) point1 and: (CGPoint)point2
{
CGFloat dx = point2.x - point1.x;
CGFloat dy = point2.y - point1.y;
return sqrt(dx*dx + dy*dy );
}
And finally, the code that uses the values in the property list to determine if the user hit the previous location:
CGPoint currentTouchLocation = [currentTouch locationInView:self];
// Lookup last Touch location from plist, and handle case when current Touch matches it:
NSMutableDictionary *mySettings = [self loadDictionaryFromPList: #"MySettings"];
NSNumber *lastXCoordinate = [mySettings objectForKey:#"lastXCoordinate"];
NSNumber *lastYCoordinate = [mySettings objectForKey:#"lastYCoordinate"];
if (lastXCoordinate && lastYCoordinate)
{
CGPoint lastTouchLocation = CGPointMake([lastXCoordinate floatValue], [lastYCoordinate floatValue]);
CGFloat distanceBetweenTouches = [self distanceBetween: currentTouchLocation and: lastTouchLocation];
if (distanceBetweenTouches < 25) // 25 is just an example
{
// Handle case where current touch is close enough to "hit" previous one
NSLog(#"You got a hit!");
}
}
// Save current touch location to property list:
[mySettings setValue: [NSNumber numberWithFloat: currentTouchLocation.x] forKey: #"lastXCoordinate"];
[mySettings setValue: [NSNumber numberWithFloat: currentTouchLocation.y] forKey: #"lastYCoordinate"];
[self saveDictionary:mySettings toPList: #"MySettings"];
The functions you're probably looking for are NSStringFromCGPoint() and CGPointFromString().
But two touch coordinates will almost certainly never be the exact same. You should almost never be comparing CGFloats with ==, let alone ones you get from such an analog input as a finger touch. You need to compare whether they are "close enough." See this blog for a good example of how to measure the distance between two points. You want that result to be less than some value (epsilon, or "a small number") that is appropriate for your purposes.