What would be the best way of counting how many times a bool flag was changed from false to true inside a game update loop? For example if I have this simple example below, where if you hold button "A" pressed the Input class sets the enable bool of the Game class to true and if you release it sets it to false and a counter inside the Game class that counts how many times enable was changed from true to false. For example if you press "A" and release twice counter should update to 2. Having Game::Update() updating at 60fps the counter would be wrong with the current approach. To fix it I moved the check and the counter inside SetEnable instead of the Update loop.
// Input class
// Waits for input
void Input::HandleKeyDown()
{
// Checks if key A is pressed down
if (key == KEY_A)
game.SetEnable(true);
}
void Input::HandleKeyUp()
{
// Checks if key A is released
if (key == KEY_A)
game.SetEnable(false);
}
// Game class
void Game::SetEnable(bool enable)
{
if(enable == enable_)
return;
enable_ = enable;
//Will increment the counter as many times A was pressed
if(enable)
counter_ += 1;
}
void Game::Update()
{
// Updates with 60fps
// Will increment the counter as long as A is pressed
/*
if(enable_ == true)
counter_ += 1;
*/
}
void Game::Update()
{
if (key == KEY_A && ! enable_)
{
enable_ = true;
++counter_;
}
else if (key == KEY_B)
enable_ = false;
}
If I get you right, you want to count how many times enable_ changes. Your code has a small flaw, imagine this example:
enable_ = false
counter = 0
update gets called, key is A -> enable_ = true, counter = 1
update gets called, key is B -> enable_ = false, counter remains 1
Function that might fix this can look, for example, like this:
void Game::Update() {
if (key == KEY_A && !enable_) { // key is A and previous state is false
++counter;
enable_ = true;
}
if (key == KEY_B && enable_) { // key is B and previous state is true
++counter;
enable_ = false;
}
}
Related
I want to stop adding new lines to a sales order based on a condition in Acumatica. How can I do this.?
I tried adding the following. But It did not worked.
protected void SOLine_RowInserting(PXCache cache, PXRowInsertingEventArgs e)
{
var row = (SOLine)e.Row;
if (row == null) return;
//Condition
if(Condition == true)
{
Base.Transaction.Delete(row);
}
}
Set AllowInsert cache property to false from the context of RowSelected event.
void _(Events.RowSelected<SOLine> e, PXRowSelected baseMethod)
{
baseMethod(e.Cache, e.Args);
bool canInsertCondition = false;
Base.Transaction.Cache.AllowInsert = canInsertCondition;
}
The basic logic of my game is:
the player goes from random room to random
there is a set of rooms that randomly repeat
each room he passes the counter goes up
he has a button where he can signal, if he goes through a room that he already passed
if a room repeats and he presses the button, he goes to the next random room and the counter goes up
if a room repeats and he didnt notice, he is set back to the unnoticed room and the counter goes back to the repeating room
The result of the following code is, that the room doesnt change at all, when he reaches the trigger at the end of the room. But there are no compiler errors.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class RoomHandler : MonoBehaviour
{
public List<Vector2> PassedRoomsAndCounter;
Vector2 roomAndCounter;
int roomCounting = 1; //position in ascending order
int roomNumber = 1; //unique number of current room
bool RepetitionWasSignaled;
float CountOfRepeatedRoom;
void Update()
{
//Has Repetition button been pressed?
bool InputRepetition = Input.GetButtonDown("Submit");
if(InputRepetition == true){
RepetitionWasSignaled = true;
}
}
void OnTriggerEnter2D(Collider2D col){
print("Trigger "+col.gameObject.name);
//collided with Scene Trigger?
if(col.gameObject.tag == "SceneTrigger"){
roomCounting++;
roomNumber = Random.Range(1,6);
roomAndCounter = new Vector2(roomNumber,roomCounting);
print(roomAndCounter);
PassedRoomsAndCounter.Add(roomAndCounter);
for(int i = 1; i < PassedRoomsAndCounter.Count; i++) { //Go throught all entries
if(PassedRoomsAndCounter[i].x == roomNumber){ //RoomNumber already passed?
if(RepetitionWasSignaled == true){ //Repetition Button pressed?
SceneManager.LoadScene(roomNumber); //Yes - go to next normal room
}else{
CountOfRepeatedRoom = PassedRoomsAndCounter[i].y;
SceneManager.LoadScene(CountOfRepeatedRoom.ToString());
}
}else{
SceneManager.LoadScene(roomNumber);
}
}
}
}
}
I'm new to SFML and I have trouble finding a solution to checking if a key is pressed during one frame. The problem I've been facing is the fact that with the Keyboard and Mouse classes, it seems impossible to use a system where one first checks for the current input state before any Update() call of objects and then after all Update() you get a previous input state for the next frame so that one can do the following:
bool Entity::KeyboardCheckPressed(sf::Keyboard::Key aKey)
{
//this part doesn't work
if (KeyboardState->isKeyPressed(aKey) and !PreviousKeyboardState->isKeyPressed(aKey))
{
return true;
}
return false;
}
But this doesn't seem to work with SFML, and other sources tell me that I'm suppose to use the Event class with its type and key.codelike the following example:
bool Entity::KeyboardCheckPressed(sf::Keyboard::Key aKey)
{
if (Event->type == sf::Event::KeyPressed)
{
if (Event->key.code == aKey)
{
return true;
}
}
return false;
}
But this results in the sf::Event::KeyPressed doing the same as KeyboardState->isKeyPressed(aKey), so then I tried the method where you set key repeat to false: window.setKeyRepeatEnabled(false);with no results what so ever. I also found out that the sf::Event::KeyPressed works only as intended inside of this part in the main.cpp:
while (window.pollEvent(event))
{
}
The problem with this is that I want to handle Input inside of my Entity objects' Update()function, and I can't put the whole Update loop inside of the while (window.pollEvent(event)). So here I am, struggling to find a solution. Any help is appreciated.
In general, if you have a thing which you can check the current state of, and you want to check if that state changed between frames, you simply use a variable, declared outside the application loop, to store the previous state, and compare it to the current state.
bool previousState = checkState();
while (true) {
// your main application loop
bool newState = checkState();
if (newState == true && previousState == false) {
doThingy("the thing went from false to true");
} else if (newState == false && previousState == true) {
doThingy("the thing went from true to false");
} else {
doThingy("no change in the thing");
}
// this is done unconditionally every frame
previousState = newState;
}
I would like to check if a key sequence is press. Like a password, i would like that to see the message box you must type "bcqwl" in right sequenze. I tried
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
while(true)
{
if(GetKeyState('B') & 0x8000)
{
cout<<"b has been press"<<endl;
if(GetKeyState('C') & 0x8000)
{
cout<<"c has been press"<<endl;
if(GetKeyState('Q') & 0x8000)
{
cout<<"Q has been press"<<endl;
if(GetKeyState('W') & 0x8000)
{
cout<<"W has been press"<<endl;
if(GetKeyState('L') & 0x8000)
{
MessageBox(NULL,"YES","YES",MB_OK);
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
continue;
}
}
}
But it doesn't works. He print "B has been press" ,many times but not infinitely times,if b is pressed. If after to press b I press c nothing happens.
So i tired:
step:
if(GetKeyState('B') & 0x8000)
{
cout<<"B has been press"<<endl;
goto step1;
}
else
{
goto step;
}
step1:
if(GetKeyState('C') & 0x8000)
{
MessageBox(NULL,"WORK","yes",MB_OK);
}
else
{
goto step;
}
But doesn't work.
I also tired:
#include <iostream>
#include <windows.h>
int main()
{
int progress = 0;
while(progress<=4)
{
if(GetKeyState('B') & 0x8000)
{
std::cout<<"b has been press"<<std::endl;
progress=1;
}
else
{
progress=0;
}
if(progress==1)
{
if(GetKeyState('C') & 0x8000)
{
std::cout<<"c has been press"<<std::endl;
progress=2;
}
else
{
progress=0;
}
}
if(progress==2)
{
if(GetKeyState('Q') & 0x8000)
{
std::cout<<"q has been press"<<std::endl;
progress=3;
}
else
{
progress=0;
}
}
if(progress==3)
{
if(GetKeyState('W') & 0x8000)
{
std::cout<<"w has been press"<<std::endl;
progress=4;
}
else
{
progress=0;
}
}
if(progress==4)
{
if(GetKeyState('L') & 0x8000)
{
std::cout<<"l has been press"<<std::endl;
progress=5;
}
else
{
progress=0;
}
}
}
return 0;
}
But that output "b has been press" for many times but not infinitely if i press b, and after if i press c nothing is happening, praticaly after press b and the program go in if(process==1) but if i press c nothing happen
P.S. sorry for my bad english.
The problem you are still having comes from the fact that you are in no way storing the progress in your key sequence.
Let's say your password is stored in a char array (for easier access to the single characters later on):
#define PWD_LEN 6 // bcqwl has a length of 5 characters but you need +1 for the '\0' (terminating character) at the end of your string
// ...
char password[PWD_LEN] = "bcqwl";
In addition you will need a counter:
#define PWD_LEN 5
// ...
char password[PWD_LEN] = "bcqwl";
int progress = 0;
while(true) { ... }
Both need to be stored before and outside the while loop because both store data that you don't want to reset in each iteration step in your loop.
The counter will be used to track the progress of the user towards completing the key sequence your password represents.
Whenever the user presses a key you will need to do the following checks:
Is the key allowed? - if you have a password abc but the user presses y or !, or something other then a, b or c the key is not allowed.
If the key is allowed take the character it represents and check if it's the same as the character in your password at index progress:
if ( key allowed )
{
if (password[progress] == '<your key character here>')
{
++progress;
}
else
{
// Handle incorrect key stroke relative to key sequence
}
}
Now in order to prevent the counter going bananas I would suggest doing all the checking upon key released, which unlike key pressed is a one time event. A key being pressed can also be part of key hold, in which case you will land in the else (from the code snippet above) many times, which might not be such a good idea.
If the key is ok and in terms of sequence it fits your password then you increase the progress so that in the next iteration step you can do the same check with a new released key event and a new index value for accessing your password array.
When your progress reaches the required value indicating that the key sequence is completed and that all the characters your password consists of have been "inserted" you can break the loop.
This is very basic so I hope that the instructions are clear enough for you to implement.
PREVIOUS ANSWER (now obsolete due to change in the question)
Unless other out-of-the-box way is available to do that (I haven't used GetKeyState() or anything else from windows.h) the general practice is to simply store the pressed state of each button (in an array, a struct etc.).
In your loop you can use a simple chain of if statements (but not nested like you do it!) to check which button is pressed during the current iteration step. Whenever a known key (one that you application wants to process) is pressed, you just need to toggle the respective state of that button in your array, struct or whatever other container you use to store this information:
while(true)
{
// Check state of supported buttons
if(GetKeyState('A') & 0x8000)
{
// store change of state of key A
}
if(GetKeyState('B') & 0x8000)
{
// store change of state of key B
}
if (...)
{
// ...
}
}
At the end or beginning of your while's body you can then ask for the state of each button and also make combined queries:
while(true)
{
// Check state of supported buttons
if(GetKeyState('A') & 0x8000)
{
// store change of state of key A
}
if(GetKeyState('B') & 0x8000)
{
// store change of state of key B
}
if (...)
{
// ...
}
// Do something
// Check for states of buttons
// ...
}
For example let's say you are using the following structure to store the key's state:
typedef struct Key
{
char keyCode;
bool pressed;
} Key;
Key keyA;
keyA.pressed = false;
you can simply do
if (keyA.pressed)
{
// Trigger some change that key 'A' controls
}
to check if your specific button is currently pressed and respectively trigger some action.
For key combinations things are not much different. You just need to use simply boolean logic to handle it:
if (keyA.pressed && keyB.pressed)
{
// Both key 'A' and 'B' are pressed - we have a key combo!
}
You can improve the readability of your code by storing all supported buttons in an array and even adding a nice enum to provide easy access to each button:
enum KeyCode
{
A,
B,
...
};
Key keys[n]; //with n being the number of keys you want to support and also the number of elements your enum has
// Access with an improved readability
if (keys[A].pressed && keys[B].pressed)
{
// ...
}
If you can't find any code for GetKeyState() in particular (highly unlikely) you can look at SDL for example.
I know this is a beginner's problem but I cannot progress with my studies until I understand what is going on here. In an if block that I'm executing in Update(), I cannot understand why the two if statements are executed simultaneously. I thought that as soon as the initiative variable was initialized at the start of the block, the compiler would move down to the first if statement to see if the condition is true. If it is true, it would execute the code in that block until the timer reached zero. Then it would move down to the next. If the condition was true in the first, then it would be false in the second so it would move up to the beginning again. A new bool value would be calculated for initiative and the process would be repeated. What's blowing my mind is that no matter what I do, both blocks are executed and the timers are completely ignored. It is very confusing!
I've made some very basic code to highlight the problem I'm having. I'm using this C# code in Unity3d:
public float firstTimer = 2;
public float secondTimer = 10;
public bool initiative;
void Update()
{
initiative = InitiativeOrder();
if(initiative == true && firstTimer > 0);
{
firstTimer -= Time.deltaTime;
Debug.Log ("First timer has finished!");
}
if(initiative == false && secondTimer > 0);
{
secondTimer -= Time.deltaTime;
Debug.Log ("Second timer has finished!");
}
}
public bool InitiativeOrder()
{
float player = Random.Range(1,10);
float enemy = Random.Range(1,10);
if(player > enemy)
{
return true;
}
else if (player < enemy)
{
return false;
}
else
{
return true;
}
}
the reason the timer isnt working is because the ; after your if()
if(initiative == true && firstTimer > 0);<----remove these from your if
make your if() like these
if(initiative == true && firstTimer > 0)
{
firstTimer -= Time.deltaTime;
Debug.Log ("First timer has finished!");
}
if(initiative == false && secondTimer > 0)
{
secondTimer -= Time.deltaTime;
Debug.Log ("Second timer has finished!");
}
its not executing both if() blocks
this code
initiative = InitiativeOrder();
is being called every frame witch is im guessing 60 fps so for every frame per second it is executing that method and the chance however many times per second that it is true or false is why it seems that it is firing both if() blocks but really each frame that update fires its either true or false which is really fast
if you put that call in OnStart() it will only fire once like
void Start(){
initiative = InitiativeOrder();
}
EDIT YOUR CODE
public float firstTimer = 2;
public float secondTimer = 10;
public bool initiative;
void Start(){
initiative = InitiativeOrder();
}
void Update()
{
if(initiative == true && firstTimer > 0)
{
firstTimer -= Time.deltaTime;
Debug.Log ("First timer has finished!");
}
if(initiative == false && secondTimer > 0)
{
secondTimer -= Time.deltaTime;
Debug.Log ("Second timer has finished!");
}
}
public bool InitiativeOrder()
{
float player = Random.Range(1,10);
float enemy = Random.Range(1,10);
if(player > enemy)
{
return true;
}
else if (player < enemy)
{
return false;
}
else
{
return true;
}
}