我正在制作一款游戏,我需要一个只在按下按钮时移动的对象。我有一个开始运动的方法,到目前为止,我通过破坏物体的主体来结束物体的运动。我遇到的问题是,我不能再次移动对象,因为程序现在会崩溃。我想知道是否有一种方法来重建身体一旦它被摧毁,因为我目前的检查身体是否仍然存在的方法是不工作。
这是我的代码。NSMutableArray *spaceObjectsArray;
#pragma mark - HelloWorldLayer
@interface HelloWorldLayer()
-(void) initPhysics;
-(void) addNewSpriteAtPosition:(CGPoint)p;
-(void) createMenu;
@end
@implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(void)gameLogic:(ccTime)delta
{
[self addSpaceObjects];
}
-(void) addSpaceObjects
{
_spaceObject = [CCSprite spriteWithFile:@"blueDot.jpg"];
//create spaceObject body
b2BodyDef spaceObjectbBodyDef;
spaceObjectbBodyDef.type=b2_dynamicBody;
spaceObjectbBodyDef.userData = _spaceObject;
//make the location of spaceObject
CGSize winSize = [CCDirector sharedDirector].winSize;
int minX= _spaceObject.contentSize.width/2;
int maxX = winSize.width - _spaceObject.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
_spaceObject.position = ccp(actualX, winSize.height + _ship.contentSize.height);
spaceObjectbBodyDef.position.Set(actualX/PTM_RATIO, (winSize.height+_ship.contentSize.height)/PTM_RATIO);
_spaceObjectBody= _world->CreateBody(&spaceObjectbBodyDef);
//create spaceObject shape
b2PolygonShape spaceObjectShape;
spaceObjectShape.SetAsBox(_spaceObject.contentSize.width/PTM_RATIO/2, _spaceObject.contentSize.height/PTM_RATIO/2);
//create spaceObject fixture
b2FixtureDef spaceObjectShapeDef;
spaceObjectShapeDef.shape= &spaceObjectShape;
spaceObjectShapeDef.density = 2;
spaceObjectShapeDef.restitution =0;
spaceObjectShapeDef.friction=0;
_spaceObjectFixture = _spaceObjectBody->CreateFixture(&spaceObjectShapeDef);
[self addChild:_spaceObject];
_spaceObject.tag=1;
[spaceObjectsArray addObject:_spaceObject];
//aply force on the object
int randomValue = ((arc4random() % 5) *-1);
b2Vec2 force = b2Vec2(0,randomValue);
_spaceObjectBody ->ApplyLinearImpulse(force, _spaceObjectBody->GetPosition());
}
init方法,包含body的创建和定义
-(id) init
{
if( (self=[super init])) {
CGSize s = [CCDirector sharedDirector].winSize;
//create spaceShip sprite and add it to the layer
_ship = [CCSprite spriteWithFile:@"theShip.gif" ];
_ship.position = ccp(s.width/2, 1.25*_ship.contentSize.height);
[self addChild:_ship];
//create the world
b2Vec2 gravity = b2Vec2_zero;
_world = new b2World(gravity);
//create ship body
b2BodyDef shipBodyDef;
shipBodyDef.type = b2_dynamicBody;
shipBodyDef.position.Set((s.width/2)/PTM_RATIO, (1.25*_ship.contentSize.height)/PTM_RATIO);
shipBodyDef.userData = _ship;
if(_shipBody == NULL){
_shipBody =_world->CreateBody(&shipBodyDef);
}
//create ship shape
b2PolygonShape shipShape;
shipShape.SetAsBox(_ship.contentSize.width/PTM_RATIO/2, _ship.contentSize.height/PTM_RATIO/2);
//create Ship definition and add to body
b2FixtureDef ShipShapeDef;
ShipShapeDef.shape = &shipShape;
ShipShapeDef.density = 3;
ShipShapeDef.friction =0;
ShipShapeDef.restitution =0;
_shipFixture = _shipBody->CreateFixture(&ShipShapeDef);
//make the paddles
//bottom left one
_paddle1 = [CCSprite spriteWithFile:@"spritePaddle.jpeg"];
int bottomOfScreenX = 0 + _paddle1.contentSize.width/2;
int bottomOfScreenY = 0+_paddle1.contentSize.height/2;
_paddle1.position = ccp(bottomOfScreenX,bottomOfScreenY);
[self addChild:_paddle1];
//bottom right one
_paddle2 = [CCSprite spriteWithFile:@"spritePaddle.jpeg"];
int bottomRightOfScreenX = s.width - _paddle2.contentSize.width/2;
_paddle2.position = ccp(bottomRightOfScreenX, bottomOfScreenY);
[self addChild:_paddle2];
//continuously spawn spaceObjects
[self schedule:@selector(gameLogic:) interval:1];
// enable events
self.touchEnabled = YES;
// init physics
[self schedule:@selector(tick:)];
}
return self;
}
-(void)tick:(ccTime) delta
{//this method is to simulate physics and to test for the position of where objects should be if force has been applied to them
_world->Step(delta, 8, 8);
for (b2Body *b=_world->GetBodyList(); b; b=b->GetNext()){
if (b->GetUserData() != NULL){
CCSprite *shipData = (CCSprite *)b->GetUserData();
shipData.position = ccp(b->GetPosition().x *PTM_RATIO, b->GetPosition().y *PTM_RATIO);
}
}
}
移动船的桨被触碰逻辑
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//Set up a way for touches to be turned into locations onscreen
NSSet *allTouches = [event allTouches];
UITouch *touch = [allTouches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location ];
//check to see if Left Paddle is being pressed
if (CGRectContainsPoint([_paddle1 boundingBox], location)){
b2Vec2 force = b2Vec2(-5,0);
_shipBody->ApplyLinearImpulse(force, _shipBody ->GetPosition());
}
if (CGRectContainsPoint([_paddle2 boundingBox], location)){
b2Vec2 force = b2Vec2(5,0);
_shipBody->ApplyLinearImpulse(force, _shipBody->GetPosition());
}
}
桨盒不再被触碰逻辑
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
_world->DestroyBody(_shipBody);
}
-(void) dealloc
{
delete _world;
_world = NULL;
[super dealloc];
}
@end
破坏身体来结束它的运动并不是最好的解决方案。只有当你真的不希望它再成为模拟的一部分时,你才应该删除它。
有几个选项可以停止身体的运动:
1 -将其线速度设置为0。这将使它立即停止。如果有其他东西在推动它(例如与身体接触),你必须决定怎么做。
body->SetLinearVelocity(b2Vec2(0,0)));
2 -将其线性/角阻尼设置为0。这将消散它的动量,所以它会慢慢停下来。你使用的因子应该大于0。当和的值较大时,物体会更快地停止,它将抵抗来自其他物体的移动(如果它们撞到它,它将减速并再次停止)。当你想让身体开始移动时,记得把线性/角阻尼调回0。
body->SetLinearDamping(0.2);
body->SetAngularDamping(0.2);
3 -将目标位置设置为seek to,并将位置设置为您想要的位置。这基本上是一个反馈控制回路,你在其中施加一个力,让它向你想要身体停留的地方移动。它可以用来让物体跟随路径等等。下面的代码是一个更大的代码库的一部分(您可以在这里看到它),但是您应该能够获得总体思路。该函数对对象施加推力,使其向目标方向推进。
void MovingEntity::ApplyThrust()
{
// Get the distance to the target.
b2Vec2 toTarget = GetTargetPos() - GetBody()->GetWorldCenter();
toTarget.Normalize();
b2Vec2 desiredVel = GetMaxSpeed()*toTarget;
b2Vec2 currentVel = GetBody()->GetLinearVelocity();
b2Vec2 thrust = GetMaxLinearAcceleration()*(desiredVel - currentVel);
GetBody()->ApplyForceToCenter(thrust);
}