Box2D Gravity to specific object? - ios

I see everyone saying that you add gravity like so in a Box2D world:
b2Vec2 gravity = b2Vec2(0.0f, -10.0f);
bool doSleep = false;
world = new b2World(gravity, doSleep);
The thing is though, what if I want gravity only on a specific b2Body which contains userData from a CCSprite? AFAIK this will apply gravity to everything in the world which I do not want, so can someone explain to me how I can apply this gravity only to a specific b2Body?
Thanks!
Edit1:
Can I just do this line,
_bottomBody->ApplyForce(gravity, _bottomBody->GetPosition());
Instead of the world = new b2World... etc... Wouldn't that work with gravity only on that b2Body?

Just apply a force/impulse to the specific b2Body every frame. It will emulate gravity.
// a procedure called every frame
void Application::on_update_world(double t)
{
m_body_with_custom_gravity->applyForce(CUSTOM_GRAVITY * m_body_with_custom_gravity->getMass());
m_phys_world->Step(t, VEL_ITERATIONS, POS_ITERATIONS);
}
A thread with a question closely related to your:
How to apply constant force on a Box2D body?

Related

Moving layer causes physics object to stay in place

I'm fiddling around with cocos2d v3 in combination with sprite builder.
The game is a simple catch and avoid game, objects coming down an the hero is standing in the bottom of the screen and you can move him around with the accelerometer.
I have a level file (cclayer) with some objects (ccnode) in it, the have physics enabled.
In my update function I move the layer slowly down.
If the objects have physics enabled, they just drop down. If I switch it to statics physics, they stay in place.
The only way I can find to move the object along with the layer is to turn off the physics completely. But then the collisions won't work anymore...
This kept me buys for the past 4 hours or so.
What is the best approach for this situation?
Thanks in advance guys!
this is my update function:
- (void)update:(CCTime)delta {
float maxX = winSize.width - _hero.contentSize.width/2;
float minX = _hero.contentSize.width/2;
CMAccelerometerData *accelerometerData = _motionManager.accelerometerData;
CMAcceleration acceleration = accelerometerData.acceleration;
CGFloat newXPosition = _hero.position.x + acceleration.x * 1000 * delta;
newXPosition = clampf(newXPosition, minX, maxX);
_hero.position = CGPointMake(newXPosition, _hero.position.y);
//level position
CGPoint oldLayerPosition = _levelNode.position;
float xNew = oldLayerPosition.x;
float yNew = oldLayerPosition.y -1.4f;
_levelNode.position = ccp(xNew, yNew);
}
This is a design decision made within the physics engine. Physics bodies do not move with their parents. See: https://github.com/cocos2d/cocos2d-iphone/issues/570
You need to change the design of your game so that your hero moves, and the obstacles stay in the same position. Then you implement a camera like mechanism to follow your moving hero.
We have used the same approach in our flappy bird tutorial.

I'm unable to make my sprites "Flip"

I'll start off by admitting that I am a beginner to ActionScript and I am in the process of coding my own basic arcade game (Similar to that of the old arcade game "Joust"). Whilst I have been able to code the sprite's movement I am looking to make the sprite flip to face the other way when I press the right arrow. I figured either I could try and rotate the object around its axis (Which I've tried multiple times and has proved difficult) or I could try and "Replace" the current sprite with another sprite (Which is just the sprite facing the opposite way). I've searched everywhere for a method of replacing a sprite with another sprite but to no avail. How would it be possible to give this sprite a flip effect when a certain keyCode is used?
Try this simple code below. Here 'object' is the movieclip/sprite that you want to flip
stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
function OnKeyDown(event:KeyboardEvent):void
{
var uiKeyCode:uint = event.keyCode;
switch (uiKeyCode)
{
case Keyboard.LEFT :
object.scaleX = -1; //flip
break;
case Keyboard.RIGHT :
object.scaleX = 1; //unflip
break;
}
}
NOTE: If you want the movieclip to flip without any shift in its position then the movieclip must be horizontally center registered.
Tell me if this works for you.
Are you using as2/as3? you could flip the axis Y 180 degrees
if your using as2 you will need to either mirror the bitmap via actionScript or
add a second bitmap that is mirrored to the display list.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedDown);
function keyPressedDown(event:KeyboardEvent):void
{
var key:uint = event.keyCode;
switch (key)
{
case Keyboard.LEFT :
myMovieClip.rotaionY = 180; // MC will be mirrored
break;
case Keyboard.RIGHT :
myMovieClip.rotaionY = 0;
}

setting the angle of a b2revolutejoint

From what I have read, in Box2d, you get the angle of a revolute joint with the GetJointAngle function, but when trying to set the angle the member m_referenceAngle is protected. Can the angle not be programmatically set?
I found that I can apply the angle from one joint to another body as:
float FirstAngle = firstArmJoint->GetJointAngle();
secondArmBody->SetTransform(b2Vec2((750.0/PTM_RATIO),(520.0f+100)/PTM_RATIO),hourAngle);
I put this in ccTouchesMoved so that when the user drags the first object (from which FirstAngle is retrieved) the second object (secondArmBody) is also moved.
What happens is that the second body rotates at the top of the image and not at the anchor point.
Any ideas?
SetTransform() can be used to set the position and rotation of a body. This happens completely independently of any joints on the body. For example, if you want to make sure a body is perfectly upright at a given moment, you can call
body->SetTransForm(body->GetPosition(), 0);
passing 0 as the angle value (upright). I've never tried this for a body with a joint on it, but I doubt it would work properly.
When I ran into the problem of having to make a revolutejoint point at a certain angle, I solved it by enabling motor on the joint and adjusting the motor speed until the angle matched the one I wanted. This simulates realistic motion of the joint. Example:
Creating the joint
b2RevoluteJointDef armJointDef;
armJointDef.Initialize(body1, body2,
b2Vec2(body1->GetPosition().x,
((body1->GetPosition().y/PTM_RATIO));
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.motorSpeed = 0.0f;
armJointDef.maxMotorTorque = 10000.0f;
armJointDef.lowerAngle = CC_DEGREES_TO_RADIANS(lowerArmAngle);
armJointDef.upperAngle = CC_DEGREES_TO_RADIANS(upperArmAngle);
_world->CreateJoint(&armJointDef);
Pointing the joint
float targetAngle = SOME_ANGLE;
b2JointEdge *j = body->GetJointList();
b2RevoluteJoint *r = (b2RevoluteJoint *)j->joint;
if(r->GetAngle() > targetAngle){
r->SetMotorSpeed(-1);
} else { r->SetMotorSpeed(1); }
Basically, you see what side of the current angle the target angle is on, and then set the motor speed to move the joint in the correct direction. Hope that helps!
http://www.box2d.org/manual.html

Jumping effect in games

I'm currently trying to make a basic platformer with XNA and I'm wondering how to create a "jumping effect." I currently have basic keyboard input which allows for sideways movement, but I would like my sprite to slowly progress into a jump rather than instantly teleporting there (right now I have something like Rectangle.Y += 40 every time I jump, making the sprite instantly appear there). Does anyone have any insight?
I'm not totally across how to implement this in XNA/C#, but in Flash games I've made I just added a vertical velocity property. I'll try write everything as C# as I can..
Example; create the velocity property:
float verticalVelocity = 0;
Vertical velocity should be constantly reduced (by gravity). Set up a gravity property somewhere accessible from your player:
float Gravity = 2.5;
And in your update() method for the player, increment the verticalVelocity by Gravity. Also increment the Y position of your player by the verticalVelocity. This will simulate falling:
verticalVelocity += Gravity;
Position.Y += verticalVelocity; // this may be -= in XNA, not sure where the y axis beings
When you hit a surface, the velocity should be reset to 0.
And finally, to jump, simply subtract a given value from verticalVelocity:
public void Jump(float height)
{
// Only jump if standing on a surface.
if(verticalVelocity == 0)
verticalVelocity -= height;
}
You'll eventually want to add gravity and possibly other forces to your game, so I highly recommend you save yourself a lot of pain and implement some kind of basic force system. This can be done using Vector2s, as you can just add them to the speed of your character. Then just apply an instantaneous force to your character to push it up.
If you really don't want to use a physics engine, you can make a Vector2 with the high point of the jump for the Y and the characters X, and then use the Vector2.Lerp method to interpolate between the characters position and the end point of the jump.
This is generally a very bad system to use, and I highly recommend you either use an existing physics engine, or make your own simple one.
use a sinusoidcode should look something like this:
float ground = 0.0f;
float angle = 330.0f;
jump(){
if(ground == 0.0f)ground = Rectangle.Y;
if(Rectangle.Y <= ground)
{
Rectangle.Y+=Math.Sin(angle/(Math.Pi*180));
angle++;
}
}
You can accurately create a gravity effect if you modify the ySpeed dynamically, as opposed to just adding 40.
You want to declare a ySpeed
ySpeed = 0;
Then you want to use an acceleration variable
acceleration = 0.25;
Okay, now that we've done that, let's add gravity, provided that our player isn't touching the floor.
if(playerLocationY + playerHeight > floorLocationY)
{
gravity = false;
}
else
{
gravity = true;
}
if(gravity)
{
ySpeed += acceleration;
}
Now that we've got that down, we want to include something that allows us to jump.
if(KeyPressed == UP)
{
ySpeed -= acceleration;
}
This will move our player in the upward direction
We now want to make sure we actually move, so let's add one last line and we're done.
playerLocationY += ySpeed;
Congratulations, you made it.

Cocos2D Gravity?

I am really looking to try to have gravity in my game. I know everyone says use Box2D, but in my case I can't. I need to use Cocos2D for the gravity.
I know Cocos2D does not have any gravity API built in so I need to do something manually. The thing is there is like no tutorials or examples anywhere on the web that show this.
Can anyone show me what they have done or can some explain step by step on how to apply a non-constant gravity (One that gets slightly stronger while falling).
I think this will help a lot of people that are facing the same issue that I am having!
Thanks!
Gravity is nothing but a constant velocity applied to the body for every physics step. Have a look at this exemplary update method:
-(void) update:(ccTime)delta
{
// use a gravity velocity that "feels good" for your app
const CGPoint gravity = CGPointMake(0, -0.2);
// update sprite position after applying downward gravity velocity
CGPoint pos = sprite.position;
pos.y += gravity.y;
sprite.position = pos;
}
Every frame the sprite y position will be decreased. That's the simple approach. For a more realistic effect you will want to have a velocity vector for each moving object, and apply gravity to the velocity (which is also a CGPoint).
-(void) update:(ccTime)delta
{
// use a gravity velocity that "feels good" for your app
const CGPoint gravity = CGPointMake(0, -0.2);
// update velocity with gravitational influence
velocity.y += gravity.y;
// update sprite position with velocity
CGPoint pos = sprite.position;
pos.y += velocity.y;
sprite.position = pos;
}
This has the effect that velocity, over time, increases in the downward y direction. This will have the object accelerate faster and faster downwards, the longer it is "falling".
Yet by modifying velocity you can still change the general direction of the object. For instance to make the character jump you could set velocity.y = 2.0 and it would move upwards and come back down again due to the effect of gravity applied over time.
This is still a simplified approach but very common in games that don't use a "real" physics engine.

Resources