Making a RTS logic on UE4. I can bind class methods or lambdas to "OnPressed", "OnReleased", and "Axis" signals. Thinking about using the Guarded State Machine pattern with the Command pattern to define key conjunctions, but there is no trivial way to determine a final command at the last step. Need something like morphs.
For e.g.:
LeftClick = Nothing
LeftClick + Unit under cursor = Select unit
Shift + LeftClick = Nothing
Shift + LeftClick + Unit under cursor = Add unit to selection
Shift + LeftClick + Moving cursor + Units under cursor = Add units to selection
Ctrl + LeftClick + Unit under cursor = Remove unit from selection
RightClick = Nothing
RightClick + Units selected = Move units
Perhaps I should use the Behavior Tree pattern instead of the State Machine pattern? But the tree will be so big (the example just has been simplified).
Heyo, good first question! Apologies for the sloppy answer but a few key points:
For inputs to be used in conjunction, you'll need to manually handle the state yourself. For example, if you wanted Ctrl then LeftClick to do something different from LeftClick, then you'll need to remember that Ctrl was clicked earlier and do different behavior. In practice, this tends to be...
In Ctrl OnPressed, set a bool to true (and OnReleased set it to false)
In LeftClick OnPressed, check if that bool is true. If it is, do X behavior. Otherwise do Y behavior
Note that this is independent of your design pattern of choice. ie, regardless of whether you use a behavior tree or a state machine, you'll need to remember what happened with prior keys in order to do behavior in conjunction
On a final point - and apologies if I misunderstood the question - but you seem to be overcomplicating determining input combinations vs corresponding behavior with a given set of inputs. ie, LeftClick + "Unit under cursor" (assuming "Unit under cursor" isn't already stored state) isn't a separate input from LeftClick but rather what you check after the LeftClick OnPressed event occurs
No matter what design pattern you choose, you'll need to handle this on a case by case basis as coding/implementation normally goes. ie, "Did my raycast hit a unit or not?" -> { choose behavior } will occur either way. I'm assuming this is what you're referring to as "morphs" and "final command"
Related
How can I select text in Gtk::TextView:
starting from where the cursor is
n number of characters backwards
The documentation from developer.gnome.org doesn't seem to help.
The selection isn't done in the Gtk::TextView itself but in the associated Gtk::TextBuffer. While I'm not sure why exactly this design choice was done I'm at least clear about the consequence: Selections may be shared between multiple Gtk::TextViews when they share the same buffer. This may be desirable or not but it's how “they” have done it.
The buffer of a Gtk::TextView can be obtained with
Glib::RefPtr< TextBuffer > get_buffer ()
Returns the Gtk::TextBuffer being displayed by this text view.
The reference count on the buffer is not incremented; the caller of this function won’t own a new reference.
Then, the Gtk::TextBuffer provides
void Gtk::TextBuffer::select_range (const iterator& ins, const iterator& bound)
This function moves the “insert” and “selection_bound” marks simultaneously.
If you move them in two steps with move_mark(), you will temporarily select a region in between their old and new locations, which can be pretty inefficient since the temporarily-selected region will force stuff to be recalculated. This function moves them as a unit, which can be optimized.
ins Where to put the “insert” mark.
bound Where to put the “selection_bound” mark.
The current cursor position can be obtained with
Glib::RefPtr Gtk::TextBuffer::get_insert()
Returns the mark that represents the cursor (insertion point).
Equivalent to calling get_mark() to get the mark named “insert”, but very slightly more efficient, and involves less typing.
The returned Gtk::TextMark can be “converted” to a Gtk::TextIter by using
TextIter Gtk::TextMark::get_iter().
Additionally, Gtk::TextBuffer provides a variety of get_iter_at functions to get the Gtk::TextBuffer::iterators for distinct parameters.
A note in general:
To learn a powerful widget API by the reference manual, is something I would consider as tedious.
In the case of gtkmm, there is a serious alternative:
Programming with gtkmm 3
(which is available in other languages as well).
Chapter 11 is about TextView and might help to get the “big picture”.
To handle text input I've set up a char-event callback with glfwSetCharCallback, and to handle non-text keypresses (arrow keys & hotkeys) I've set up a key-event callback with glfwSetKeyCallback.
What happens in this situation is that for a key press of a character key, I get two calls, one in the key-event callback, and then one in the char-event callback. This can cause unwanted effects - for example let's suppose the user configured the key "a" to enter "Append Mode" of a text editor - after it enters the mode it will also enter the character "a".. Is there a good way to handle this?
So far I've relied on both events arriving together before glfwPollEvents returns, and have merged them. But I get reports that this scheme doesn't work well on some Ubuntu systems..
I've been having trouble with this one as well. After some rudimentary debugging I found that if you press, hold then release a 'typable' key (meaning a key which may fire both the glfwKeyCallback and glfwCharCallback), the output is as follows:
KeyCallback - pressed
CharCallback - typed
KeyCallback - repeated
CharCallback - typed
(3. and 4. repeat until key is released)
KeyCallback - released
With this, and judging from the fact that there is a 0ms delay between the two events firing, they're probably fired sequentially. The solution I came up with (is rather janky), and involves creating some sort of KeyEvent structure:
(examples are in C++)
enum KeyEventType
{
Pressed,
Repeated,
Released
}
struct KeyEvent
{
KeyEventType Type;
int Key;
unsigned char Codepoint;
bool IsTyped;
}
and store it along with an index variable, such as
[main/input class]
std::vector<KeyEvent> m_KeyEvents;
size_t m_LastKeyEventIndex;
in the main file.
Then, when the glfwKeyCallback fires, push a new KeyEvent into the vector:
[glfwKeyCallback]
KeyEventType type = (action == GLFW_PRESS ? KeyEventType::Pressed : (action == GLFW_REPEAT ? KeyEventType::Repeated : KeyEventType::Released));
KeyEvent event = KeyEvent(type, key);
m_KeyEvents.push_back(event);
m_LastKeyEventIndex = m_KeyEvents.size() - 1;
and if the glfwCharCallback fires, we know from the debugging that it should be (immediately) after the corresponding keyCallback event, so you can modify the last added entry in the vector to add the codepoint and mark it as a 'typed' event, after-the-fact. This also gives the added benefit of tying the actual key that was pressed to the generated codepoint, which could come in useful.
[glfwCharCallback]
m_KeyEvents.at(m_LastKeyEventIndex).Codepoint = codepoint;
m_KeyEvents.at(m_LastKeyEventIndex).IsTyped = true;
Finally, in the main loop when you go to call glfwPollEvents(), process all those pending KeyEvents and then clear the vector and reset the index.
I haven't fully tested this yet, but some very rudimentary debugging shows this as a promising solution, resulting in the following*:
*I'm using a custom Key enum in place of the int Key. You could probably use glfwGetKeyName() to get the printable key name, however this resulted in exceptions for me when pressing some keys.
I recently switched to QTCreator for C++ from Eclipse background.
I am looking for these two features in QtCreator...
(1) I want to open the file a class is written in by typing that class's name. For example Ctrl+Shft+T in Eclipse.
(2) I want to move back to where my cursor were before the current operation.
Any shortcuts for above two features?
To open the file of a class:
If you are in a file that is making use of the class, you can place the cursor on the class then press F2. By default, F2 is bound to the Follow Symbol Under Cursor action.
If you want to get to the class without to find an instance of it, you can use the Locator . By default Press:
ctrl + k to access the locator
Type c then space to locate classes
Now type the name of your class. Once you've selected the class, hit enter
To navigate back to where you were, you can use GoBack and GoForward, as mentioned by Roman Zaytsev. These default to alt + left and alt + right. It has been many years since I have used eclipse, but I thought it also used alt + left and right as I was pleased to find QtCreator used it as well.
(2) I want to move back to where my cursor were before the current operation.
Go to Tools > Options > Environment > Keyboard. There assign shortcuts for "GoBack" and "GoForward" in "QtCreator" section.
I'm creating this 2D game and I'm having problems with the Jump function. It works, the character jumps up and down, but I would like to be able to jump and then move the character while its in the air,e.g. so it can jump onto a platform. I'm using SDLK...
case SDL_KEYDOWN:
switch (event.key.keysym.sym){
RArrow = (event.button.button = SDLK_RIGHT);
Jump = (event.button.button = SDLK_SPACE);
if((RArrow) && (Jump))
{
if(g->getPlayer()->worldY = GROUND_LEVEL)
{
g->getPlayer()->jump();
g->getPlayer()->move(10);
}
}
break;
This is one of the ways I've tried. I've also tried to make a switch function inside the jump case to navigate left or right but I either didn't code it right or just didn't work.
I'm unfamiliar with SDLK and how this actually is done in real game development.
However one way I've implemented this is to see if both keys are pressed on each game tick. So if w+d is pressed the character would go up and right at the same time. But it's a hackish solution in my opinion.
With the implementation listed, looks like the character will only move right when they are on the ground level. You need to change your code so that every tick, the game checks if the character is jumping and if so, moves the character in the direction it is facing/jumping. This code may need to live outside of your event handler.
Ideally, your keyboard event handler would just set a flag on the character indicating that they are jumping and which direction, then in your game loop you call an update() method which actually handles the jumping (and stops jumping when the character collides with the world geometry, like a floor or wall).
Hope this helps!
EDIT:
Without seeing the rest of your code, I can't say much more. I'm also not great with C++, which I'm assuming this uses. One way you could implement this is:
Replace "g->getPlayer()->jump()" with "g->getPlayer()->setJumping()".
Implement "setJumping()" on the Character to set a jumping flag.
In the game loop, call "g->getPlayer()->updatePos()"
Implement "updatePos()" on the Character to update the character's position. In this, check the jumping flag, and if it's true update the position based on your jumping algorithm.
In Qt's QKeyEvent I can check whether Ctrl was pressed by checking if ev->key() is Qt::Key_Control. But how can I distinguish between the left and right Ctrl keys?
I also need the same thing for Alt and Shift keys.
There is no way to do this using pure Qt methods, as far as I know.
Depending on your platform, however, you might be able to distinguish between the keys using the QKeyEvent::nativeScanCode() method instead of QKeyEvent::key().
For example, on Windows you should be able to test which Ctrl key was pressed as follows:
if (event->nativeScanCode() == VK_LCONTROL) {
// left control pressed
} else if (event->nativeScanCode() == VK_RCONTROL) {
// right control pressed
}
According to the Qt Namespace Reference, the enum Qt::Key has a different value for Qt::Key_Alt and Qt::Key_AltGr.
However, enum Qt::KeyboardModifier and enum Qt::Modifier don't see the pair of keys as different modifiers.
(note: I would have posted this as a comment but I don't have enough rep. yet)
Left and Right keys are part of virtual key code -> use nativeVirtualKey() to compare with windows VK_* enums instead of nativescancode().
If VK_RCONTROLdoes not work, check your nativeScanCode value of ctrl-right:
std::cout<<keyEvent->nativeScanCode(); and use this value:
int control_right = 285;
if(key->nativeScanCode() == control_right){...