Mutable Array and Sprites - objective-c

I'm making a "snake game" like player and I have the body moving fine so that it adds a block in the previous position each time it moves up to 4 then it removes the last one... etc. I'm adding each block to a NSMutableArray (each block is a sprite and I add the sprite to the array) and I was wondering how to get the position of one of the sprites in the array. I need this so I can check to see if the "head" is trying to move onto itself.
P.S. I'm using cocos2d for iPhone.
When I say position I mean the coordinates, not the index position in the array.
[tail insertObject:block atIndex:i];
[self addChild:[tail objectAtIndex:i]];
i +=1;
CCSprite *sect;
for (int j = 0; j >= i; j++) {
sect = [tail objectAtIndex:j];
}
if (i > maxHealth) {
[self removeChild:[tail objectAtIndex:i-maxHealth-1] cleanup:YES];
id object = [tail objectAtIndex:i-maxHealth-1];
[tail removeObject:object];
}
When the scene is started i is set to 0 and the max health equals 3.

Get the position of a node in an array? Like
// Get the node from the array
CCNode *node = (CCNode*)[myArray objectAtIndex:0];
// Retrieve the position
CGPoint nodePosition = node.position;

Related

Spritekit Screen/Background Update

Is it possible to get 2 positions from the same SKSpriteNode in the -(void)update:(CFTimeInterval)currentTime method?
I am making a demo. A ball is shot from a random point outside of the screen. I want to get the ball's direction and an array of positions so that I can do something based on it. But when I use the update: method, it seems that it fills the array in each update. How do I add only one SKSpriteNode to the array for each update?
NSMutableArray *nodePos;
int returnPosCount;
-(void)update:(CFTimeInterval)currentTime {
if ([self childNodeWithName:#"//ball"]!=nil){
returnPosCount++;
if (returnPosCount == 15) {
SKNode *node = [self childNodeWithName:#"//ball"];
[nodePos addObject:node];
if ([nodePos count]>4) {
[nodePos removeObjectAtIndex:0];
NSLog(#"%#",nodePos);
}
returnPosCount =0;
}
NSLOG:
<SKSpriteNode> name:'ball' (64 x 64)] position:{-127.63968658447266, 135.19813537597656}
<SKSpriteNode> name:'ball' (64 x 64)] position:{-127.63968658447266, 135.19813537597656}
<SKSpriteNode> name:'ball' (64 x 64)] position:{-127.63968658447266, 135.19813537597656}
You are not filling the array in each each update. You are seeing the array full, because you are only printing the data when it is full. Just move your NSLog outside the [nodePos count] condition.
Now the reason why you have the same value is because you are adding the node, instead of its position at each update. Since the node is a reference, you will have an array full of references to the same object, thus obtaining the same position. You should build an array of CGPoint instead of an array of SKNode.
To do so, try changing:
[nodePos addObject:node];
To
[nodePos addObject:node.position];

Draw polyline between given points on the map

I am implementing an iOS application, and I want to draw a polyline between several given coordinates on the map.
I wrote the code and got the polylines being drawn from my point reaching an infinite point. In other words the beginning point of the line starts from the my given lat and long point, but the end of the line is infinite and not the other point.
This is my code...
I filled the coordinates in a NSMutableArray called routeLatitudes. The array cells are being filled one for latitude and one for longitude.
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * [routeLatitudes count]);
for(int idx = 0; idx < [routeLatitudes count]; idx=idx+2)
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude=[[routeLatitudes objectAtIndex:idx] doubleValue];
workingCoordinate.longitude=[[routeLatitudes objectAtIndex:idx+1] doubleValue];
MKMapPoint point = MKMapPointForCoordinate(workingCoordinate);
pointArr[idx] = point;
}
// create the polyline based on the array of points.
routeLine = [MKPolyline polylineWithPoints:pointArr count:[routeLatitudes count]];
[mapView addOverlay:self.routeLine];
free(pointArr);
and overlay delegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayView* overlayView = nil;
if(overlay == routeLine)
{
self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];
self.routeLineView.fillColor = [UIColor colorWithRed:51 green:51 blue:255 alpha:1];
self.routeLineView.strokeColor = [UIColor colorWithRed:204 green:0 blue:0 alpha:1];
self.routeLineView.lineWidth = 3;
overlayView = routeLineView;
}
return overlayView;
}
So I need the lines to be drawn between the points over the map. The beginning of the line is the first dropped pin, and the end is on the last dropped pin.
According to the code, the routeLatitudes array has objects listed like this:
index 0: latitude for point 1
index 1: longitude for point 1
index 2: latitude for point 2
index 3: longitude for point 2
index 4: latitude for point 3
index 5: longitude for point 3
...
So if routeLatitudes.count is 6, it actually has only 3 points.
This means the malloc is allocating the wrong number of points and the polylineWithPoints call is also specifying the wrong number of points for the overlay.
The other problem is that since pointArr will contain only half the objects that routeLatitudes has, you can't use the same index value for both arrays.
The for loop index counter idx is being incremented by 2 at each iteration because that's how the routeLatitudes points are layed out but then the same idx value is used to set pointArr.
So for idx=0, pointArr[0] is set but then for idx=2, pointArr[2] is set (instead of pointArr[1]), and so on. This means every other position in pointArr is left uninitialized resulting in the lines "going to infinity".
So the corrected code might look like this:
int pointCount = [routeLatitudes count] / 2;
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * pointCount);
int pointArrIndex = 0; //it's simpler to keep a separate index for pointArr
for (int idx = 0; idx < [routeLatitudes count]; idx=idx+2)
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude=[[routeLatitudes objectAtIndex:idx] doubleValue];
workingCoordinate.longitude=[[routeLatitudes objectAtIndex:idx+1] doubleValue];
MKMapPoint point = MKMapPointForCoordinate(workingCoordinate);
pointArr[pointArrIndex] = point;
pointArrIndex++;
}
// create the polyline based on the array of points.
routeLine = [MKPolyline polylineWithPoints:pointArr count:pointCount];
[mapView addOverlay:routeLine];
free(pointArr);
Also note in the malloc line, I corrected sizeof(CLLocationCoordinate2D) to sizeof(MKMapPoint). This technically wasn't causing a problem because those two structs happen to be the same length but it's correct to use sizeof(MKMapPoint) since that's what the array is going to contain.

Checking to see if two positions are equal

Right now I have a NSMutableArray that holds 3 sprite objects. I need to be able to see if another sprite not in the Array shares the same position as any of the sprites in the array.
I tried doing this:
CCSprite *sect;
if (i > maxHealth) {
for (int j = 0; j < i; j++) {
sect = [tail objectAtIndex:j];
}
if (CGRectContainsPoint(sect.boundingBox, playerPos)) {
NSLog(#"On top");
return;
}
But it does't work. I think it's trying to see if it intersects all of them at once.
Your if is outside the for loop. It is only going to test one object; the last one accessed in the loop.

MKMapView not refreshing annotations

I have a MKMapView (obviously), that shows housing locations around the user.
I have a Radius tool that when a selection is made, the annotations should add/remove based on distance around the user.
I have it add/removing fine but for some reason the annotations won't show up until I zoom in or out.
This is the method that adds/removes the annotations based on distance. I have tried two different variations of the method.
Adds the new annotations to an array, then adds to the map by [mapView addAnnotations:NSArray].
Add the annotations as it finds them using [mapView addAnnotation:MKMapAnnotation];
1.
- (void)updateBasedDistance:(NSNumber *)distance {
//Setup increment for HUD animation loading
float hudIncrement = ( 1.0f / [[[[self appDelegate] rssParser]rssItems] count]);
//Remove all the current annotations from the map
[self._mapView removeAnnotations:self._mapView.annotations];
//Hold all the new annotations to add to map
NSMutableArray *tempAnnotations;
/*
I have an array that holds all the annotations on the map becuase
a lot of filtering/searching happens. So for memory reasons it is
more efficient to load annoations once then add/remove as needed.
*/
for (int i = 0; i < [annotations count]; i++) {
//Current annotations location
CLLocation *tempLoc = [[CLLocation alloc] initWithLatitude:[[annotations objectAtIndex:i] coordinate].latitude longitude:[[annotations objectAtIndex:i] coordinate].longitude];
//Distance of current annotaiton from user location converted to miles
CLLocationDistance miles = [self._mapView.userLocation.location distanceFromLocation:tempLoc] * 0.000621371192;
//If distance is less than user selection, add it to the map.
if (miles <= [distance floatValue]){
if (tempAnnotations == nil)
tempAnnotations = [[NSMutableArray alloc] init];
[tempAnnotations addObject:[annotations objectAtIndex:i]];
}
//For some reason, even with ARC, helps a little with memory consumption
tempLoc = nil;
//Update a progress HUD I use.
HUD.progress += hudIncrement;
}
//Add the new annotaitons to the map
if (tempAnnotations != nil)
[self._mapView addAnnotations:tempAnnotations];
}
2.
- (void)updateBasedDistance:(NSNumber *)distance {
//Setup increment for HUD animation loading
float hudIncrement = ( 1.0f / [[[[self appDelegate] rssParser]rssItems] count]);
//Remove all the current annotations from the map
[self._mapView removeAnnotations:self._mapView.annotations];
/*
I have an array that holds all the annotations on the map becuase
a lot of filtering/searching happens. So for memory reasons it is
more efficient to load annoations once then add/remove as needed.
*/
for (int i = 0; i < [annotations count]; i++) {
//Current annotations location
CLLocation *tempLoc = [[CLLocation alloc] initWithLatitude:[[annotations objectAtIndex:i] coordinate].latitude longitude:[[annotations objectAtIndex:i] coordinate].longitude];
//Distance of current annotaiton from user location converted to miles
CLLocationDistance miles = [self._mapView.userLocation.location distanceFromLocation:tempLoc] * 0.000621371192;
//If distance is less than user selection, add it to the map.
if (miles <= [distance floatValue])
[self._mapView addAnnotation:[annotations objectAtIndex:i]];
//For some reason, even with ARC, helps a little with memory consumption
tempLoc = nil;
//Update a progress HUD I use.
HUD.progress += hudIncrement;
}
}
I have also attempted at the end of the above method:
[self._mapView setNeedsDisplay];
[self._mapView setNeedsLayout];
Also, to force a refresh (saw somewhere it might work):
self._mapView.showsUserLocation = NO;
self._mapView.showsUserLocation = YES;
Any help would be very much appreciated and as always, thank you for taking the time to read.
I'm going to guess that updateBasedDistance: gets called from a background thread. Check with NSLog(#"Am I in the UI thread? %d", [NSThread isMainThread]);. If it's 0, then you should move the removeAnnotations: and addAnnotation: to a performSelectorOnMainThread: invocation, or with GCD blocks on the main thread.

loop Nsmutable arrray of uiimages from end to beginning

I have an NSMUtable array of images where a different image is displayed with a previous and a next button, but when I get to the end of the array the simulator crashes. I want to loop the end of the array to the beginning so that when I get to the end of the array of images when I hit the next button again it loops back to the first image, also when Im at the first image if I hit the previous button it loops to the last image with no crashes
What you want is a circular array, which is easy to implement using a standard NSMutableArray. For instance, say you store your images in an array called imageArray and use a simple variable to keep track of the index of your current image, like:
int currentImageIndex = 0;
...then you might implement nextImage and previousImage like:
- (UIImage*) nextImage {
currentImageIndex = (currentImageIndex + 1) % [imageArray count];
return [imageArray objectAtIndex:currentImageIndex];
}
- (UIImage*) previousImage {
currentImageIndex--;
if (currentImageIndex < 0) {
currentImageIndex = [imageArray count] - 1;
}
return [imageArray objectAtIndex:currentImageIndex];
}
Then just use nextImage and previousImage whenever you want to step through the array, and problem solved.
Simple enough to do. all you need to do is create a check to see if you're on the last element, and if so, set your tracker (like count or i etc) to 0 again,
Heres the psudo code
//set index
if ( array [ index ] == len(array) - 1) //at end
{
index = 0
}
if(array [index] == -1)//at beginning
{
index = len(array) -1
}
// do something with array[index]
I want to propose this solution:
A property for the selected UIImage, a NSInteger property to hold the current index.
-(IBAction) nextButtonTapped:(id)sender
{
self.currentIndex = self.currentIndex++ % [self.images count];
self.selectedImage= [self.images objectAtIndex:self.currentIndex];
[self reloadImageView];
}
-(IBAction) previousButtonTapped:(id)sender
{
self.currentIndex--;
if (self.currentIndex < 0)
self.currentIndex += [self.images count];
self.selectedImage= [self.images objectAtIndex:self.currentIndex];
[self reloadImageView];
}
-(void)reloadImageView
{
//do, what is necessary to display new image. Animation?
}