Can I add friction in air? - cocos2d-iphone

I have issue regarding speed in air.
When I jump and move simultaneously that time speed of player increase. I use impuls for jump and I use force for movement .I want to know how to slow down it when player is in air.
This is my code of movement left and right
-(void)update:(ccTime)dt :(b2Body *)ballBody :(CCSprite *)player1 :(b2World *)world
{
if (moveRight.active==YES)
{
// maxSpeed=10.0f;
ballBody->SetActive(true);
// b2Vec2 locationworld=b2Vec2(maxSpeed,0);
double mass=ballBody->GetMass();
ballBody->ApplyForce(mass*locationworld, ballBody->GetWorldCenter());
ballBody->SetLinearDamping(1.2f);
}
else if(moveLeft.active==YES)
{
ballBody->SetActive(true);
b2Vec2 locationworld=b2Vec2(-10,0);
double mass=ballBody->GetMass();
ballBody->ApplyForce(mass*locationworld, ballBody->GetWorldCenter());
// ballBody->SetLinearDamping(1.2f);
}
}
And following is for jumping player
-(void)jump:(b2Body*)ballBody:(ccTime)dt:(BOOL)touch
{
if (touch)
{
if (jumpSprte.active==YES)
{
ballBody->SetActive(true);
b2Vec2 locationWorld;
locationWorld=b2Vec2(0,25);
ballBody->ApplyLinearImpulse(locationWorld, ballBody->GetWorldCenter());
}
}
}
So where i used logic??
Thanks in advance

You need to model air resistance to slow the player down in the air. There are several ways to do this depending on how realistic you want the simulation to be. For a simple model linearDampening would slow it down.
True air resistance is not linear. To model this in a more realistic way you'd need to use something like this:
F = - C * v * |v|
F is the total force of the air drag
C is a drag constant that depends on the shape of the object
v is the velocity vector ( |v| is the magnitude of the velocity, or length if you so wish)
It also sounds like your players are able to increase their speed while in the air using move. This is because you allow the player to apply force while his legs aren't touching the ground. In order to disallow this if this is your goal make sure that when the character is touching the ground is the only time when more force can be applied to make him move.
Note that this all very much depends on what sort of game you want this to be. If it looks and feels good when making physics for games it is good. Do not stress out if you don't manage to make a wholly accurate simulation of reality as long as the end result plays well.

This is my code of movement left and right
-(void)update:(ccTime)dt :(b2Body *)ballBody :(CCSprite *)player1 :(b2World *)world
{
if (moveRight.active==YES)
{
// maxSpeed=10.0f;
ballBody->SetActive(true);
// b2Vec2 locationworld=b2Vec2(maxSpeed,0);
double mass=ballBody->GetMass();
ballBody->ApplyForce(mass*locationworld, ballBody->GetWorldCenter());
ballBody->SetLinearDamping(1.2f);
}
else if(moveLeft.active==YES)
{
ballBody->SetActive(true);
b2Vec2 locationworld=b2Vec2(-10,0);
double mass=ballBody->GetMass();
ballBody->ApplyForce(mass*locationworld, ballBody->GetWorldCenter());
// ballBody->SetLinearDamping(1.2f);
}
}
And following is for jumping player
-(void)jump:(b2Body*)ballBody:(ccTime)dt:(BOOL)touch
{
if (touch)
{
if (jumpSprte.active==YES)
{
ballBody->SetActive(true);
b2Vec2 locationWorld;
locationWorld=b2Vec2(0,25);
ballBody->ApplyLinearImpulse(locationWorld, ballBody->GetWorldCenter());
}
}
}
So where i used logic??

Related

Proper collision in SFML (C++)

So, I had a test going on to see how collision operates in SFML. I have made this snippet of code:
if (floor.getGlobalBounds().intersects(SuperMario.getGlobalBounds())) // Floor
{
SuperMario.setPosition(SuperMario.getPosition().x, floor.getPosition().y - SuperMario.getOrigin().y);
IsTouching = true;
}
As the code suggests, Mario will change his position when he touches the floor object and will teleport above the floor.
However, this has the following side-effect, illustrated by the pictures below.
Note that the "green box" is the floor object I mentioned earlier. Also, ignore the word "left" in picture 1, I mean "right".
Of course, this behaviour is intended (i.e. is not a bug), but it is unwanted.
So my question is: How can I eliminate this "side-effect"? I mean, how can I modify my code, so Mario will not teleport above the floor, when he touches its sides(making platforming work like a proper platforming)? I want Mario to be stopped by the box, not to be teleported.
UPDATE: So now, I have this:
for (unsigned int i = 0; i <= solidObjects.size() - 1; i++)
{
if (solidObjects[i].getGlobalBounds().intersects(SuperMario.getGlobalBounds()))
{
if (SuperMario.getPosition().x - solidObjects[i].getPosition().x < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
{
SuperMario.setPosition(solidObjects[i].getPosition().x - SuperMario.getOrigin().x, SuperMario.getPosition().y);
IsTouching = false;
}
else if (SuperMario.getPosition().y - solidObjects[i].getPosition().y < SuperMario.getPosition().x - solidObjects[i].getPosition().x)
{
SuperMario.setPosition(SuperMario.getPosition().x, solidObjects[i].getPosition().y - SuperMario.getOrigin().y);
IsTouching = true;
}
else if (SuperMario.getPosition().x - solidObjects[i].getTextureRect().width < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
{
SuperMario.setPosition(solidObjects[i].getTextureRect().width + SuperMario.getOrigin().x, SuperMario.getPosition().y);
IsTouching = false;
}
}
else
{
IsTouching = false;
}
}
However, there is one problem. When Mario touches the sides of the floor, he sticks on them meaning he is unable to move right.
If I am not clear enough, please specify what i should add or clarify more.
This feels really weird, because you'd typically define solid areas rather than those the player can walk inside. You'll want your player to jump after all, rather than having them glued to the ground.
The rest is pretty straightforward:
Iterate over all solid objects and determine whether the player and the solid rectangle overlap.
If they do, determine which distance is smaller (x or y). This lets you determine which axis to move the player.
Determine which direction the player leaves the solid area quicker, i.e. which direction to push the player.
Push the player in the calculated direction and repeat the checks.
Depending on your map complexity this can become rather complex, so you'll most likely want some sorting/spatialisation to reduce the number of comparisons (e.g. skip checking impossible/far away shapes).

How do I accomplish proper trajectory with a Cocos2d-x node using Chipmunk 2D impulses and rotation?

I'm building a game with Cocos2d-x version 3.13.1 and I've decided to go with the built-in physics engine (Chipmunk 2D) to accomplish animations and collision detection. I have a simple projectile called BulletUnit that inherits from cocos2d::Node. It has a child sprite that displays artwork, and a rectangular physics body with the same dimensions as the artwork.
The BulletUnit has a method called fireAtPoint, which determines the angle between itself and the point specified, then sets the initial velocity based on the angle. On each update cycle, acceleration is applied to the projectile. This is done by applying impulses to the body based on an acceleration variable and the angle calculated in fireAtPoint. Here's the code:
bool BulletUnit::init() {
if (!Unit::init()) return false;
displaySprite_ = Sprite::createWithSpriteFrameName(frameName_);
this->addChild(displaySprite_);
auto physicsBody = PhysicsBody::createBox(displaySprite_->getContentSize());
physicsBody->setCollisionBitmask(0);
this->setPhysicsBody(physicsBody);
return true;
}
void BulletUnit::update(float dt) {
auto mass = this->getPhysicsBody()->getMass();
this->getPhysicsBody()->applyImpulse({
acceleration_ * mass * cosf(angle_),
acceleration_ * mass * sinf(angle_)
});
}
void BulletUnit::fireAtPoint(const Point &point) {
angle_ = Trig::angleBetweenPoints(this->getPosition(), point);
auto physicsBody = this->getPhysicsBody();
physicsBody->setVelocityLimit(maxSpeed_);
physicsBody->setVelocity({
startingSpeed_ * cosf(angle_),
startingSpeed_ * sinf(angle_)
});
}
This works exactly as I want it to. You can see in the image below, my bullets are accelerating as planned and traveling directly towards my mouse clicks.
But, there's one obvious flaw: the bullet is remaining flat instead of rotating to "point" towards the target. So, I adjust fireAtPoint to apply a rotation to the node. Here's the updated method:
void BulletUnit::fireAtPoint(const Point &point) {
angle_ = Trig::angleBetweenPoints(this->getPosition(), point);
// This rotates the node to make it point towards the target
this->setRotation(angle_ * -180.0f/M_PI);
auto physicsBody = this->getPhysicsBody();
physicsBody->setVelocityLimit(maxSpeed_);
physicsBody->setVelocity({
startingSpeed_ * cosf(angle_),
startingSpeed_ * sinf(angle_)
});
}
This almost works. The bullet is pointing in the right direction, but the trajectory is now way off and seems to be arcing away from the target as a result of the rotation: the more drastic the rotation, the more drastic the arcing. The following image illustrates what's happening:
So, it seems that setting the rotation is causing the physics engine to behave in a way I hadn't originally expected. I've been racking my brain on ways to correct the flight path, but so far, no luck! Any suggestions would be greatly apprecitated. Thanks!

How i can make better jump to my game? - C++ SFML

So, I ask question about my 2D game, actually it is not game, but it is something like poor game. Well i made moving system and now is time to make jump. I made some kind of gravity with tutorial but I don't like it. It is simple and nice but there is problems in that gravity example: 1. You can hold up arrow and "fly" with jump. I tried to fix that and make some kind of limit to jump but it was bad try. Second problem is that when you jump and you release up arrow (jumping key) then my sprite fall very fast and I can't really control that sprite in air.
This is my first game and I want spend time to do that, but now i have problem that i can't solve with my self so if you can help, please do it. I use C++ with CodeBlocks and SFML multimedia library.
So there is little parts of my code.
First there is velocity and gravity configuration:
//gravity & velocity
const float gravity = 1;
int ground = 600; //height of ground
Vector2f velocity(Vector2f(0,0));
float movingSpeed = 0.5f, jumpingSpeed = 2.0f;
Then there is simple when you press button you jump:
if(Keyboard::isKeyPressed(Keyboard::Up)){
skeleton.move(0,velocity.y = -jumpingSpeed);
source.y = Up;
isWalking = true;
}
And there is system what recognize if you jump and this make you fall:
if(skeleton.getPosition().y + skeleton.getScale().y < ground || velocity.y < 0){
velocity.y += gravity;
}else{
skeleton.setPosition(skeleton.getPosition().x, ground - skeleton.getScale().y);
}
So my sprite name is "skeleton". And yeah this is first time with game physics. I'm not very good game programmer so these code can be poor and yeah... if you invent a solution share it.

How to move a sprite with dynamic physics body with constant speed

Until lately I've been just changing the x coordinate of my sprite on each update and I was happy with it. But yesterday when being in the debugDraw mode, I found out that after certain speed physics body wouldn't align correctly with the sprite ,like this:
Later I got told that, (by Birkemose in cocos2d forum) the preferred way to move a physics body from A to B is to apply impulse to it. But I have no idea how to achieve constant speed this way. This is the code I used to move it without applying any impulse:
-(void)update:(CCTime)delta{
rollingHero.position=ccp(rollingHero.position.x+scrollSpeed*delta,
rollingHero.position.y);
physicsNode.position=ccp(physicsNode.position.x-scrollSpeed*delta,
physicsNode.position.y);
}
So to create a feeling of moving I scroll the physics node and the hero in opposite directions with the same scrolling speed.
I tried lots of different variants of applying impulse, but I never got it moving with constant speed. The speed accelerates and the hero gets offscreen. I would appreciate it very much if someone would post a sample code.
The reason impulse isn't working to keep your character at a constant speed is because impulse translates directly into a change in momentum (and thus a change in velocity). So if you were to try to maintain a constant velocity through impulse, you would have to check your sprite's velocity first, and although you could get pretty close to a constant velocity, it wouldn't be truly constant.
static const float kRollingHeroMoveSpeed = 10.f;
static const float kRollingHeroAccelConstant = 10.f;
-(void)update:(CCTime)delta {
// check velocity of sprite
if(_rollingHero.physicsBody.velocity.x < kRollingHeroMoveSpeed) {
// if velocity is under limit, push character
[_rollingHero.physicsBody applyImpulse:ccp(kRollingHeroAccelConstant, 0)];
}
}
The better way to do this is to step into the C level of the Chipmunk2D physics engine that powers Cocos2D physics.
-(void)onEnter {
[super onEnter];
// tell physics engine to use our C function to update physics body
_rollingHero.physicsBody.body.body->velocity_func = playerUpdateVelocity;
}
static void playerUpdateVelocity(cpBody *body,
cpVect gravity,
cpFloat damping,
cpFloat dt) {
// check validity of cpBody
cpAssertSoft(body->m > 0.0f && body->i > 0.0f, "Body's mass and moment must be positive to simulate. (Mass: %f Moment: %f)", body->m, body->i);
// update velocity and angular velocity
body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));
body->w = body->w*damping + body->t*body->i_inv*dt;
// reset force vector
body->f = cpvzero;
// reset torque
body->t = 0.0f;
// set body's velocity to desired velocity
body->v.x = kRollingHeroMoveSpeed;
}
Here's cpBody.h on Github.

Ball passing through paddle from certain angles

I'm creating a pong clone for school with C++ and SFML 2.1 and I'm having a little problem when the ball hits the left paddle at sharp angles (It goes through).
The right paddle works fine at all angles, and as far as i can remember they're using the same code.
This is the code I'm using for collision:
for (auto& it : collisionPaddles)
{
if (this->ballShape.getGlobalBounds().intersects(it->getGlobalPaddleBounds()))
{
float deltaDistance = (this->y + this->radius) - (it->y + it->height / 2);
bool fromLeft = true;
if ((ballAngle < (3*myMath::MY_PI/2) && ballAngle > myMath::MY_PI/2))
{
fromLeft = false;
}
else
{
fromLeft = true;
}
ballAngle = static_cast<float>(deltaDistance * (myMath::MY_PI/180));
if (fromLeft)
{
ballAngle = static_cast<float>(myMath::MY_PI - ballAngle);
}
moveBall(2);
}
}
That's not the way a good pong should be implemented. When your model of physics uses some deltas, you get a lot of artefacts. The one of most prominent is objects passing through each other. In such simple cases deltas should be used for animation only.
Here's the way I would solve it. When the ball gets its initial speed and vector of movement, I would calculate the whole path until it hits the player's baseline.
Calculate an initial ray from the current position of the ball, directed the same way it moves.
Intersect that ray with segments that consistute the borders of your field.
Calculate the time that is needed to reach that intersection point.
Calculate the new ray from the intersection point towards the new movement vector.
Repeat steps 2-4 until you hit a player's base line. Sum all the times.
Now you have a relative time of the hit with baseline and the place it will happen. Now on every frame you should
Check if that collision time has been between the previous frame and the current one. If it was,
Calculate the expected position of paddle at that moment.
If the segment of paddle contains that intersection point, it was reflected. Calculate the new path as described before.
This way you'll get true game mechanics that are not limited by most of the aspects of game development, i.e. FPS, sudden lags etc.