C++ Sfml,如何为我的 Sprite 创建一个碰撞框
C++ Sfml, How can I create a collision box for my Sprite
我有问题要问sfml
我对 C++ 和 sfml 比较陌生。
我正在尝试创建 Space Invaders 类型的游戏。
我目前有一些碰撞问题,
在敌人的子弹和火箭之间,
我说的是第 145 行。这一行:
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
你能创造出类似碰撞盒的东西吗?,
因为我不想和整个火箭精灵发生碰撞,
我只想与它的一部分发生碰撞,例如透明部分。
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
void print(std::string string)
{
std::cout << string << std::endl;
}
sf::CircleShape create_bullet(sf::Vector2f possition, sf::Int16 offset)
{
sf::CircleShape circel;
circel.setRadius(10);
circel.setPosition(possition.x + offset, possition.y);
return circel;
}
bool collide(sf::Sprite a, sf::CircleShape b)
{
return a.getGlobalBounds().intersects(b.getGlobalBounds());
}
int main()
{
int speed;
speed = 25;
sf::RenderWindow window(sf::VideoMode(1200, 800), "Space Invaders", sf::Style::Titlebar | sf::Style::Close);
sf::Texture rocket_texture;
if (!rocket_texture.loadFromFile("data/rocket.png"))
{
print("Problem with loding file data/rocket.png");
exit(-1);
}
sf::Texture enemy_texture;
if (!enemy_texture.loadFromFile("data/enemy.png"))
{
print("Problem with loding file data/enemy.png");
exit(-1);
}
sf::Sprite rocket;
sf::Sprite enemy;
std::chrono::milliseconds couldown = std::chrono::milliseconds(0);
std::chrono::milliseconds time;
std::chrono::milliseconds enemy_couldown = std::chrono::milliseconds(0);
bool enemy_fire = false;
float bulletspeed = 0.02;
// sf::CircleShape test = create_bullet();
int changex;
rocket.setTexture(rocket_texture);
rocket.setPosition(500, 650);
rocket.scale(0.5, 0.5);
std::vector<sf::Sprite> enemy_list;
std::vector<sf::CircleShape> player_bullets;
std::vector<sf::CircleShape> enemy_bullets;
enemy.setTexture(enemy_texture);
enemy.scale(0.2, 0.2);
for (int i =0; i<8; i++)
{
enemy.setPosition(i * 150, 400);
enemy_list.push_back(enemy);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
changex = 0;
switch (event.type)
{
// window closed
case sf::Event::Closed:
window.close();
break;
// key pressed
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::A)
{
if (rocket.getPosition().x >= 0 )
{
changex = changex - speed;
}
}
else if (event.key.code == sf::Keyboard::D)
{
if (rocket.getPosition().x <= 1100)
{
changex = changex + speed;
}
}
else if (event.key.code == sf::Keyboard::Space)
{
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (couldown < time - std::chrono::milliseconds(100)){
couldown = time;
player_bullets.push_back(create_bullet(rocket.getPosition(), 47));
}
}
break;
default:
break;
}
rocket.move(changex, 0);
}
window.clear();
window.draw(rocket);
//swindow.draw(test);
for (int i=0; i<player_bullets.size();i++)
{
player_bullets[i].move(0,-bulletspeed);
window.draw(player_bullets[i]);
if (player_bullets[i].getPosition().y < 0)
{
player_bullets.erase(player_bullets.begin()+i);
}
}
for (int i = 0; i < enemy_bullets.size(); i++)
{
enemy_bullets[i].move(0, bulletspeed);
window.draw(enemy_bullets[i]);
if (enemy_bullets[i].getPosition().y > 800)
{
enemy_bullets.erase(enemy_bullets.begin() + i);
}
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
}
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (enemy_couldown < time - std::chrono::milliseconds(2000))
{
enemy_couldown = time;
enemy_fire = true;
}
// Draw all Enemys
for (int i = 0; i < enemy_list.size(); i++)
{
for (int j = 0; j < player_bullets.size(); j++)
{
if (collide(enemy_list[i], player_bullets[j]))
{
enemy_list.erase(enemy_list.begin() + i);
}
}
if (enemy_fire)
{
enemy_couldown = time;
// ADD: Move enemys
enemy_bullets.push_back(create_bullet(enemy_list[i].getPosition(), 13));
}
window.draw(enemy_list[i]);
}
enemy_fire = false;
window.display();
}
return 0;
}
如果你知道怎么做,
我想听听
提前致谢
您可以创建一个从 sf::Sprite 派生的 class,它有一个 sf::FloatRect 作为碰撞框,您需要创建一个函数来设置碰撞框。
class Sprite : public sf::Sprite {
sf::FloatRect hitbox;
}
您可以通过以下方式将 Hitbox 移动到精灵位置:
getTransform().transformRect(hitbox);
我过去曾将此用于 SFML 的命中框。
编辑,这是一个完整的示例程序:
#include <SFML/Graphics.hpp>
/// custom sprite class with hitbox
class HitboxSprite : public sf::Sprite {
public:
/// sets the hitbox
void setHitbox(const sf::FloatRect& hitbox) {
m_hitbox = hitbox;
}
/// gets the hitbox (use this instead of getGlobalBounds())
sf::FloatRect getGlobalHitbox() const {
return getTransform().transformRect(m_hitbox);
}
private:
sf::FloatRect m_hitbox;
};
int main() {
sf::RenderWindow window(sf::VideoMode(256, 128), "Example");
// create two sprites, player and enemy
HitboxSprite player;
player.setPosition({ 64.f, 64.f });
HitboxSprite enemy;
enemy.setPosition({ 128.f, 64.f });
enemy.setColor(sf::Color::Red);
// create sprite texture and apply to sprites
sf::Texture square_texture;
square_texture.loadFromFile("32x32square.png");
player.setTexture(square_texture);
enemy.setTexture(square_texture);
// set custom hitboxes
// (this one starts (8, 8) pixels from the top left and has a size of (16, 16)
// (this means the hitbox will be 1/2 of the square in the middle)
player.setHitbox({ 8.f, 8.f, 16.f, 16.f });
enemy.setHitbox({ 8.f, 8.f, 16.f, 16.f });
sf::Clock clock;
while (window.isOpen()) {
// process events
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
const float dt = clock.restart().asSeconds();
constexpr float player_speed = 128.f;
// move player with arrow keys
player.move({
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) - sf::Keyboard::isKeyPressed(sf::Keyboard::Left)),
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) - sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
});
// check for collision
const bool colliding = player.getGlobalHitbox().intersects(enemy.getGlobalHitbox());
// set background color based on collision
window.clear(colliding ? sf::Color::Green : sf::Color::Blue);
// draw sprites
window.draw(enemy);
window.draw(player);
// display
window.display();
}
return 0;
}
如果您需要解释任何部分,请告诉我。
这是我制作的半透明 png,中间部分是 hitbox:
我有问题要问sfml
我对 C++ 和 sfml 比较陌生。 我正在尝试创建 Space Invaders 类型的游戏。 我目前有一些碰撞问题, 在敌人的子弹和火箭之间, 我说的是第 145 行。这一行:
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
你能创造出类似碰撞盒的东西吗?, 因为我不想和整个火箭精灵发生碰撞, 我只想与它的一部分发生碰撞,例如透明部分。
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
void print(std::string string)
{
std::cout << string << std::endl;
}
sf::CircleShape create_bullet(sf::Vector2f possition, sf::Int16 offset)
{
sf::CircleShape circel;
circel.setRadius(10);
circel.setPosition(possition.x + offset, possition.y);
return circel;
}
bool collide(sf::Sprite a, sf::CircleShape b)
{
return a.getGlobalBounds().intersects(b.getGlobalBounds());
}
int main()
{
int speed;
speed = 25;
sf::RenderWindow window(sf::VideoMode(1200, 800), "Space Invaders", sf::Style::Titlebar | sf::Style::Close);
sf::Texture rocket_texture;
if (!rocket_texture.loadFromFile("data/rocket.png"))
{
print("Problem with loding file data/rocket.png");
exit(-1);
}
sf::Texture enemy_texture;
if (!enemy_texture.loadFromFile("data/enemy.png"))
{
print("Problem with loding file data/enemy.png");
exit(-1);
}
sf::Sprite rocket;
sf::Sprite enemy;
std::chrono::milliseconds couldown = std::chrono::milliseconds(0);
std::chrono::milliseconds time;
std::chrono::milliseconds enemy_couldown = std::chrono::milliseconds(0);
bool enemy_fire = false;
float bulletspeed = 0.02;
// sf::CircleShape test = create_bullet();
int changex;
rocket.setTexture(rocket_texture);
rocket.setPosition(500, 650);
rocket.scale(0.5, 0.5);
std::vector<sf::Sprite> enemy_list;
std::vector<sf::CircleShape> player_bullets;
std::vector<sf::CircleShape> enemy_bullets;
enemy.setTexture(enemy_texture);
enemy.scale(0.2, 0.2);
for (int i =0; i<8; i++)
{
enemy.setPosition(i * 150, 400);
enemy_list.push_back(enemy);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
changex = 0;
switch (event.type)
{
// window closed
case sf::Event::Closed:
window.close();
break;
// key pressed
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::A)
{
if (rocket.getPosition().x >= 0 )
{
changex = changex - speed;
}
}
else if (event.key.code == sf::Keyboard::D)
{
if (rocket.getPosition().x <= 1100)
{
changex = changex + speed;
}
}
else if (event.key.code == sf::Keyboard::Space)
{
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (couldown < time - std::chrono::milliseconds(100)){
couldown = time;
player_bullets.push_back(create_bullet(rocket.getPosition(), 47));
}
}
break;
default:
break;
}
rocket.move(changex, 0);
}
window.clear();
window.draw(rocket);
//swindow.draw(test);
for (int i=0; i<player_bullets.size();i++)
{
player_bullets[i].move(0,-bulletspeed);
window.draw(player_bullets[i]);
if (player_bullets[i].getPosition().y < 0)
{
player_bullets.erase(player_bullets.begin()+i);
}
}
for (int i = 0; i < enemy_bullets.size(); i++)
{
enemy_bullets[i].move(0, bulletspeed);
window.draw(enemy_bullets[i]);
if (enemy_bullets[i].getPosition().y > 800)
{
enemy_bullets.erase(enemy_bullets.begin() + i);
}
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
}
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (enemy_couldown < time - std::chrono::milliseconds(2000))
{
enemy_couldown = time;
enemy_fire = true;
}
// Draw all Enemys
for (int i = 0; i < enemy_list.size(); i++)
{
for (int j = 0; j < player_bullets.size(); j++)
{
if (collide(enemy_list[i], player_bullets[j]))
{
enemy_list.erase(enemy_list.begin() + i);
}
}
if (enemy_fire)
{
enemy_couldown = time;
// ADD: Move enemys
enemy_bullets.push_back(create_bullet(enemy_list[i].getPosition(), 13));
}
window.draw(enemy_list[i]);
}
enemy_fire = false;
window.display();
}
return 0;
}
如果你知道怎么做, 我想听听
提前致谢
您可以创建一个从 sf::Sprite 派生的 class,它有一个 sf::FloatRect 作为碰撞框,您需要创建一个函数来设置碰撞框。
class Sprite : public sf::Sprite {
sf::FloatRect hitbox;
}
您可以通过以下方式将 Hitbox 移动到精灵位置:
getTransform().transformRect(hitbox);
我过去曾将此用于 SFML 的命中框。
编辑,这是一个完整的示例程序:
#include <SFML/Graphics.hpp>
/// custom sprite class with hitbox
class HitboxSprite : public sf::Sprite {
public:
/// sets the hitbox
void setHitbox(const sf::FloatRect& hitbox) {
m_hitbox = hitbox;
}
/// gets the hitbox (use this instead of getGlobalBounds())
sf::FloatRect getGlobalHitbox() const {
return getTransform().transformRect(m_hitbox);
}
private:
sf::FloatRect m_hitbox;
};
int main() {
sf::RenderWindow window(sf::VideoMode(256, 128), "Example");
// create two sprites, player and enemy
HitboxSprite player;
player.setPosition({ 64.f, 64.f });
HitboxSprite enemy;
enemy.setPosition({ 128.f, 64.f });
enemy.setColor(sf::Color::Red);
// create sprite texture and apply to sprites
sf::Texture square_texture;
square_texture.loadFromFile("32x32square.png");
player.setTexture(square_texture);
enemy.setTexture(square_texture);
// set custom hitboxes
// (this one starts (8, 8) pixels from the top left and has a size of (16, 16)
// (this means the hitbox will be 1/2 of the square in the middle)
player.setHitbox({ 8.f, 8.f, 16.f, 16.f });
enemy.setHitbox({ 8.f, 8.f, 16.f, 16.f });
sf::Clock clock;
while (window.isOpen()) {
// process events
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
const float dt = clock.restart().asSeconds();
constexpr float player_speed = 128.f;
// move player with arrow keys
player.move({
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) - sf::Keyboard::isKeyPressed(sf::Keyboard::Left)),
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) - sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
});
// check for collision
const bool colliding = player.getGlobalHitbox().intersects(enemy.getGlobalHitbox());
// set background color based on collision
window.clear(colliding ? sf::Color::Green : sf::Color::Blue);
// draw sprites
window.draw(enemy);
window.draw(player);
// display
window.display();
}
return 0;
}
如果您需要解释任何部分,请告诉我。
这是我制作的半透明 png,中间部分是 hitbox: