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;
}
Related
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();
}
}
I'm calling an undo command from within QML:
cppClass.undoHandler.createCommand(option)
The C++ undo-handler pushes undo command into undo stack:
void UndoHandler::createCommand(
const QString & option
)
{
m_undoStack->push(new Command(
option
));
}
The actual C++ undo command is:
class Command : public QUndoCommand
{
// ...
virtual void undo();
virtual void redo();
// ...
Logic *m_logic;
}
void Command::redo()
{
m_outputName = m_logic->run(m_option);
}
And the logic runs like this:
QString Logic::run(const QString option)
{
if ( /* some condition here */ ) {
// ** What I want to achieve:
// If this condition is met
// abort the current undo-command
// I mean pop the current undo-command which is already pushed into stack
}
}
How can I abort/pop/break the undo-command by the above condition inside the logic? I'm not sure how it should be designed, any idea?
You can use QUndoCommand::setObsolete() and make the command obsolete.
The boolean is used for the automatic removal of commands that are not necessary in the stack anymore. The isObsolete function is checked in the functions QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex().
I used the if condition before pushing undo command into stack like this:
void UndoHandler::createCommand(
const QString & option
)
{
Command *command = new Command(option);
// Check validity before pushing undo command into undo stack
bool isValid = command->doubleCheck();
if (isValid) {
m_undoStack->push(command);
} else {
delete command;
}
}
Undo command has a new method to check the if condition:
class Command : public QUndoCommand
{
// ...
virtual void undo();
virtual void redo();
// ...
// New method to check validity
bool doubleCheck();
// ...
Logic *m_logic;
const QString m_option;
}
bool Command::doubleCheck() {
return m_logic->doubleCheck(m_option);
}
void Command::redo()
{
// Redo method has to be modified accordingly
}
The if condition is inside a separate method in logic:
bool Logic::doubleCheck(const QString option)
{
if ( /* some condition here */ )
return true;
else
return false;
}
My question is:
I am trying to implement basic state management in my project and i stuck at changing states.
I have all my states in std::stack<State*> container, and push/pop them directly from Application class or from State class.
Problem is when i change current state from State class, it can be destroyed before render method called, whitch results in exeption. So how do i avoid this?
PS sorry for my english and please say me if something in my problem/code isn clear
Application class:
void Application::pushState(State* state)
{
this->m_states.push(state);
this->m_states.top()->open();//enter state
}
void Application::popState()
{
if (!this->m_states.empty())
{
this->m_states.top()->close();//leave state
delete this->m_states.top();
}
if (!this->m_states.empty())
this->m_states.pop();
}
void Application::changeState(State* state)
{
if (!this->m_states.empty())
popState();
pushState(state);
}
State* Application::peekState()
{
if (this->m_states.empty()) return nullptr;
return this->m_states.top();
}
void Application::mainLoop()
{
sf::Clock clock;
while (this->m_window.isOpen())
{
sf::Time elapsed = clock.restart();
float delta = elapsed.asSeconds();
if (this->peekState() == nullptr)
this->m_window.close();
this->peekState()->update(delta)//if i change state in State.update(), it may be that code below will now point to not existing state
if (this->peekState() == nullptr)
this->m_window.close();
this->peekState()->render(delta);
}
}
State class:
void EditorState::update(const float delta)
{
sf::Event event;
while (this->m_application->m_window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
this->m_application->popState();
return;
}
}
}
Okay maybe this is not really a problem, but something like "how to" question. As you can see in my code, i update and render states in mainLoop() method. What im tying to figure out is how to manage those updates, asuming that state can be changed from state itself, not only from stateManager (in my case Application class)
Ok, so I'm guessing this is for a game (but it doesn't have to be). Instead of doing what you're doing for switching between states, I use an enum.
enum class GameState {
MENU, PLAY, PAUSE
}
Then, in your main header
GameState m_gameState = GameState::MENU;
In your main loop, you can check what the current state is by simply doing
if (m_gameState == GameState::MENU)
{
...
}
or you can use a switch statement
switch (m_gameState)
{
case GameState::MENU:
...
break;
case GameState::PLAY:
...
break;
case GameState::PAUSE:
...
break;
}
And, if you ever want to switch the state, you can just do
m_gameState = GameState::PAUSE;
Hope this answered your question :D
If not, I must have misunderstood (sorry).
Alright so here is my code. This should be really simple but it doesn't want to work with me for some reason. Raycast sends a ray from the mouse, if it hits an object with a tag, it assigns a number to a variable. If it doesn't hit an object, then it sets the variable as -99. For some reason mine is hanging on:
A. I don't hit the objects, it outputs -99 the first time but after that it hangs on getting assigned 4.
B.I hit the objects and it will work just fine. After I click OFF the objects it hangs on the variable from the object I just hit previously.
em.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameFunctions : MonoBehaviour {
int Hitnum = -99;
void Start () {
}
void Update () {
if (Input.GetMouseButtonDown (0)) {
objectCheck ();
}
}
//end of UPDATE function
public void objectCheck () {
RaycastHit hit;
Ray ray = camera.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, 10000.0f)) {
if (hit.collider.tag == "Box") {
Hitnum = 1;
} else if (hit.collider.tag == "Sphere") {
Hitnum = 2;
} else if (hit.collider.tag == "Pyramid") {
Hitnum = 3;
} else if (hit.collider.tag == "Trapezoid") {
Hitnum = 4;
} else {
Hitnum = -99;
}
}
Debug.Log (Hitnum);
}
//end of check
}
Thanks in advance. This is driving me nuts because it should be simple.
EDIT: posted full code this time, yes all of it. I should mention that there are no other objects with tags, it's just null space. This was supposed to be a very basic shape identifier for kids.
EDIT:EDIT: I expect it to put out -99 if you do not hit the object. Later I will probably do something with the numbers but right now I jest need to fix this.
Restarted unity, everything works fine now. Thanks. Looked through my settings to see what had changed. I earlier deleted the background that had a background tag on it. I guess unity decided that if there is not hit on raycast, it will get the object that it last hit?
Is it possible to make SFML 1.6 handle end of music by itself? Currently I have this:
//in music.cpp
music.Play()
//in main.cpp
//on every frame check for end of music
if(music.getStatus() == Sound::Stopped)
loadNextMusicFile();
Isn't there a way in SFML to just say, "Play until music stopped, then load the next," without implementing this yourself? Or at least a more "elegant" way of noticing when the music stopped (like an OnStopped event)?
If you look at the code from Music.cpp
bool Music::OnGetData(SoundStream::Chunk& data)
{
Lock lock(myMutex);
// Fill the chunk parameters
data.Samples = &mySamples[0];
data.NbSamples = myFile->Read(&mySamples[0], mySamples.size());
// Check if we have reached the end of the audio file
return data.NbSamples == mySamples.size();
}
You see that it will return false when its at the end of the file.
So what you want to do is subclass sf::Music. e.g.
class MyMusic : public sf::Music
{
bool OnGetData(SoundStream::Chunk& data)
{
bool running = sf::Music::OnGetData(data);
if(!running)
OnMusicEnd();
return running;
}
public:
void OnMusicEnd()
{
// ...
}
};