Всем привет) Пожалуйста, помогите разобраться. Кратко расскажу в чём дело. В учебных целях делаю игру Arkanoid на
SFML. Сделал простенький вариант с счётчиком очков, уровня. Из объектов (
structur) шарик, платформа и кирпичики. Вот в последних вся проблема. Решил сделать у них sprite, чтоб красиво было. Не поучилось. Посидел ещё. В итоге сделал sprite для платформы, а кирпичи не получаются. Точнее они рисуются коряво. Возможно проблема в
initBricks, а именно в моменте заполнения вектора
bricks
За ранние извиняюсь за говно код) Все картинки хранятся в
images в одной директории с исходным кодом
//RenderWindow window(VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Arkanoid");
/*
Реализована пауза при нажатии на пробел
Подсчёт очков
*/
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cmath>
using namespace std;
using namespace sf;
constexpr int WINDOW_WIDTH{ 800 }, WINDOW_HEIGHT{ 600 };
constexpr float BULL_RADIUS{ 10.f }, BALL_VELOCITY{ 200.f };
constexpr float PABBLE_WIDTH{ 60.f }, PABBLE_HEIGHT{ 20.f }, PABBLE_VELOCITY{ 200.f };
constexpr float BLOCK_WIDTH{ 60.f }, BLOCK_HEIGHT{ 20.f };
constexpr int COUNT_BLOCKS_X{ 11 }, COUNT_BLOCKS_Y{ 4 };
const string IMG_PADLE{ "images/paddle.png" }, IMG_BRICK{ "images/brick_01.png" };
struct Ball
{
CircleShape shape;
Vector2f velocity{ -BALL_VELOCITY, -BALL_VELOCITY };
bool lost{ false };
Ball(float mX, float mY)
{
shape.setPosition(mX, mY);
shape.setRadius(BULL_RADIUS);
shape.setFillColor(Color::White);
shape.setOrigin(BULL_RADIUS, BULL_RADIUS);
}
void lostTheBall(bool &lost)
{
lost = !lost;
cout << "Game over!" << endl;
}
void update(const float dt)
{
Vector2f position = shape.getPosition();
position += velocity * dt;
if ((position.x + BULL_RADIUS >= WINDOW_WIDTH) && (velocity.x > 0))
velocity.x = -velocity.x;
if ((position.x - BULL_RADIUS < 0) && (velocity.x < 0))
velocity.x = -velocity.x;
if ((position.y + BULL_RADIUS >= WINDOW_HEIGHT) && (velocity.y > 0))
{
velocity.y = -velocity.y;
lostTheBall(lost);
}
if ((position.y - BULL_RADIUS < 0) && (velocity.y < 0))
velocity.y = -velocity.y;
shape.setPosition(position);
}
float sideLeft() { return shape.getPosition().x - shape.getRadius(); }
float sideRight() { return shape.getPosition().x + shape.getRadius(); }
float sideUp() { return shape.getPosition().y - shape.getRadius(); }
float sideBown() { return shape.getPosition().y + shape.getRadius(); }
};
struct Paddle
{
Texture texture;
Sprite sprite;
Vector2f velocity;
Paddle(const string &path, float mX, float mY)
{
if (!texture.loadFromFile(path))
{
cout << "Error loading file" << endl;
exit(1);
}
texture.setSmooth(true);
sprite.setTexture(texture);
sprite.setPosition(mX, mY);
Rect<float> size = sprite.getGlobalBounds();
sprite.setOrigin(Vector2f(size.width / 2, size.height / 2));
}
void update(const float dt)
{
Vector2f position = sprite.getPosition();
position += velocity * dt;
float step = sprite.getOrigin().x;
if (Keyboard::isKeyPressed(Keyboard::Key::Left) && (position.x - step > 0))
velocity.x = -PABBLE_VELOCITY;
else if (Keyboard::isKeyPressed(Keyboard::Key::Right) && (position.x + step < WINDOW_WIDTH))
velocity.x = PABBLE_VELOCITY;
else
velocity.x = 0;
sprite.setPosition(position);
}
float sideLeft() { return sprite.getPosition().x - sprite.getOrigin().x; }
float sideRight() { return sprite.getPosition().x + sprite.getOrigin().x; }
float sideUp() { return sprite.getPosition().y - sprite.getOrigin().y; }
float sideBown() { return sprite.getPosition().y + sprite.getOrigin().y; }
};
struct Brick
{
Texture texture;
Sprite sprite;
bool destroyed{ false };
Brick(const string &path, float mX, float mY)
{
if (!texture.loadFromFile(path))
{
cout << "Error loading file" << endl;
exit(1);
}
texture.setSmooth(true);
sprite.setTexture(texture);
sprite.setPosition(mX, mY);
Rect<float> size = sprite.getGlobalBounds();
sprite.setOrigin(Vector2f(size.width / 2, size.height / 2));
}
float sideLeft() { return sprite.getPosition().x - sprite.getOrigin().x; }
float sideRight() { return sprite.getPosition().x + sprite.getOrigin().x; }
float sideUp() { return sprite.getPosition().y - sprite.getOrigin().y; }
float sideBown() { return sprite.getPosition().y + sprite.getOrigin().y; }
};
struct Progress
{
int playerPoints{ 0 };
int playerLevel{ 0 };
};
struct World
{
Ball ball{ WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 };
Paddle paddle{ IMG_PADLE, WINDOW_WIDTH / 2, WINDOW_HEIGHT - 50 };
Progress progress;
vector<Brick> bricks;
bool pause{ false };
bool restart{ false };
};
template <class T1, class T2>
bool isIntersecting(T1 &mA, T2 &mB)
{
//если есть пересечение, то возвращает TRUE
return mA.sideRight() >= mB.sideLeft() && mA.sideLeft() <= mB.sideRight() &&
mA.sideBown() >= mB.sideUp() && mA.sideUp() <= mB.sideBown();
}
void testCollision(Paddle &mPaddle, Ball &mBall)
{
if (!isIntersecting(mPaddle, mBall))
return;
mBall.velocity.y = -BALL_VELOCITY;
if (mBall.shape.getPosition().x < mPaddle.sprite.getPosition().x)
mBall.velocity.x = -BALL_VELOCITY;
else
mBall.velocity.x = BALL_VELOCITY;
}
void testCollision(Brick &mBrick, Ball &mBall, Progress &mProg)
{
if (!isIntersecting(mBrick, mBall))
return;
mBrick.destroyed = true;
mProg.playerPoints += 10;
cout << "playerPoints = " << mProg.playerPoints << endl;
float overlapLeft{ mBall.sideRight() - mBrick.sideLeft() };
float overlapRight{ mBrick.sideRight() - mBall.sideLeft() };
float overlapTop{ mBall.sideBown() - mBrick.sideUp() };
float overlapBottom{ mBrick.sideBown() - mBall.sideUp() };
bool ballFromLeft(abs(overlapLeft) < abs(overlapRight));
bool ballFromTop(abs(overlapTop) < abs(overlapBottom));
float minOverlapX{ ballFromLeft ? overlapLeft : overlapRight };
float minOverlapY{ ballFromTop ? overlapTop : overlapBottom };
if (abs(minOverlapX) < abs(minOverlapY))
mBall.velocity.x = ballFromLeft ? -BALL_VELOCITY : BALL_VELOCITY;
else
mBall.velocity.y = ballFromTop ? -BALL_VELOCITY : BALL_VELOCITY;
}
void initBricks(World &world)
{
/*Texture brickTexture;
brickTexture.loadFromFile(IMG_BRICK);
brickTexture.setSmooth(true);*/
//инициализация кирпичей
for (int iX{ 0 }; iX < COUNT_BLOCKS_X; ++iX)
for (int iY{ 0 }; iY < COUNT_BLOCKS_Y; ++iY)
world.bricks.emplace_back(IMG_BRICK, (iX + 1) * (BLOCK_WIDTH + 3) + 22, (iY + 2) * (BLOCK_HEIGHT + 3));
}
void updateWorld(World &world, Clock &clock)
{
const float deltaTime = clock.restart().asSeconds();
if (world.pause)
return;
world.ball.update(deltaTime);
world.paddle.update(deltaTime);
testCollision(world.paddle, world.ball);
for (auto &brick : world.bricks)
testCollision(brick, world.ball, world.progress);
world.bricks.erase(remove_if(begin(world.bricks), end(world.bricks), [](const Brick &mBrick) { return mBrick.destroyed; }), end(world.bricks));
}
void pollEvents(World &world, RenderWindow &window)
{
Event event;
while (window.pollEvent(event))
{
switch (event.type)
{
case Event::Closed:
window.close();
break;
case Event::KeyPressed:
if (event.key.code == Keyboard::Space)
world.pause = !world.pause;
break;
default:
break;
}
}
}
void redrawWorld(World &world, RenderWindow &window)
{
window.setFramerateLimit(60);
window.clear(Color::Black);
window.draw(world.ball.shape);
window.draw(world.paddle.sprite);
for (auto &brick : world.bricks)
window.draw(brick.sprite);
window.display();
}
int main()
{
ContextSettings settings;
settings.antialiasingLevel = 8;
RenderWindow window(VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Arkanoid");
Clock clock;
World world;
initBricks(world);
while (window.isOpen())
{
pollEvents(world, window);
updateWorld(world, clock);
redrawWorld(world, window);
}
return 0;
}