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.
Related
I hope someone out there can answer my question. Currently I am doing some collision detection using D3DXVectors.
I have the collision down, but what I need is what to do AFTER the collision has been made.
I have a player object and the object the player is being collided with and pass these into my function.
Basically, I have this so far (variables names have been changed for clarity):
D3DXVECTOR3 Collision::wallCol(D3DXVECTOR3 player, D3DXVECTOR3 object, float playerWidth, float playerDepth, float objectWidth, float objectDepth)
{
//store the values of the objects into temps
//left hand side of a box
float minX = object.x - (objectWidth / 2);
//right hand side of a box
float maxX = object.x + (objectWidth / 2);
//front of a box
float minZ = object.z - (objectDepth / 2);
//back of a box
float maxZ = object.z + (objectDepth / 2);
//store the players positions into temps
float pminX = player.x - (playerWidth / 2);
float pmaxX = player.x + (playerWidth / 2);
float pminZ = player.z - (playerDepth / 2);
float pmaxZ = player.z + (playerDepth / 2);
//check to see if we are in the box at all
if (pminX <= maxX && pmaxX >= minX &&
pminZ <= maxZ && pmaxZ >= minZ)
{
//x collision for the left side of the block
if (pmaxX >= minX && pmaxX <= maxX)
{
pmaxX = minX - 50;
player.x = pmaxX;
return player;
}
//x collision for the right side of the block
if (pminX <= maxX && pminX >= minX)
{
pminX = maxX + 50;
player.x = pminX;
return player;
}
//z collision for the front
if (pmaxZ >= minZ && pmaxZ <= maxZ)
{
pmaxZ = minZ - 20;
player.z = pmaxZ;
return player;
}
//z collision for the back
if (pminZ <= maxZ && pminZ >= minZ)
{
pminZ = maxZ + 20;
player.z = pminZ;
return player;
}
}
return player;
}
As you can see, I would like to move my player object away from whatever it is that it is bumping into. The problem I am having is that no matter what, my player will always move either to the left or the right on the X axis because it accounts for the X first, it never has the chance to even get to the Z if statements.
I've considered making 2 Booleans to tell if the player makes contact with the X or the Z first, but since the first if statement is to even see if we are in the box, I believe it would trigger them both at the same time and there would be no way to tell which came first.
If anyone could offer some advice on this problem, it would be greatly appreciated! Thank you.
In order to implement more or less realistic bouncing it is not enough to have only positions and bounding boxes of colliding objects. You need to have some kind of kinematic history: to be able to tell how objects move after collision you should also know how they were moving before the collision.
In simplest case, you want to have at least a velocity (speed) vector (direction and magnitude) and, probably, a mass for every object. When collision is detected you may simply invert the direction of the velocity vector of one of the objects (for example, smaller and lighter one).
The pseudocode will be something like:
if have_collided(object1, object2):
if object1.mass > object2.mass:
object2.velocity = -object2.velocity
else:
object1.velocity = -object1.velocity
This would not look very realistic, but is very simple to implement.
For more realism you could use momentum conservation principle or elastic collisions. For even more realistic bouncing, implement acceleration vector and re-calculate both, velocity and acceleration after collision is detected. Having acceleration you may now add arbitrary forces influencing your objects (gravity, friction, maybe even electromagnetic forces etc.). Adding more attributes make it more interesting: for example adding elasticity and viscosity may be used to calculate deformations.
As you see there is more in object interactions involved than just positions.
Additionally, collision detection and bouncing code could (and should) be decoupled. That means that you would want to implement them in different parts of code (different set of functions and classes): collision subsystem will detect the collision event, providing information like: whether collision happened or not and if yes, by how far objects currently intersect with each other. After that, bouncing code, based on this information, will decide how to change objects traveling, while deformation code will decide how to change objects shapes etc. Thus, there will be no silly problems like which "if" statement in collision code came first decides the direction of bouncing.
Overall I would suggest you:
To look up some physics. For example:
Wiki: Inelastic collision
Wiki: Elastic collision
To get this excellent book: Real-Time Collision Detection
To read through some popular questions on gamedev.stackexchange.com, for example on collision (sort by votes)
Finally, you should know that DirectX 9 API is wildly obsolete, not supported and should not be used for new projects. It is notoriously hard to port D3DX* stuff to modern APIs. You may want to take a look at DirectX 11 and OpenGL 4, along with their support library ecosystems, or maybe even a good rendering or game engine. Specifically you may want to use some good math library (with vectors, matrices, linear algebra, geometry).
Just to preface this question please note I am not asking 'fix my code', rather what techniques would I employ to fix this problem. I also apologise if my spelling is not very good.
Okay so I have a 2D platformer game which compares the players position with all of the tiles (in a loop), the resolves the collision accordingly. This is pretty much the structure of the main game loop:
Check all collisions (And enable jumping if a collision bellow the
player occurred)
Get input and change player velocity accordingly
Add gravity to the Y velocity
Apply velocity and friction to the players position
Draw the game
repeat
But despite this system working there are two minor, but noticeable problems with the collision system (I have provided images to make it easier). There are two problems, the first is not that bad, but the second renderers the game almost unplayable!
Problem 1. When just moving left and right across the floor in the game, occasionally the player looses all the velocity it has gained and then has to re-accumulate that velocity. I think this is because every now and then my collision detection function does not return properly. here is a image:
I hope that was clear, the problem only really becomes apparent when moving across lots of flat land.
Problem 2 (This one is way worse) The problem is that player can essentially jump up walls, because if you say for example hold down left arrow and hold jump, the player will jump up the wall. I am assuming this is because My collision detection function is returning true if the collision is coming from the side (although it should not). Here is another picture (the text is small, sorry):
So here is my collision detection function, which should take in two 'Objects' then return the direction from the first object at which the collision occurred, I think the problem arouses when It comes to determining the direction as this is causing problems, as shown above:
//Find the collision vectors
float vectorX = (a.Position.x + (a.Scale.x / 2)) - (b.Position.x + (b.Scale.x / 2));
float vectorY = (a.Position.y + (a.Scale.y / 2)) - (b.Position.y + (b.Scale.y / 2));
//Find the distance between the two objects
float deltaWidth = (a.Scale.x / 2) + (b.Scale.x / 2);
float deltaHeight = (a.Scale.y / 2) + (b.Scale.y / 2);
//Stores the direction of collision
Direction collisionDir = Direction::None;
//Check if the two objects are intersecting on the x and y axis
if (fabs(vectorX) < deltaWidth && fabs(vectorY) < deltaHeight)
{
//The direction of collision
float directionX = deltaWidth - fabs(vectorX);
float directionY = deltaHeight - fabs(vectorY);
//Check for vertical collision
if (directionX >= directionY)
{
//Check for collisions from the top
if (vectorY > 0)
{
a.Velocity.y = 0;
a.Position.y += directionY;
collisionDir = Direction::Up;
}
//Collisions form the botttom
else
{
a.Velocity.y = 0;
a.Position.y -= directionY;
collisionDir = Direction::Down;
}
}
else if (directionX < directionY / 2)
{
//Check for collisions from the left
if (vectorX > 0 )
{
a.Velocity.x = 0;
a.Position.x += directionX;
collisionDir = Direction::Left;
}
//Collisions form the right side
else
{
a.Velocity.x = 0;
a.Position.x -= directionX;
collisionDir = Direction::Right;
}
}
}
//Return the direction.
return collisionDir;
This will return a direction, My other code also checks if that direction == Bottom, then it will allow jumping.
Thank-you for any help. I am practising for Ludum Dare, because I plan on (probably) making a platformer and If I cant figure out collision detection I don't know how good my game will be.
First thing I would recommend is make yourself a Vector2D class which holds your x and y coordinates and a few overload some operators to allow for addition and subtraction of two Vector2Ds and multiplication and division by ints, floats and doubles. Trust me it will make your life a lot easier as they can hold all your forces and collision points.
Next when I have used the style of collision you are currently using I have always found that it's:
A)Harder to debug.
B)Harder for other people to follow your code.
So I would recommend creating a Rectangle2D class which handles collisions with other Rectangles and other needed functionality.
As a recommendation have the top left corner and the bottom right corner as a vector from the center of the rectangle which makes scaling and collision detection much easier this also means you can derive the other corners without directly needing to store them.
Here's a code example that will probably help what I'm trying to explain:
bool Intersects(Rectangle2D other)
{
//Checks the right, left, bottom then top of the rectangle
//against the other.
if(other.topLeftCorner.x >= bottomRightCorner.x //Checks the right
|| other.bottomRightCorner.x <= topLeftCorner.x //Checks the left
|| other.topLeftCorner.y >= bottomRightCorner.y //Checks the bottom
|| other.bottomRightCorner.y <= topLeftCorner.y) //Checks the top
return false;
else
return true;
}
You can easily manipulate this code to give you the direction of the collision. Hope this helps.
I am creating a small 2D top-down program that will have a projectile created when the left mouse is pressed. Then the projectile moves toward a goal. My issue is that the projectile slows when it moves closer to the goal. It should remain the same speed. I looked into normalize thinking that would help but have had a hard time finding much on SFML normalize. What I did find has not helped.
Here is my update for my projectile (agents):
void agent::update(const sf::CircleShape* goal, sf::Time delta) {
direction = goal->getPosition() - body.getPosition();
sf::Vector2f newPos = body.getPosition() + sf::Vector2f(direction.x * speed * delta.asSeconds(), direction.y * speed * delta.asSeconds());
body.setPosition(newPos);
}
ps. I have it in asSeconds instead of asMilliseconds or it goes weird and lags.
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.
I'm a little bit of a new programmer, kinda doing relatively basic stuff. Over the past while (although I haven't been working on it very often) I've been, with the help of SDL, been making a 2D game. Right now, I'm working on the code for causing the player to jump when pressing the w key (controls are wsad). I quickly realized that I couldn't keep the speed constant because this would cause the jump to go more like the graph of y=-|x| than y=-x^2, which would look more like an actual jump than the former. Here's the bits of code that make it work.
//The part which happens when the jump key is pressed (w)
case SDLK_w:
if(InAir != true) {
StartOfJump = PlayerYCoord;
InAir = true;
velocity = 0.01;
break;
}
//And skip to a different part.
if(InAir == true) {
if(StartOfJump - PlayerYCoord < JumpHeight) {
PlayerYCoord = PlayerYCoord - velocity;
velocity = velocity * velocity;
velocity is there to make the speed that the Y coord of the player increases, increase exponentially. Right now, it's set to 0.01 at the start of the program.
JumpHeight is the number of pixels the player jumps. This is for the purpose of being able to modify it with ease. As it is, JumpHeight is set to 100 pixels.
StartOfJump is there to ensure that the jump is cut off at the right point, because while at the moment the map for the game is flat I don't expect to keep it that way.
And PlayerYCoord is fairly self-explanatory, but basically it's the Y coordinate of the player on the plane. it is a double.
And yes, I know that right now there is no code for falling. That's not really important when I can't even get the rising part.
Anyway, I'm not really certain why, but for some reason the player's position just increases by one pixel on the pressing of the w key, and it doesn't do anything else. I tried modifying the code to say this
if(InAir == true) {
if(StartOfJump - PlayerYCoord < JumpHeight) {
//PlayerYCoord = PlayerYCoord - 0.1;
PlayerYCoord = PlayerYCoord - velocity;
velocity = velocity * velocity;
cout << fixed << setprecision(4);
cout << "The velocity is" << velocity << " " << endl;
Uuuunfortunately, it starts by printing out 0.0001 then prints 0.000 forever. But that's not right, is it?... The value of velocity is 0.01... so, I changed that last line to say this:
cout << "The velocity is" << velocity * 100 << " " << endl;
Sure enough, it output 0.0100 and then output 0.0000 infinitely like last time. I'm honestly unsure what's causing this issue, but I think it has something to do with the fact that the player's Y coordinate only increases by one pixel then stops.
I'm probably making a really stupid mistake that can be fixed very easily. Anyway, if there's any other bits of code that I need to include (first time on programming forums, I haven't quite got this stuff nailed down yet) I'd be happy to include it. Thanks in advance for the help!
P.S. In case any of my code is system-dependent, I'm on Ubuntu 13.10, 32 bit.
You've implemented gravity incorrectly. You need to start off with an upwards velocity. You then need to subtract the downwards acceleration from gravity each unit of time. This will handle both rising and falling. Your code does... strange things.
velocity = 50
each unit of time while player is in the air:
playerY -= velocity
velocity -= acceleration
I don't quite agree with the above solution.
Your player should always be affected by gravity, right? Even if we are on the ground we are affected by gravity?
Always affect the player by gravity but when we press a jump button or so, add counter force that flings the player upwards (but only once) and then the gravity will outtake this force and push the player down.
The boolean InAirshould only determine if the player can jump again. So if we are in the air we shouldn't be able to execute another jump command. But if we are grounded (InAir = false ) Then we should be able to jump again.
This also makes it more efficient to add double jump or such.
Happy coding!