Swapping Physics Body on Sprite in Update Function : Error :(


#1

This works fine

INIT
	sprite->setPhysicsBody(physicsBody);
	sprite->setPhysicsBody(physicsBodyShield);

The sprite is assigned one and then the other, the other remains active of course

However, this doesn’t work, breaks

INIT
	sprite->setPhysicsBody(physicsBody);

UPDATE
	sprite->setPhysicsBody(physicsBodyShield);

I’m aware there are other threads about this but no solution that I could understand or get working

How can we swap Physics Bodies during game play ? Thanks


#2

Try first setting nullptr
In Update:

sprite->setPhysicsBody(nullptr);
sprite->setPhysicsBody(physicsBodyShield);

#4

Nah Still breaks :frowning:


#5

okay.
If you are using latest version then try with addComponent & removeComponent
That should work.


#7

sprite->removeComponent(physicsBody);
//sprite->addComponent(physicsBodyShield);
sprite->setPhysicsBody(physicsBodyShield);
Tried both with comments and without , still breaks when set new body or when set new component


#8

For me its working, i had done in lots of games.
I will try to check in simple helloworld and will let you know.


#9

Well let me explain a little further first…

I have a Vehicle Class… The class constructor set up vehicle and sets up two physics bodies

Vehicle::Vehicle()
{
	//CAR SPRITE
	sprite = Sprite::create("Ship/VehicleOne/vehicleOne.png");
	sprite->setPosition(Vec2(-2550 / TIscale, 1000 / TIscale));

	//PHYSICS BODY
	mArray[0] = cocos2d::Vec2(-26 / TIscale, -3 / TIscale);
	mArray[1] = cocos2d::Vec2(-22 / TIscale, -6 / TIscale);
	mArray[2] = cocos2d::Vec2(35 / TIscale, -3 / TIscale);
	mArray[3] = cocos2d::Vec2(37 / TIscale, -1 / TIscale);
	mArray[4] = cocos2d::Vec2(37 / TIscale, 1 / TIscale);
	mArray[5] = cocos2d::Vec2(35 / TIscale, 3 / TIscale);
	mArray[6] = cocos2d::Vec2(-22 / TIscale, 6 / TIscale);
	mArray[7] = cocos2d::Vec2(-26 / TIscale, 3 / TIscale);
	mArray[8] = cocos2d::Vec2(-26 / TIscale, -3 / TIscale);
	physicsBody = PhysicsBody::createPolygon(mArray, 9, PhysicsMaterial(1, 0, 0));
	physicsBody->setCollisionBitmask(4);
	physicsBody->setContactTestBitmask(true);
	physicsBody->setAngularDamping(10);
	physicsBody->setDynamic(true);
	//sprite->setPhysicsBody(physicsBody);

	//SHIELD PHYSCIS BODY INITIALIZED FOR LATER USE
	shieldArray[0] = cocos2d::Vec2(-30 / TIscale, -13 / TIscale);
	shieldArray[1] = cocos2d::Vec2(-36 / TIscale, -9 / TIscale);
	shieldArray[2] = cocos2d::Vec2(-40 / TIscale, -2 / TIscale);
	shieldArray[3] = cocos2d::Vec2(-40 / TIscale, 2 / TIscale);
	shieldArray[4] = cocos2d::Vec2(-36 / TIscale, 9 / TIscale);
	shieldArray[5] = cocos2d::Vec2(-30 / TIscale, 13 / TIscale);
	shieldArray[6] = cocos2d::Vec2(40 / TIscale, 12 / TIscale);
	shieldArray[7] = cocos2d::Vec2(47 / TIscale, 7 / TIscale);
	shieldArray[8] = cocos2d::Vec2(50 / TIscale, 2 / TIscale);
	shieldArray[9] = cocos2d::Vec2(50 / TIscale, -2 / TIscale);
	shieldArray[10] = cocos2d::Vec2(47 / TIscale, -7 / TIscale);
	shieldArray[11] = cocos2d::Vec2(40 / TIscale, -12 / TIscale);
	shieldArray[12] = cocos2d::Vec2(-30 / TIscale, -13 / TIscale);
	physicsBodyShield = PhysicsBody::createPolygon(shieldArray, 13, PhysicsMaterial(0, 0, 0));
	physicsBodyShield->setCollisionBitmask(4);
	physicsBodyShield->setContactTestBitmask(true);
	physicsBodyShield->setAngularDamping(10);
	physicsBodyShield->setDynamic(true);

	sprite->setPhysicsBody(physicsBody);
}

Then I have a fucntion that is called in the scene class by pressing space bar like so

void Vehicle::deployShield()
{
	shieldStatus = false;
	//VEHICLE SPRITE WITH SHIELD - WORKING ON IT
	//sprite = Sprite::create("Ship/VehicleOne/vehicleOneShield.png");
	//sprite->removeComponent(physicsBody);
	//sprite->addComponent(physicsBodyShield);
	//sprite->setPhysicsBody(physicsBodyShield);
}

This is in a keyboard listener function in first world after space bar is pressed, loads of the other weapons work fine with exactly shame functions

				if (playerVehicleObject->getShieldStatus())
				{
					CCLOG("SHIELD ACTIVATED - WORKING ON THIS");
					weaponTimer = 0;
					activeWeaponTimer = true;
					playerVehicleObject->deployShield();
				}

#10

Which version you are using?
I tried in simple helloworld and its working fine in 3.14.1

In init

	sp = Sprite::create("image.png");
	sp->setPosition(viewSize / 2);
	this->addChild(sp);
	pb = PhysicsBody::createCircle(36);
	sp->addComponent(pb);

On Space bar press:

	sp->removeComponent(pb);
	PhysicsBody *pb2 = PhysicsBody::createCircle(72);
	sp->addComponent(pb2);

#11

Ok I’m going to download Cocos2-x new from site and install, then generate new solution, then drag all classes over and build !!

Ill be back


#12

Weird thing here look

//CONSTRUCTOR - DE-CONSTRUCTOR
Vehicle::Vehicle() ://WE INITIALIZE ALL VARIABLES TO DEFAULT VALUES
	trusterStatus(false),
	machineGunStatus(false),
	rocketStatus(false),
	shieldStatus(true),
	mineStatus(false),
	velocityPoint(cocos2d::Vec2(0, 0)),
	angle_I(0.0), angle_II(0.0),
	slowDown(false),
	m_speed(0.0),
	driveStatus(true),
	bulletSpawnPoint(cocos2d::Vec2(0, 0)),
	bulletFirePoint(cocos2d::Vec2(0, 0)),
	weaponStatus("Empty"),
	position(Vec2(0, 0)),
	TIScale(1.7068),//1.7068
	steeringPower(5),
	autoDrive(false),
	angle_III(0.0),
	driveOffTimer(5),
	machineGunVelocity(500),
	machineGunSpawnGap(50),
	m_health(100),
	bullets(10),
	accelerateLock(false),
	de_accelerateLock(false),
	rocketSpeed(200),
	shieldLock(false)
{
	//CAR SPRITE
	sprite = Sprite::create("Ship/VehicleOne/vehicleOne.png");
	sprite->setPosition(Vec2(-2550 / TIscale, 1000 / TIscale));

	//PHYSICS BODY
	mArray[0] = cocos2d::Vec2(-26 / TIscale, -3 / TIscale);
	mArray[1] = cocos2d::Vec2(-22 / TIscale, -6 / TIscale);
	mArray[2] = cocos2d::Vec2(35 / TIscale, -3 / TIscale);
	mArray[3] = cocos2d::Vec2(37 / TIscale, -1 / TIscale);
	mArray[4] = cocos2d::Vec2(37 / TIscale, 1 / TIscale);
	mArray[5] = cocos2d::Vec2(35 / TIscale, 3 / TIscale);
	mArray[6] = cocos2d::Vec2(-22 / TIscale, 6 / TIscale);
	mArray[7] = cocos2d::Vec2(-26 / TIscale, 3 / TIscale);
	mArray[8] = cocos2d::Vec2(-26 / TIscale, -3 / TIscale);
	physicsBody = PhysicsBody::createPolygon(mArray, 9, PhysicsMaterial(1, 0, 0));
	physicsBody->setCollisionBitmask(4);
	physicsBody->setContactTestBitmask(true);
	physicsBody->setAngularDamping(10);
	physicsBody->setDynamic(true);
	//sprite->setPhysicsBody(physicsBody);

	//SHIELD PHYSCIS BODY INITIALIZED FOR LATER USE
	shieldArray[0] = cocos2d::Vec2(-30 / TIscale, -13 / TIscale);
	shieldArray[1] = cocos2d::Vec2(-36 / TIscale, -9 / TIscale);
	shieldArray[2] = cocos2d::Vec2(-40 / TIscale, -2 / TIscale);
	shieldArray[3] = cocos2d::Vec2(-40 / TIscale, 2 / TIscale);
	shieldArray[4] = cocos2d::Vec2(-36 / TIscale, 9 / TIscale);
	shieldArray[5] = cocos2d::Vec2(-30 / TIscale, 13 / TIscale);
	shieldArray[6] = cocos2d::Vec2(40 / TIscale, 12 / TIscale);
	shieldArray[7] = cocos2d::Vec2(47 / TIscale, 7 / TIscale);
	shieldArray[8] = cocos2d::Vec2(50 / TIscale, 2 / TIscale);
	shieldArray[9] = cocos2d::Vec2(50 / TIscale, -2 / TIscale);
	shieldArray[10] = cocos2d::Vec2(47 / TIscale, -7 / TIscale);
	shieldArray[11] = cocos2d::Vec2(40 / TIscale, -12 / TIscale);
	shieldArray[12] = cocos2d::Vec2(-30 / TIscale, -13 / TIscale);
	physicsBodyShield = PhysicsBody::createPolygon(shieldArray, 13, PhysicsMaterial(0, 0, 0));


	sprite->addComponent(physicsBody);
}

In this class I have a deploy shield function

void Vehicle::deployShield()
{
	shieldStatus = false;
	sprite->removeComponent(physicsBody);
	sprite->addComponent(physicsBodyShield);
}

Now above caused null pointer error when i assign new physics body

BUT

If I do this, all im doing is moving that line of code from constructor to this function, it works, the creating physics Shield body… Then it works, why is that ? Do you have any idea ?

void Vehicle::deployShield()
{
	shieldStatus = false;
	sprite->removeComponent(physicsBody);
	physicsBodyShield = PhysicsBody::createPolygon(shieldArray, 13, PhysicsMaterial(0, 0, 0));
	sprite->addComponent(physicsBodyShield);
}

#13

Because its getting released as its not used.
Just retain when you are creating then it will work or create in deployshield method.

physicsBodyShield = PhysicsBody::createPolygon(shieldArray, 13, PhysicsMaterial(0, 0, 0));
physicsBodyShield->retain();