Why doesn't gravity scale work in box2d - iphone

I am trying to turn off gravity on one of my bodies. I have used the bodyDef.gravityScale = 0.0f but I am having no luck. Here u can look at my code below. Please help.
b2BodyDef monkey1BodyDef;
monkey1BodyDef.position.Set(0, 200/PTM_RATIO);
monkey1BodyDef.type = b2_dynamicBody;
monkey1BodyDef.userData = monkey1;
monkey1BodyDef.bullet = true;
monkey1BodyDef.gravityScale = 0.0f; //Why doesn't this work I get an error that says no member named 'gravityScale' in 'b2BodyDef'
b2Body *monkey1Body = world->CreateBody(&monkey1BodyDef);

I've hit this problem too. After a little digging I've found that the stable Cocos2D builds don't include recent versions of Box2D, so gravityScale is missing from b2BodyDef. That explains the discrepancy with the Box2D documentation.
There are workarounds, but I've opted to update my Box2D to 2.2.1 (currently the latest). In doing that I encountered the following issues (with solutions):
The b2PolygonShape.SetAsEdge method no longer exists. If you're using that to define screen boundaries you'll need to use something like "myPolygonShape.Set(lowerLeftCorner, lowerRightCorner);" for each screen edge. There's an excellent discussion of this at Programmers' Goodies.
b2DebugDraw has been superseded by b2Draw. Just replace any calls to b2DebugDraw with b2Draw and you should be set. For example, if, like me, you're using the Cocos2D Box2D template, you'll need to replace this:
// Debug Draw functions
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
_world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2DebugDraw::e_shapeBit;
flags += b2DebugDraw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);
with this:
// Debug Draw functions
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
_world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);
b2Transform has different attribute names for position and rotation. For example, myTransform.position is now myTransform.p (but is still a b2Vec2). myTransform.R, which was defined as b2Mat22, has been replaced with myTransform.q, defined as b2Rot. Again, if you're using the Cocos2D Box2D template, replace the following in GLES-Render.mm:
void GLESDebugDraw::DrawTransform(const b2Transform& xf)
{
b2Vec2 p1 = xf.position, p2;
const float32 k_axisScale = 0.4f;
p2 = p1 + k_axisScale * xf.R.col1;
DrawSegment(p1,p2,b2Color(1,0,0));
p2 = p1 + k_axisScale * xf.R.col2;
DrawSegment(p1,p2,b2Color(0,1,0));
}
…with:
void GLESDebugDraw::DrawTransform(const b2Transform& xf)
{
b2Vec2 p1 = xf.p, p2;
const float32 k_axisScale = 0.4f;
p2 = p1 + k_axisScale * xf.q.GetXAxis();
DrawSegment(p1,p2,b2Color(1,0,0));
p2 = p1 + k_axisScale * xf.q.GetXAxis();
DrawSegment(p1,p2,b2Color(0,1,0));
}
I hope this helps!

Because no member named 'gravityScale' exists in 'b2BodyDef' :(
documentation is outdated compared with the code

Change gravity definition of world, coz it's world, that have gravity, As:
b2Vec2 gravity = b2Vec2(0.0f, -10.0f);
bool doSleep = false;
world = new b2World(gravity, doSleep);
World is b2World

If body.setGravityScale(0); doesn't work, you can use it with body.setAwake(false); at second line.

Related

Unity: Ignore collision of a plateform if jump to it from below. Using ContactFilter & rigidBody.Cast()

I am able to avoid a collision between my player and my entire plateform with the use of contactFilter2D.SetLayerMask() + rigidBody2D.Cast(Vector2, contactFilter, ...);
But I don't find a way to avoid the collision only if my player try to acces to the plateform from below it (with a vertical jump).
I'm pretty sure I should use the contactFilter2D.setNormalAngle() (after specify the minAngle and maxAngle) but no matter the size of my angles, I can't pass threw it.
This is how I initialize my contactFilter2D.
protected ContactFilter2D cf;
void Start () {
cf.useTriggers = false;
cf.minNormalAngle = 0;
cf.maxNormalAngle = 180;
cf.SetNormalAngle(cf.minNormalAngle, cf.maxNormalAngle);
cf.useNormalAngle = true;
}
void Update () {
}
I use it with
count = rb.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
Any ideas ? If you want more code, tell me. But I don't think it will be usefull to understand the matter.
unity actualy has a ready made component for this: it is a physics component called "Platform Effector 2D" if you drag and drop it on your platform it will immediately work the way you want, and it has adjustable settings for tweaking the parameters. hope this helps!

Using a Tilemap composite collider as a trigger, what is the best approach for getting hold of the subcollider that is actually being triggered?

This seems a lot less straight forward than perhaps it should be. I'm using a Tilemap with a composite collider set up as a trigger to draw ladders on the map, and want to lock the player to the central x point of the ladder when they're climbing it. However, I'm hitting a wall in that it seems very difficult to simply get ahold of the individual tile that is being collided with.
The method mentioned elsewhere only works for collisions (ie non-triggers), and even that seems somewhat convoluted for what I would've expected to be a routine task.
Does anyone have any suggestions how to do this? I need to either somehow get the contact point of the trigger (seems to be unsupported) in order to then fire a ray to get the collider, or otherwise add additional gameobjects to the scene that can act as anchors for the ladder, which seems to go against the point of using tilemaps.
Thanks for any help.
There is a way to create a separate collider at the tile location of the tile map to use that location.
It is more accurate than raycast.
Because it is an example script, please refactor and use it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
[RequireComponent( typeof( Tilemap ) )]
public class TilemapCollider : MonoBehaviour
{
Tilemap t;
void Start()
{
t = GetComponent<Tilemap>();
BoundsInt bounds = t.cellBounds;
TileBase[] allTiles = t.GetTilesBlock( bounds );
var s = t.layoutGrid.cellSize / 2;
var availablePlaces = new List<Vector3>();
for( int n = t.cellBounds.xMin; n < t.cellBounds.xMax; n++ )
{
for( int p = t.cellBounds.yMin; p < t.cellBounds.yMax; p++ )
{
Vector3Int localPlace = ( new Vector3Int( n, p, (int)t.transform.position.y ) );
Vector3 place = t.CellToWorld( localPlace );
var tile = t.GetTile( localPlace );
if( tile )
{
availablePlaces.Add( place );
var c = new GameObject().AddComponent<BoxCollider2D>();
c.isTrigger = true;
c.transform.parent = t.transform;
c.transform.localPosition = t.CellToLocal( localPlace ) + s;
Debug.Log( "x:" + n + " y:" + p + " tile:" + tile.name );
}
}
}
}
}
TilemapCollider.cs
private void OnTriggerEnter2D( Collider2D collision )
{
var tilemap = GameObject.Find( "Grid/Tilemap" ).GetComponent<Tilemap>();
tilemap.SetTile( tilemap.WorldToCell( collision.transform.position ), null );
}
Example of finding a location on OnTriggerEnter2D

How to detect a touch inside a box2d fixture created by PhyicsEditor in Cocos2d-x?

My testing environment:
Xcode 4.6, New cocos2d-x+box2d project
cocos2d-2.1beta3-x-2.1.1
PhysicsEditor 1.0.10
I modified a bit in HelloWorldScene of PhysicsEditor cocos2dx demo to make it simpler, Here are some of my code:
initPhysics
gravity.Set(0.0f, 0.0f);
So that the sprite will not move.
Replace source code inside ccTouchesEnded to:
CCTouch* pTouch = (CCTouch *)touches->anyObject();
CCPoint location = pTouch->locationInView(pTouch->view());
CCPoint convLoc = CCDirector::sharedDirector()->convertToGL(location);
b2Vec2 v = b2Vec2(convLoc.x/PTM_RATIO, convLoc.y/PTM_RATIO);
for (b2Body *b = world->GetBodyList(); b; b = b->GetNext())
{
b2Fixture *f = b->GetFixtureList(); // get the first fixture
CCSprite *sprite =(CCSprite *) b->GetUserData();
if(sprite != NULL)
{
if(f -> TestPoint(v))
{
CCLog("You touched a body %d",sprite->getTag());
}
}
}
The problem is that TestPoint only return true in a very small area (not for whole shape area).
Here is the screenshot:
Can anybody suggest how I debug this problem? Thanks
Updated: showing the generated data from PhysicsEditor
The problem is that you only probe for the first fixture. But complex bodies are made from several. The reason is that
Box2d only allows 8 vertexes per fixture
Box2d can only work with convex shapes
This is why complex shapes are decomposed into a list of polygons.
Iterate over the fixture list instead.
b2Fixture *f = body->GetFixtureList();
while(f)
{
if(f -> TestPoint(v))
{
CCLog("You touched a body %d",sprite->getTag());
}
f = f->GetNext();
}

Chipmunk 6 space initialization

I am trying to use chipmunk6.x and having problems with it. It is not creating the physics environment. How do I enable the chipmunk6.x physics environment in my project? The space manager system is working well. I hope there is no problem with the chipmunk lib attachment.
I am using the cocos2d old version I just replaced the chipmunk lib.
space = cpSpaceNew();
space->gravity = cpv(0, -100);
//
// rogue shapes
// We have to free them manually
//
// bottom
cpShape *walls_[4];
walls_[0] = cpSegmentShapeNew( space->staticBody, cpv(0,0), cpv(s.width,0), 0.0f);
// top
walls_[1] = cpSegmentShapeNew( space->staticBody, cpv(0,s.height), cpv(s.width,s.height), 0.0f);
// left
walls_[2] = cpSegmentShapeNew( space->staticBody, cpv(0,0), cpv(0,s.height), 0.0f);
// right
walls_[3] = cpSegmentShapeNew( space->staticBody, cpv(s.width,0), cpv(s.width,s.height), 0.0f);
for( int i=0;i<4;i++) {
walls_[i]->e = 1.0f;
walls_[i]->u = 1.0f;
cpSpaceAddStaticShape(space, walls_[i] );
}
You need to be more specific than "It is not creating the physics environment."
The code you pasted otherwise looks fine. What happens with it, and what are you expecting should happen.

PhysX 3.2: Simple box dynamic are not moving

I've uppgraded to PhysX 3.2 and have been struggling for days to have my test box moved by gravity but it simply won't to it.
I've followed the PhysX documentation but implemented it in my way. It's pretty much a default setup:
physx::PxSceneDesc sceneDesc = physx::PxSceneDesc((physx::PxTolerancesScale()));
sceneDesc.gravity = physx::PxVec3(0.0f, -9.8f, 0.0f);
if(!sceneDesc.cpuDispatcher)
{
physx::PxDefaultCpuDispatcher* mCpuDispatcher = physx::PxDefaultCpuDispatcherCreate(4);
if(!mCpuDispatcher)
LOG("PxDefaultCpuDispatcherCreate failed!");
sceneDesc.cpuDispatcher = mCpuDispatcher;
}
if(!sceneDesc.filterShader)
sceneDesc.filterShader = &physx::PxDefaultSimulationFilterShader;
physxScene = physMgr->getSDK()->createScene(sceneDesc);
Creating the dynamic actor:
PxRigidDynamic* body = mPxSDK->createRigidDynamic(Convert::toPxTransform(transform));
PxRigidBodyExt::updateMassAndInertia(*body, 1.0f);
mPxScene->addActor(*body);
Add the box shape:
PxBoxGeometry geometry = PxBoxGeometry(Convert::toPxVector3(size));
if(geometry.isValid())
{
PxMaterial* material = api->createMaterial(0.5f, 0.5f, 0.1f);
PxShape* shape = createShape(actor, geometry, material);
PxRigidBodyExt::updateMassAndInertia(*body, 33.0f);
}
Simulating the scene as:
float elapsedTime = float((float)mTime.getElapsedTime() / 1000.0f);
mAccumulator += elapsedTime;
if(mAccumulator < mStepSize)
{
return;
}
else
{
mAccumulator -= mStepSize;
mPxScene->simulate(mStepSize);
mDynamicBodySys->updateGameObjectPositions();
mPxScene->fetchResults(true);
mTime.restart();
}
When I look into the Visual Debugger I can see the box and the frame count increasing. But it's not moving. The actor's and the box shape seem to have the correct propeties. LinearVelocity is increasing in negative Y axis, its mass is 33 etc. But the pose is still zero/identity. What am I missing?
Solved. The error was in my own logic. There was a sync logic problem where PhysX was trying to update my graphics while in the same time my positioning logic was telling PhysX to update with its previous position. So it got stuck and appeared to never be simulated.