比较完美版本的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