-
Hello,
I tried to write a little program of arkanoid and there is a problem. when I try to move the ball after it bounce in the left wall or in the right wall the ball got stuck. I did'nt know what is the problem.
// Move the ball
float factor = ballSpeed * deltaTime;
ball.move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor);
// Check collisions between the ball and the screen
if (ball.getPosition().x - ballRadius < 0.f)
{
ballAngle = -ballAngle;
ball.setPosition(ballRadius + 0.1f, ball.getPosition().y);
}
else if (ball.getPosition().x + ballRadius > gameWidth)
{
ballAngle = -ballAngle;
ball.setPosition(gameWidth - ballRadius - 0.1f, ball.getPosition().y);
}
// up
if (ball.getPosition().y - ballRadius < 0.f)
{
ballAngle = -ballAngle;
ball.setPosition(ball.getPosition().x, ballRadius + 0.1f);
}
// down
else if (ball.getPosition().y + ballRadius > gameHeight)
{
ballAngle = -ballAngle;
ball.setPosition(ball.getPosition().x, gameHeight - ballRadius - 0.1f);
}
Thank you
-
I recommend to you put the setPosition function on the game loop and when you check the collision you could just play with the values (x, y), so you will not need so many setPosition functions for each collision check...
-
Please post in the correct subforum next time. This has nothing to do with the wiki. ;)
Start your debugger or place some std::cout to trck the values to figure out why it gets stuck.
I can't directly see anything wrong with your code.
-
I recommend to you put the setPosition function on the game loop and when you check the collision you could just play with the values (x, y), so you will not need so many setPosition functions for each collision check...
setPosition is very fast, no need to over-optimize it.
As for original problem. Your problem is that you're using the code which will only deflect the ball by X axis, not Y axis. That's because your angle is stored in radians and formulas for inverting the angle along the Y axis are different and can be seen here (https://github.com/SFML/SFML/blob/master/examples/pong/Pong.cpp#L196).
But, I think that it's much easier to just store velocity as Vector2f and invert needed axis to be explicit... For example:
if(/*collided with left or right wall*/) {
v.x = -v.x;
}
if(/*collided with up or down wall*/) {
v.y = -v.y;
}
ball.move(v * dt.asSeconds());
-
@EliasDaler you are right... and that is was exactly what I was trying to say it... putting one setPosition fuction in every collision check is no necessary... and move fuction work as well, since its code behind is a setPosition fuction getting the actual position of each axis and adding with a offset of our choice, doing the move... have a nice day :)
-
Thank you very much,
I am new in SFML, I tried to do the ideas you suggested and I was not so successful. My program is based on the pong program that comes with the installation of SFML.
I would be very happy if you could direct me how to combine the ideas you have suggested in my program.
Thank you :)
The program:
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <cmath>
#include <ctime>
#include <cstdlib>
int main()
{
std::srand(static_cast<unsigned int>(std::time(NULL)));
// Define some constants
const float pi = 3.14159f;
const int gameWidth = 800;
const int gameHeight = 600;
sf::Vector2f paddleSize(100, 25);
float ballRadius = 10.f;
// Create the window of the application
sf::RenderWindow window(sf::VideoMode(gameWidth, gameHeight, 32), "SFML Pong",
sf::Style::Titlebar | sf::Style::Close);
window.setVerticalSyncEnabled(true);
// Create the left paddle
sf::RectangleShape paddle;
paddle.setSize(paddleSize);
paddle.setOutlineThickness(3);
paddle.setOutlineColor(sf::Color::Black);
paddle.setFillColor(sf::Color(100, 100, 200));
paddle.setOrigin(paddleSize / 2.f);
// Create the ball
sf::CircleShape ball;
ball.setRadius(ballRadius);
ball.setOutlineThickness(3);
ball.setOutlineColor(sf::Color::Black);
ball.setFillColor(sf::Color::White);
ball.setOrigin(ballRadius / 2, ballRadius / 2);
// Define the paddles properties
sf::Clock AITimer;
const sf::Time AITime = sf::seconds(0.1f);
const float paddleSpeed = 400.f;
const float ballSpeed = 400.f;
float ballAngle = 0.f; // to be changed later
sf::Clock clock;
bool isPlaying = false;
while (window.isOpen())
{
// Handle events
sf::Event event;
while (window.pollEvent(event))
{
// Window closed or escape key pressed: exit
if ((event.type == sf::Event::Closed) ||
((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
{
window.close();
break;
}
// Space key pressed: play
if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space))
{
if (!isPlaying)
{
// (re)start the game
isPlaying = true;
clock.restart();
// Reset the position of the paddles and ball
paddle.setPosition(gameWidth / 2, gameHeight - paddleSize.y / 2 - 10);
ball.setPosition(gameWidth / 2, gameHeight - paddleSize.y / 2 - 40);
// Reset the ball angle
do
{
// Make sure the ball initial angle is not too much vertical
ballAngle = (std::rand() % 360) * 2 * pi / 360;
} while (std::abs(std::cos(ballAngle)) < 0.7f);
}
}
}
if (isPlaying)
{
float deltaTime = clock.restart().asSeconds();
// Move the player's paddle
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) &&
(paddle.getPosition().x - paddleSize.x / 2 > 15.f))
{
paddle.move(-paddleSpeed * deltaTime, 0.f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) &&
(paddle.getPosition().x + paddleSize.x / 2 < gameWidth - 15.f))
{
paddle.move(paddleSpeed * deltaTime, 0.f);
}
// Move the ball
float factor = ballSpeed * deltaTime;
ball.move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor);
// Check collisions between the ball and the screen
if (ball.getPosition().x - ballRadius < 0.f)
{
ballAngle = -ballAngle;
ball.setPosition(ballRadius + 0.1f, ball.getPosition().y);
}
else if (ball.getPosition().x + ballRadius > gameWidth)
{
ballAngle = -ballAngle;
ball.setPosition(gameWidth - ballRadius - 0.1f, ball.getPosition().y);
}
// up
if (ball.getPosition().y - ballRadius < 0.f)
{
ballAngle = -ballAngle;
ball.setPosition(ball.getPosition().x, ballRadius + 0.1f);
}
// down
else if (ball.getPosition().y + ballRadius > gameHeight)
{
ballAngle = -ballAngle;
ball.setPosition(ball.getPosition().x, gameHeight - ballRadius - 0.1f);
}
// Check the collisions between the ball and the paddles
// Left Paddle
if (ball.getPosition().x - ballRadius < paddle.getPosition().x + paddleSize.x / 2 &&
ball.getPosition().x - ballRadius > paddle.getPosition().x &&
ball.getPosition().y + ballRadius >= paddle.getPosition().y - paddleSize.y / 2 &&
ball.getPosition().y - ballRadius <= paddle.getPosition().y + paddleSize.y / 2)
{
if (ball.getPosition().y > paddle.getPosition().y)
ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180;
else
ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180;
ball.setPosition(paddle.getPosition().x + ballRadius + paddleSize.x / 2 + 0.1f, ball.getPosition().y);
}
}
// Clear the window
window.clear(sf::Color(50, 200, 50));
if (isPlaying)
{
// Draw the paddles and the ball
window.draw(paddle);
window.draw(ball);
}
// Display things on screen
window.display();
}
return EXIT_SUCCESS;
}
-
Sorry for dont reply quickly... btw... I have removed the paddle to focus on ball movement... so now its working... so you can check and study the code and put the paddle...
there goes:
#include <SFML/Graphics.hpp>
#include <random>
#include <functional>
#include <cstdlib>
#include <cmath>
int main(int argc, char* argv[])
{
const int window_width = 800;
const int window_height = 600;
const float ball_radius = 16.f;
sf::RenderWindow window(sf::VideoMode(window_width, window_height), "SFML Pong");
window.setVerticalSyncEnabled(true);
std::random_device seed_device;
std::default_random_engine engine(seed_device());
std::uniform_int_distribution<int> distribution(-16, 16);
auto random = std::bind(distribution, std::ref(engine));
sf::Vector2f direction(random(), random());
const float velocity = 15;
sf::CircleShape ball(ball_radius - 4);
ball.setOutlineThickness(4);
ball.setOutlineColor(sf::Color::Black);
ball.setFillColor(sf::Color::White);
ball.setOrigin(ball.getRadius(), ball.getRadius());
ball.setPosition(window_width / 2, window_height / 2);
sf::Clock clock;
sf::Time elapsed = clock.restart();
const sf::Time update_ms = sf::seconds(1.f / 30.f);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if ((event.type == sf::Event::Closed) || ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
{
window.close();
break;
}
}
elapsed += clock.restart();
while (elapsed >= update_ms)
{
const auto pos = ball.getPosition();
const auto delta = update_ms.asSeconds() * velocity;
sf::Vector2f ball_pos(pos.x + direction.x * delta * 2, pos.y + direction.y * delta * 2);
if (new_pos.x - ball_radius < 0)
{ // left window edge
direction.x *= -1;
ball_pos.x = 0 + ball_radius;
}
else if (new_pos.x + ball_radius >= window_width)
{ // right window edge
direction.x *= -1;
ball_pos.x = window_width - ball_radius;
}
else if (new_pos.y - ball_radius < 0)
{ // top of window
direction.y *= -1;
ball_pos.y = 0 + ball_radius;
}
else if (new_pos.y + ball_radius >= window_height)
{ // bottom of window
direction.y *= -1;
ball_pos.y = window_height - ball_radius;
}
ball.setPosition(ball_pos);
elapsed -= update_ms;
}
window.clear(sf::Color(50, 200, 50));
window.draw(ball);
window.display();
}
return EXIT_SUCCESS;
}
-
Thank you,
You are very help me and I put also the paddle.
-
You are welcome... good to know that it helps :)