[Pong] Debugging Ball Movement

Started by
6 comments, last by stevo58 11 years, 5 months ago
Hello community,

Project: Pong, Lang + Library: C++, SFML

I am having a small issue with the Ball movement. It works, when a collision is detected, I negate the Xspeed or Yspeed of the ball so that it reverses direction. Currently I only do this when it hits the screen edge. as I want to understand the issue before I continue. My issue is that when Breakpoint my code (at any place), I find that the X/Y coordinates inflate to a massive size, depending on where the ball was before a break occurred. For example; If the ball is about to hit the right-edge and it breaks on hit, then cycling through the breakpoint makes it jump from 800 (Screen Edge) to 3400, which is way outside the bounds of the play area. It is also same for the Y, even if a collision doesn't occur, it's like the debugger interrupts the logic in some way.

Also, when I break and then return to the window, the sprites on the screen no longer move and nothing happens. I don't remember anything like this happening when I was using Allegro 4, is this some sort of issue with SFML (the display, not so much the logic)?

I have included the code for the Entire ball class and the portion which deals with Collision from the Game loop:


[source lang="cpp"]#ifndef BALL_H
#define BALL_H

class Ball
{
public:

Ball(sf::Vector2f position, float speed); // constructor
~Ball(); // destructor

void MoveBall(float elapsedTime); // Move the ball.
void ReverseSpeed(int colType); // Set the speed to different values depending on what has occured.
bool LoadImage(std::string filename);
void DisplayBall(sf::RenderWindow &targetWindow);
sf::Rect<float> getArea();
private:

sf::Vector2f position_;
float speed_;
sf::Image ballImage_;
sf::Sprite ballSprite_;
bool isFileLoaded_;
float xSpeed_, ySpeed_;
};

#endif BALL_H[/source]

[source lang="cpp"]#include "stdafx.h"
#include "Ball.h"

Ball::Ball(sf::Vector2f position, float speed)
{
position_ = position;
speed_ = 35.0f;
isFileLoaded_ = false;
xSpeed_ = -65.0f;
ySpeed_ = 65.0f;
}

Ball::~Ball()
{
}

void Ball::MoveBall(float elapsedTime)
{
position_.x += (xSpeed_ * elapsedTime);
position_.y += (ySpeed_ * elapsedTime);
}

void Ball::ReverseSpeed(int colType)
{
if(colType == 1)
xSpeed_ = -xSpeed_;
else if(colType == 2)
ySpeed_ = -ySpeed_;
}

bool Ball::LoadImage(std::string filename)
{
// Load an image using the string provided.
if(!ballImage_.LoadFromFile(filename))
{
// If the file cannot be found, then the method returns
// false, could be used to load a default graphic or exit.
return false;
}
else
{
// Else, set the sprite to the image loaded.
// and set file loaded to True.
ballSprite_.SetImage(ballImage_);
// set the sprite position to that of the class position/centre.
ballSprite_.SetCenter(ballSprite_.GetSize().x/2, ballSprite_.GetSize().y/2);
ballSprite_.SetPosition(position_);
// set the file loaded boolean to true, for other functions to use.
isFileLoaded_ = true;

// Return successful.
return true;
}
}

void Ball::DisplayBall(sf::RenderWindow &targetWindow)
{
if(isFileLoaded_)
{
ballSprite_.SetPosition(position_.x, position_.y);
sf::Shape rect = sf::Shape::Rectangle(position_, sf::Vector2f(position_.x + 32, position_.y + 32), sf::Color(255,255,0), 0, sf::Color(0,0,0));
targetWindow.Draw(rect);
targetWindow.Draw(ballSprite_);
}
}

sf::Rect<float> Ball::getArea()
{
/*sf::Shape colRect = sf::Shape::Rectangle(position_.x - (ballSprite_.GetSize().x/2),
position_.y - (ballSprite_.GetSize().y/2),
position_.x + (ballSprite_.GetSize().x/2),
position_.y + (ballSprite_.GetSize().y/2),
sf::Color(0, 0, 0),
0,
sf::Color(0, 0, 0));*/
sf::Rect<float> colRect(position_.x - (ballSprite_.GetSize().x/2),
position_.y - (ballSprite_.GetSize().y/2),
position_.x + (ballSprite_.GetSize().x/2),
position_.y + (ballSprite_.GetSize().y/2));

return colRect;
}[/source]

[source lang="cpp"]//TODO: collision does not work for negative values.
if(ball_->getArea().Left <= 0 || ball_->getArea().Right >= 800)
{
ball_->ReverseSpeed(1);
}
else if(ball_->getArea().Top <= 0 || ball_->getArea().Bottom >= 600)
{
ball_->ReverseSpeed(2);
}
ball_->MoveBall(gameWindow_.GetFrameTime());[/source]


Please ignore some of the hard-coded values for collision/the fact ball handles drawing, it's stuff I intend to work on once I get the basic game down.

Regards,

Stitchs.
Advertisement
I dont see how do you count elapsedTime. Its better to have an 50 millisec (or something like that) limit, .....plus pause the game when the window loses focus.
Two things:
I'm not sure if elapsed time is your delta time or if it's just a counter variable on how long the application has been running for
So have you tried doing this?


void Ball::MoveBall(float elapsedTime)
{
position_.x += xSpeed_;
position_.y += ySpeed_;
}


And what's the point of the speed variable? Also you should at least assign the speed variable in your constructor

Ball::Ball(sf::Vector2f position, float speed)
{
position_ = position;
speed_ = speed; // changed from 35.0f
isFileLoaded_ = false;
xSpeed_ = -65.0f;
ySpeed_ = 65.0f;
}


You could use a sf::Vector2 to determine the direction of what the ball requires to go in (you should pre normalise it though) and your speed variable for the multiplier

i.e.

void Ball::MoveBall(float elapsedTime)
{
// where direction is a normalised vector
position_ += direction_ * speed_;
}

anax - An open source C++ entity system


i.e.
void Ball::MoveBall(float elapsedTime)
{
// where direction is a normalised vector
position_ += direction_ * speed_;
}



speed_x and speed_y already determine direction and speed.
obejct_position+= move_dir * move_speed can be used when you want the move the object(or camera) "manually" but even then you need the elapsedTime.
I derive my elapsed time from the sf::Window.GetFrameTime(), which I have since learned is somewhat inaccurate, so now I manage a Clock provided by SFML. This is passed in and helps to control the speed of the logic.

The speed parameter in my Ball is known to be unset (embarrassingly, I should have edited that out before posting) and it will be used, I was just using hard-coded values in order to determine the cause of my issue, and would set it so after.

@Aliii; how would I limit the frame time, should I divide the FrameTime by a value and make a check on some sort of millisecond cap and reduce should it go over?

Regards,

Stitchs.
Just simply limit it:)

At the start of the iteration you have to determine how much time has passed since the last iteration:


gameLoop{

passed_time= whatever.getPassedTime();
if( passed_time > some_value)
passed_time= some_value;

input();
physics( passed_time);
render();
....
....

}


Its up to you how you measure the delta time. To the physics function always pass the passed seconds in a float.
In a simple game like this it can happen that the passed millisecond since the last iteration will be less than 1 ms, ...so watch out for that.
Ideally if you add all your passed_time values in one real second it should be equal to 1 second.

If some program starts in the background the passed_time can be 1000 millisecs or more ....so if your speed was 15 m/s you will move 15 meters in one iteration. ....you fly through the wall or something ...you dont want that. Thats why you limit it.
I had a similar problem that only showed up when I was debugging. Its because the game timer is working off of real wall-clock time and when you pause, the timer is still going. You can can fix it by making your timer send fixed increments or looking for exceptionally large values and capping them at a normal amount. In my system, any frame times > 200ms was considered a significant lag and a 16ms was returned as the frame time. This helped me debug things as though there were happening at a normal rate, while I took my sweet time figuring out my bugs in the debugger.

Cheers,

Bob

[size="3"]Halfway down the trail to Hell...
You should also reposition the ball after collision.

Example
if(ball.y < 0)
{
ball.y = 0;
then reverse directions.
}

This topic is closed to new replies.

Advertisement