Bonjour!
Je fais un projet basé sur le tutorial du bouquin pour apprendre la SFML. Il faut cliquer sur des fruits mais quand je clique dessu rien se passe... J'éssaie d'adapter le code pour faire fonctionner la souris mais rien se produit quand je clique sur les dit-fruits.
Voici les quelques codes concerner, enfin ce que je crois:
Fruit.cpp
#include "Fruit.hpp"
#include "DataTables.hpp"
#include "Utility.hpp"
#include "CommandQueue.hpp"
#include "SoundNode.hpp"
#include "ResourceHolder.hpp"
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderStates.hpp>
#include <cmath>
using namespace std::placeholders;
namespace
{
const std::vector<FruitData> Table = initializeFruitData();
}
Fruit::Fruit(Type type, const TextureHolder& textures, const FontHolder& fonts)
: Entity(Table[type].hitpoints)
, mType(type)
, mSprite(textures.get(Table[type].texture), Table[type].textureRect)
, mExplosion(textures.get(Textures::Explosion))
, mShowExplosion(true)
, mPlayedExplosionSound(false)
, mTravelledDistance(0.f)
, mDirectionIndex(0)
{
mExplosion.setFrameSize(sf::Vector2i(256, 256));
mExplosion.setNumFrames(16);
mExplosion.setDuration(sf::seconds(1));
centerOrigin(mSprite);
centerOrigin(mExplosion);
}
void Fruit::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{
if (isDestroyed() && mShowExplosion)
target.draw(mExplosion, states);
else
target.draw(mSprite, states);
}
void Fruit::updateCurrent(sf::Time dt, CommandQueue& commands)
{
if (isDestroyed())
{
mExplosion.update(dt);
// Play explosion sound only once
if (!mPlayedExplosionSound)
{
SoundEffect::ID soundEffect = (randomInt(2) == 0) ? SoundEffect::Explosion1 : SoundEffect::Explosion2;
playLocalSound(commands, soundEffect);
mPlayedExplosionSound = true;
}
return;
}
// Update enemy movement pattern; apply velocity
updateMovementPattern(dt);
Entity::updateCurrent(dt, commands);
}
unsigned int Fruit::getCategory() const
{
if (isAllied())
return Category::Fruit;
else
return Category::PlayerMouse;
}
sf::FloatRect Fruit::getBoundingRect() const
{
return getWorldTransform().transformRect(mSprite.getGlobalBounds());
}
bool Fruit::isMarkedForRemoval() const
{
return isDestroyed() && (mExplosion.isFinished() || !mShowExplosion);
}
void Fruit::remove()
{
Entity::remove();
mShowExplosion = false;
}
bool Fruit::isAllied() const
{
return mType == Neutral;
}
float Fruit::getMaxSpeed() const
{
return Table[mType].speed;
}
void Fruit::playLocalSound(CommandQueue& commands, SoundEffect::ID effect)
{
sf::Vector2f worldPosition = getWorldPosition();
Command command;
command.category = Category::SoundEffect;
command.action = derivedAction<SoundNode>(
[effect, worldPosition](SoundNode& node, sf::Time)
{
node.playSound(effect, worldPosition);
});
commands.push(command);
}
void Fruit::updateMovementPattern(sf::Time dt)
{
// Enemy airplane: Movement pattern
const std::vector<Direction>& directions = Table[mType].directions;
if (!directions.empty())
{
// Moved long enough in current direction: Change direction
if (mTravelledDistance > directions[mDirectionIndex].distance)
{
mDirectionIndex = (mDirectionIndex + 1) % directions.size();
mTravelledDistance = 0.f;
}
// Compute velocity from direction
float radians = toRadian(directions[mDirectionIndex].angle + 90.f);
float vx = getMaxSpeed() * std::cos(radians);
float vy = getMaxSpeed() * std::sin(radians);
setVelocity(vx, vy);
mTravelledDistance += getMaxSpeed() * dt.asSeconds();
}
}
Fruit.hpp
#ifndef FRUIT_HPP
#define FRUIT_HPP
#include "Entity.hpp"
#include "Command.hpp"
#include "ResourceIdentifiers.hpp"
#include "TextNode.hpp"
#include "Animation.hpp"
#include <SFML/System/Clock.hpp>
#include <SFML/Graphics/Sprite.hpp>
class Fruit : public Entity
{
public:
enum Type
{
Apple,
Orange,
Cherry,
Pear,
Banana,
Pineapple,
Neutral,
TypeCount
};
public:
Fruit(Type type, const TextureHolder& textures, const FontHolder& fonts);
virtual unsigned int getCategory() const;
virtual sf::FloatRect getBoundingRect() const;
virtual void remove();
virtual bool isMarkedForRemoval() const;
bool isAllied() const;
float getMaxSpeed() const;
void playLocalSound(CommandQueue& commands, SoundEffect::ID effect);
private:
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const;
virtual void updateCurrent(sf::Time dt, CommandQueue& commands);
void updateMovementPattern(sf::Time dt);
private:
Type mType;
sf::Sprite mSprite;
Animation mExplosion;
bool mPlayedExplosionSound;
bool mShowExplosion;
float mTravelledDistance;
std::size_t mDirectionIndex;
};
#endif // FRUIT_HPP
Player.cpp
#include "Player.hpp"
#include "CommandQueue.hpp"
#include "Fruit.hpp"
#include "Foreach.hpp"
#include "SoundNode.hpp"
#include "DataTables.hpp"
#include <map>
#include <string>
#include <algorithm>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderStates.hpp>
using namespace std::placeholders;
struct ClickOnFruit
{
ClickOnFruit(bool checkFruitClicked)
: ifFruitClickTrue(checkFruitClicked)
{
}
void operator() (Fruit& fruit, sf::Time) const
{
fruit.remove();
}
bool ifFruitClickTrue;
};
Player::Player()
{
}
Player::Player(Action Action)
: mCurrentMissionStatus(MissionRunning)
{
// Set initial key bindings
mKeyBinding[sf::Mouse::Left] = LeftClick;
// Set initial action bindings
initializeActions();
// Assign all categories to player
FOREACH(auto& pair, mActionBinding)
pair.second.category = Category::PlayerMouse;
}
void Player::handleEvent(const sf::Event& event, CommandQueue& commands)
{
if (event.type == sf::Event::MouseButtonPressed)
{
// Check if pressed key appears in key binding, trigger command if so
auto found = mKeyBinding.find(event.mouseButton.button);
if (found != mKeyBinding.end() && !isRealtimeAction(found->second))
commands.push(mActionBinding[found->second]);
}
}
void Player::handleRealtimeInput(CommandQueue& commands)
{
// Traverse all assigned keys and check if they are pressed
FOREACH(auto pair, mKeyBinding)
{
// If key is pressed, lookup action and trigger corresponding command
if (sf::Mouse::isButtonPressed(pair.first) && isRealtimeAction(pair.second))
commands.push(mActionBinding[pair.second]);
}
}
void Player::setMissionStatus(MissionStatus status)
{
mCurrentMissionStatus = status;
}
Player::MissionStatus Player::getMissionStatus() const
{
return mCurrentMissionStatus;
}
void Player::initializeActions()
{
mActionBinding[LeftClick].action = derivedAction<Fruit>(ClickOnFruit(true));
}
bool Player::isRealtimeAction(Action action)
{
switch (action)
{
case LeftClick:
return true;
default:
return false;
}
}
void Player::assignKey(Action action, sf::Mouse::Button key)
{
// Remove all keys that already map to action
for (auto itr = mKeyBinding.begin(); itr != mKeyBinding.end();)
{
if (itr->second == action)
mKeyBinding.erase(itr++);
else
++itr;
}
// Insert new binding
mKeyBinding[key] = action;
}
sf::Mouse::Button Player::getAssignedKey(Action action) const
{
FOREACH(auto pair, mKeyBinding)
{
if (pair.second == action)
return pair.first;
}
return sf::Mouse::Button::Left;
}
unsigned int Player::getCategory() const
{
return Category::PlayerMouse;
}
void Player::remove()
{
Entity::remove();
}
bool Player::isMarkedForRemoval() const
{
return isDestroyed();
}
Player.hpp
#ifndef BOOK_PLAYER_HPP
#define BOOK_PLAYER_HPP
#include "Command.hpp"
#include "Entity.hpp"
#include <SFML/Window/Event.hpp>
#include <map>
class CommandQueue;
class Player : public Entity
{
public:
enum Action
{
LeftClick,
ActionCount
};
enum MissionStatus
{
MissionRunning,
MissionSuccess,
MissionFailure
};
public:
enum Type
{
HitPoints,
TypeCount
};
public:
Player();
Player(Action action);
virtual unsigned int getCategory() const;
void handleEvent(const sf::Event& event, CommandQueue& commands);
void handleRealtimeInput(CommandQueue& commands);
void remove();
void assignKey(Action action, sf::Mouse::Button key);
sf::Mouse::Button getAssignedKey(Action action) const;
bool isMarkedForRemoval() const;
void setMissionStatus(MissionStatus status);
MissionStatus getMissionStatus() const;
private:
Type mType;
void initializeActions();
static bool isRealtimeAction(Action action);
private:
std::map<sf::Mouse::Button, Action> mKeyBinding;
std::map<Action, Command> mActionBinding;
MissionStatus mCurrentMissionStatus;
};
#endif // BOOK_PLAYER_HPP
World.cpp
`#include "World.hpp"
#include "Foreach.hpp"
#include "TextNode.hpp"
#include "ParticleNode.hpp"
#include "SoundNode.hpp"
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <algorithm>
#include <cmath>
#include <limits>
World::World(sf::RenderTarget& outputTarget, FontHolder& fonts, SoundPlayer& sounds)
: mTarget(outputTarget)
, mSceneTexture()
, mWorldView(outputTarget.getDefaultView())
, mTextures()
, mFonts(fonts)
, mSounds(sounds)
, mSceneGraph()
, mSceneLayers()
, mWorldBounds(0.f, 0.f, mWorldView.getSize().x, 5000.f)
, mSpawnPosition(mWorldView.getSize().x / 2.f, mWorldBounds.height - mWorldView.getSize().y / 2.f)
, mScrollSpeed(-50.f)
, mPlayerMouse(nullptr)
, mEnemySpawnPoints()
, mActiveFruits()
{
mSceneTexture.create(mTarget.getSize().x, mTarget.getSize().y);
loadTextures();
buildScene();
// Prepare the view
mWorldView.setCenter(mSpawnPosition);
}
void World::update(sf::Time dt)
{
// Scroll the world, reset player velocity
mWorldView.move(0.f, mScrollSpeed * dt.asSeconds());
// Setup commands to destroy entities
destroyEntitiesOutsideView();
// Forward commands to scene graph
while (!mCommandQueue.isEmpty())
mSceneGraph.onCommand(mCommandQueue.pop(), dt);
handleCollisions();
// Remove all destroyed entities, create new ones
mSceneGraph.removeWrecks();
spawnEnemies();
// Regular update step
mSceneGraph.update(dt, mCommandQueue);
updateSounds();
}
void World::draw()
{
if (PostEffect::isSupported())
{
mSceneTexture.clear();
mSceneTexture.setView(mWorldView);
mSceneTexture.draw(mSceneGraph);
mSceneTexture.display();
mBloomEffect.apply(mSceneTexture, mTarget);
}
else
{
mTarget.setView(mWorldView);
mTarget.draw(mSceneGraph);
}
}
CommandQueue& World::getCommandQueue()
{
return mCommandQueue;
}
bool World::hasAlivePlayer() const
{
return !mPlayerMouse->isMarkedForRemoval();
}
void World::loadTextures()
{
mTextures.load(Textures::Entities, "Media/Graphiques/Entitées.png");
mTextures.load(Textures::Background,"Media/Graphiques/Background.png");
mTextures.load(Textures::Explosion, "Media/Graphiques/Explosion.png");
mTextures.load(Textures::Particle, "Media/Graphiques/Particule.png");
}
void World::adaptPlayerVelocity()
{
sf::Vector2f velocity = mPlayerMouse->getVelocity();
// If moving diagonally, reduce velocity (to have always same velocity)
if (velocity.x != 0.f && velocity.y != 0.f)
mPlayerMouse->setVelocity(velocity / std::sqrt(2.f));
// Add scrolling velocity
mPlayerMouse->accelerate(0.f, mScrollSpeed);
}
bool matchesCategories(SceneNode::Pair& colliders, Category::Type type1, Category::Type type2)
{
unsigned int category1 = colliders.first->getCategory();
unsigned int category2 = colliders.second->getCategory();
// Make sure first pair entry has category type1 and second has type2
if (type1 & category1 && type2 & category2)
{
return true;
}
else if (type1 & category2 && type2 & category1)
{
std::swap(colliders.first, colliders.second);
return true;
}
else
{
return false;
}
}
void World::updateSounds()
{
// Set listener's position to player position
mSounds.setListenerPosition();
// Remove unused sounds
mSounds.removeStoppedSounds();
}
void World::buildScene()
{
// Initialize the different layers
for (std::size_t i = 0; i < LayerCount; ++i)
{
Category::Type category = (i == Background) ? Category::Layer : Category::None;
SceneNode::Ptr layer(new SceneNode(category));
mSceneLayers[i] = layer.get();
mSceneGraph.attachChild(std::move(layer));
}
// Prepare the tiled background
sf::Texture& backgroundTexture = mTextures.get(Textures::Background);
backgroundTexture.setRepeated(true);
float viewHeight = mWorldView.getSize().y;
sf::IntRect textureRect(mWorldBounds);
textureRect.height += static_cast<int>(viewHeight);
// Add the background sprite to the scene
std::unique_ptr<SpriteNode> backgroundSprite(new SpriteNode(backgroundTexture, textureRect));
backgroundSprite->setPosition(mWorldBounds.left, mWorldBounds.top - viewHeight);
mSceneLayers[Background]->attachChild(std::move(backgroundSprite));
// Add particle node to the scene
std::unique_ptr<ParticleNode> smokeNode(new ParticleNode(Particle::Smoke, mTextures));
mSceneLayers[Background]->attachChild(std::move(smokeNode));
// Add propellant particle node to the scene
std::unique_ptr<ParticleNode> propellantNode(new ParticleNode(Particle::Propellant, mTextures));
mSceneLayers[Background]->attachChild(std::move(propellantNode));
// Add sound effect node
std::unique_ptr<SoundNode> soundNode(new SoundNode(mSounds));
mSceneGraph.attachChild(std::move(soundNode));
// Add player
std::unique_ptr<Player> player(new Player(Player::LeftClick));
mPlayerMouse = player.get();
mSceneLayers[Background]->attachChild(std::move(player));
// Add enemy aircraft
addEnemies();
}
void World::addEnemies()
{
// Add enemies to the spawn point container
addEnemy(Fruit::Apple, 0.f, 500.f);
addEnemy(Fruit::Orange, 0.f, 400.f);
addEnemy(Fruit::Apple, +100.f, 1150.f);
addEnemy(Fruit::Apple, -100.f, 1150.f);
// Sort all enemies according to their y value, such that lower enemies are checked first for spawning
std::sort(mEnemySpawnPoints.begin(), mEnemySpawnPoints.end(), [](SpawnPoint lhs, SpawnPoint rhs)
{
return lhs.y < rhs.y;
});
}
void World::addEnemy(Fruit::Type type, float relX, float relY)
{
SpawnPoint spawn(type, mSpawnPosition.x + relX, mSpawnPosition.y - relY);
mEnemySpawnPoints.push_back(spawn);
}
void World::spawnEnemies()
{
// Spawn all enemies entering the view area (including distance) this frame
while (!mEnemySpawnPoints.empty()
&& mEnemySpawnPoints.back().y > getBattlefieldBounds().top)
{
SpawnPoint spawn = mEnemySpawnPoints.back();
std::unique_ptr<Fruit> enemy(new Fruit(spawn.type, mTextures, mFonts));
enemy->setPosition(spawn.x, spawn.y);
enemy->setRotation(180.f);
mSceneLayers[Background]->attachChild(std::move(enemy));
// Enemy is spawned, remove from the list to spawn
mEnemySpawnPoints.pop_back();
}
}
void World::destroyEntitiesOutsideView()
{
Command command;
command.category = Category::Fruit;
command.action = derivedAction<Entity>([this](Entity& e, sf::Time)
{
if (!getBattlefieldBounds().intersects(e.getBoundingRect()))
e.remove();
});
mCommandQueue.push(command);
}
void World::guideMissiles()
{
// Setup command that stores all enemies in mActiveEnemies
Command enemyCollector;
enemyCollector.category = Category::Fruit;
enemyCollector.action = derivedAction<Fruit>([this](Fruit& enemy, sf::Time)
{
if (!enemy.isDestroyed())
mActiveFruits.push_back(&enemy);
});
// Push commands, reset active enemies
mCommandQueue.push(enemyCollector);
mActiveFruits.clear();
}
sf::FloatRect World::getViewBounds() const
{
return sf::FloatRect(mWorldView.getCenter() - mWorldView.getSize() / 2.f, mWorldView.getSize());
}
sf::FloatRect World::getBattlefieldBounds() const
{
// Return view bounds + some area at top, where enemies spawn
sf::FloatRect bounds = getViewBounds();
bounds.top -= 100.f;
bounds.height += 100.f;
return bounds;
}
void World::handleCollisions()
{
std::set<SceneNode::Pair> collisionPairs;
mSceneGraph.checkSceneCollision(mSceneGraph, collisionPairs);
FOREACH(SceneNode::Pair pair, collisionPairs)
{
if (matchesCategories(pair, Category::PlayerMouse, Category::Fruit))
{
auto& player = static_cast<Player&>(*pair.first);
auto& enemy = static_cast<Fruit&>(*pair.second);
enemy.destroy();
}
}
}
World.h
#include "Player.hpp"
#include <SFML/System/NonCopyable.hpp>
#include <SFML/Graphics/View.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <array>
#include <queue>
// Forward declaration
namespace sf
{
class RenderTarget;
}
class World : private sf::NonCopyable
{
public:
World(sf::RenderTarget& outputTarget, FontHolder& fonts, SoundPlayer& sounds);
void update(sf::Time dt);
void draw();
CommandQueue& getCommandQueue();
bool hasAlivePlayer() const;
int initializeEnemies();
private:
void loadTextures();
void adaptPlayerVelocity();
void handleCollisions();
void updateSounds();
void buildScene();
void addEnemies();
void addEnemy(Fruit::Type type, float relX, float relY);
void spawnEnemies();
void destroyEntitiesOutsideView();
void guideMissiles();
sf::FloatRect getViewBounds() const;
sf::FloatRect getBattlefieldBounds() const;
private:
enum Layer
{
Background,
LayerCount
};
struct SpawnPoint
{
SpawnPoint(Fruit::Type type, float x, float y)
: type(type)
, x(x)
, y(y)
{
}
Fruit::Type type;
float x;
float y;
};
private:
sf::RenderTarget& mTarget;
sf::RenderTexture mSceneTexture;
sf::View mWorldView;
TextureHolder mTextures;
FontHolder& mFonts;
SoundPlayer& mSounds;
SceneNode mSceneGraph;
std::array<SceneNode*, LayerCount> mSceneLayers;
CommandQueue mCommandQueue;
sf::FloatRect mWorldBounds;
sf::Vector2f mSpawnPosition;
Player* mPlayerMouse;
float mScrollSpeed;
Fruit* mFruits;
std::vector<SpawnPoint> mEnemySpawnPoints;
std::vector<Fruit*> mActiveFruits;
BloomEffect mBloomEffect;
int mRounds;
};
#endif // BOOK_WORLD_HPP
merci