Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - MasterYi

Pages: [1]
1
Thanks kojack.  This turned out to be a more layered question than I originally thought, but at this point, I think all parts of it have been clarified and answered, thanks to your reply filling the last gap.  If there are any questions about any of the topics here that aren't clear, though, I'd be happy to discuss.


=== The Question Parts We've Answered ===

1.  The wall I hit implementing this code originally, was what you point out.  I had the static variable, without the instantiation in the .cpp file.  For many other static variables throughout the application, I had used inline, but couldn't manage to make it work in this case (although I bet there is syntax that could work).  In the original question, the .cpp instantiation is not there, but by a later time, I had discovered the answer and posted my finding as a reply, albeit with a different data structure -- but I didn't clarify that the same would have worked for the static std::array (so thanks for pointing it out).

2.  I also wanted to inquire about other possible ways to make this work in case I was looking at the problem wrong or reinventing the wheel.  With the discovery of the "event.key.control" and the like, a simple use case became evident, which will probably suffice for most people (ctrl,alt,shift,system).

3.  Third, is what kind of datastructure is ideal to tackle the "every key" goal.  I do think that the unordered map is clean and expressive, and also allows for 'at-reference-instantiation' of values (so that init isn't even necessary -- when you reference a key (as in key-value-pair key, not sfml key) in an unordered map that doesn't exist in that map, a default value will be created at the key).  Shout out to eXpl0it3r

4.  How to iterate the sf::Keyboard::Key enum.  Which, is also solved!


So, I thank everyone for their contribution, and I believe (and hope) that this thread may help others.  Also hidden here is a demonstration of how to implement a toggle in a game loop via the "checkToggle" function which I didn't include all of the code for, but did briefly explain via a comment.


Thanks again everyone  :D

2
Quote
Why?
Are you not accessing the map with the same enum values?

Well, I am -- the idea is that if A was reordered to come after numbers, for example, then the loop above would start iterating at a later "index".

But, that's an easy fix, which is to make the loop like this (just change the initial int to 0 instead of sf::Keyboard::Key::A)

void InputManager::initializeKeyState() {
    for (int keyInt = 0; keyInt != sf::Keyboard::Key::KeyCount; keyInt++)  {
        sf::Keyboard::Key key = static_cast<sf::Keyboard::Key>(keyInt);
        keyStateMap[key] = false;
    }
}
 

And in fact, this function is probably unnecessary with an unordered_map, as iterating the event loop / accessing values in the map will populate it --- so prefilling probably isn't necessary.  But, maybe the code in this thread will help someone just looking to iterate the Key enum, etc.

I can see the light now.

Thanks again eXpl0it3r

3
Thank you for the reply eXpl0it3r!  I've lurked without being a member on this forum for a minute, and it's cool to have one of the main SFML contributors reply on your post  8)

That does sound like a good idea.  For others looking at this in the future, this is what the initializeKeys() function looks like, using this idea:

// in InputManager.h the map looks like:
static std::unordered_map<sf::Keyboard::Key, bool> keyStateMap;

// in the .cpp file:

      // required to instantiate the static unordered_map (must put this line in the cpp)
std::unordered_map<sf::Keyboard::Key,bool> InputManager::keyStateMap;

void InputManager::initializeKeyState() {
    for (int keyInt = sf::Keyboard::Key::A; keyInt != sf::Keyboard::Key::KeyCount; keyInt++)  {
        sf::Keyboard::Key key = static_cast<sf::Keyboard::Key>(keyInt);
        keyStateMap[key] = false;
    }
}
 

@expl0it3r, this solution does somewhat rely on the sf::Keyboard::Key enum being stable -- but the items in question probably would not move (sf::Keyboard::Key::A, and sf::Keyboard::Key::KeyCount) -- keyCount for obvious reasons, and A I would think would not move.

Is there any better way off the top, that one could iterate the Key enum?

Thanks again, big help!!  :)

4
For anyone else wondering about this, I did find a reasonable answer for use cases where you only need to check "ctrl", "alt", "shift", or "system" key presses combined with another key.

Instead of using manual bools at all, one can simply do the following:

        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
            if (event.type == sf::Event::KeyPressed) {
                if (event.key.code == sf::Keyboard::F) {
                    if (event.key.control) {
                        fpsDisplayText.shouldToggle = true;
                    }
                }
            }
        }
 

This is straight from the wonderful documentation provided by the SFML team:
https://www.sfml-dev.org/documentation/2.5.1/structsf_1_1Event_1_1KeyEvent.php

My question still stands for other key combinations, though.  Ideas are very much appreciated.

5
General / Initialize a Container of sf::Keyboard:Key and bool pairs
« on: April 11, 2021, 07:08:18 pm »
Hello, this is my first post here, so I hope I am able to format everything correctly.

I am looking to initialize a container that holds pairs of sf::Keyboard:Key and bool, which is intended to track the state of each key pressed using the event loop.  I am doing this in order to allow for checking if multiple key combinations are pressed (for example, Ctrl-F is pressed), in an InputManager class.

I saw this post: https://stackoverflow.com/questions/17888993/key-repetition-in-sfml-2-0
which has a great idea to initialize an std::array<bool, sf::Keyboard::KeyCount> and then fill it with false.

However, I can not determine how to do this within a class initialization / method.  I want the InputManager to have a private member variable like this, that I fill with false.  Ideally, this class would have only static members to make it easier to use throughout the application.

I tried the following:

class InputManager {
private:
        static std::array<bool, sf::Keyboard::KeyCount> keyState;
public:
        static void initializeKeyStates();
};
 

However, when I try to use "keyState", it complains about incomplete type.  For example, in InputManager.cpp, I have:

void InputManager::initializeKeyStates()
{
        keyState.fill(false);   // Error here, incomplete type is not allowed
}
 

I realize this may be more of a "std::array" question.  But, I also considered using an std::map<sf::Keyboard::Key, bool>, but then actually inserting every sf::Keyboard::Key becomes very tedious -- I can't determine how to insert the pairs via a loop.

Any help on this is greatly appreciated -- having this datastructure in my InputManager will make everything much easier for my game!

Please let me know if I'm missing anything important in this post  :)

EDIT:  I want to also clarify a few things in the above post --
1.  Using sf::Keyboard::isKeyPressed() is not appropriate for my goal, as I have items that I want to check for using events so that it only happens once (I have window.setKeyRepeatEnabled(false)).
2.  The first usage of this (as a proof of concept) will be toggling an FPS display.  I have that working currently via the standard event loop, like this:
    bool control_pressed = false;
    while (window.isOpen()) {
        window.clear();

        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
            if (event.type == sf::Event::KeyPressed) {
                if (event.key.code == sf::Keyboard::F) {
                    if (control_pressed) {
                        fpsDisplayText.shouldToggle = true;
                    }
                } else if (event.key.code == sf::Keyboard::LControl) {
                    control_pressed = true;
                }
            }
            if (event.type == sf::Event::KeyReleased) {
                if (event.key.code == sf::Keyboard::LControl) {
                    control_pressed = false;
                }
            }
        }

        fpsDisplayText.checkToggle(); // this will determine if "shouldToggle" and then toggle
                                       // and set "shouldToggle" to false if it toggled

   .
   .
   ...
 

Pages: [1]
anything