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

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.

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.

Pushback to array without copying

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;
}

SFML Networking - Error Sending Packet through UDP protocol

I'm pretty new to SFML networking and have been working on a pong clone for quite some time. I've written two programs: a client and a server. My problem is that the two don't seem to properly send/receive data between each other. I've checked and my ports properly bind and my packet isn't larger than the max datagram size. However, when I check the status of socket.send(...) against Socket::Done it finds that the data did not send. Is there something I'm doing wrong?
Client:
#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include <ctime>
#include <iostream>
#include <sstream>
using namespace sf;
using namespace std;
template <typename T>
string NumberToString ( T Number )
{
stringstream ss;
ss << Number;
return ss.str();
}
int main()
{
cout << "Enter an IP address: ";
string address;
cin >> address;
IpAddress other = address;
//window
RenderWindow window(VideoMode(800, 600), "Pong");
//player 1
RectangleShape rect(Vector2f(40, 130));
rect.setPosition(40, 50);
rect.setFillColor(Color::Blue);
rect.setOutlineThickness(4);
rect.setOutlineColor(Color::Black);
//player 2
RectangleShape player2(Vector2f(40, 130));
player2.setPosition(520,50);
player2.setFillColor(Color(255, 0, 208));
player2.setOutlineThickness(4);
player2.setOutlineColor(Color::Black);
//ball
CircleShape ball(50, 50);
ball.setOrigin(ball.getRadius(), ball.getRadius());
ball.setPosition(400, 300);
ball.setFillColor(Color(255, 255, 0));
ball.setOutlineThickness(4);
ball.setOutlineColor(Color::Black);
//score
Uint16 score1;
Uint16 score2;
//socket
short unsigned int port = 54000;
UdpSocket socket;
if (socket.bind(port) != Socket::Done)
{
cout << "Error\n";
}
socket.setBlocking(false);
//text
Font font;
font.loadFromFile("SF Electrotome.ttf");
Text score;
score.setFont(font);
score.setColor(Color::Black);
score.setString("0 0");
score.setCharacterSize(16);
score.setPosition(300, 50);
//loop
bool running = true;
while (running) //game loop
{
Event ev;
while (window.pollEvent(ev)) //event loop
{
switch (ev.type)
{
case Event::Closed: //quit on click x
running = false;
break;
case Event::KeyPressed:
if (ev.key.code == Keyboard::Escape) //quit on escape
{
running = false;
}
break;
}
}
//get that sweet info
Packet received;
socket.receive(received, other, port);
float player1pos[2];
float player2pos[2];
float ballpos[2];
received >> player1pos[0] >> player1pos[1] >> player2pos[0] >> player2pos[1] >>
ballpos[0] >> ballpos[1] >> score1 >> score2;
rect.setPosition(player1pos[0], player1pos[1]);
player2.setPosition(player2pos[0], player2pos[1]);
ball.setPosition(ballpos[0], ballpos[1]);
//scores
score.setString(NumberToString(score1) + " " + NumberToString(score2));
//handle player input
if (Keyboard::isKeyPressed(Keyboard::Up))
{
if (rect.getPosition().y >= 0) //keep in bounds
{
Packet p;
Uint16 direction = 1;
p << direction;
socket.send(p, other, port);
}
} else if (Keyboard::isKeyPressed(Keyboard::Down)){
if (player2.getPosition().y + player2.getSize().y <= 600) //keep in bounds
{
Packet p;
Uint16 direction = 2;
p << direction;
socket.send(p, other, port);
}
}
//draw everything
window.clear(Color::White);
window.draw(rect);
window.draw(player2);
window.draw(ball);
window.draw(score);
window.display();
}
return 0;
}
Server:
#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <iostream>
using namespace sf;
using namespace std;
template <typename T>
string NumberToString ( T Number )
{
stringstream ss;
ss << Number;
return ss.str();
}
int main()
{
cout << "Enter an IP address: ";
string address;
cin >> address;
IpAddress other(address);
if (other == IpAddress::None)
{
cout << "Error loading ip";
}
srand(time(NULL));
//window
RenderWindow window(VideoMode(800, 600), "Pong");
//player 1
RectangleShape rect(Vector2f(40, 130));
rect.setPosition(40, 50);
rect.setFillColor(Color::Blue);
rect.setOutlineThickness(4);
rect.setOutlineColor(Color::Black);
//player 2
RectangleShape player2(Vector2f(40, 130));
player2.setPosition(720, 50);
player2.setFillColor(Color(255, 0, 208));
player2.setOutlineThickness(4);
player2.setOutlineColor(Color::Black);
//ball
CircleShape ball(50, 50);
ball.setOrigin(ball.getRadius(), ball.getRadius());
ball.setPosition(400, 300);
ball.setFillColor(Color(255, 255, 0));
ball.setOutlineThickness(4);
ball.setOutlineColor(Color::Black);
float randX = (rand() % 5 + 1);
float randY = (rand() % 5 + 1);
Vector2f ballVelocity(randX/15, randY/15);
//score
Uint16 score1 = 0;
Uint16 score2 = 0;
//text
Font font;
font.loadFromFile("SF Electrotome.ttf");
Text score;
score.setFont(font);
score.setColor(Color::Black);
score.setString("0 0");
score.setCharacterSize(16);
score.setPosition(350, 50);
//network socket
UdpSocket socket;
short unsigned int sendPort = 54000;
if (!(socket.bind(sendPort) == Socket::Done))
{
cout << "Error";
}
socket.setBlocking(false);
//loop
bool running = true;
while (running) //game loop
{
Event ev;
while (window.pollEvent(ev)) //event loop
{
switch (ev.type)
{
case Event::Closed: //quit on click x
running = false;
break;
case Event::KeyPressed:
if (ev.key.code == Keyboard::Escape) //quit on escape
{
running = false;
}
break;
}
}
//handle player input
if (Keyboard::isKeyPressed(Keyboard::Up))
{
if (rect.getPosition().y >= 0) //keep in bounds
{
rect.move(0, -0.2);
}
} else if (Keyboard::isKeyPressed(Keyboard::Down)){
if (rect.getPosition().y + rect.getSize().y <= 600) //keep in bounds
{
rect.move(0, 0.2);
}
}
//handle player 2 input
Uint16 direction;
IpAddress sender;
Packet received;
if ((socket.receive(received, other, sendPort)) != Socket::Done)
{
cout << "Error receiving data";
}
received >> direction;
if (sender == other)
{
switch (direction)
{
case 1:
player2.move(0, -0.2);
break;
case 2:
player2.move(0, 0.2);
break;
}
}
//handle ball direction changes
if ((ball.getPosition().y - ball.getRadius() <= 0) || (ball.getPosition().y + ball.getRadius() >= 600)) { //top or bottom
ballVelocity.y *= -1;
} else if ((ball.getPosition().x + ball.getRadius() >= 800)) { //right edge
ballVelocity.x *= -1;
score1 += 1;
} else if (ball.getPosition().x - ball.getRadius() <= 0) { //left edge
ballVelocity.x *= -1;
score2 += 1;
}
ball.move(ballVelocity);
//handle player/ball collisions
FloatRect player1Box = rect.getGlobalBounds();
FloatRect ballBox = ball.getGlobalBounds();
FloatRect player2Box = player2.getGlobalBounds();
if (player1Box.intersects(ballBox) || player2Box.intersects(ballBox))
{
ballVelocity.x *= -1;
}
//set score
score.setString(NumberToString(score1) + " " + NumberToString(score2));
//send everything over
Packet p;
p << rect.getPosition().x << rect.getPosition().y << player2.getPosition().x << player2.getPosition().y <<
ball.getPosition().x << ball.getPosition().y << score1 << score2;
socket.send(p, other, sendPort);
//draw everything
window.clear(Color::White);
window.draw(rect);
window.draw(player2);
window.draw(ball);
window.draw(score);
window.display();
}
return 0;
}

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);

Trackball mouse Rotation in OpenGL

I'm trying to implement a basic solution for trackball with openGL.
There are 2 rotations :
- around x axis (right direction) , linked with up/down mouse movement.
- around y axis (up direction) , linked with right/left mouse movement.
The cube is centered on 0, camera is on z axis. Axis are drawn : x in blue, y in green, z in red.
2 different groups of rotations:
90° around x by moving the mouse down. Z toward down, x right, y in front.
Then another rotation: 90° around z (z as displayed), mouse movement on the right. z towards the right direction, x up and y in front.
I process again, position start from scratch.
90° around y. y : up , z: right , x: in front
Another rotation of 90° around z. x: up , z: right : y : in front .
I identify a different behaviour between the second rotations.
For coherence, I was waiting that for the first operation, the second rotation was around z
Or for the second operation, the second rotation was around x axis.
Why ?
For me, the second operation has the goood rotations, that's the behaviour i would like to have.
Thank you for your help.
Below the code
cube.cpp :
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>
#include <iostream>
#include "sdlglutils.h"
#include "trackballcamera.h"
using namespace std;
void Dessiner();
double angleZ = 0;
double angleX = 0;
double angleY = 0;
TrackBallCamera * camera;
int main(int argc, char *argv[])
{
cout<<"in main cube"<<endl;
freopen("CON", "w", stdout);
freopen("CON", "r", stdin);
freopen("CON", "w", stderr);
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
atexit(SDL_Quit);
SDL_WM_SetCaption("SDL GL Application", NULL);
SDL_SetVideoMode(640, 480, 32, SDL_OPENGL);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(70,(double)640/480,1,1000);
glEnable(GL_DEPTH_TEST);
camera = new TrackBallCamera();
camera->setScrollSensivity(10);
Dessiner();
Uint32 last_time = SDL_GetTicks();
Uint32 current_time,ellapsed_time;
Uint32 start_time;
GLUquadric* params;
params = gluNewQuadric();
for (;;)
{
start_time = SDL_GetTicks();
while (SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
exit(0);
break;
case SDL_MOUSEBUTTONUP:
cout<<"SDL_MOUSEBUTTONUP"<<endl;
camera->OnMouseButton(event.button);
break;
case SDL_MOUSEBUTTONDOWN:
cout<<"SDL_MOUSEBUTTONDOWN"<<endl;
camera->OnMouseButton(event.button);
break;
case SDL_MOUSEMOTION:
camera->OnMouseMotion(event.motion);
break;
}
}
current_time = SDL_GetTicks();
ellapsed_time = current_time - last_time;
last_time = current_time;
//angleZ += 0.05 * ellapsed_time;
//angleX += 0.05 * ellapsed_time;
Dessiner();
ellapsed_time = SDL_GetTicks() - start_time;
if (ellapsed_time < 10)
{
SDL_Delay(10 - ellapsed_time);
}
}
return 0;
}
void dessinerRepere(unsigned int echelle = 10)
{
//glPushMatrix();
glScalef(echelle,echelle,echelle);
glBegin(GL_LINES);
glColor3ub(0,0,255);
glVertex3i(0,0,0);
glVertex3i(1,0,0);
glColor3ub(0,255,0);
glVertex3i(0,0,0);
glVertex3i(0,1,0);
glColor3ub(255,0,0);
glVertex3i(0,0,0);
glVertex3i(0,0,1);
glEnd();
//glPopMatrix();
}
void Dessiner()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
//gluLookAt(20,20,20,0,0,0,0,0,1);
camera->look(0,0,camera->getDistance()
,0,0,0
,0,1,0);
//glRotated(angleZ,0,0,1);
//glRotated(angleX,1,0,0);
glBegin(GL_QUADS);
glColor3ub(255,0,0); //face rouge
glVertex3d(1,1,1);
glVertex3d(1,1,-1);
glVertex3d(-1,1,-1);
glVertex3d(-1,1,1);
glColor3ub(0,255,0); //face verte
glVertex3d(1,-1,1);
glVertex3d(1,-1,-1);
glVertex3d(1,1,-1);
glVertex3d(1,1,1);
glColor3ub(0,0,255); //face bleue
glVertex3d(-1,-1,1);
glVertex3d(-1,-1,-1);
glVertex3d(1,-1,-1);
glVertex3d(1,-1,1);
glColor3ub(255,255,0); //face jaune
glVertex3d(-1,1,1);
glVertex3d(-1,1,-1);
glVertex3d(-1,-1,-1);
glVertex3d(-1,-1,1);
glColor3ub(0,255,255); //face cyan
glVertex3d(1,1,-1);
glVertex3d(1,-1,-1);
glVertex3d(-1,-1,-1);
glVertex3d(-1,1,-1);
glColor3ub(255,0,255); //face magenta
glVertex3d(1,-1,1);
glVertex3d(1,1,1);
glVertex3d(-1,1,1);
glVertex3d(-1,-1,1);
glEnd();
//glLoadIdentity( );
dessinerRepere();
glFlush();
SDL_GL_SwapBuffers();
}
trackballcamera.cpp :
#include "trackballcamera.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <cmath>
#include "trackballcamera.h"
#include "sdlglutils.h"
void TrackBallCamera::setDistance(const double & newDistance)
{
_distance = newDistance;
}
const double & TrackBallCamera::getDistance() const
{
return _distance;
}
TrackBallCamera::TrackBallCamera()
{
const char *hand1[] =
{
/* width height num_colors chars_per_pixel */
" 16 16 3 1 ",
/* colors */
"X c #000000",
". c #ffffff",
" c None",
/* pixels */
" XX ",
" XX X..XXX ",
" X..XX..X..X ",
" X..XX..X..X X ",
" X..X..X..XX.X",
" X..X..X..X..X",
" XX X.......X..X",
"X..XX..........X",
"X...X.........X ",
" X............X ",
" X...........X ",
" X..........X ",
" X.........X ",
" X.......X ",
" X......X ",
" X......X ",
"0,0"
};
const char *hand2[] =
{
/* width height num_colors chars_per_pixel */
" 16 16 3 1 ",
/* colors */
"X c #000000",
". c #ffffff",
" c None",
/* pixels */
" ",
" ",
" ",
" ",
" XX XX XX ",
" X..X..X..XX ",
" X........X.X ",
" X.........X ",
" XX.........X ",
" X...........X ",
" X...........X ",
" X..........X ",
" X.........X ",
" X.......X ",
" X......X ",
" X......X ",
"0,0"
};
_hand1 = cursorFromXPM(hand1);
_hand2 = cursorFromXPM(hand2);
SDL_SetCursor(_hand1);
_holdRotation = false;
_holdTranslation = false;
_angleX = 0;
_angleY = 0;
_angleZ = 0;
_transX = 0;
_transY = 0;
_transZ = 0;
_distance = 50;
_motionSensivity = 0.3;
//_scrollSensivity = 1;
_scrollSensivity = 10;
}
void TrackBallCamera::OnMouseMotion(const SDL_MouseMotionEvent & event)
{
printf("OnMouseMotion; _holdRotation:%d; _holdTranslation:%d\n", _holdRotation, _holdTranslation);
if (_holdRotation)
{
_angleY += event.xrel*_motionSensivity;
_angleX += event.yrel*_motionSensivity;
printf("_angleX:%lf; _angleY:%lf\n",_angleX,_angleY);
// if (_angleY > 90)
// _angleY = 90;
// else if (_angleY < -90)
// _angleY = -90;
}
if (_holdTranslation)
{
_transX += event.xrel*_motionSensivity;
_transY += event.yrel*_motionSensivity;
printf("_transZ:%lf, _transY:%lf\n",_transZ, _transY);
}
}
void TrackBallCamera::OnMouseButton(const SDL_MouseButtonEvent & event)
{
printf("OnMouseButton\n");
if (event.button == SDL_BUTTON_LEFT)
{
if ((_holdRotation)&&(event.type == SDL_MOUSEBUTTONUP))
{
_holdRotation = false;
SDL_SetCursor(_hand1);
}
else if ((!_holdRotation)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
_holdRotation = true;
SDL_SetCursor(_hand2);
}
printf("_holdRotation:%d\n",_holdRotation);
}
else if (event.button == SDL_BUTTON_RIGHT)
{
if ((_holdTranslation)&&(event.type == SDL_MOUSEBUTTONUP))
{
_holdTranslation = false;
SDL_SetCursor(_hand1);
}
else if ((!_holdTranslation)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
_holdTranslation = true;
SDL_SetCursor(_hand2);
}
}
else if ((event.button == SDL_BUTTON_WHEELUP)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
printf("OK WHEELUP, _scrollSensivity:%lf; _distance:%lf\n", _scrollSensivity,_distance);
_distance -= _scrollSensivity;
//if (_distance < 0.1)
//_distance = 0.1;
printf("APRES WHEELUP, _distance:%lf\n", _distance);
}
else if ((event.button == SDL_BUTTON_WHEELDOWN)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
printf("OK WHEELDOWN, _distance:%lf\n",_distance);
_distance += _scrollSensivity;
}
}
void TrackBallCamera::OnKeyboard(const SDL_KeyboardEvent & event)
{
if ((event.type == SDL_KEYDOWN)&&(event.keysym.sym == SDLK_HOME))
{
_angleY = 0;
_angleX = 0;
}
}
void TrackBallCamera::setMotionSensivity(double sensivity)
{
_motionSensivity = sensivity;
}
void TrackBallCamera::setScrollSensivity(double sensivity)
{
_scrollSensivity = sensivity;
}
TrackBallCamera::~TrackBallCamera()
{
SDL_FreeCursor(_hand1);
SDL_FreeCursor(_hand2);
SDL_SetCursor(NULL);
}
//camera->look(cloud.pointPosition[lastElement*3],0,75,cloud.pointPosition[lastElement*3],0,0,0,1,0);
void TrackBallCamera::look(const GLfloat& xPointOfView
,const GLfloat& yPointOfView
,const GLfloat& zPointOfView
,const GLfloat& xCenter
,const GLfloat& yCenter
,const GLfloat& zCenter
,const GLfloat& xVerticalVector
,const GLfloat& yVerticalVector
,const GLfloat& zVerticalVector
)
//void TrackBallCamera::look()
{
//gluLookAt(_distance,0,0,
//0,0,0,
//0,0,1);
//printf("look, xPointOfView:%lf\n",xPointOfView);
gluLookAt(xPointOfView,yPointOfView,zPointOfView,
xCenter,yCenter,zCenter,
xVerticalVector,yVerticalVector,zVerticalVector);
glRotated(_angleX,1,0,0);
glRotated(_angleY,0,1,0);
//glRotated(_angleZ,0,0,1);
//glTranslated(_transX,0,0);
//glTranslated(0,_transY,0);
//glTranslated(0,0,_transZ);
}
trackballcamera.h :
#ifndef TRACKBALLCAMERA_H
#define TRACKBALLCAMERA_H
#include <SDL/SDL.h>
#include <GL/gl.h>
class TrackBallCamera
{
public:
TrackBallCamera();
virtual void OnMouseMotion(const SDL_MouseMotionEvent & event);
virtual void OnMouseButton(const SDL_MouseButtonEvent & event);
virtual void OnKeyboard(const SDL_KeyboardEvent & event);
//virtual void look();
virtual void look(const GLfloat& xPointOfView
,const GLfloat& yPointOfView
,const GLfloat& zPointOfView
,const GLfloat& xCenter
,const GLfloat& yCenter
,const GLfloat& zCenter
,const GLfloat& xVerticalVector
,const GLfloat& yVerticalVector
,const GLfloat& zVerticalVector
);
virtual void setMotionSensivity(double sensivity);
virtual void setScrollSensivity(double sensivity);
void setDistance(const double & newDistance);
const double & getDistance() const ;
virtual ~TrackBallCamera();
protected:
double _motionSensivity;
double _scrollSensivity;
//bool _hold;
bool _holdRotation;
bool _holdTranslation;
double _distance;
double _angleX;
double _angleY;
double _angleZ;
double _transX;
double _transY;
double _transZ;
SDL_Cursor * _hand1;
SDL_Cursor * _hand2;
};
#endif //TRACKBALLCAMERA_H
sdlglutils.cpp :
#include "sdlglutils.h"
#include <SDL/SDL.h>
//#include <SDL/SDL_image.h>
#include <GL/glu.h>
#include <cstring>
#include <cstdlib>
SDL_Cursor * cursorFromXPM(const char * xpm[])
{
int i, row, col;
int width, height;
Uint8 * data;
Uint8 * mask;
int hot_x, hot_y;
SDL_Cursor * cursor = NULL;
sscanf(xpm[0], "%d %d", &width, &height);
data = (Uint8*)calloc(width/8*height,sizeof(Uint8));
mask = (Uint8*)calloc(width/8*height,sizeof(Uint8));
i = -1;
for ( row=0; row<height; ++row )
{
for ( col=0; col<width; ++col )
{
if ( col % 8 )
{
data[i] <<= 1;
mask[i] <<= 1;
}
else
{
++i;
data[i] = mask[i] = 0;
}
switch (xpm[4+row][col])
{
case 'X':
data[i] |= 0x01;
mask[i] |= 0x01;
break;
case '.':
mask[i] |= 0x01;
break;
case ' ':
break;
}
}
}
sscanf(xpm[4+row], "%d,%d", &hot_x, &hot_y);
//printf("data :%" PRIu8 "; mask:%" PRIu8 ";width:%d; height:%d; hot_x:%d; hot_y:%d\n", *data, *mask, width, height, hot_x, hot_y);
cursor = SDL_CreateCursor(data, mask, width, height, hot_x, hot_y);
free(data);
free(mask);
return cursor;
}
sdlglutils.h :
#ifndef SDLGLUTILS_H
#define SDLGLUTILS_H
#include <GL/gl.h>
#include <SDL/SDL.h>
SDL_Cursor * cursorFromXPM(const char * xpm[]);
#endif //SDLGLUTILS_H
You seem to be running into a classic problem with Euler Angles, the order of incremental rotations matters.
Furthermore for an intuitive Trackball behavior for 3D rotation, you need to consider that the model and global rotation axes are not aligned, and thus when you apply the trackball deltas to the global axes, the rotation might be in an unexpected direction. To remedy this, you need to do a coordinate transformation of the user input into global space, or compute a rotation matrix in user space, and transform that rotation matrix from model space into global space, so that the rendering does the right thing.