现在的位置: 首页 > 综合 > 正文

cocos2d简单弹球

2013年10月11日 ⁄ 综合 ⁄ 共 5074字 ⁄ 字号 评论关闭

cocos2d简单弹球


今天我们介绍如何用cocos2d/Box2d实现一个简单的弹球程序:点击屏幕会新生成一个小球,在下落过程中碰到其他球或墙壁则会反弹。



1.

新建一个cocos2d/Box2d Application,输入名称Ball:




2.

修改HelloWorldLayer.h如下:

#import "cocos2d.h"
#import "Box2D.h"


// HelloWorldLayer
@interface HelloWorldLayer : CCLayer
{
	CGSize _screenSize;
	
	b2World * _world;
	b2Body * _groundBody;
}


+(CCScene *)scene;
-(void)initWorld;
-(void)addBall:(CGPoint)p;
-(void)showLabel:(NSString *)str fontName:(NSString *)name fontSize:(int)size position:(CGPoint)pos rgb:(ccColor3B)color;

@end

函数功能不解释了,看名字就知道了。




3.

修改HelloWorldLayer.mm如下:

#import "HelloWorldLayer.h"


#define PTM_RATIO 32


// HelloWorldLayer implementation
@implementation HelloWorldLayer

+(CCScene *)scene
{
	CCScene * scene = [CCScene node];

	HelloWorldLayer * layer = [HelloWorldLayer node];

	[scene addChild: layer];

	return scene;
}



-(id)init
{
	if( (self=[super init]))
	{
		// Enable touches
		self.isTouchEnabled = YES;
	
		_screenSize = [CCDirector sharedDirector].winSize;
		CCLOG(@"Width: %0.2f, Height: %0.2f", _screenSize.width, _screenSize.height);
		
		// Init the world
		[self initWorld];
		
		//Create the sprite
		[self addBall:CGPointMake((int)(_screenSize.width / 2), (int)(_screenSize.height / 2))];

		//Show label
		[self showLabel:@"Tap screen" fontName:@"Marker Felt" fontSize:32 position:ccp(_screenSize.width/2, _screenSize.height-50) rgb:ccc3(0,0,255)];
		
		[self schedule: @selector(tick:)];
	}
	return self;
}



-(void)initWorld
{
	// Create the world
	b2Vec2 gravity;
	gravity.Set(0.0f, -10.0f);
	bool doSleep = true;
	_world = new b2World(gravity, doSleep);
	_world->SetContinuousPhysics(true);
	
	// Create the ground
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0,0);
	_groundBody = _world->CreateBody(&groundBodyDef);
	
	b2PolygonShape groundBox;
	b2FixtureDef groundBoxDef;
	groundBoxDef.shape = &groundBox;
	
	groundBox.SetAsEdge(b2Vec2(0, 0), b2Vec2(_screenSize.width / PTM_RATIO, 0));
	_groundBody->CreateFixture(&groundBoxDef);
	
	groundBox.SetAsEdge(b2Vec2(0, 0), b2Vec2(0, _screenSize.height / PTM_RATIO));
	_groundBody->CreateFixture(&groundBoxDef);
	
	groundBox.SetAsEdge(b2Vec2(0, _screenSize.height / PTM_RATIO), b2Vec2(_screenSize.width / PTM_RATIO, _screenSize.height / PTM_RATIO));
	_groundBody->CreateFixture(&groundBoxDef);
	
	groundBox.SetAsEdge(b2Vec2(_screenSize.width / PTM_RATIO, _screenSize.height / PTM_RATIO), b2Vec2(_screenSize.width / PTM_RATIO, 0));
	_groundBody->CreateFixture(&groundBoxDef);
}



// Init the world
-(void)addBall:(CGPoint)p
{
	CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);
	

	//Create the sprite
	CCSprite * ballSprite = [CCSprite spriteWithFile:@"Ball.jpg" rect:CGRectMake(0, 0, 52, 52)];
	ballSprite.position = p;
	ballSprite.tag = 1;
	[self addChild:ballSprite];
	
	
	// Create ball body 
	b2BodyDef ballBodyDef;
	ballBodyDef.type = b2_dynamicBody;
	ballBodyDef.position.Set(p.x / PTM_RATIO, p.y / PTM_RATIO);
	ballBodyDef.userData = ballSprite;
	b2Body * ballBody = _world->CreateBody(&ballBodyDef);
	
	// Create circle shape
	b2CircleShape circle;
	circle.m_radius = 26.0 / PTM_RATIO;
	
	// Create shape definition and add to body
	b2FixtureDef ballShapeDef;
	ballShapeDef.shape = &circle;
	ballShapeDef.density = 1.0f;
	ballShapeDef.friction = 0.0f;
	ballShapeDef.restitution = 0.8f;
	ballBody->CreateFixture(&ballShapeDef);
}



-(void)showLabel:(NSString *)str fontName:(NSString *)name fontSize:(int)size position:(CGPoint)pos rgb:(ccColor3B)color
{
	CCLabelTTF * label = [CCLabelTTF labelWithString:str fontName:name fontSize:size];
	[self addChild:label z:0];
	[label setColor:color];
	label.position = pos;
}



-(void)tick: (ccTime) dt
{
	//It is recommended that a fixed time step is used with Box2D for stability
	//of the simulation, however, we are using a variable time step here.
	//You need to make an informed choice, the following URL is useful
	//http://gafferongames.com/game-physics/fix-your-timestep/
	
	int32 velocityIterations = 8;
	int32 positionIterations = 1;
	
	// Instruct the world to perform a single step of simulation. It is
	// generally best to keep the time step and iterations fixed.
	_world->Step(dt, velocityIterations, positionIterations);


	//Iterate over the bodies in the physics world
	for (b2Body * b = _world->GetBodyList(); b; b = b->GetNext())
	{
		if (b->GetUserData() != NULL)
		{
			CCLOG(@"X: %0.2f, Y: %02.f",b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);

			//Synchronize the AtlasSprites position and rotation with the corresponding body
			CCSprite * myActor = (CCSprite *)b->GetUserData();
			myActor.position = CGPointMake(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
			myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
		}
	}
}


- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	//Add a new body/atlas sprite at the touched location
	for(UITouch * touch in touches)
	{
		CGPoint location = [touch locationInView: [touch view]];
		
		location = [[CCDirector sharedDirector] convertToGL: location];
		
		[self addBall:location];
	}
}



- (void)dealloc
{
	delete _world;
	_world = NULL;

	// don't forget to call "super dealloc"
	[super dealloc];
}
@end



在init函数中:

self.isTouchEnabled = YES;

表示启用触摸:在触摸开始时会自动调用ccTouch(es)Began函数,在触摸结束时会自动调用ccTouch(es)Ended函数,在其中我们调用addBall函数创建一个球。


之后我们创建了一个重力为10,垂直向下的World,并在屏幕的四周创建了四面墙壁。


然后我们调用addBall创建一个球:

首先我们创建了一个sprite(精灵),之后创建了一个b2Body,然后用userData将它们绑定起来,方便我们之后获取它。


在init函数的最后我们调用了:

[self schedule: @selector(tick:)];

表示每一帧后都会调用tick函数,而在tick函数中,我们一个一个遍历World中的b2Body,一旦userData不空,我们就把它转为sprite,然后根据b2Body的坐标设置sprite的坐标。



因此可以总结如下:

我们创建了一个cocos2d中的sprite和一个Box2d中的b2Body。sprite通过spriteWithFile函数载入图片,因此可见;b2Body不可见,但它的运动遵循物理定律,因此在b2Body每运动一帧后我们都根据它的坐标设置sprite的坐标,这样看上去就像是这个sprite按物理定律运动一样。



好了,程序很简单,



结果如下:







最后我把代码也上传上来了:

http://download.csdn.net/detail/htttw/4464843






完成!

抱歉!评论已关闭.