c++ sfml apply only when button pressed - c++

I have a probleme my character stay running when i release the LShift button
How can i reset the speed when the button is released ?
Actually i have this :
int speed(4);
int speedSprinte(20);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
{
keyCount++;
speed=speedSprinte;
std::cout<<speed<<std::endl;
}
i can add that but i think it possible to do that easier :
if(!sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
{
keyCount++;
speed=4;
std::cout<<speed<<std::endl;
}

Either use SFML events and listen to sf::Events::KeyReleased (https://www.sfml-dev.org/tutorials/2.5/window-events.php) or do it manually by storing the last state.
int speed(4);
int speedSprinte(20);
bool pressedLastTime{false};
if(sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
{
keyCount++;
speed=speedSprinte;
std::cout<<speed<<std::endl;
pressedLastTime = true;
}
else
{
if (pressedLastTime)
{
speed = 4;
pressedLastTime = false;
}
}

Related

GetAsyncKeyState constantly active

I am trying to make an autoclicker to mess around with getkeystate and key pressing functions in VS and c++, for some odd reason it will never stop clicking once it is initially clicked. I looked over my code and couldn't find anything wrong with it, i know the issue is gonna be something stupidly small. Heres my code:
#include <iostream>
#include <Windows.h>
using namespace std;
bool click = false;
int x = 0, y = 0, cps;
void gui()
{
cout << "Enter desired clicks per second: ";
cin >> cps;
}
void clicked()
{
while (1)
{
if (GetAsyncKeyState(VK_LBUTTON)) // Left mbutton
{
click = true;
}
else
{
click = false;
}
if (click == true)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
Sleep(1000 / cps);
}
if (click == false)
{
continue;
}
}
}
int main()
{
gui();
clicked();
}```
You maybe missed to read the documentation about return value of GetAsyncKeyState.
The return value of GetAsyncKeyState is zero for the following cases:
The current desktop is not the active desktop
The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.
And,if the most significant bit is set , the key is down.
So, for checking up, you need to check, if the most significant bit is reset.
[Sorry, I am writing the answer on mobile. So, could not provide source code.]

How do I assign a value in an array when a mouse is pressed SFML C++

I am trying to make a program where you are allowed to select between an option of shapes, and then drawing it. To allow for multiple shapes I created a vector of a class which creates shapes (Shapes are set up with the chosen function). My problem is the mouse click is too long, so it assigns it to everything in the vector, so you can't create a new shape. Is there a problem in my logic, or is there a problem in the code?
Here is my attempt:
for (auto& it : onCanvas) {
if (Mouse::isButtonPressed(Mouse::Left)) {
if (mousepointer.getGlobalBounds().intersects(circleOption.getGlobalBounds())) {
it.chosen(circles);
}
if (mousepointer.getGlobalBounds().intersects(rectOption.getGlobalBounds())) {
it.chosen(rectangle);
}
if (mousepointer.getGlobalBounds().intersects(triOption.getGlobalBounds())) {
it.chosen(triangles);
}
if (mousepointer.getGlobalBounds().intersects(it.shape.getGlobalBounds()) || it.dragging) {
it.shape.setPosition(mousepointer.getPosition());
it.dragging = true;
}
}
if (!Mouse::isButtonPressed) {
it.dragging = false;
}
win.draw(it.shape);
}
Your source-code is a bit incomplete (what is onCanvas and mousepointer). But I guess the problem is that this snippet is called multiple times while your mouse is clicked. To avoid that you can do two thing.
In the first solution you use events, so you only add shapes when the state of the mousebutton changes (you can additionally listen to the MouseButtonReleased to simulate a full click):
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
// Hit Detection
}
}
or second solution you remember the last state of the button (probably do the mouse check once outside of the for loop):
bool mouse_was_up = true;
if (mouse_was_up && Mouse::isButtonPressed(Mouse::Left)) {
mouse_was_up = false;
for (auto& it : onCanvas) {
// Hit Detection
}
}
else if (!Mouse::isButtonPressed(Mouse::Left))
mouse_was_up = true;
I would rather stick to the first solution because when your click is too short and your gameloop is in another part of the game logic, you can miss the click.

SFML objects won't draw when its parent class is reinitialised

I'm working on a new project and an implementing a basic scene change. I have the different scenes setup as their own classes, with the intialisation function being used to create and reposition different SFML objects. I saw this answer and have written my scene switcher similarly:
// Create scene monitoring variable
int scene[2];
scene[0] = 0; // Set current scene to menu
scene[1] = 0; // Set scene change to no
...
// Check for scene change
if(scene[1] == 0) {
// Run tick function based on current scene
switch(scene[0]) {
case 0:
// Main menu - run tick function
menu.tick();
}
}
if(scene[1] == 1) {
// Reset scene that you've changed to
switch(scene[0]) {
case 0:
// Main menu - reset it
menu = Menu(window, scene); // <-- Reinitialise menu here
}
// Set change variable to 0
scene[1] = 0;
}
You can see the full code on the github repository.
However, this doesn't seem to work properly - as soon as a scene change is made, the screen goes blank. The class is reintialised (I added a cout to check), the draw function is still run and mouse clicks are still processed, yet nothing appears in the window.
Am I doing something wrong here?
Doing things that way can lead into leak memory errors. I suggest you a different approach: the StateStack
How this works?
The basics of having a StateStack object is store each possible state of your game/app into a stack. This way, you can process each one in the stack order.
What is an State?
An State is something that can be updated, drawn and handle events. We can make an interface or an abstract class to make our screens behave like a State.
Which are the advantages?
With a stack structure, you can easily control how your different scenes are going to handle the three different processing methods. For instance. If you have a mouse click while you're in a pause menu, you won't that click event to reach the menu state or the "game" state. To achieve this, the solution is really easy, simply return false in your handleEvent method if you don't want the event go further this particular state. Note that this idea is also expandable to draw or update methods. In your pause menu, you won't update your "game" state. In your "game" state you won't draw tour menu state.
Example
With this points in mind, this is one possible way of implementation. First, the State interface:
class State{
public:
virtual bool update() = 0;
virtual bool draw(sf::RenderTarget& target) const = 0;
// We will use a vector instead a stack because we can iterate vectors (for drawing, update, etc)
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack) = 0;
};
Following this interface we can have a example MenuState and PauseState:
MenuState
class MenuState : public State{
public:
MenuState(){
m_count = 0;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("MenuState: " + std::to_string(m_count));
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);
}
virtual bool update() {
m_count++;
m_text.setString("MenuState: " + std::to_string(m_count));
return true;
}
virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
return true;
}
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::P){
stack.push_back(new PauseState());
return true;
}
}
return true;
}
private:
sf::Font m_font;
sf::Text m_text;
unsigned int m_count;
};
PauseState
class PauseState : public State{
public:
PauseState(){
sf::Font f;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("PauseState");
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);
}
virtual bool update() {
// By returning false, we prevent States UNDER Pause to update too
return false;
}
virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
// By returning false, we prevent States UNDER Pause to draw too
return false;
}
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::Escape){
stack.pop_back();
return true;
}
}
return false;
}
private:
sf::Font m_font;
sf::Text m_text;
};
By the way, while I was doing this, I notice that you must have the fonts as an attribute of the class in order to keep the reference. If not, when your text is drawn, its font is lost ant then it fails. Another way to face this is using a resource holder, which is much more efficient and robust.
Said this, our main will look like:
Main
int main() {
// Create window object
sf::RenderWindow window(sf::VideoMode(720, 720), "OpenTMS");
// Set window frame rate
window.setFramerateLimit(60);
std::vector<State*> stack;
// Create menu
stack.push_back(new MenuState());
// Main window loops
while (window.isOpen()) {
// Create events object
sf::Event event;
// Loop through events
while (window.pollEvent(event)) {
// Close window
if (event.type == sf::Event::Closed) {
window.close();
}
handleEventStack(event, stack);
}
updateStack(stack);
// Clear window
window.clear(sf::Color::Black);
drawStack(window, stack);
// Display window contents
window.display();
}
return 0;
}
The stack functions are simple for-loop but, with the detail that iterate the vector backwards. This is the way to imitate that stack behavior, starting from top (size-1 index) and ending at 0.
Stack functions
void handleEventStack(sf::Event e, std::vector<State*> &stack){
for (int i = stack.size()-1; i >=0; --i){
if (!stack[i]->handleEvent(e, stack)){
break;
}
}
}
void updateStack(std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->update()){
break;
}
}
}
void drawStack(sf::RenderTarget &target, std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->draw(target)){
break;
}
}
}
You can learn more about StateStacks and gamedev in general with this book

wxwidget application crashes on exit, when I add code to do drag and drop

I have a wxwidget application that uses dragandrop and when I close the application, it crashes on this line:
virtual ~wxDropTargetBase()
{ delete m_dataObject; }
I setup the drapand drop in this way:
MainWindow::MainWindow() : MainWindowTemplate(NULL), m_fileDropTarget(textSourceFolder)
{
// connect events
this->Connect(wxEVT_IDLE, wxIdleEventHandler(MainWindow::OnIdle));
// set window minimum size - work around bug that ignores outer border and sets min size slightly too small
wxSize minSize = sizerOuter->GetMinSize();
minSize.SetWidth(minSize.GetWidth() + 16);
minSize.SetHeight(minSize.GetHeight() + 16);
SetMinSize(minSize);
Layout();
// set file drop target
SetDropTarget(&m_fileDropTarget);
}
and the source code for my
class MyFileDropTarget : public wxFileDropTarget
{
public:
MyFileDropTarget(wxTextCtrl *textCtrl)
{
m_fileTextCtrl = textCtrl;
}
virtual bool wxFileDropTarget::OnDropFiles (wxCoord x, wxCoord y, const wxArrayString &filenames)
{
if (filenames.size() > 0)
{
m_fileTextCtrl->SetValue(filenames.Item(0));
return true;
}
return false;
}
private:
wxTextCtrl *m_fileTextCtrl;
};
what is the problem and how I can fix it?
It looks like your m_fileDropTarget is an object, in which case it is deleted twice, as when you call SetDropTarget() it takes ownership of the pointer passed to it.

Why isn't my game pausing? (Windows C++ Keyboard Input Statemachine)

I'm writing a game in C++ using the Windows API which has a Splash Screen at the start, before gameplay begins, and can be paused.
I store the state of the game in an enum, game_state {PAUSED, PLAYING, SPLASHSCREEN}, and rely on Keyboard input to control the game.
The game was working properly, switching between paused and playing, but when I tried to add a splashscreen to begin the game on, the pause functionality stopped working, and I'm not sure why...
if(Keyboard.GetKey(VK_RETURN) && game_state == SPLASHSCREEN)
{
game_state = PLAYING;
Keyboard.SetKey(VK_RETURN, false);
}
if(Keyboard.GetKey(VK_RETURN))
{
if(game_state == PAUSED)
{
game_state = PLAYING;
}
else
{
game_state = PAUSED;
}
Keyboard.SetKey(VK_RETURN, false);
}
//If Paused, go to Pause Screen
if(game_state == PAUSED)
{
pauseScreen();
}
//If Splash Screen, go to Splash Screen
if(game_state == SPLASHSCREEN)
{
splashScreen();
}
//If not paused, do game processing
if(game_state == PLAYING)
{
gamePlay();
}
GetKey() returns true if the key is held down.
game_state is an enum global containing the current state of the game.
SetKey() sets the specified key as down (true) or up (false)
Oh, and all splashScreen() pauseScreen() and gamePlay() do are display sprites representing each state (at the moment)
SetKey
void Keyboard::SetKey(WPARAM key, bool key_down)
{
if(key_down)
{
m_keys[key] = true;
}
else
{
m_keys[key] = false;
}
}
GetKey
bool Keyboard::GetKey(WPARAM key)
{
if(m_keys[key])
{
m_keys[key] = false;
return true;
}
else
{
return false;
}
}
Remove m_keys[key] = false; from the Keyboard::GetKey method. As it is being set to false in the first check, it prevents the next check from seeing that it was pressed.
Calling GetKey() sets the key as released - since it checks to see if the key is pressed and the state is splashscreen before checking anything else - the key will always be released when checking it again.
Alter GetKey or alter the way the code is written.
My best guess is that your splash screen has the focus and it will take over the message loop, then you don't get the key event. Just a guess, can't really know without seeing the window creation/registration code of your splash and main windows.