making my own tile system cause lag - iphone

- (void) loadStartingTiles //16 by 24
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"clonespritesheet.plist"];
for(int x = 0; x < 16; x++) //minus 1 for one at the begining
{
for(int y = 0; y < 26; y++)
{
CCSprite *tempsprite;
switch (currentscreen[x][y])
{
case 0:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block0.png"];
break;
case 1:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
break;
}
tempsprite.position = ccp(y*20+10,(16-x)*20-10); //+10 for align for tile size
[self addChild:tempsprite z:3];
[tiles addObject:tempsprite];
}
}
}
So I make a bunch of sprites from an int array that tells them where they should be then i add them into the nsmutable array tile. then i move everything in the array to the left slowly, and im losing around 20 FPS. what is a more efficient way to make a tile system? my goal is to make randomly generated tiles later on.
- (void) manageTiles:(CGFloat)dt
{
int tileamount = [tiles count];
for(int i = 0; i < tileamount; i++)
{
CCSprite *tempsprite = [tiles objectAtIndex:i];
tempsprite.position = ccp(tempsprite.position.x-20*dt,tempsprite.position.y);
}
}
EDIT: the awnser is
int themap = -20;
- (void) manageTiles:(CGFloat)dt
{
tiles.position = ccp(tiles.position.x-10*dt,tiles.position.y);
NSLog(#"%d",themap);
if(tiles.position.x < themap)
{
CCSprite *tempsprite;
for(int i = 0; i < 16; i++)
{
[tiles removeChildAtIndex:0 cleanup:YES];
}
for(int i = 0; i < 16; i++)
{
switch (tilewall[i])
{
case 0:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
break;
case 1:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
break;
}
tempsprite.position = ccp((themap*-1)+500+10,((16-i)*20-10));
[tiles addChild:tempsprite];
}
themap = themap-20;
}
}

Where you are going wrong is, you are not using a CCSpriteBatchNode. A CCSpriteBatchNode will draw all of the tiles in one draw operation instead of doing one draw operation per tile. The drawbacks are, each tile in the batch node will have the same zOrder (in a way), and it all must use one source spritesheet per batch node. SO basically if you wanted different layers at different zOrders, or different layers which use different source images for the tiles, you would have to create multiple batch nodes, one for each.
http://www.cocos2d-iphone.org/api-ref/0.99.5/interface_c_c_sprite_batch_node.html

Preload the tempsprite variable outside your loop:
CSprite *sprite0 = [CCSprite spriteWithSpriteFrameName:#"block0.png"];
CSprite *sprite1 = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
And then refer them to them in the loop:
switch (currentscreen[x][y])
{
case 0:
tempsprite = sprite0;
break;
case 1:
tempsprite = sprite1;
break;
}
or even better:
tempsprite = currentscreen[x][y] ? sprite1 : sprite0;
Oh, and your inner loop should refer to 24, not 26.

Related

how to synchronise removal of b2bodies when firing in game

In my game i have some monsters and my hero. when i fire some bullets i remove bodies on collision either with monster or ground body, and also added a timer event to remove the bullet as
-(void) removeProjectile:(CCPhysicsSprite*)projectile{
dispatch_time_t removeProjectile = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1* NSEC_PER_SEC));
dispatch_after(removeProjectile, dispatch_get_main_queue(), ^(void){
int i;
for(i=0;i<deadBodyCount;i++)
{
if(deadBodies[i] == projectile.b2Body)
{
break;
}
}
if(i==deadBodyCount)
{
deadBodies[deadBodyCount]=projectile.b2Body;
deadBodyCount++;
}
});
}
but what happens my code crashes, don't know. please help me. If you have any approach to do this.
i am removing deadbodies in
-(void)removeDeadBodies{
for (int i=0; i<deadBodyCount; i++) {
if(deadBodies[i]){
if([self getPSTag:deadBodies[i]]==3){
CCPhysicsSprite *temp=(CCPhysicsSprite *)deadBodies[i]->GetUserData();
NSLog(#"%#",temp);
[[self getChildByTag:kTagParentNode]removeChild:temp cleanup:YES];
}
else if([self getPSTag:deadBodies[i]]==2){
for (int j=0; j<monsterCount; j++) {
if (monsters[j].b2Body==deadBodies[i]) {
[[self getChildByTag:kTagParentNode]removeChild:monsters[j] cleanup:YES];
monsters[j]=NULL;
}
}
}
_world->DestroyBody(deadBodies[i]);
deadBodies[i]=NULL;}
}
deadBodyCount=0;
}
-(int)getPSTag:(b2Body *)body{ //physics sprite tag value from a b2Body
CCPhysicsSprite *sprite=(CCPhysicsSprite*)body->GetUserData();
//Here is the error------------------------------------
if(sprite)
return (int)sprite.tag;
else
return 0;
}
and this is my begin contact method
-(void)beginContact:(b2Contact *)contact{
b2Body *bodyA=contact->GetFixtureA()->GetBody();
b2Body *bodyB=contact->GetFixtureB()->GetBody();
int collideCheck=[self checkForCollisionGroups:bodyA And:bodyB];
if(!collideCheck)
return;
switch (collideCheck) {
case 1:
for (int i=0; i<monsterCount; i++) {
if(monsters[i].isVisible){
//Checking if Projectile hitting the monster
//bodyA is monster and bodyB is projectile
if([self getPSTag:bodyA]==2&&[self getPSTag:bodyB]==3){
[monsters[i] monsterHit];
[self doExplosionAtPoint:monsters[i].position];
deadBodies[deadBodyCount++]=monsters[i].b2Body;
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyB->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
[self.top updateScore:100];
}//bodyA is Projectile and bodyB is Monster
else if([self getPSTag:bodyA]==3&&[self getPSTag:bodyB]==2){//if one of the body is projectile
[monsters[i] monsterHit];
[self doExplosionAtPoint:monsters[i].position];
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyA->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
deadBodies[deadBodyCount++]=monsters[i].b2Body;
[self.top updateScore:100];
}
}
}
break;
case 2:
if (jumping==YES) {
jumping=NO;
}
break;
case 3: //bullet hitting with any object
if([self getPSTag:bodyA]==3){//if one of the body is projectile
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyA->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
}
else if ([self getPSTag:bodyB]==3){
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyB->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
}
break;
case 4:
for (int i=0; i<monsterCount; i++) {
if(monsters[i].isVisible){
if( (bodyA==monsters[i].b2Body&&bodyB==_heroBody)||(bodyA==_heroBody&&bodyB==monsters[i].b2Body)) {
_heroBody->SetLinearVelocity(b2Vec2(-3*hero.scaleX, 5));
lifeCount=[_top updateHealthMeterWithDamage:10];
NSLog(#"collide");
moving=false;
}
}
}
break;
/*case 6:if([self getPSTag:bodyA]==33){
movingTile.position=((CCSprite*)bodyA->GetUserData()).position;
}
else
movingTile.position=((CCSprite*)bodyB->GetUserData()).position;*/
default:
break;
}
}
I looked at your code. I dont understand the use of removeProjectile: CCPhysicsSprite*)projectile{} method while you indirectly actually adding the projectiles to the deadBodies[] in the beginContact(). So i guess here you have two pointers pointing to same body. And when you run the removeDeadBodies() for loop, it actually first deletes the body and then in next iteration when again it gets the dangling pointer with no body then it crashes.
I commented the line [self removeProjectile:projectile]; in the createProjectileAt() method. And now everything is working fine.
I know it might be late to implement but a suggestion, to have better hold on your b2Bodies and safe deletion from world, you can take a struct datatype with data members as a Sprite and a BOOL variable say isDelete. And use this struct as the userdata of the body. So now you can just set this bool variable to YES inside beginContact() call back. And in you update: tick method after the world->step is over just iterate through the world of bodies and check the BOOL var that can be deleted. HEre you can safely delete the bodies. No need to maintain an array of deadBodies etc. Hence there will not be any synchronization issue.

Sprites are disappear after some time

Here some code for Add sprite for Enemies.....
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
for (int i = 0; i < kNumAstroids; ++i) {
CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:#"robber.png"];
asteroid.visible = NO;
[_batchNode addChild:asteroid];
[_robbers addObject:asteroid];
}
And in Update method ........
double curTime = CACurrentMediaTime();
if (curTime > _nextRunemanSpawn) {
float randSecs = [self randomValueBetween:0.20 andValue:1.0];
_nextRunemanSpawn = randSecs + curTime;
float randY = [self randomValueBetween:80 andValue:80];
float randDuration = [self randomValueBetween:4.5 andValue:4.5];
float randDuration1 = [self randomValueBetween:1.0 andValue:1.0];
CCSprite *asteroid = [_robbers objectAtIndex:_nextRobber];
_nextRobber++;
if (_nextRobber >= _robbers.count) {
_nextRobber = 1;
}
[asteroid stopAllActions];
asteroid.position = ccp(winSize.width +asteroid.contentSize.width / 2 , randY);
asteroid.visible = YES;
[asteroid runAction:[CCSequence actions:[CCMoveBy actionWithDuration:randDuration position:ccp(-winSize.width-asteroid.contentSize.width, 0)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],nil]];
All Sprites are Move from right to left in screen
when Sprite crosses the middle of the screen it automatically disappear
what is the reason for this problem ??
I agree with the previously mentioned statement from LearnCocos2D. It is also possible that you are adding multiple objects and reaching the end of the capacity in the line
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
If you try to spawn more objects than whatever number you have specified for kNumAsteroids it will remove the oldest object and use the new one in its place. I.e. if kNumAsteroids is 5, you have 5 on the screen and then add a sixth, 1 will become 6 and its position will be whatever you set it to.

iPhone:How can I shuffle buttons in view

I have many no. of buttons on my view and I want to shuffle the buttons(change in position) then how can I shuffle the button in my view.
use arc4random()
and change position of your buttons
In your .h file : UIButton *buttonsarray[10];
In your .m file :
// Make array of button using following way.I used this method to creates button and you can use yours.
- (void)viewDidLoad {
[super viewDidLoad];
float y = 5;
int x = 0;
int count = 0;
for (int i = 0 ; i < 10; i++)
{
count ++;
buttonsarray[i] = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buttonsarray[i].frame = CGRectMake(x, y, 100, 100);
[buttonsarray[i] setTitle:[NSString stringWithFormat:#"%d",i+1] forState:UIControlStateNormal];
x = x + 105;
[self.view addSubview:b[i]];
if(count == 3)
{
count = 0;
x = 0;
y = y+ 105;
}
}
}
// This function will soufflé your buttons
- (IBAction)btnClicked:(id)sender
{
int n = 10;
int swaper;
for (int i = 0 ; i < 10 ; i++)
{
int r = arc4random()%n;
if(r != swaper){
swaper = r;
CGRect r1 = buttonsarray[i].frame;
buttonsarray[i].frame = buttonsarray[swaper].frame;
buttonsarray[swaper].frame = r1;
n--;
}
}
}
Hope,this will help you..
You can do this
Make an Array with a group of CGPoints you will need to store the points as strings.
In the layoutSubViews method set something like this:
-(void)layoutSubViews{
[self.subviews enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
CGPoint newPoint = CGPointFromString([positionsArray objectAtIndex:idx]);
object.frame = CGRectMake(newPoint.x,newPoint.y,object.frame.size.width,object.frame.size.height);
}];
}
Then you will need to shuffle the positions in the positions array, you can see an example method here :How to Shuffle an Array
Now every time you need to Shuffle the positions you can call -(void)setNeedsLayout on your view.
There are more options but that was the first I thought of.
Good Luck

Problem with Objective-C for loop

I have two methods, the generateRandomCard method gets called within the testMethod, where there is a for loop that runs 100 times. That way it works perfect, but if I set the for loop limit to 1000 or any other number greater than 100 it crashes. Can you see what's wrong??
- (void)testMethod {
Globals *myGlobals = [Globals sharedInstance];
int rankOfFirst = 0;
int rankOfSecond = 0;
int playerOneWin = 0;
int playerTwoWin = 0;
int ties = 0;
float firstPercent = 0;
float secondPercent = 0;
float tiePercent = 0;
FiveEval *evaluator = [FiveEval theEvaluator];
for (int i = 0; i < 100; i++) {
short fPF = [self generateRandomCard];
short fPS = [self generateRandomCard];
short sPF = [self generateRandomCard];
short sPS = [self generateRandomCard];
short fFlop = [self generateRandomCard];
short sFlop = [self generateRandomCard];
short tFlop = [self generateRandomCard];
short tur = [self generateRandomCard];
short riv = [self generateRandomCard];
rankOfFirst = [evaluator getRankOfSeven:fFlop
:sFlop
:tFlop
:tur
:riv
:fPF
:fPS];
rankOfSecond = [evaluator getRankOfSeven:fFlop
:sFlop
:tFlop
:tur
:riv
:sPF
:sPS];
if (rankOfFirst > rankOfSecond) {
playerOneWin++;
} else if (rankOfSecond > rankOfFirst) {
playerTwoWin++;
} else {
ties++;
}
[myGlobals.alreadyPickedCards removeAllObjects];
}
firstPercent = ((float)playerOneWin/(float)10000)*100;
secondPercent = ((float)playerTwoWin/(float)10000)*100;
tiePercent = ((float)ties/(float)10000)*100;
NSLog(#"First Player Equity: %f", firstPercent);
NSLog(#"Second Player Equity: %f", secondPercent);
NSLog(#"Tie Equity: %f", tiePercent);
}
- (short)generateRandomCard {
Globals *myGlobals = [Globals sharedInstance];
short i = arc4random()%51;
for (int j = 0; j < [myGlobals.alreadyPickedCards count]; j++) {
if (i == [[myGlobals.alreadyPickedCards objectAtIndex:j] shortValue]) {
[self generateRandomCard];
}
}
[myGlobals.alreadyPickedCards addObject:[NSNumber numberWithShort:i]];
return i;
}
You're probably overflowing your stack in the recursive call to -generateRandomCard. If you generate a card that's already been picked, you call yourself recursively (and ignore the result, which is a different bug). So, if your random number stream gave you an unlucky sequence that kept returning cards you've already picked, then you'll recurse infinitely until the stack overflows.
Change your card selection algorithm so that instead of using rejection sampling with the potential for infinite looping/recursion, it uses an algorithm with a bounded runtime such as the Fisher-Yates shuffle.
Not sure if this could in any way lead to the crash - It may be unrelated. However, it does look like you have a bug in the way you recursively call generateRandomCard when a card is found in the alreadyPickedCards array. Instead of
[self generateRandomCard];
I think you should have
return [self generateRandomCard];
You have in -testMethod:
[myGlobals.alreadyPickedCards removeAllObjects];
and in -generateRandomCard you have:
for (int j = 0; j < [myGlobals.alreadyPickedCards count]; j++) {
if (i == [[myGlobals.alreadyPickedCards objectAtIndex:j] shortValue]) {
[self generateRandomCard];
}
}
I can't bet for sure, but this looks like a situation where you removeAllObjects in 1 loop and access an out of bound index in another loop.
If you wanna play like this with arrays, I suggest you make copies of arrays and remove items from those copied arrays.

Image replacement in iphone

I have added some sprite by using the following code and then by checking the rect
intersection I want to replace these sprites with another one.Can you help me out by providing code
to replace these random images.Problem is that the image to be replaced is also taken
randomly.........
yp = 40;
//CCSprite *spr;
movableSprites = [[NSMutableArray alloc] init];
for(int m=0; m<4; m++)
{
do
{
i = 'a';
//NSLog(#"valueeeeeeeee %d",i);
next = arc4random()%maxalphabets;
//NSLog(#"valueeeeeeeeenexttttt %d",next);
i+=next;
//NSLog(#"valueeeeeeeee %d",i);
spr = (CCSprite*)[self getChildByTag:i];//checks if found alreadyyyyyy
NSLog(#"Strrrrrrrr is:%#",spr);
}while(spr);
spNameStr = [NSString stringWithFormat:#"%c3.png",i];
NSLog(#"tagggg %d",i);
NSLog(#"spNameStr is:%#",spNameStr);
spr = [CCSprite spriteWithFile:spNameStr ];
spr.tag = i;
//NSLog(#"tagiiiiii %d",i);
spr.position = ccp(60,yp);
[self addChild:spr z:2];
[movableSprites addObject:spr];
yp+=spr.contentSize.height+35;
}
yp = 40;
NSMutableArray *answerimagesCopy = [NSMutableArray arrayWithArray:movableSprites];
NSLog(#"answer image copy elements areeeee %#",answerimagesCopy);
for(k = 0; k < movableSprites.count; ++k)
{
NSLog(#"inside forrrr");
int j=arc4random()%([answerimagesCopy count]);
NSLog(#"valueee of jjjjjjjj %d",j);
CCSprite *ansimage = [answerimagesCopy objectAtIndex:j];
//NSLog(#"................ %#",ansimage);
p=ansimage.tag;
NSLog(#"tagg..... %d",p);
[answerimagesCopy removeObjectAtIndex:j];
//NSLog(#"tagg..... %d",j);
spNameStr = [NSString stringWithFormat:#"%c4.png",p];
NSLog(#"spNameStr is:%#",spNameStr);
//NSLog(#"tagggg %d",j);
spr = [CCSprite spriteWithFile:spNameStr ];
spr.tag = p+100;
spr.position = ccp(260,yp);
[self addChild:spr z:1];
yp+=spr.contentSize.height+35;
}
I have did this using sprite sheet. if you can create a sprite sheet and then assign that sprite sheet to CCSpriteBatchNode's object like
$ CCSpriteBatchNod * m_meteoritesSprites =[CCSpriteBatchNode batchNodeWithFile:#"Meteo.pvr.ccz"];
and then load plist
$[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"Meteo.plist"];
and then use sprite frames to assign images to your sprite like
$ m_meteoritesSprites =[CCSpriteBatchNode batchNodeWithFile:#"Meteo.pvr.ccz"];
i used TexrturePacker to make sprite sheets
hope this helps you.