this code loads a map1.tmx tileMap when player reaches the "door". When the player enters the door it loads a new map2.tmx file. Problem is when the new map2.tmx file is loaded, the old map1.tmx is running behind map.2.tmx and using all of map.1.tmx wall collisions AND ignoring map2.tmx wall collisions. Is there a way to do an opposite of addObject like removeObject and add map2.tmx as the new map? I would like to make map.2 run when the players enters the door.
I have tried removeAllActions, removeAllChildren, removeTileAtCoord: and other approaches but I lack of SpriteKit experience. Any help is appreciated.
- (void)handleDoorCollisions:(Player *)player
{
if (self.doorOver) return;
NSInteger indices[8] = {7, 1, 3, 5, 0, 2, 6, 8};
for (NSUInteger i = 0; i < 8; i++) {
NSInteger tileIndex = indices[i];
CGRect playerRect = [player collisionBoundingBox];
CGPoint playerCoord = [self.doors coordForPoint:player.desiredPosition];
NSInteger tileColumn = tileIndex % 3;
NSInteger tileRow = tileIndex / 3;
CGPoint tileCoord = CGPointMake(playerCoord.x + (tileColumn - 1), playerCoord.y + (tileRow - 1));
NSInteger gid = [self tileGIDAtTileCoord:tileCoord forLayer:self.doors];
if (gid != 0) {
CGRect tileRect = [self tileRectFromTileCoords:tileCoord];
if (CGRectIntersectsRect(playerRect, tileRect)) {
[self.doors removeTileAtCoord:tileCoord];
// add new map2.tmx
self.map = [JSTileMap mapNamed:#"map2.tmx"];
[self addChild:self.map];
[self removeObject:????]
}
}
}
}
I had the same issue. My solution was/is on map load I collect all collision data in a List<> and check any collisions against this list.
When the player enters a different map the list is beeing cleared and reinitialized with the data from the new map.
I use this approach for some other things as well like objects the player can interact with or areas that trigger some actions.
Related
I wanted to create a space background so I make a for loop to create the stars. Here is the code:
for (int i = 0; i<100; i++) {
SKShapeNode *star= [SKShapeNode shapeNodeWithPath:Path.CGPath];
star.fillColor = [UIColor whiteColor];
star.physicsBody = nil;
int xposition = arc4random()%960;
int yposition = arc4random()%640;
star.position = CGPointMake(xposition, yposition);
float size = (arc4random()%3 + 1)/10.0;
star.xScale = size;
star.yScale = size;
star.alpha = (arc4random()%10 + 1 )/ 10.0;
star.zPosition = -2;
[self addChild:star];
}
But it takes a lot from my cpu. when the code is activated the cpu at top 78%.(I check the code in the iPhone simulator);
Somebody know how to fix it? thanks.
Your physics bodies continue to calculate even when off of the screen. You will need to remove them once they go out of the frame, otherwise everything will slow to a crawl. (And to echo what others have stated you will eventually need a real device).
From this document: Jumping Into Sprite Kit
You can implement the "Did Simulate Physics" method to get rid of the stars that fell from the bottom of the screen like so:
-(void)didSimulatePhysics
{
[self enumerateChildNodesWithName:#"star" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.y < 0)
[node removeFromParent];
}];
}
Note that you will first need to set the name of your star shapes by using the name property like so:
star.name = "star"
I'm trying to make a couple hundred levels for a game I'm developing, so obviously I want to use a for loop and not create each button individually.
I do all of this fine, but the code I'm currently using makes it so that the call block for each button is the same. Obviously if I'm going to have the different level buttons go to different levels, the call block must be different for each one.
In order to differentiate which level I'm on, I call [[LevelManager sharedInstance] nextLevel] the number of times corresponding to the level number. I attempted to change this number by getting the touch location of the user touching the button, getting a row/column number, then running the above code a certain number of times. However, it was not updating the touch position before running the whole call block after touching the button, which obviously makes my code not work.
Is there a way to update the touch position manually, before the call block finishes? Is there a way to somehow store every button in an array and establish a different call block for each one? I'm not sure what the best approach is to fixing my problem. Thanks and my code is below.
Called upon initialization
for (int l = 0; l < NUMBER_OF_WORLDS; l++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 5; k++) {
NSString *tempTitle = [NSString stringWithFormat:#"%i",(k+1)+(l*5)];
CCButton *tempButton;
tempButton = [CCButton buttonWithTitle:tempTitle]
tempButton.block = ^(id sender) {
int row = floorf(touchLocation.y/(screenBounds.size.height/6)) + 1;
int column = floorf(touchLocation.x/(screenBounds.size.width/4)) + 1;
int buttonIndex = row*column;
for (int m = 1; m < buttonIndex; m++) {
[[LevelManager sharedInstance] nextLevel];
}
CCScene *gameplayScene = [CCBReader loadAsScene:#"LevelScene"];
[[CCDirector sharedDirector] replaceScene:gameplayScene];
levelNumber = i;
};
tempButton.position = ccp((screenBounds.size.width/4)*j + levelImagePlaceholder.contentSize.width*tempButton.scale, screenBounds.size.height/6*k + 50 + l*screenBounds.size.height);
[self addChild:tempButton];
i++;
}
}
}
Method for getting touch position
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CCLOG(#"touch ran");
touchLocation = [touch locationInNode:self];
}
You already have the row/column available. They are j and k. Those variables can be referenced in your button's "on pressed" block.
I am in front of a problem when adding sprites on my game layer.
When the game starts it's initialize a two dimensional array (that I created) and put 30 sprites in it (5 columns, 6 lines). It's always the same image that I use for the 30 sprites.
The problem is that each time I create a new sprite...
Every 3 sec all sprites deseaper and new ones appear. I am using ARC but when I check into Instruments (allocations part) I can see the number of living sprites increasing every 3sec 30, 60, 90, 120 ...
So when I play for 15 minutes my game crash. How can I use the same sprite without creating a new one ?
I tried to create it in the init method but then when I enter in [self addChild : mysprite] it says to me that the sprite had already been add.
Here is my code :
int yValue = 400;
for (int line = 0; line < nbLines; line++) {
int xValue = 32;
for (int section = 0; section < nbSection ; section++) {
MySprite *mySprite = [[MySprite alloc] initWithFile:#"mySprite.png"];
mySprite.position = ccp(xValue, yValue);
[gameTab setObject:mySprite :section :line];
[self addChild:mySprite];
xValue += 64;
}
yValue -= 64;
}
and here is what I do for deleting the sprite :
[gameTab removeChild:mySprite cleanup:YES];
[self removeChild:mySprite cleanup:YES];
I don't know when ARC deallocate my sprites.
Thx.
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.
If I have a NSView with 10 subviews, and I drag one of the subviews, what is the easiest way to determine which of the remaining views is closes to the dragged one? My code is working but I somehow feel I'm using a monkey wrench to fine tune a violin. Is there a more elegant way?
subviews is an array of the subviews of the parent view of this view (so it includes this view)
the toolTip of the sub views contain their page # formatted like "Page_#"
- (void) mouseUp: (NSEvent* ) e {
//set up a ridiclous # for current distance
float mtDistance = 12000000.0;
//get this page number
selfPageNum = [[[self toolTip] substringFromIndex:5] intValue];
//set up pageViews array
pageViews = [[NSMutableArray alloc] init];
//loop through the subviews
for (int i=0; i<[subviews count]; i++) {
//set up the view
thisView = [subviews objectAtIndex:i];
//filter for view classes
NSString* thisViewClass = [NSString stringWithFormat:#"%#", [thisView className]];
if ( [thisViewClass isEqual:#"Page"]) {
//add to the pageViews array
[pageViews addObject:thisView];
if (self != thisView) {
//get the view and self frame
NSRect movedViewFrame = [self frame];
NSRect thisViewFrame = [thisView frame];
//get the location area (x*y)
float movedViewLoc = movedViewFrame.origin.x * (movedViewFrame.origin.y * -1);
float thisViewLoc = thisViewFrame.origin.x * (thisViewFrame.origin.y * -1);
//get the difference between x locations
float mtDifference = movedViewLoc - thisViewLoc;
if (mtDifference < 0) {
mtDifference = mtDifference * -1;
}
if (mtDifference < mtDistance) {
mtDistance = mtDifference;
closesView = thisView;
}
}
}//end class check
}//end loop
//....more stuff
}
http://en.wikipedia.org/wiki/Distance
sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2)))
Edit: Since you only need to find the shortest distance, not exact distances, you don't need to take the square root. Thanks for the insight Abizern
pow((x2 - x1), 2) + pow((y2 - y1), 2)