Very new at Box2D, would appreciate help.
I've got a simple function that takes in a b2World and b2Body*, where the body is supposed to fall until it collides with a ground box (already created in main())
The code is essentially as follows:
void snake::update(b2World world, b2Body* snake)
{
bool running = true;
Clock deltaClock;
Time deltaTime;
while (running)
{
deltaTime = deltaClock.getElapsedTime();
deltaClock.restart();
world.Step(deltaTime.asSeconds(), 6, 2);
position = snake->GetPosition();
char ch;
if (_kbhit())
{
ch = _getch();
if (ch == 'x')
{
running = false;
}
}
}
}
This code was originally implemented in main(), and it worked fine. However, when I tried to move it to its own function in a separate class, the collision no longer works... I've got no idea as to why, as it was literally copy/pasted, just changing around variable names to fit the parameters...
I've got no idea what's going wrong, and if you need any additional information, I'd be more than happy to provide.
Thanks in advance.
Basically the way you had your parameter set before you were passing the b2World object by value in your original function head.
void snake::update(b2World world, b2Body* snake)
This means you are creating a copy and if this copy is being modified, the original object that was passed to the function remains the same. With the & behind the type you are now passing the object by reference.
void snake::update(b2World& world, b2Body* snake)
This means there is no copy being created but instead the function works with the original object and thus, changes do affect it aswell.
So when you were using this loop before it was probably nested inside of your main function or whatever and could modify the original variable world which was declared in that scope. Now that you have moved it to a seperate function you have to tell the compiler you want to work with the original object.
Read more about passing by value and passing by reference here and here for example
Related
Greetings fellow programmers.
I've been struggeling with learning c++ within the Unreal engine. I thought I understood how to track time properly within a class but alas my variable is chaning it's contents to a vastly different number in the time between two function calls.
For context there are a small number of objects present:
Global Time system
This class is responsible for managing the time and receiving update ticks from the time watcher. This is also a singleton!
TimeWatcher
Super simple, just a Uobject I spawn into the world so it can receive update ticks from the engine and pass them onto the Global Time system
Time class
A class to hold the hours, minutes and seconds. How it is used beyond that is up to the developer using the class. In my case I am simply trying to store it and from that point on remove time off of it to create a countdown timer.
We have our own little logging system to help debugging along, mainly to generate logs without all the unreal stuff and in a format we prefer. This log outputs the following data:
<Log, TimerSystem> [2] 2019.03.17-17.41.42: init attempt, init time should be: 23:6.0
<Log, TimerSystem> [3] 2019.03.17-17.41.42: init attempt succes, 23:6.0
<Log, TimerSystem> [6] 2019.03.17-17.41.42: Timer tick occured, lets see what our timer thinks about the time -225161083:32766:00
So from this we can interpret that the variable in the scope it gets set in(shown below) is set there properly. But the moment we try to read it again in the handleTick function the variable is all wrong.
InitTimer function:
void GlobalTimerSystem::InitTimer(UWorld* world, Time* initialTime)
{
DebugUtility::WriteLog("init attempt, init time should be: " + initialTime->ToString(), DebugUtility::Log, DebugUtility::TimerSystem);
check(world);
//create timeWatcher in the world
FVector location(0.0f, 0.0f, 0.0f);
FRotator rotation(0.0f, 0.0f, 0.0f);
FActorSpawnParameters SpawnInfo;
world->SpawnActor<ATimeWatcher>(location, rotation, SpawnInfo);
//set current time to init value
Time* trPointer = new Time(initialTime->GetHours(), initialTime->GetMinutes(), initialTime->GetSeconds());
this->timeRemaining = *trPointer;
DebugUtility::WriteLog("init attempt succes, " + timeRemaining.ToString(), DebugUtility::Log, DebugUtility::TimerSystem);
}
There is some stupid pointer crap I am doing here, partly because of desperation at this point though.
The Handle tick function:
void GlobalTimerSystem::HandleTimerTick(float deltaTime)
{
DebugUtility::WriteLog("Timer tick occured, lets see what our timer thinks about the time " + timeRemaining.ToString(), DebugUtility::Log, DebugUtility::TimerSystem);
ticksReceived++;
FString debug2;
debug2.Append("Ticks received: ");
debug2.AppendInt(ticksReceived);
DebugUtility::WriteLog(debug2, DebugUtility::Log, DebugUtility::TimerSystem);
double t = static_cast<double>(deltaTime);
DecreaseTimer(&t);
if (deltaTime != NULL) {
FString debug;
debug.Append(TEXT("current time remaining is "));
debug.Append(*timeRemaining.ToString());
DebugUtility::WriteLog(debug, DebugUtility::Log, DebugUtility::TimerSystem);
}
}
Now we know things are already wrong the moment we enter the above function. For good measure here is the header file for this class.
class PGT_PROJECT_API GlobalTimerSystem
{
friend class ATimeWatcher;
private:
Time timeRemaining;
Time timeElapsedNotPaused;
Time timeElapsedPaused;
UINT ticksReceived = 0;
bool paused = false;
bool initComplete = false;
void HandleTimerTick(float deltaTime);
static GlobalTimerSystem* timerSystem;
public:
static GlobalTimerSystem* GetTimerSystem();
void InitTimer(UWorld* world, Time* initialTime);
void IncreaseTimer(double* additionalSeconds);
void DecreaseTimer(double* removeSeconds);
double GetTimeRemaining();
double GetTimeElapsed();
GlobalTimerSystem();
~GlobalTimerSystem();
};
If any more information is required I will be happy to provide. Thank you for your time!
EDIT:
I am overloading the Time::operator= which appears as follows:
Time & Time::operator=(Time & t)
{
_seconds = t._seconds;
_minutes = t._minutes;
_hours = t._hours;
return *this;
}
And using it as follows:
this->timeRemaining = Time(initialTime->GetHours(), initialTime->GetMinutes(), initialTime->GetSeconds());
However this results in the following compiler error that I do not understand:
Path...\Private\GlobalTimerSystem.cpp(62) : error C4239: nonstandard extension used: 'argument': conversion from 'Time' to 'Time &'
In GlobalTimerSystem::InitTimer(UWorld*, Time*), you do the following:
Time* trPointer = new Time(initialTime->GetHours(),
initialTime->GetMinutes(),
initialTime->GetSeconds());
this->timeRemaining = trPointer;
which means:
Create a new object of type Time on the heap, construct it with the following arguments and, once it's ready, return a pointer to it (Time*) which I'll store in my local variable trPointer;
assign the value of the pointer trPointer (which is the address of the instance of the class Time that we just allocated and initialized on the heap) to my instance variable timeRemaining (which is an instance of the class Time).
So once you reach GlobalTimerSystem::HandleTimerTick, this->timeRemaining contains garbage which stays garbage when translated ToString (hence the -225161083:32766:00 you see). Furthermore, the memory you now have allocated on the heap for that instance of Time you've created is wasted as you will never release it and won't even use it.
The thing is that, in this case, you don't need the heap at all!
Depending on how operator= behaves (you said you overloaded it), you should be able to do:
this->timeRemaining = Time(initialTime->GetHours(),
initialTime->GetMinutes(),
initialTime->GetSeconds());
which will create a temporary Time instance and initialize it with the passed arguments, then "copy" it (=) inside your instance variable timeRemaining. If you do this, you might want to look into Time::operator=(Time&&) as that "temporary Time instance" is an rvalue. Please note that, in this case, we do not leak memory as everything is allocated on the stack and will be released when the function returns.
If this does not work, that means Time::operator= is not behaving as a proper "copy operator" and should be fixed. Another approach would be to manually set the hours, minutes and seconds fields of timeRemaining (if they are public or friend) or (much better), to have a method such as Time::set(/*hours, minutes, seconds*/) allowing you to this->timeRemaining->set(...).
Finally, once again depending on the internals of Time and how Time::operator= has been written, noticing that initialTime is itself a Time*, the "temporary intermediate Time instance" shouldn't even be needed, leading to the much simpler and more readable
this->timeRemaining = *initialTime;
As a conclusion, I believe your issue comes from the implementation of Time::operator=.
I'm working on using pointers to add objects to a queue and ran into a weird behavioral problem I can't quite figure out.
Each object that gets added to the queue has a 'next' pointer that links them all together and I have a 'start' and 'end' pointer to keep track where each end of the queue is.
The problem I have is that when I pass the end pointer and the object (which is stored in pArray by its processID), it also changes the start pointer -- even though I'm not passing it to the function.
// snippet from my main.cpp
RQCount = 0;
if (RQCount == 0)
{
RQStart = &pArray[processID];
RQStart -> next = &pArray[processID];
endRQ = &pArray[processID];
pArray[processID].setStatus("Ready");
CPUHolder = RQStart;
CPU = RQStart -> CPUBurst;
RQStart ->pStatus = "Executing";
}
else
{
*endRQ = FCFS(endRQ, &pArray[processID]);
pArray[processID].setStatus("Ready")
}
RQCount++;
FCSC Method:
PCB FCFS (PCB *endRQ, PCB *obj)
{
endRQ -> next = obj;
endRQ = obj;
return *endRQ;
};
I've narrowed it down to the function, and what really stumps me is that I move those two lines of code to my main, it runs and behaves just fine. It's when I add the function it doesn't. I think it has to do with how I'm dealing with the pointers and dereferencing, but I could use some help understanding this. Thanks!
EDIT:
To emphasize, I'm not having an issue with variables not changing in the function, as someone marked this a duplicate question for. The issue is after the function is called, it changes RQStart (which is not passed to the function).
If I don't use a function, RQStart stay the same, when I use the function, RQStart changes to a different object.
If you do
RQStart = &pArray[processID];
// ...
endRQ = &pArray[processID];
and then pass endRQ to the function, that will be the same as if you passed RQStart.
So when you change endRQ->next that will also change RQStart->next.
This is one reason for the standard containers to have end() point one past the last element, and not to the last element.
I am building a text based adventure game and I'm currently stuck on an issue.
I have a two variables that hold the values for the map(rooms) called x and y, I am changing them from a class and as soon as it exits the class code back to main it resets the values for x and y.
int x = 0, y = 0;
...
void IncreaseY(){
y++;
}
void MoveDirection(Direction direction)
{
switch (direction)
{
case North:
DecreaseY();
break;
case South:
IncreaseY();
break;
case East:
IncreaseX();
break;
case West:
DecreaseX();
break;
case None:
break;
default:
break;
}
}
...
class player{
void DoStuff()
{
MoveDirection(South);
}
}
...
void main()
{
Player player = Player.NewOrLoadCharacter();
player.doStuff();
}
This is most of the relevant code summarized.
I have stepped through the program using breakpoints and stepping several times and I am completely sure that as soon as I leave the Player class the variables x and y reset back to 0.
Question:
What could be causing the resetting of the variables x and y?
Note: This is an issue that just popped up since it has worked previously just fine.
edit: Source code: http://pastebin.com/uKS55LEZ
P.S.: I know the code is poorly written, I started with C++ moving from C# a week ago.
The code changed considerably since this answer was first posted, yet the problem is still actually a kind of mirage.
Here's what's happening at the current version of the code (the OP question does not represent this situation at the time of this writing):
In main, there is a Player declared thus:
Player player;
In a standard game loop, this code exists:
while( true )
{
ClearConsole();
Print(map.CreateMap(player));
map.doRoom(player);
}
This is greatly improved over earlier versions (much cleaner). There is one small problem causing the behavior described. It's the signature of the function doRoom (and this may apply to CreateMap, though I doubt it).
void doRoom(Player player)
This is a member of Room (in the loop above, that's map). The problem is that player is passed by value. This means a copy of player is made to provide the input parameter for doRoom. This copy is changed by doRoom (moving x and y, for example). When doRoom returns, the copy which it acts upon evaporates (falls from scope) - and the edited data goes with it.
Change the signature to
void doRoom(Player & player)
Now, the function takes a reference to player. There is no copy being made. As such, changes made to player are retained from one iteration of the loop to the next.
I said earlier this MIGHT apply to map.CreateMap, but that's true only if CreateMap modifies contents of player. If not, it wouldn't matter, but it would be technically slower to create a copy of player just to make the output CreateMap produces. It can take a reference, as I've suggested doRoom must take.
There is one other minor problem. The main loop above has no means of escape. There is no way to end the game. map.doRoom( player ) should probably return a bool, and perhaps if a false is returned, break the loop.
I've found a question sorta similar to this one, though put in a more complex way than I think I require (received a -2 for question score). Hopefully this will be easier to follow.
The general gist of things is the two classes involved are GUI and Player (I've had the same problem elsewhere with other classes, but if I can understand why this one isn't working, it should apply to the rest).
GUI includes "Player.h". The class Player has a public boolean variable 'hasBall'; When a 'Player' is passed into a function Pass() and the boolean value changed, it seems that it is only a temp object thus isn't updating the object being passed itself. See code below:
This works fine, boolean values for Plyr1A and Plyr2A (defined in Gui.h) are changed and preserved
Plyr1A.hasBall = false;
Plyr2A.hasBall = true;
However boolean values for Plyr1A and Plyr2A remain the same with this.
Pass(Plyr1A,Plyr2A); //Boolean values for Plyr1A and Plyr2A remain the same with this.
void GUI::Pass(Player passer, Player receiver) {
passer.hasBall = false;
receiver.hasBall = true;
}
If anyone could explain to me why this occurs I'd be rather thankful! If there is any extra information needed please let me know.
Cheers :)
Your function makes a copy of the arguments (they are passed by value), then changes the copy, not the "original" objects(in the body of the function).
You should change it to take pointers or references, for example:
//-------------------v---------------v <---these are references
void GUI::Pass(Player& passer, Player& receiver) {
Of course, you should change the declaration, too.
Use references to pass your objects.
Consider this function:
void someFunction (int j)
{
j = 8;
}
And say we call it like this:
someFunction (3);
Are you thinking the assignment in someFunction somehow makes that 3 become an 8? Your expectation makes no sense. Without some kind of special arrangement, it cannot be that an assignment inside a function changes values in the caller.
This code is segfaulting and I can't really figure out why. When I use gdb it segfaults at the end of the function (the curly brace). So that doesn't really give me a lot of information as to what's going on. Here's the code, I'll provide extra info if needed.
typedef std::list<Ground> l_Ground;
void Player::y_collisions(l_Ground grounds) {
for (l_Ground::const_iterator ent = grounds.begin(); ent != grounds.end(); ent++) {
if (getGlobalBounds().intersects(ent->getGlobalBounds())) {
in_air = false;
velocity -= gravity;
}
}
}
EDIT: Upon closer inspection, it's probably segfaulting at the end of that for loop. Which still doesn't really make sense because of the way the for loop is written. It shouldn't go beyond the end of the list.
EDIT2: This will work because of the answer below.
typedef std::list<Ground> l_Ground;
void Player::y_collisions(const l_Ground& grounds) {
for (l_Ground::const_iterator ent = grounds.begin(); ent != grounds.end(); ent++) {
if (getGlobalBounds().intersects(ent->getGlobalBounds())) {
in_air = false;
velocity -= gravity;
}
}
}
You were passing the grounds parameter by value. That means a copy of the list was made. Apparently your Ground class have a broken copy constructor, which makes the getGlobalBounds() method referring to some invalid pointer, which caused the crash.
You should almost never pass a big object by value unless you want to immediately copy it. Always train yourself to type const & all the time :).