I am using raylib 3.5.0 and here is my code:
Vector2 startMousePos = GetMousePosition();
Vector2 endMousePos;
bool mousePressed = false;
while (1)
{
if (!IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
break;
}
mousePressed = true;
endMousePos = GetMousePosition();
}
I want to create a line based on the position the mouse starts clicking and where it ends but this code causes a infinit loop.
I figured out i should use the glfwPollEvents function that I got from using a function declaration at the top of my file, this declaration gets pulled from glfw as raylib uses this to manage windows. Calling this method yourself could hinder raylibs input handling so be careful.
extern "C" void glfwPollEvents(void);
I also changed my code to (no, while(1) can't be replaced with while(!IsMouseButtonDown(MOUSE_LEFT_BUTTON))):
Vector2 startMousePos = GetMousePosition();
Vector2 endMousePos;
bool mousePressed;
while (1)
{
if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
break;
}
else
{
glfwPollEvents();
if (!mousePressed)
{
mousePressed = true;
}
endMousePos = GetMousePosition();
}
}
Related
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;
}
}
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
I'm making a game with a debugging console. It is structured like:
class Game
{
bool debugMode;
// ...
std::unique_ptr<Loop> loop;
std::unique_ptr<Debugger> debugger;
// ...
}
It works great in the class functions:
void Game::init()
{
// ...
loop = std::make_unique<Loop>();
if (debugMode)
{
debugger = std::make_unique<Debugger>();
debugger->console->write(L"Game initialized."); // works great!
}
}
But what if I want to write something to the console in loop?
I don't want to pass debugger to loop.
I don't want to create
another debugger in loop.
How do I give loop access to debugger?
Use a shared_ptr as suggested by Sam Varshavchik.
Several shared_ptr objects may own the same object.1
This is now I got it to work, in case your interested:
class Game
{
bool debugMode;
// ...
std::unique_ptr<Loop> loop;
std::shared_ptr<Debugger> debugger;
// ...
}
The init function:
void Game::init()
{
// ...
if (debugMode)
{
debugger = std::make_unique<Debugger>();
loop = std::make_unique<Loop>(debugger);
debugger->console->write(L"Game initialized."); // works great!
}
else
{
loop = std::make_unique<Loop>();
}
}
The Loop constructor:
Loop::Loop(std::shared_ptr<Debugger> debugger) : Loop()
{
this->debugger = debugger;
}
I have created a drawGrid() function that draws a squared grid along my X and Y axis, which works fine. I have then created a menu() function (called in the main()), that toggles the grid on and off, here's the code for that:
void menu(int item)
{
switch (item)
{
case MENU_SWITCH_OFF_GRID:
{
if (gridActive == true)
{
gridActive = true;
}
}
break;
case MENU_SWITCH_ON_GRID:
{
if (gridActive == true)
{
gridActive = false;
}
}
break;
default:
{ /* Nothing */ }
break;
}
glutPostRedisplay();
return;
}
}
The menu switch works fine, as I have created a global variable called gridActive without a true or false value so it doesn't reset each time, that way it can be accessed in my display() function like so:
if (gridActive != true)
{
drawGrid();
gridActive = true;
}
All of this works just fine.
What's my issue?
My issue is, whenever I click the left mouse button, my grid disappears, which I don't want. So I've made a mouse() function like this:
case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN)
{
exit(0); // this has been added to see if
// my program will exit!
}
break;
To test if my program exits when I click the left mouse, and it does.
So instead of using exit(0); what code can i put here so that my grid doesn't disappear when I click the left mouse button? Or is the issue beyond that?
UPDATE:
Here's the mouse function:
void mouse(int button, int state, int x, int y)
{
// these have simply been set-up for me to use
// in the future
switch (button)
{
case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN)
{
}
break;
case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN)
{
}
break;
default: break;
}
}
Based on your code:
if (gridActive != true)
{
drawGrid();
gridActive = true;
}
You only draw the grid when gridActive is false. However, after every time you draw it, you set gridActive=true which will then stop it from being drawn.
Without more of your code, it's impossible to tell exactly what's going on, but these lines may not be doing what you think they are, and that may be causing some issues.
This never does anything.
if (gridActive == true)
{
gridActive = true;
}
This:
if (gridActive == true)
{
gridActive = false;
}
is the same as:
gridActive = false;
In order to tell what's going on, though, we need to know what happens when you click your mouse button when the exit call isn't there, but you didn't post that code yet.
Also, i don't quite know what you mean by:
I have created a global variable called gridActive without a true or false value so it doesn't reset each time
but it sounds like you made an uninitialized global variable and expect that it has some specific meaning because it's uninitialized?
I've got a player class, having MoveUp, MoveLeft and MoveRight functions.
At MainScene.cpp (my only scene so far), I've got a listener
auto keyboardListener = EventListenerKeyboard::create();
keyboardListener->onKeyPressed = CC_CALLBACK_2(MainScene::keyPressed, this);
keyboardListener->onKeyReleased = CC_CALLBACK_2(MainScene::keyReleased, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(keyboardListener, this);
Also, I've got a pointer player, defined by
this->player = rootNode->getChildByName<Player*>("Player1");
Also, I've got a function keyPressed and keyReleased in MainScene.
In keyPressed function, I was scheduling functions with if's:
if (keyCode == cocos2d::EventKeyboard::KeyCode::KEY_D) { schedule(schedule_selector(MainScene::MoveRight)); }
But there was a problem, when I tried to do the same thing with objects instead of sprites and with functions located in separated class, not within the same file.
If I try to run code like this in MainScene::keyPressed:
if (keyCode == cocos2d::EventKeyboard::KeyCode::KEY_W) { this->player->MoveLeft(5); }
, player moves only once per key press (I want it to move till I release that key), and if I try to schedule it or do something like this, it doesn't work or there are errors.
I tried to make something with CallFunc and CCCallFunc, but nothing seems to work.
Could you please help me? :)
Why not create a method startMoving() and stopMoving() in Player class?
Something like this:
void Player::init(){
scheduleUpdate()
}
void Play::startMoving(){
isMoving = true;
}
void Player::stopMoving(){
isMoving = false;
}
void Player::update(float delta){
if(isMoving){
//move player here
sprite->setPositionX(sprite->getPositionX() + speed * delta);
}
}
and then call them from keyPressed/keyReleased?