Pushback to array without copying - c++

I have a program that has a public static array of sf::RenderWindows, a non copyable window from the sfml library. Anyway when I try to push_back to the vector I get a error because it is not copy able. I have tried doing it with refrances and pointers and well and always get some sort of error. If I try to use refrances i get like 20 errors saying pointer to refrance is illegal and if I try to use pointers constructors like .draw and .clear "Don't exist". If there is a way to use something like push_back that just doesn't copy that would be great if not I'll give my code when I try with both refrances and pointers.
Refrances
static vector <MakeKey::NewKey> KeyArray;
static vector <sf::RenderWindow&> WindowArray;
static void StepWindows(sf::RenderWindow & window, MakeKey::NewKey key)
{
sf::Clock clock;
MakeTopWindow(window);
setShape(window, key.Img);
window.clear(sf::Color::Transparent);
window.draw(key.Sprite);
window.display();
if (clock.getElapsedTime().asMicroseconds() > 1000)
{
window.setPosition(MakeKey::Gravity(window, key));
}
}
Refrances when i push_back
MakeKey::KeyArray.push_back(Key);
MakeKey::WindowArray.push_back(window);
Pointers
static vector <MakeKey::NewKey> KeyArray;
static vector <sf::RenderWindow*> WindowArray;
static void StepWindows(sf::RenderWindow & window, MakeKey::NewKey key)
{
sf::Clock clock;
MakeTopWindow(window);
setShape(window, key.Img);
window.clear(sf::Color::Transparent);
window.draw(key.Sprite);
window.display();
if (clock.getElapsedTime().asMicroseconds() > 1000)
{
window.setPosition(MakeKey::Gravity(window, key));
}
}
Pointers when i push_back
MakeKey::KeyArray.push_back(Key);
MakeKey::WindowArray.push_back(&window);
//The error here is that is 2 undefined external symbol because I declaired both arrays as static but if they are not static I get a error on where I push_back saying refrance must be relative to specific class.
Thanks
My entire class because someone wanted it - still getting linker error but im trying to figure that out.
static class MakeKey
{
public:
typedef struct KeyStruct {
sf::Image Img;
sf::Texture Tex;
sf::Sprite Sprite;
typedef struct Velocety {
static int x;
static int y;
};
typedef struct Acceleration {
static int x;
static int y;
};
typedef struct HitSide {
static bool x()
{
typedef struct Side {
static bool left(sf::RenderWindow window, sf::Image image) {
int XPos{ window.getPosition().x };
if (XPos > (sf::VideoMode::getDesktopMode().width - image.getSize().x - 1))
return true;
return false;
}
static bool right(sf::RenderWindow window, sf::Image image)
{
int XPos{ window.getPosition().x };
if (XPos < 1 + image.getSize().x)
return true;
return false;
}
};
}
static bool y(sf::RenderWindow window, sf::Image image)
{
typedef struct Side {
static bool top(sf::RenderWindow window, sf::Image image) {
int YPos = window.getPosition().y;
if (YPos > (sf::VideoMode::getDesktopMode().width - image.getSize().y - 1))
return true;
return false;
}
static bool bottom(sf::RenderWindow window, sf::Image image)
{
int YPos = window.getPosition().y;
if (YPos < 1 + image.getSize().y)
return true;
return false;
}
};
}
};
static sf::Clock OffGroundClock;
}NewKey;
static sf::Vector2i Gravity(sf::RenderWindow * window, MakeKey::NewKey Key)
{
int XPos = window->getPosition().x;
int YPos = window->getPosition().y;
cout << "Gravity Debug Starting\n" << XPos << " and " << YPos << endl;
YPos += 2;
if (YPos < 1 + Key.Img.getSize().y)
YPos = 1 + Key.Img.getSize().y;
if (YPos > (sf::VideoMode::getDesktopMode().height - Key.Img.getSize().y - 1))
YPos = (YPos = sf::VideoMode::getDesktopMode().height - Key.Img.getSize().y);
if (XPos < 1 + Key.Img.getSize().x)
XPos = (1 + Key.Img.getSize().x);
if (XPos > (sf::VideoMode::getDesktopMode().width - Key.Img.getSize().x - 1))
XPos = sf::VideoMode::getDesktopMode().width - Key.Img.getSize().x;
cout << XPos << " and " << YPos << endl;
return sf::Vector2i(XPos, YPos);
}
/*void Step() {
velocity.x += acceleration.x;
velocity.y += acceleration.y;
}*/
static bool setShape(sf::RenderWindow * window, const sf::Image& image)
{
HWND hwnd = window->getSystemHandle();
const sf::Uint8* pixelData = image.getPixelsPtr();
HRGN hRegion = CreateRectRgn(0, 0, image.getSize().x, image.getSize().y);
// Determine the visible region
for (unsigned int y = 0; y < image.getSize().y; y++)
{
for (unsigned int x = 0; x < image.getSize().x; x++)
{
if (pixelData[y * image.getSize().x * 4 + x * 4 + 3] == 0)
{
HRGN hRegionPixel = CreateRectRgn(x, y, x + 1, y + 1);
CombineRgn(hRegion, hRegion, hRegionPixel, RGN_XOR);
DeleteObject(hRegionPixel);
}
}
}
SetWindowRgn(hwnd, hRegion, true);
DeleteObject(hRegion);
return true;
}
static sf::Vector2i RandSpawn(sf::Image image)
{
cout << "Desktop Demensions:" << sf::VideoMode::getDesktopMode().width << " by " << sf::VideoMode::getDesktopMode().height << endl;
cout << "Starting Relocation Debug" << endl;
std::random_device rand;
int RandX = (rand() % sf::VideoMode::getDesktopMode().width) - image.getSize().x;
int RandY = (rand() % sf::VideoMode::getDesktopMode().height) - image.getSize().y;
if (RandX < 1 + image.getSize().x)
cout << "Image X Size: " << image.getSize().x << endl << "RandX: " << RandX << endl;
RandX = image.getSize().x;
cout << "Image X Size: " << image.getSize().x << endl << "RandX: " << RandX << endl;
if (RandY < 1 + image.getSize().y)
cout << "Image Y Size: " << image.getSize().y << endl << "RandY: " << RandY << endl;
RandY = image.getSize().y;
cout << "Image Y Size: " << image.getSize().y << endl << "RandY: " << RandY << endl;
cout << "Randomly Relocated\n" << RandX << " and " << RandY << endl;
cout << "Relocation Debug Complete\n\n" << endl;
return sf::Vector2i(RandX, RandY);
}
static bool setTransparency(HWND hwnd, unsigned char alpha)
{
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
return true;
}
static void MakeTopWindow(sf::RenderWindow * windowPoint)
{
HWND hwndPoint = windowPoint->getSystemHandle();
SetWindowPos(hwndPoint, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
static vector <MakeKey::NewKey> KeyArray;
static vector <sf::RenderWindow*> WindowArray;
static void StepWindows()
{
for (int i{ 0 }; i > MakeKey::KeyArray.size(); i++)
{
sf::Clock clock;
MakeTopWindow(WindowArray[i]);
setShape(WindowArray[i], KeyArray[i].Img);
WindowArray[i]->clear(sf::Color::Transparent);
WindowArray[i]->draw(KeyArray[i].Sprite);
WindowArray[i]->display();
if (clock.getElapsedTime().asMicroseconds() > 1000)
{
WindowArray[i]->setPosition(MakeKey::Gravity(WindowArray[i], KeyArray[i]));
}
}
}
static void DrawKey(string input)
{
MakeKey::NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
else if (input == "E")
Key.Img.loadFromFile("Assets/Images/E.png");
else if (input == "Q")
Key.Img.loadFromFile("Assets/Images/Q.png");
else if (input == "S")
Key.Img.loadFromFile("Assets/Images/S.png");
else if (input == "W")
Key.Img.loadFromFile("Assets/Images/W.png");
else if (input == "X")
Key.Img.loadFromFile("Assets/Images/X.png");
else if (input == "Z")
Key.Img.loadFromFile("Assets/Images/Z.png");
else if (input == "Esc")
Key.Img.loadFromFile("Assets/Images/esc.png");
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
//Open Window
sf::RenderWindow window(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
window.setPosition(MakeKey::RandSpawn(Key.Img));
sf::RenderWindow* windowPoint = &window;
//Make Transparent
const unsigned char opacity = 1000;
setTransparency(window.getSystemHandle(), opacity);
setShape(windowPoint, Key.Img);
MakeKey::KeyArray.push_back(Key);
MakeKey::WindowArray.push_back(&window);
}
};
Main
int main()
{
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::None);
sf::RenderWindow* windowRef = &window;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
MakeKey::MakeTopWindow(windowRef);
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A)
MakeKey::DrawKey("A");
else if (event.key.code == sf::Keyboard::D)
MakeKey::DrawKey("D");
else if (event.key.code == sf::Keyboard::E)
MakeKey::DrawKey("E");
else if (event.key.code == sf::Keyboard::Q)
MakeKey::DrawKey("Q");
else if (event.key.code == sf::Keyboard::S)
MakeKey::DrawKey("S");
else if (event.key.code == sf::Keyboard::W)
MakeKey::DrawKey("W");
else if (event.key.code == sf::Keyboard::X)
MakeKey::DrawKey("X");
else if (event.key.code == sf::Keyboard::Z)
MakeKey::DrawKey("Z");
else if (event.key.code == sf::Keyboard::Escape)
MakeKey::DrawKey("Esc");
}
//Close
if (event.type == sf::Event::Closed)
window.close();
}
MakeKey::StepWindows();
}
return EXIT_SUCCESS;
}

Related

c++ sfml - changing the sprite isn't working

I was working on changing sprite in my SFML project but it just doesn't want to wark. I tried everything - pointers, refrences and normal string objects. You can see in debug console i printed out this->path that containted a path to file to change but when it left the function this->path was null (empty "" string). Can you please help me? Here's the code:
Player.cpp
#include "Player.h"
#include <iostream>
Player::Player(std::string path)
{
this->path = path;
texture.loadFromFile(path);
sprite.setTexture(texture);
sprite.setPosition(500.f, 700.f);
}
void Player::update()
{
// Movement //
//if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
//sprite.move(0.f, -velocity);
//if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
//sprite.move(0.f, velocity);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
sprite.move(-velocity, 0.f);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
sprite.move(velocity, 0.f);
// Movement //
float szerokosc = sprite.getGlobalBounds().width;
float wysokosc = sprite.getGlobalBounds().height;
// Collision with screen //
// Left
if (sprite.getPosition().x < 0.f)
sprite.setPosition(0.f, sprite.getPosition().y);
// Top
if (sprite.getPosition().y < 0.f)
sprite.setPosition(sprite.getPosition().x, 0.f);
// Right
if (sprite.getPosition().x + szerokosc > 1000)
sprite.setPosition(1000 - szerokosc, sprite.getPosition().y);
// Bottom
if (sprite.getPosition().y + wysokosc > 800)
sprite.setPosition(sprite.getPosition().x, 800 - wysokosc);
// Collision with screen //
}
sf::Sprite Player::getSprite()
{
return sprite;
}
bool Player::collides(Food obj)
{
if (sprite.getGlobalBounds().intersects(obj.getSprite().getGlobalBounds()))
return true;
else
return false;
}
void Player::changeSkin(std::string path)
{
this->path = path;
std::cout << "changeSkin(): *this->path" << this->path << std::endl;
std::cout << "changeSkin(): *path" << path << std::endl;
texture.loadFromFile(path);
sprite.setTexture(texture);
}
void Player::updateSkin()
{
std::cout << "updateSkin() *this->path: " << this->path << std::endl;
std::cout << "updateSkin() *path: " << path << std::endl;
}
Player::~Player()
{
//delete texture;
//delete sprite;
}
Player.h
#pragma once
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <time.h>
#include "Food.h"
#include "ShopItem.h"
class Player
{
sf::Texture texture;
sf::Sprite sprite;
std::string path;
bool has_skin = false;
float velocity = 5.f;
public:
explicit Player(std::string path);
~Player();
void update();
sf::Sprite getSprite();
bool collides(Food obj);
void changeSkin(std::string path);
void updateSkin();
};
main.cpp - main() has Player::updateSkin() call
int main()
{
RenderWindow window(VideoMode(1000, 800), "Tomczyszyn Eater v0.21 BETA");
window.setFramerateLimit(60);
srand(time(nullptr));
Texture bg_text;
bg_text.loadFromFile("Assets/Textures/bg.png");
Sprite bg{ bg_text };
Player player{ "Assets/Textures/player.png" };
time_t start{};
Event event;
Intro* intro = new Intro{window};
MainMenu* menu = new MainMenu{&window};
Shop shop(&window);
Game game{player, &window};
bool intro_deleted{ false };
bool menu_deleted{ false };
bool game_started{ false };
int menuState{ 2 };
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == Event::EventType::Closed)
window.close();
if (Keyboard::isKeyPressed(Keyboard::Space) && game.gameRunning() == false)
{
start = time(nullptr);
game.runGame();
}
else if (Keyboard::isKeyPressed(Keyboard::Escape) && game.gameRunning() == false)
{
menuState = 0;
}
}
window.clear();
if (game.gameRunning() == true && menuState == 1) // Main Game
{
if (game_started == false)
{
start = time(nullptr);
game_started = true;
}
if (intro_deleted == false)
{
delete intro;
intro_deleted = true;
}
if (menu_deleted == false)
{
delete menu;
menu_deleted = true;
}
window.draw(bg);
game.drawMoney();
player.update();
window.draw(player.getSprite());
// Player::updateSkin() - source of the problem
player.updateSkin();
game.update();
game.draw();
if (time(nullptr) - start == 2)
{
start = time(nullptr);
int liczba = rand() % 6 + 1;
string file_name{ "Assets/Textures/food" + to_string(liczba) + ".png" };
Food* newFood = new Food{file_name};
game.spawn(newFood);
}
game.catched();
game.fell();
}
else if (menuState == 0) // Menu
{
if (menu_deleted == true) menu = new MainMenu{ &window };
menu->draw();
menu->update(menuState);
menu_deleted = false;
}
else if (menuState == -1) // Intro
{
start = time(nullptr);
intro->play();
if (intro->intro_started() == true) menuState = 0;
}
else if (menuState == 2) // Shop
{
shop.draw();
shop.backIfClicked(menuState);
shop.checkIfBought(player, game.balance());
game.drawMoney();
}
else
{
game.drawDeathScreen();
}
window.display();
}
}
Shop.cpp - checkIfBought() has Player::changeSkin() call
void Shop::checkIfBought(Player player, int& money)
{
for (int i = 0; i < skins.size(); i++)
{
if (isClicking(skins[i].getSprite()) == true)
{
skins[i].buy(money);
player.changeSkin(skins[i].getPath()); //Plaer::changeSkin() here - source of the problem
std::cout << skins[i].getPath() << std::endl;
}
}
for (int i = 0; i < bg_skins.size(); i++)
{
if (isClicking(bg_skins[i].getSprite()) == true)
{
bg_skins[i].buy(money);
player.changeSkin(bg_skins[i].getPath()); //Plaer::changeSkin() here - source of the problem
}
}
}
Debug Console output:
changeSkin(): this->path = Assets/Textures/skin1.png
changeSkin(): path = Assets/Textures/skin1.png
Assets/Textures/skin1.png
updateSkin() this->path = Assets/Textures/player.png
updateSkin() path = Assets/Textures/player.png
Sorry if you didn't understand my english is bad. I really do need help i've spent so much time on fixing this that i just gave up.

sfml managing multiple windows at once

Ok so this week I have put a lot of time into learning how to open and run multiple sfml widows at once. I have a vector of unique pointers to the windows and a for loop that displays them and processes their events. The issue I am having that I can't think of a way to fix is that the for loop also runs a gravity function. As more and more windows open the keys drop at slower rates. What is something I can do to make sure that they are always dropping at a somewhat consistent rate no matter how many windows I am processing. For reference here is my code:
MakeKey.h
class MakeKey
{
public:
class NewKey {
public:
sf::Image Img;
sf::Texture Tex;
sf::Sprite Sprite;
int velocetyX;
int velocetyY;
int accelerationX;
int accelerationY;
static bool hitLeft(sf::RenderWindow * window, sf::Image image)
{
int XPos{ window->getPosition().x };
if (XPos <= -40)
return true;
return false;
}
static bool hitRight(sf::RenderWindow * window, sf::Image image)
{
int XPos{ window->getPosition().x };
if (XPos >= sf::VideoMode::getDesktopMode().width - image.getSize().x + 30)
return true;
return false;
}
static bool hitTop(sf::RenderWindow * window, sf::Image image)
{
int YPos = window->getPosition().y;
if (YPos <= -22)
return true;
return false;
}
static bool hitBottom(sf::RenderWindow * window, sf::Image image)
{
int YPos = window->getPosition().y;
if (YPos >= sf::VideoMode::getDesktopMode().height - image.getSize().y + 20)
return true;
return false;
}
static void impact(int & velocity)
{
if (velocity > 0) {
velocity -= 6;
velocity *= -1;
}
if (velocity < 0) {
velocity += 6;
velocity *= -1;
}
}
sf::Clock OffGroundClock;
};
sf::Vector2i Gravity(MakeKey::NewKey& Key, sf::RenderWindow* window);
bool setShape(sf::RenderWindow * window, const sf::Image& image);
sf::Vector2i RandSpawn(sf::Image image);
bool setTransparency(HWND hwnd, unsigned char alpha);
void MakeTopWindow(sf::RenderWindow* window);
void StepWindows();
void RunEvents(sf::RenderWindow* window);
void DrawKey(string input);
private:
vector <MakeKey::NewKey> KeyArray;
vector <unique_ptr <sf::RenderWindow>> WindowArray;
bool grabbedWindow{ false };
sf::Vector2i grabbedOffSet;
};
MakeKey.cpp
static void StepVelocity(MakeKey::NewKey* Key) {
Key->velocetyX += Key->accelerationX;
Key->velocetyY += Key->accelerationY;
}
sf::Vector2i MakeKey::Gravity(MakeKey::NewKey & Key, sf::RenderWindow * window)
{
int XPos = window->getPosition().x;
int YPos = window->getPosition().y;
YPos += 10;
if (Key.hitTop(window, Key.Img))
YPos = -22;
if (Key.hitBottom(window, Key.Img))
YPos = sf::VideoMode::getDesktopMode().height - Key.Img.getSize().y + 20;
if (Key.hitRight(window, Key.Img))
XPos = sf::VideoMode::getDesktopMode().width - Key.Img.getSize().x + 30;
if (Key.hitLeft(window, Key.Img))
XPos = (-44);
/*StepVelocity(Key);
XPos += Key->velocetyX;
YPos += Key->velocetyY;*/
return sf::Vector2i(XPos, YPos);
}
bool MakeKey::setShape(sf::RenderWindow * window, const sf::Image& image)
{
HWND hwnd = window->getSystemHandle();
const sf::Uint8* pixelData = image.getPixelsPtr();
HRGN hRegion = CreateRectRgn(0, 0, image.getSize().x, image.getSize().y);
// Determine the visible region
for (unsigned int y = 0; y < image.getSize().y; y++)
{
for (unsigned int x = 0; x < image.getSize().x; x++)
{
if (pixelData[y * image.getSize().x * 4 + x * 4 + 3] == 0)
{
HRGN hRegionPixel = CreateRectRgn(x, y, x + 1, y + 1);
CombineRgn(hRegion, hRegion, hRegionPixel, RGN_XOR);
DeleteObject(hRegionPixel);
}
}
}
SetWindowRgn(hwnd, hRegion, true);
DeleteObject(hRegion);
return true;
}
sf::Vector2i MakeKey::RandSpawn(sf::Image image)
{
std::random_device rand;
int RandX = (rand() % sf::VideoMode::getDesktopMode().width) - image.getSize().x;
int RandY = (rand() % sf::VideoMode::getDesktopMode().height) - image.getSize().y;
if (RandX < 1 + image.getSize().x)
RandX = image.getSize().x;
if (RandY < 1 + image.getSize().y)
RandY = image.getSize().y;
return sf::Vector2i(RandX, RandY);
}
bool MakeKey::setTransparency(HWND hwnd, unsigned char alpha)
{
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
return true;
}
void MakeKey::MakeTopWindow(sf::RenderWindow* window)
{
HWND hwndPoint = window->getSystemHandle();
SetWindowPos(hwndPoint, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
void MakeKey::RunEvents(sf::RenderWindow* window) {
sf::Event event;
while (window->pollEvent(event))
{
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A) {
DrawKey("A");
}
else if (event.key.code == sf::Keyboard::D)
{
DrawKey("D");
}
else if (event.key.code == sf::Keyboard::E)
{
DrawKey("E");
}
else if (event.key.code == sf::Keyboard::Q)
{
DrawKey("Q");
}
else if (event.key.code == sf::Keyboard::S)
{
DrawKey("S");
}
else if (event.key.code == sf::Keyboard::W)
{
DrawKey("W");
}
else if (event.key.code == sf::Keyboard::X)
{
DrawKey("X");
}
else if (event.key.code == sf::Keyboard::Z)
{
DrawKey("Z");
}
else if (event.key.code == sf::Keyboard::Escape)
{
DrawKey("Esc");
}
}
else if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
grabbedOffSet = window->getPosition() - sf::Mouse::getPosition();
grabbedWindow = true;
}
}
else if (event.type == sf::Event::MouseButtonReleased)
{
if (event.mouseButton.button == sf::Mouse::Left)
grabbedWindow = false;
}
else if (event.type == sf::Event::MouseMoved)
{
if (grabbedWindow)
window->setPosition(sf::Mouse::getPosition() + grabbedOffSet);
}
}
}
void MakeKey::StepWindows()
{
for (int i{ 0 }; i < WindowArray.size(); i++)
{
cout << "Inside Step Windows For Loop" << endl;
WindowArray[i]->setActive(true);
MakeTopWindow(WindowArray[i].get());
setShape(WindowArray[i].get(), KeyArray[i].Img);
RunEvents(WindowArray[i].get());
WindowArray[i]->clear(sf::Color::Transparent);
KeyArray[i].Sprite.setTexture(KeyArray[i].Tex);
WindowArray[i]->draw(KeyArray[i].Sprite);
WindowArray[i]->display();
WindowArray[i]->setPosition(Gravity(KeyArray[i], WindowArray[i].get()));
}
}
void MakeKey::DrawKey(string input)
{
unique_ptr <sf::RenderWindow> window = make_unique<sf::RenderWindow>();
NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
else if (input == "E")
Key.Img.loadFromFile("Assets/Images/E.png");
else if (input == "Q")
Key.Img.loadFromFile("Assets/Images/Q.png");
else if (input == "S")
Key.Img.loadFromFile("Assets/Images/S.png");
else if (input == "W")
Key.Img.loadFromFile("Assets/Images/W.png");
else if (input == "X")
Key.Img.loadFromFile("Assets/Images/X.png");
else if (input == "Z")
Key.Img.loadFromFile("Assets/Images/Z.png");
else if (input == "Esc")
Key.Img.loadFromFile("Assets/Images/esc.png");
window->create(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
window->setPosition(RandSpawn(Key.Img));
//Make Transparent
const unsigned char opacity = 1000;
setTransparency(window->getSystemHandle(), opacity);
KeyArray.emplace_back(move(Key));
WindowArray.emplace_back(move(window));
}
Main
int main()
{
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::Default);
MakeKey MakeKey;
while (window.isOpen())
{
MakeKey::NewKey Key;
MakeKey.RunEvents(&window);
MakeKey.StepWindows();
}
return EXIT_SUCCESS;
}

How to make cv::setMouseCallback function work

I've seen a few questions that are probably the same. I am still unable to make my code work after reading the answers. So I am sorry in advance if I am repeating the posts.
I managed to write this code :
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
bool leftButtonDown = false, leftButtonUp = false;
cv::Mat img;
cv::Point cor1, cor2;
cv::Rect rect;
void mouseCall(int event, int x, int y, int, void*) {
if (event == cv::EVENT_LBUTTONDOWN) //finding first corner
{
leftButtonDown = true; cor1.x = x; cor1.y = y; std::cout << "Corner 1: " << cor1 << std::endl;
}
if (event == cv::EVENT_LBUTTONUP) {
if (abs(x - cor1.x)>20 && abs(y - cor1.y)>5) //finding second corner and checking whether the region is too small
{
leftButtonUp = true; cor2.x = x; cor2.y = y; std::cout << "Corner 2: " << cor2 << std::endl;
}
else { std::cout << "Select more than 5 pixels" << std::endl; }
}
if (leftButtonDown == true && leftButtonUp == false) //when the left button is clicked and let off
{ //draw a rectangle continuously
cv::Point pt; pt.x = x; pt.y = y;
cv::Mat temp_img = img.clone();
rectangle(temp_img, cor1, pt, cv::Scalar(0, 0, 255));
cv::imshow("Original", temp_img);
}
else if (event == cv::EVENT_MOUSEMOVE) //tracking mouse movement
{
std::cout << "Mouse moving over the window - position (" << x << ", " << y << ")" << std::endl;
}
if (leftButtonDown == true && leftButtonUp == true) //when the selection is done
{
rect.width = abs(cor1.x - cor2.x);
rect.height = abs(cor1.y - cor2.y);
rect.x = cv::min(cor1.x, cor2.x);
rect.y = cv::min(cor1.y, cor2.y);
cv::Mat cutTempImg(img, rect); //Selecting a ROI(region of interest) from the original img
cv::namedWindow("Cut Temporary Image");
cv::imshow("Cut Temporary Image", cutTempImg); //showing the cropped image
leftButtonDown = false;
leftButtonUp = false;
}
}
int main(){
img = cv::imread("image.jpg");
cv::namedWindow("Original");
cv::imshow("Original", img);
cv::setMouseCallback("Original", mouseCall); //setting the mouse callback for selecting the region with mouse
while (char(cv::waitKey(1) != 'q')) //waiting for the 'q' key to finish the execution
{
}
return 0;
}
And it is working fine. Now I want to make same code, with using class.(OOP)
But cv::setMouseCallback function is not letting me do that.
Can any one help me fix this?
My second code :
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
class ResizeImage {
cv::Mat img;
cv::Point cor1, cor2;
cv::Rect rect;
std::string name;
public:
void setImg(cv::Mat img) { this->img = img; };
cv::Mat getImg() { return img; };
void setRect();
int getCoordinates1X() { return cor1.x; };
int getCoordinates1Y() { return cor1.y; };
int getCoordinates2X() { return cor2.x; };
int getCoordinates2Y() { return cor2.y; };
void setCoordinates1(int x, int y) { this->cor1.x = x; this->cor1.y = y; };
void setCoordinates2(int x, int y) { this->cor2.x = x; this->cor2.y = y; };
void mouseCall(int event, int x, int y, int flags, void* param);
void showImgOriginal();
void setImgName(std::string name) { this->name = name; };
std::string getImgName() { return name; };
};
void ResizeImage :: showImgOriginal() {
cv::namedWindow(name, CV_WINDOW_AUTOSIZE);
cv::imshow(name, img);
};
void ResizeImage::setRect() {
rect.width = abs(cor1.x - cor2.x);
rect.height = abs(cor1.y - cor2.y);
rect.x = cv::min(cor1.x, cor2.x);
rect.y = cv::min(cor1.y, cor2.y);
}
void ResizeImage::mouseCall(int event, int x, int y, int flags, void* param) {
if (event == cv::EVENT_LBUTTONDOWN) //finding first corner
{
leftButtonDown = true; setCoordinates1(x,y); std::cout << "Corner 1: " << getCoordinates1X()<<" "<<getCoordinates1Y() << std::endl;
}
if (event == cv::EVENT_LBUTTONUP) {
if (abs(x - cor1.x)>20 && abs(y - cor1.y)>5) //finding second corner and checking whether the region is too small
{
leftButtonUp = true; setCoordinates2(x, y); std::cout << "Corner 2: " << getCoordinates2X() << " " << getCoordinates2Y() << std::endl;
}
else { std::cout << "Select more than 5 pixels" << std::endl; }
}
if (leftButtonDown == true && leftButtonUp == false) //when the left button is down
{
cv::Point pt; pt.x = x; pt.y = y;
cv::Mat temp_img = img.clone();
rectangle(temp_img, cor1, pt, cv::Scalar(0, 0, 255)); //drawing a rectangle continuously
cv::imshow("Original", temp_img);
}
else if (event == cv::EVENT_MOUSEMOVE) //tracking mouse movement
{
std::cout << "Mouse moving over the window - position (" << x << ", " << y << ")" << std::endl;
}
if (leftButtonDown == true && leftButtonUp == true) //when the selection is done
{
setRect();
cv::Mat cutTempImg(img, rect); //Selecting a ROI(region of interest) from the original img
cv::namedWindow("Cut Temporary Image");
cv::imshow("Cut Temporary Image", cutTempImg); //showing the cropped image
leftButtonDown = false;
leftButtonUp = false;
}
}
int main(){
cv::Mat img = cv::imread("image.jpg");
ResizeImage img_;
img_.setImg(img);
img_.setImgName("original");
img_.showImgOriginal();
cv::setMouseCallback(img_.getImgName(),img_.mouseCall());
while (char(cv::waitKey(1) != 'q')) //waiting for the 'q' key to finish the execution
{
}
return 0;
}
Code after changes :
//Program is loading image, and showing it to user.
//User can use mouse to make a rectangle and cut the loaded image.
//Command line is tracking mouse movements and the coordinates of the rectangle.
//User can end the program using 'q'.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
bool leftButtonDown = false, leftButtonUp = false; //flags for mouse clicks
class ResizeImage {
cv::Mat img; //image to process
cv::Point cor1, cor2; //coordinates of selected rectangle
cv::Rect rect; //rectangle
std::string name; //windows name
public:
//////////////////////////////////////////////////////////////////////////////
ResizeImage() { std::cout << "Starting..."<<std::endl; }; //Constructor/Destructor
~ResizeImage() { std::cout << "Ending..." << std::endl; };
//////////////////////////////////////////////////////////////////////////////
void setImg(cv::Mat img) { this->img = img; };
void setImgName(std::string name) { this->name = name; }; //set functions
void setRect();
void setCoordinates1(int x, int y) { this->cor1.x = x; this->cor1.y = y; };
void setCoordinates2(int x, int y) { this->cor2.x = x; this->cor2.y = y; };
//////////////////////////////////////////////////////////////////////////////
int getCoordinates1X() { return cor1.x; }; //getfunctions
int getCoordinates1Y() { return cor1.y; };
int getCoordinates2X() { return cor2.x; };
int getCoordinates2Y() { return cor2.y; };
cv::Mat getImg() { return img; };
std::string getImgName() { return name; };
//////////////////////////////////////////////////////////////////////////////
static void mouseCall(int event, int x, int y, int flags, void* param); //static function
//////////////////////////////////////////////////////////////////////////////
void showImgOriginal(); //show function (priting image)
//////////////////////////////////////////////////////////////////////////////
};
void ResizeImage :: showImgOriginal() { //showing image
cv::namedWindow(name, CV_WINDOW_AUTOSIZE);
cv::imshow(name, img);
};
void ResizeImage::setRect() { //calculating selected rectangle
rect.width = abs(cor1.x - cor2.x);
rect.height = abs(cor1.y - cor2.y);
rect.x = cv::min(cor1.x, cor2.x);
rect.y = cv::min(cor1.y, cor2.y);
}
void ResizeImage::mouseCall(int event, int x, int y, int flags, void* param) {
if (event == cv::EVENT_LBUTTONDOWN) //finding first corner
{
leftButtonDown = true; ((ResizeImage*)param)->cor1.x = x; ((ResizeImage*)param)->cor1.y = y; //saving coordinates
std::cout << "Corner 1: " << ((ResizeImage*)param)->cor1.x << " " << ((ResizeImage*)param)->cor1.y << std::endl; //printing coordinates
}
if (event == cv::EVENT_LBUTTONUP) {
if (abs(x - ((ResizeImage*)param)->cor1.x)>20 && abs(y - ((ResizeImage*)param)->cor1.y)>10) //finding second corner and checking whether the region is too small
{
leftButtonUp = true; ((ResizeImage*)param)->cor2.x = x; ((ResizeImage*)param)->cor2.y = y; //saving coordinates
std::cout << "Corner 2: " << ((ResizeImage*)param)->cor2.x << " " << ((ResizeImage*)param)->cor2.y << std::endl; //printing coordinates
}
else { std::cout << "Select more than 10 pixels" << std::endl; } //warning if region is too small
}
if (leftButtonDown == true && leftButtonUp == false) //when the left button is down
{
cv::Point pt; pt.x = x; pt.y = y;
cv::Mat temp_img = ((ResizeImage*)param)->img.clone();
rectangle(temp_img, ((ResizeImage*)param)->cor1, pt, cv::Scalar(0, 0, 255)); //drawing a rectangle continuously
}
else if (event == cv::EVENT_MOUSEMOVE) //tracking mouse movement
{
std::cout << "Mouse moving over the window - position (" << x << ", " << y << ")" << std::endl;
}
if (leftButtonDown == true && leftButtonUp == true) //when the selection is done
{
((ResizeImage*)param)->setRect();
cv::Mat cutTempImg(((ResizeImage*)param)->img, ((ResizeImage*)param)->rect); //Selecting a ROI(region of interest) from the original img
cv::namedWindow("Cut Temporary Image");
cv::imshow("Cut Temporary Image", cutTempImg); //showing the cropped image
leftButtonDown = false;
leftButtonUp = false;
}
}
int main() {
cv::Mat img = cv::imread("image.jpg");
ResizeImage img_;
img_.setImg(img);
img_.setImgName("Original");
img_.showImgOriginal();
cv::setMouseCallback(img_.getImgName(),ResizeImage::mouseCall,&img_);
while (char(cv::waitKey(1) != 'q')) //waiting for the 'q' key to finish the execution
{
}
return 0;
}
If you want to use a class method as a callback, you should indeed declare the method as static. However, you also need to pass an object to the callback to be able to access non static members of your class such as cor1 or cor2.
Here is a minimal example of how you can achieve this:
class Call {
public:
Call(int i) : a(i){};
int a;
static void mouse(int event, int x, int y, int flags, void* param) {
std::cout << ((Call*)param)->a << std::endl;
}
};
cv::namedWindow("Call");
Call call(10);
cv::setMouseCallback("Call", Call::mouse, &call);
cv::imshow("Call", cv::Mat(100, 100, CV_8U, cv::Scalar(0)));
cv::waitKey();
I create a Call object and use its mouse method as the window callback while still passing the object to the call back.
You should make the function static:
static void mouseCall(int event, int x, int y, int flags, void* param);
and then:
cv::setMouseCallback(img_.getImgName(),ResizeImage::mouseCall);

Snake Rectangle Vector Collision

I'm new to SFML and C++ so I'm trying to learn both at the same time. I've decided to write a Snake game. For my snakes body I am using a vector of RectangleShapes. I've drawn a berry in the center of the screen and I can detect when the head of my snake is in collision with the berry, however I have no idea how to test if the snake is colliding with itself.
I've thought about testing collision between the head of the snake against the entire vector of blocks, but this will always return true as the head of the snake is in collision with itself.
I would appreciate any suggestions and criticisms of my code, Thanks!
#include <iostream>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <string>
#include <sstream>
using namespace sf;
constexpr int windowWidth{800}, windowHeight{600};
Vector2f blockLocation{0, 0};
struct Block
{
RectangleShape shape;
Vector2f blockSize{15,15};
Block(float posX, float posY)
{
shape.setPosition(posX, posY);
shape.setSize(blockSize);
shape.setFillColor(Color::Blue);
shape.setOutlineColor(Color::Green);
shape.setOutlineThickness(3);
}
};
struct Berry
{
CircleShape shape;
Berry(float posX, float posY)
{
shape.setPosition(posX, posY);
shape.setRadius(8);
shape.setFillColor(Color::Red);
shape.setOutlineColor(Color::Magenta);
shape.setOutlineThickness(3);
}
};
bool keyUp(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Up)) return true;
return false;
}
bool keyDown(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Down)) return true;
return false;
}
bool keyLeft(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Left)) return true;
return false;
}
bool keyRight(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Right)) return true;
return false;
}
int stat(std::vector<Block> *blocks, RenderWindow *window)
{
sf::Font font;
if(!font.loadFromFile("Oswald-Bold.ttf"))
{
std::cerr << "Cannot load font!" << std::endl;
return 1;
}
sf::Text text;
text.setFont(font);
std::ostringstream message;
message << "x: " << blockLocation.x << std::endl
<< "y: " << blockLocation.y << std::endl
<< "blocks: " << blocks->size() << std::endl;
text.setString(message.str());
text.setCharacterSize(24);
text.setColor(sf::Color::Magenta);
text.setOrigin(0, 0);
window->draw(text);
return 0;
}
bool collision(Block *shapeA, Berry *shapeB)
{
if( shapeA->shape.getGlobalBounds().intersects(shapeB->shape.getGlobalBounds()) )
{
std::cout << "collision with ";
std::cout << "x: " << shapeA->shape.getPosition().x << "y: " <<
shapeA->shape.getPosition().y << "and x: " << shapeB->shape.getPosition().x << "y: " << shapeB->shape.getPosition().y << std::endl;
return true;
}
else
return false;
}
int main(void)
{
Clock clock;
Time timeSinceLastUpdate = Time::Zero;
const Time TimePerFrame = seconds(3.0f/30.f);
std::vector<Block> blocks;
RenderWindow window{ {windowWidth, windowHeight} , "blocks!"};
bool up(false);
bool down(false);
bool left(false);
bool right(false);
window.setFramerateLimit(60);
Berry berry(400, 300);
blocks.emplace_back(blockLocation.x, blockLocation.y);
while(window.isOpen())
{
if(Keyboard::isKeyPressed(Keyboard::Key::Escape)) return 0;
Time elapsedTime = clock.restart();
timeSinceLastUpdate += elapsedTime;
while(timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
window.clear(Color::Black);
// Get the Head of the snake
auto first = blocks.back();
if(keyUp())
{
up = true;
down = false, left = false, right = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
else if(keyDown())
{
down = true;
up = false, left = false, right = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
else if(keyLeft())
{
left = true;
right = false, up = false, down = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
else if(keyRight())
{
right = true;
left = false, up = false, down = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
if(up) { blockLocation.y-=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if(down) { blockLocation.y+=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if(left) { blockLocation.x-=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if(right){ blockLocation.x+=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if (collision(&first, &berry)) blocks.emplace_back(blockLocation.x, blockLocation.y);
if(blocks.size() > 50)
{
blocks.erase(blocks.begin());
}
for(auto a : blocks)
{
window.draw(a.shape);
}
window.draw(berry.shape);
stat(&blocks, &window);
window.display();
}
}
return 0;
}

C++ - Can't get if statement to work using states

I'm currently creating a project which involves switching between different game states such as main menu to play state and play state to battle state etc. I'm currently struggling with getting my battle state to only draw the enemy the player collides with inside the play state. I tried doing this using a very simply "enemyNo =;" where the first enemy was 1, second was 2, and so on. then in battle state, tell it "if(enemyNo =1) then draw enemy 1 and it's corresponding stats. Can't for the life of me figure it out, pretty sure im not inheriting the enemyNo value across states properly. Any and all help would be appreciated.
StatePlay.cpp
#include "StatePlay.h"
#include <iostream>
// stringstream and string
#include <sstream>
#include <string>
#include "Game.h"
StatePlay::StatePlay(void)
{
}
StatePlay::~StatePlay(void)
{
}
void StatePlay::init(Game &context)
{
std::cout << "Initialising play state." << std::endl;
player = new Rect(0.0f, 0.0f, 0.15f, 0.15f);
//player stats
health = 10;
maxHealth = 10;
strength = 10;
speed = 10;
dollars = 0;
noTargets = false;
targetCount = 5;
bruteCount = 3;
raiderCount = 1;
//target
for(int i = 1; i <=5; i++)
{
target[i] = new Rect();
target[i]->setX((float)rand()/RAND_MAX - 0.75f);
target[i]->setY((float)rand()/RAND_MAX - 0.75f);
targetAlive[i] = true;
}
//brute
for(int i = 1; i <=3; i++)
{
brute[i] = new Rect();
brute[i]->setX((float)rand()/RAND_MAX - 0.75f);
brute[i]->setY((float)rand()/RAND_MAX - 0.75f);
bruteAlive[i] = true;
}
//raider
for(int i = 1; i <=1; i++)
{
raider[i] = new Rect();
raider[i]->setX((float)rand()/RAND_MAX - 0.75f);
raider[i]->setY((float)rand()/RAND_MAX - 0.75f);
raiderAlive[i] = true;
}
score = 0;
}
void StatePlay::enter()
{
std::cout << "Entering play state. Press ESCAPE to return to menu" << std::endl;
}
void StatePlay::exit()
{
}
void StatePlay::draw(SDL_Window * window)
{
// Replace this with OpenGL draw calls to draw the main menu screen
TTF_Font *textFont = TTF_OpenFont("MavenPro-Regular.ttf", 24);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
player->draw();
std::stringstream strStream2;
std::stringstream strStream3;
strStream2 << "Player" << std::endl;
strStream3 << "Target" << std::endl;
Label :: displayString(player->x() + player->w()/2.0,player->y() + player->h(), strStream2.str().c_str(), textFont);
//enemy
for(int i = 1; i <=5; i++)
{
if(targetAlive[i] == true)
{
Label :: displayString(target[i]->x() + target[i]->w()/2.0,target[i]->y() + target[i]->h(), strStream3.str().c_str(), textFont);
glColor3f(1.0,0.0,0.0);
targetAlive[i] = target[i];
target[i]->draw();
}
}
std::stringstream strStream4;
strStream4 << "Brute" << std::endl;
//brute
for(int i = 1; i <=3; i++)
{
if(bruteAlive[i] == true)
{
Label :: displayString(brute[i]->x() + brute[i]->w()/2.0,brute[i]->y() + brute[i]->h(), strStream4.str().c_str(), textFont);
glColor3f(0.6,0.3,0.1);
bruteAlive[i] = brute[i];
brute[i]->draw();
}
}
std::stringstream strStream6;
strStream6 << "Raider" << std::endl;
//raider
for(int i = 1; i <=1; i++)
{
if(raiderAlive[i] == true)
{
Label :: displayString(raider[i]->x() + raider[i]->w()/2.0,raider[i]->y() + raider[i]->h(), strStream6.str().c_str(), textFont);
glColor3f(0.2,0.9,0.4);
raiderAlive[i] = raider[i];
raider[i]->draw();
}
}
//information
std::stringstream strStream;
std::stringstream strStream1;
strStream << "Score:" << score;
strStream1 << "Health:" << health;
Label :: displayString(-0.9,-0.9, strStream.str().c_str(), textFont);
Label :: displayString(-0.4,-0.9, strStream1.str().c_str(), textFont);
SDL_GL_SwapWindow(window); // swap buffers
}
void StatePlay::handleSDLEvent(SDL_Event const &sdlEvent, Game &context)
{
if (sdlEvent.type == SDL_KEYDOWN)
{
//std::cout << "Scancode: " << sdlEvent.key.keysym.scancode ;
//std::cout << ", Name: " << SDL_GetKeyName( sdlEvent.key.keysym.sym ) << std::endl;
switch( sdlEvent.key.keysym.sym )
{
case SDLK_UP:
case 'w': case 'W':
player->setY(player->y() + 0.05f);
break;
case SDLK_DOWN:
case 's': case 'S':
player->setY(player->y() - 0.05f);
break;
case SDLK_LEFT:
case 'a': case 'A':
player->setX(player->x() - 0.05f);
break;
case SDLK_RIGHT:
case 'd': case 'D':
player->setX(player->x() + 0.05f);
break;
default:
break;
}
}
if (sdlEvent.type == SDL_KEYDOWN)
{
//std::cout << "Scancode: " << sdlEvent.key.keysym.scancode ;
//std::cout << ", Name: " << SDL_GetKeyName( sdlEvent.key.keysym.sym ) << std::endl;
switch( sdlEvent.key.keysym.sym )
{
case SDLK_ESCAPE:
context.setState(context.getMainMenuState());
default:
break;
}
}
//target
for(int i = 1; i <=5; i++)
{
if ( (target[i]->x() >= player->x()) && (target[i]->x()+target[i]->w() <= player->x()+player->w()) // cursor surrounds target in x
&& (target[i]->y() >= player->y()) && (target[i]->y()+target[i]->h() <= player->y()+player->h() ) && targetAlive[i] == true ) // cursor surrounds target in y
{
score += 100;
enemyNo = 1;
context.setState(context.getBattleState());
delete target[i];
targetAlive[i] = false;
targetCount -= 1;
}
}
//brute
for(int i = 1; i <=3; i++)
{
if ( (brute[i]->x() >= player->x()) && (brute[i]->x()+brute[i]->w() <= player->x()+player->w()) // cursor surrounds target in x
&& (brute[i]->y() >= player->y()) && (brute[i]->y()+brute[i]->h() <= player->y()+player->h() ) && bruteAlive[i] == true ) // cursor surrounds target in y
{
score += 100;
enemyNo = 2;
context.setState(context.getBattleState());
delete brute[i];
bruteAlive[i] = false;
bruteCount -= 1;
}
}
//raider
for(int i = 1; i <=1; i++)
{
if ( (raider[i]->x() >= player->x()) && (raider[i]->x()+raider[i]->w() <= player->x()+player->w()) // cursor surrounds target in x
&& (raider[i]->y() >= player->y()) && (raider[i]->y()+raider[i]->h() <= player->y()+player->h() ) && raiderAlive[i] == true ) // cursor surrounds target in y
{
score += 100;
enemyNo = 3;
context.setState(context.getBattleState());
delete raider[i];
raiderAlive[i] = false;
raiderCount -= 1;
}
}
}
StatePlay.h
#ifndef STATE_PLAY
#define STATE_PLAY
#include "gameState.h"
#include "Label.h"
// C stdlib and C time libraries for rand and time functions
#include <cstdlib>
#include <ctime>
#include "rect.h"
class StatePlay : public GameState
{
public:
StatePlay(void);
~StatePlay(void);
void init(Game &context);
void draw(SDL_Window * window);
void handleSDLEvent(SDL_Event const &sdlEvent, Game &context);
void enter();
void exit();
int enemyNo;
int targetCount;
private:
//player Stats
int score;
int health;
int maxHealth;
int strength;
int speed;
int dollars;
int getHealth() {return health;}
int getMaxHealth() { return maxHealth;}
int getStrength() { return strength;}
int getSpeed() { return speed;}
int getDollars() { return dollars; }
void setHealth(int newHealth) { health = newHealth; }
void damageTaken(int damage) { health = health - damage; }
void setMaxHealth(int newHealth) { maxHealth = maxHealth + newHealth; }
void setStrength(int newStrength) { strength = strength+newStrength; }
void setSpeed(int newSpeed) { speed = speed+newSpeed; }
void setDollars(int newDollars) { dollars = dollars+newDollars; }
// Another *strong* candidate for creating a new class type
// is character/agent, to encapsulate player and target data,
// potentially to include an Agent::draw() function and
// perhaps also generalise collision detection
// This is left as a further exercise
float xpos;
float ypos;
float xsize;
float ysize;
//target
float targetXPos;
float targetYPos;
float targetXSize;
float targetYSize;
bool targetAlive[5];
bool noTargets;
//brute
float bruteXPos;
float bruteYPos;
float bruteXSize;
float bruteYSize;
int bruteCount;
bool bruteAlive[5];
bool noBrutes;
//raider
float raiderXPos;
float raiderYPos;
float raiderXSize;
float raiderYSize;
int raiderCount;
bool raiderAlive[1];
bool noRaider;
clock_t lastTime; // clock_t is an integer type
clock_t currentTime; // use this to track time between frames
Label * playerLabel;
Label * targetLabel;
Label * bruteLabel;
Label * raiderLabel;
TTF_Font * textFont; // SDL type for True-Type font rendering
Rect * player;
Rect * target[5];
Rect * brute[3];
Rect * raider[1];
};
#endif
StateBattle.cpp
#include "StateBattle.h"
#include <iostream>
#include "Game.h"
#include "StatePlay.h"
#include "rect.h"
StateBattle::StateBattle(void)
{
}
StateBattle::~StateBattle(void)
{
}
void StateBattle::init(Game &context)
{
fighting = false;
}
void StateBattle::enter()
{
std::cout << "Entering main menu state: Press RETURN to play or ESCAPE to quit " << std::endl;
}
void StateBattle::exit()
{
}
void StateBattle::draw(SDL_Window * window)
{
glClearColor(0.0f,0.0f,0.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
TTF_Font *textFont = TTF_OpenFont("MavenPro-Regular.ttf", 24);
std::stringstream strStream;
strStream << "FIGHT!" <<std::endl;
Label :: displayString(-0.8 ,0.8, strStream.str().c_str(),textFont);
//player
Rect * player;
player = new Rect(-0.4f, 0.0f, 0.15f, 0.15f);
player ->draw();
std::stringstream playerStrStream1;
playerStrStream1 << "Health:" << std::endl;
Label :: displayString(-0.4 ,0.5, playerStrStream1.str().c_str(),textFont);
std::stringstream playerStrStream2;
playerStrStream2 << "Strength:" << std::endl;
Label :: displayString(-0.4 , -0.2, playerStrStream2.str().c_str(),textFont);
std::stringstream playerStrStream3;
playerStrStream3 << "Speed:" << std::endl;
Label :: displayString(-0.4 , -0.3, playerStrStream3.str().c_str(),textFont);
std::stringstream playerStrStream4;
playerStrStream4 << "Dollars:" << std::endl;
Label :: displayString(-0.4 , -0.4, playerStrStream4.str().c_str(),textFont);
//Enemy
if(enemyNo = 1)
{
Rect * target;
glColor3f(1.0,0.0,0.0);
target = new Rect(0.4f, 0.0f, 0.15f, 0.15f);
target->draw();
std::stringstream targetStrStream1;
targetStrStream1 << "Health:" << std::endl;
Label :: displayString(0.4f,0.5f, targetStrStream1.str().c_str(),textFont);
std::stringstream targetStrStream2;
targetStrStream2 << "Strength:" << std::endl;
Label :: displayString(0.4, -0.2, targetStrStream2.str().c_str(),textFont);
std::stringstream targetStrStream3;
targetStrStream3 << "Speed:" << std::endl;
Label :: displayString(0.4, -0.3, targetStrStream3.str().c_str(),textFont);
std::stringstream targetStrStream4;
targetStrStream4 << "Dollars:" << std::endl;
Label :: displayString(0.4, -0.4, playerStrStream4.str().c_str(),textFont);
}
//brute
if(enemyNo = 2)
{
Rect * brute;
glColor3f(0.6,0.3,0.1);
brute = new Rect(0.6f, 0.0f, 0.15f, 0.15f);
brute->draw();
std::stringstream bruteStrStream1;
bruteStrStream1 << "Health:" << std::endl;
Label :: displayString(0.4, 0.5, bruteStrStream1.str().c_str(),textFont);
std::stringstream bruteStrStream2;
bruteStrStream2 << "Strength:" << std::endl;
Label :: displayString(0.4, -0.2, bruteStrStream2.str().c_str(),textFont);
std::stringstream bruteStrStream3;
bruteStrStream3 << "Speed:" << std::endl;
Label :: displayString(0.4, -0.3, bruteStrStream3.str().c_str(),textFont);
std::stringstream bruteStrStream4;
bruteStrStream4 << "Dollars:" << std::endl;
Label :: displayString(0.4, -0.4, bruteStrStream4.str().c_str(),textFont);
}
//raider
if(enemyNo = 3)
{
Rect * raider;
glColor3f(0.2,0.9,0.4);
raider = new Rect(0.8f, 0.0f, 0.15f, 0.15f);
raider->draw();
std::stringstream raiderStrStream1;
raiderStrStream1 << "Health:" << std::endl;
Label :: displayString(0.4, 0.5, raiderStrStream1.str().c_str(),textFont);
std::stringstream raiderStrStream2;
raiderStrStream2 << "Strength:" << std::endl;
Label :: displayString(0.4, -0.2, raiderStrStream2.str().c_str(),textFont);
std::stringstream raiderStrStream3;
raiderStrStream3 << "Speed:" << std::endl;
Label :: displayString(0.4, -0.3, raiderStrStream3.str().c_str(),textFont);
std::stringstream raiderStrStream4;
raiderStrStream4 << "Dollars:" << std::endl;
Label :: displayString(0.4, -0.4, raiderStrStream4.str().c_str(),textFont);
}
SDL_GL_SwapWindow(window); // swap buffers
}
void StateBattle::handleSDLEvent(SDL_Event const &sdlEvent, Game &context)
{
// Add additional input checks for any other actions carried out in this state
std::cout << "Event handling in main menu state." << std::endl;
if (sdlEvent.type == SDL_KEYDOWN)
{
//std::cout << "Scancode: " << sdlEvent.key.keysym.scancode ;
//std::cout << ", Name: " << SDL_GetKeyName( sdlEvent.key.keysym.sym ) << std::endl;
switch( sdlEvent.key.keysym.sym )
{
case SDLK_RETURN:
context.setState(context.getPlayState());
break;
case SDLK_ESCAPE:
// Create a SDL quit event and push into the event queue
SDL_Event quitEvent;
quitEvent.type = SDL_QUIT;
SDL_PushEvent(&quitEvent);
default:
break;
}
}
}
StateBattle.h
#ifndef STATE_BATTLE
#define STATE_BATTLE
#include "GameState.h"
#include "Label.h"
#include "StatePlay.h"
class StateBattle : public GameState, public StatePlay
{
public:
StateBattle(void);
~StateBattle(void);
void init(Game &context);
void draw(SDL_Window * window);
void handleSDLEvent(SDL_Event const &sdlEvent, Game &context);
void enter();
void exit();
bool fighting;
};
#endif
I've included all the .cpp and .h files involved, hopefully this is enough. If not i can upload more.
Thanks again
You are missing a =, you should write
if(enemyNo == 1)
instead of
if(enemyNo = 1)
But for the next time, please provide a smaller example (as already suggested) with the exact error message.
You should declare the dstor in StatePlay virtual, because it acts as a base class for the StateBattle class. And in the StateBattle implementation file your are initializing enemyNo to 1 instead of comparing it to 1:
//Enemy
if(enemyNo == 1) // <-- missing ==
Inside your states you should only hold state variables: variables that are bound to only this specific state. Enemies could be a state variable if you have just one game state and all other states are complelty independent (i.e. menu state, setting state...). But your states kind of having cross dependencies.
To solve this problem you should extract first everything that doesn't belong to one specific state into another class. I.e. You could have a 'World' class, which manages the list of enemies, terrain, ... Or a class for a List of your Entities. It's a design decision you have to take yourself.
However, your StatePlay shouldn't handle the enemies - and get it inherited by the StateBattle. StateBattle overrides the init(Game &context) function from StatePlay - so it get's never called if you don't call it yourself. The enemyNo in StateBattle is never initalized this way (in fact it is, but just because of another mistake)!
You could write:
void StateBattle::init(Game &context)
{
StatePlay::init(context);
fighting = false;
}
to do so. But like I pointed out, there are some things in your class design, that makes handling these things hard and redundant.
Also you are not checking the enemyNo - you're setting it. = is the assignment Operator - you want to use the compare Operator ==
So better use:
if(enemyNo == 1)
instead of
if(enemyNo = 1)
Otherwise it will set your variable enemyNo to 1 instead of compare it against 1.