解决在场景中销毁无用对象的问题,详见tick方法

比较完美版本的GameScene,借助于userData,可以比较彻底的将超出界限外的BYShape 对象回收掉

参见前面写过的一篇文章。。。。

//
//  GameScene.mm
//  GameFrameWork
//
//  Created by Eric Zhu on 6/12/11.
//  Copyright 2011 Home. All rights reserved.
//

#import "GameScene.h"

// enums that will be used as tags
enum {
	kTagDemoNode = 1,
	kTagEleBallNode = 2,
	kTagEleBoxNode = 3,
	kTagBgGame = 4,
};

@implementation GameScene

+(CCScene *) scene {
	CCScene *scene = [CCScene node];	// 'scene' is an autorelease object.
	
	CCLayer *bgLayer = [GameBgLayerA node];
	[scene addChild:bgLayer z:0];
	
	CCLayer *gameLayer = [GameScene node];
	[scene addChild:gameLayer z:2];
	
	return scene;
}


-(void) createBox2dWorld {	// 创建 box2d 世界~
	b2Vec2 gravity;
	gravity.Set(0.0f, -10.0f);
	bool doSleep = true;
	_world = new b2World(gravity, doSleep);
	
	_world->SetContinuousPhysics(true);
	
	_m_debugDraw = new GLESDebugDraw(PTM_RATIO);
	_world->SetDebugDraw(_m_debugDraw);
	
	// Add contact listener
	MyContactListener *_contactListener = new MyContactListener();
	_world->SetContactListener(_contactListener);
	
	// 如果 DEBUG_DRAW 的开关打开了的话,还可以对 DEBUG_DRAW 具体要画出些什么内容进行详细配置~
	uint32 flags = 1;
	if(DEBUG_DRAW) {
		flags = 0;
	}
	flags += b2DebugDraw::e_shapeBit;
//	flags += b2DebugDraw::e_jointBit;
//	flags += b2DebugDraw::e_aabbBit;
//	flags += b2DebugDraw::e_pairBit;
//	flags += b2DebugDraw::e_centerOfMassBit;
	_m_debugDraw->SetFlags(flags);
	
}


-(void) addToolBar {
	_toolBar = [ToolBar node];
	[_toolBar setShapes:_shapes];
	[self addChild:_toolBar];
}


-(void) loadTmxTiledMap {	// 加载 TMX 地图~
	_gameMap = [CCTMXTiledMap tiledMapWithTMXFile:[NSString stringWithFormat:@"level_%@.tmx", @"demo"]];
	[self addChild:_gameMap];
	
	// Element Group 中的 Table 类表示的是地图中的拦路方块儿~
	CCTMXLayer *ground = [_gameMap layerNamed:@"Ground"];
	for (int x = 0; x < GAME_WIDTH; x ++) {
		for (int y = 0; y < GAME_HEIGH; y ++) {
			int tileGID = [ground tileGIDAt:CGPointMake(x, y)];
			if (tileGID) {
				NSDictionary *properties = [_gameMap propertiesForGID:tileGID];
				if (properties) {
					NSString *collision = [properties valueForKey:@"collidable"];
					if (collision && [collision compare:@"hori"] == NSOrderedSame) {
						[[Table alloc] init:_world type:1 
								x:[ground tileAt:CGPointMake(x, y)].position.x/PTM_RATIO 
								y:[ground tileAt:CGPointMake(x, y)].position.y/PTM_RATIO];
					} else if (collision && [collision compare:@"left"] == NSOrderedSame) {
						[[Table alloc] init:_world type:2 
								x:[ground tileAt:CGPointMake(x, y)].position.x/PTM_RATIO 
								y:[ground tileAt:CGPointMake(x, y)].position.y/PTM_RATIO];
					} else if (collision && [collision compare:@"right"] == NSOrderedSame) {
						[[Table alloc] init:_world type:3 
								x:[ground tileAt:CGPointMake(x, y)].position.x/PTM_RATIO 
								y:[ground tileAt:CGPointMake(x, y)].position.y/PTM_RATIO];
					} else if (collision && [collision compare:@"full"] == NSOrderedSame) {
						[[Table alloc] init:_world type:4 
								x:[ground tileAt:CGPointMake(x, y)].position.x/PTM_RATIO 
								y:[ground tileAt:CGPointMake(x, y)].position.y/PTM_RATIO];
					}
				}
			}
		}
	}
	NSLog(@"Enter the loadTmxTiledMap method2");
	
	// 读取对象层中配置的数据(将所有形状均保存至1个统一的数组 _shapes,便于在越界的时候做清除遍历)~
	CCTMXObjectGroup *objects = [_gameMap objectGroupNamed:@"Objects"];
	NSAssert(objects != nil, @"'Objects' object group not found");
	
	for( NSMutableDictionary *child in [objects objects] ) {
		CGPoint p = CGPointMake([[child valueForKey:@"x"] intValue], [[child valueForKey:@"y"] intValue]);
		CGSize sz = CGSizeMake([[child valueForKey:@"w"] intValue], [[child valueForKey:@"h"] intValue]);
		float rotateDegree = [[child valueForKey:@"r"] floatValue];
		if( [[child valueForKey:@"name"] isEqual: @"Triangle"] ) {	// 三角形~
			BYTriangle *triangle = [[BYTriangle alloc] init:_world 
								size:sz 
								 rotate:rotateDegree 
							textureImgName:@"darkWoodenTexture.png"];
			[_shapes addObject:triangle];
		} else if ( [[child valueForKey:@"name"] isEqual:@"Rectangle"] ) {	// 矩形~
			BYRectangle *rectangle = [[BYRectangle alloc] init:_world 
									size:sz 
									rotate:rotateDegree 
								insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
								outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
								textureImgName:@"redWoodFloor.png" 
								noiseImgName:@"paperNoise_compact512.png"];
			[_shapes addObject:rectangle];
		} else if ( [[child valueForKey:@"name"] isEqual:@"Trapezium"] ) {	// 梯形~
			BYTrapezium *trapezium = [[BYTrapezium alloc] init:_world 
									size:sz 
									rotate:rotateDegree 
								   insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
								  outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
								textureImgName:@"colorMixed_compact256.png"];
			[_shapes addObject:trapezium];
		} else if ( [[child valueForKey:@"name"] isEqual:@"Pentagon"] ) {	// 五边形~
			BYPentagon *pentagon = [[BYPentagon alloc] init:_world 
								size:sz 
								rotate:rotateDegree];
			[_shapes addObject:pentagon];
		} else if ( [[child valueForKey:@"name"] isEqual:@"Sexangle"] ) {	// 六边形~
			BYSexangle *sexangle = [[BYSexangle alloc] init:_world 
								size:sz 
								 rotate:rotateDegree 
								insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
								outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
								textureImgName:@"greenStoneTexture.png"];
			[_shapes addObject:sexangle];
		} else if ( [[child valueForKey:@"name"] isEqual:@"Circle"] ) {	// 圆~
			BYCircle *circle = [[BYCircle alloc] init:_world 
								size:sz 
								rotate:rotateDegree];
			[_shapes addObject:circle];
		}
	}
//	for(int i = 0; i < [_shapes count]; i ++) {
//		NSLog(@"shape%d 的角度为: %0.2f", i, CC_RADIANS_TO_DEGREES([[_shapes objectAtIndex:i] getSprite].rotation));
//	}
}

-(void) initMemberVariable {
	_spriteContainer = [[NSMutableArray alloc] init];	// init sprite container
	
	_shapes = [[NSMutableArray alloc] init];	// 真bug,_shapes没有初始化竟然编译通过运行时也不报错,nnd~
	
	// Set up sprite, you could get this batchNode by tag anywhere in this class
	_testBatch = [CCSpriteBatchNode batchNodeWithFile:@"blocks.png" capacity:150];
	[self addChild:_testBatch z:0 tag:kTagDemoNode];
	
	_eleBallBatch = [CCSpriteBatchNode batchNodeWithFile:@"ele-ball.png" capacity:1];
	[self addChild:_eleBallBatch z:0 tag:kTagEleBallNode];
	
	_eleBoxBatch = [CCSpriteBatchNode batchNodeWithFile:@"ele-box.png" capacity:150];
	[self addChild:_eleBoxBatch z:0 tag:kTagEleBoxNode];
}

-(id) init {
	if( (self=[super init])) {
		self.isTouchEnabled = YES;	// 1.启用屏幕的触摸,三轴陀螺仪特性~
//		self.isAccelerometerEnabled = YES;	//enable accelerometer	
		[self createBox2dWorld];	// 2.创建 box2d 物理模拟世界~
		[self initMemberVariable];	// 3.初始化该类的一些成员变量~
		[self loadTmxTiledMap];		// 4.加载 TiledMap 地图
		[self addToolBar];		// 5.添加形状条~
		[self schedule: @selector(tick:)];	// 6.指定计划任务方法(每隔一段固定的时间就调用1次)~
	}
	return self;
}


-(void) draw {	// draw will be called fps
	CC_DISABLE_DEFAULT_GL_STATES();
	glEnableClientState(GL_VERTEX_ARRAY);
	
	_world->DrawDebugData();
	 
	// restore default GL states
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

-(BOOL) isPositionOutOfBounds:(CGPoint)p {	// 判断 BYShape 对象是否越界,越界即将之销毁(可用来判定游戏失败)~
	BOOL flag = NO;
	if(p.x < -320.0f || p.x > 640.0f || p.y < -480.0f) {	// 将范围适当扩大,避免失真~
		flag = YES;
	}
	return flag;
}

-(void) tick: (ccTime) dt {
    int32 velocityIterations = 8;  
    int32 positionIterations = 1;  

    _world->Step(dt, velocityIterations, positionIterations);  
	
    b2Body *node = _world->GetBodyList();  
    while(node) {  
        b2Body *b = node;  
        if(b->GetUserData() != NULL) {  
            //Synchronize(同步) the AtlasSprites position and rotation with the corresponding(相应的) body
            // 根据 box2d 对物理世界的现实模拟得到的结果同步更新 精灵的位置以及旋转角度~
	    BYShape *shape = (BYShape*)b->GetUserData();
            CCSprite *myActor = [shape getSprite];
            CGPoint position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO );  
			
            if([self isPositionOutOfBounds:position] == NO) {	// 如果没有越界的话,实时更新~
                myActor.position = position;
                myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
                node = node->GetNext();
            } else {
                // 1.在1个物体摧毁之前一切都很顺利。1旦1个物体摧毁了,它的next指针就变得非法,所以 b2Body::GetNext()就会返回垃圾。  
                // 解决方法是在摧毁之前拷贝 next 指针。
                node = node->GetNext();
		[_shapes removeObject:shape];	// 将 body 所属的 BYShape 对象从 _shapes 中移除~
		[shape dealloc];	// 释放 shape 对象所占用的内存(包括销毁 b2Body,b2Fixture,CCSprite 对象)~
            }
        } else {  
            node = node->GetNext();  
        }  
    }
}


-(void) addNewSpriteWithCoords:(CGPoint)p {
	CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [self getChildByTag:kTagDemoNode];
	
	//We have a 64 x 64 sprite sheet with 4 different 32 x 32 images.
	//The following code is just randomly picking one of the images
	int idx = (CCRANDOM_0_1() > 0.5 ? 0 : 1);
	int idy = (CCRANDOM_0_1() > 0.5 ? 0 : 1);
	CCSprite *sprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake(32*idx, 32*idy, 32, 32)];
	[batch addChild:sprite];
	
	sprite.position = ccp( p.x, p.y);
	
	//add sprite into container
	[_spriteContainer addObject:sprite];
	NSLog(@"new sprite added at x:%d y:%d", p.x, p.y);
}


- (void) addBallElementWithCoords:(CGPoint)p {	// 保留这个方法是为实验销毁BYShape对象是否符合要求~
	// ****************************** 多边形 ***********************************
	CGPoint *input = new CGPoint[4];
	input[0] = ccp(0, 0);
	input[1] = ccp(10, 50);
	input[2] = ccp(50, 50);
	input[3] = ccp(40, 0);
	BYTextureDef *textureDef = [[BYTextureDef alloc] init:input vertexCount:4 
						insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
						outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
						textureImgName:@"greenWaveTexture.png" 
						 noiseImgName:@"Noise_compact512.png" 
						rotateDegree:0];
	
	BYPolygon *elePolygon = [[BYPolygon alloc] init:_world textureDef:textureDef];
	[self addChild:[elePolygon getSprite]];
	[elePolygon addSprite2b2World:p];
	
	// ******************************* 矩形 *******************************
	BYRectangle *rectangle = [[BYRectangle alloc] init:_world 
							size:CGSizeMake(80.0f, 15.0f) 
						insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
						outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
						textureImgName:@"redWoodFloor.png" 
						noiseImgName:@"paperNoise_compact512.png"];
	[self addChild:[rectangle getSprite]];
	[rectangle addSprite2b2World:p];
	
	// ******************************* 三角形 *******************************	
	BYTriangle *triangle = [[BYTriangle alloc] init:_world size:CGSizeMake(60.0f, 30.0f)
							 textureImgName:@"darkWoodenTexture.png"];
	[self addChild:[triangle getSprite]];
	[triangle addSprite2b2World:p];
	
	// ******************************* 梯形 *******************************
	BYTrapezium *trapezium = [[BYTrapezium alloc] init:_world size:CGSizeMake(60.0f, 30.0f)
						insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
						outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
						textureImgName:@"colorMixed_compact256.png"];
	[self addChild:[trapezium getSprite]];
	[trapezium addSprite2b2World:p];
	
	// ******************************* 五边形 *******************************
	BYPentagon *pentagon = [[BYPentagon alloc] init:_world 
						 size:CGSizeMake(80.0f, 80.0f)];
	[self addChild:[pentagon getSprite]];
	[pentagon addSprite2b2World:p];
	
	// *********************** 六边形(宽高比 115.4:100 ) **************************
	BYSexangle *sexangle = [[BYSexangle alloc] init:_world 
						size:CGSizeMake(57.0f, 50.0f)
					insideColor:(ccColor4F){0, 0.0f, 0, 0.3f} 
					outsideColor:(ccColor4F){1.0f, 1.0f, 1.0f, 0.7f} 
					textureImgName:@"greenStoneTexture.png"];
	[self addChild:[sexangle getSprite]];
	[sexangle addSprite2b2World:p];
	
	// ******************** 圆形 ************************
	BYCircle *circle = [[BYCircle alloc] init:_world 
					size:CGSizeMake(30.0f, 180.0f)];
	[self addChild:[circle getSprite]];
	[circle addSprite2b2World:p];
}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	for( UITouch *touch in touches ) {
		CGPoint location = [touch locationInView: [touch view]];
		location = [[CCDirector sharedDirector] convertToGL: location];
		[self addBallElementWithCoords:location];
	}
}

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	for( UITouch *touch in touches ) {
		CGPoint location = [touch locationInView: [touch view]];
		location = [[CCDirector sharedDirector] convertToGL: location];
		CCSprite *shapeSprite = [[_toolBar getFirstShape] getSprite];
		shapeSprite.position = ccp(location.x, location.y);
	}
//	NSLog(@"ccTouchesMoved");
}


- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	for( UITouch *touch in touches ) {
		CGPoint location = [touch locationInView: [touch view]];
		location = [[CCDirector sharedDirector] convertToGL: location];
		CCSprite *shapeSprite = [[_toolBar getFirstShape] getSprite];
		[(BYShape*)shapeSprite.userData addSprite2b2World:ccp(location.x, location.y)];
		[_toolBar removeFirstShape];
	}
	NSLog(@"ccTouchesEnded");
}


- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
	NSLog(@"ccTouchesCancelled");
}


// on "dealloc" you need to release all your retained objects
- (void) dealloc {
	// 1.if the object extends CCNode, you needn't care how to free the heap space(dynamic allocated memmery-space)
	// 2.if the object is contained by objective-c_baseclass_framework, free heapspace by "[*** dealloc];"
	// 3.if the object comes from box2d(writing in C++), free heapspace by "delete ****;"
	delete _world;
	_world = NULL;
	
	delete _m_debugDraw;
	_m_debugDraw = NULL;
	
	// below is the second case! since the CCSpriteBatchNode extends CCNode,
	// there is no need to dealloc it! so, below is no neccessary!
//	[_testBatch dealloc];
//	[_eleBallBatch dealloc];
//	[_eleBoxBatch dealloc];
	
	// below is the third case!
	[_spriteContainer dealloc];
	[_eleBallContainer dealloc];
	[_shapes dealloc];
	
	// don't forget to call "super dealloc"
	[super dealloc];
}

@end

你可能感兴趣的:(properties,object,table,delete,input,Shapes)