Creating tweening functions using C++? - c++

How should one create an interface for tweening something using C++? For instance, I want to fade a picture in over a duration of five seconds using a static function call like:
Graphics::FadeSurface( Surface mySurface, int FrameHeight, int NumOfFrames,
int FadeDirection, double Duration )
I have a hard-coded setup that creates an object for each tween action that needs to be performed. I have been using a DeltaTime variable that keeps track of how much time has passed since the program has launched to control logic and such. I've included an example (much less refined) to show you kind of what I'm trying to do:
Example Logic Loop:
gameLoop( double DeltaTime ){
// ...
// logic
// ...
bool isItDone = otherClass.HaveFiveSecondsElapsed( double DeltaTime );
if( isItDone == true )
exit(1);
// ...
// logic
// ...
}
Example Tweening Class:
other_Class::other_Class(){
InitialTime = 0;
InitialTime_isSet = false;
}
bool other_class::HaveFiveSecondsElapsed( double DeltaTime ){
// Setting InitialTime if it hasn't already been set
if( otherClass.InitialTime_isSet == false ){
otherClass.InitialTime = DeltaTime;
otherClass.InitialTime_isSet = true;
}
bool toReturn = false;
if( DeltaTime - InitialTime > 5 )
toReturn = true;
return toReturn;
}
Any help is greatly appreciated. Thanks!

I built a Tween engine for java that is generic enough to be used to tween any attribute of any object. The generic part is done through the definition of a "Tweenable" interface that users need to implement to tween their objects.
I greatly encourage you to use it as inspiration to build your engine, or directly port it. I can also plan a home-made port to C++, but it would be quite a lot of work to maintain it up-to-date with the current java version (which grows very fast).
http://code.google.com/p/java-universal-tween-engine/
NB: I made a more elaborated answer about this engine in this question:
Android: tween animation of a bitmap

Related

Simulating Leach has encounter a problem. Finished with error in omnet++

When running the simulation in omnet++ 5.7 the execution stops suddenly and closes.
This is the code that is being run in omnet
auto simulation = getSimulation();
for (i = 1; i <= simulation->getLastComponentId(); i++) {
int x, y, id;
//scan the simulation module vector
mod = (cModule*)simulation->getModule(i);
if (strcmp(mod->getName(), "node") == 0) {
id = ((Node*)mod)->myId;
x = ((Node*)mod)->xpos;
y = ((Node*)mod)->ypos;
nodePtr[id] = ((Node*)mod);
if (id != this->myId) {
cGate* g;
char gName1[32], gName2[32];
// make new gate here
if (this->hasGate(gName1)) {
this->gate(gName1)->disconnect();
this->deleteGate(gName1);
}
this->addGate(gName1, cGate::OUTPUT, false);
// make new gate at other side
if (mod->hasGate(gName2)) {
mod->gate(gName2)->disconnect();
mod->deleteGate(gName2);
}
mod->addGate(gName2, omnetpp::cGate::INPUT, false);
//CHANNEL
cIdealChannel* ch = NULL;
this->gate(gName1)->connectTo(mod->gate(gName2), ch);
g = this->gate(gName1);
g->setDisplayString(g->getDisplayString());
}
}
}
I assume that the last line g->setDisplayString(g->getDisplayString()); is probably where the code breaks. The code repeats in the for loop with i<= simulation->getLastComponentId(). I'm new to Omnet++. Any suggestion to fix this would be helpful.
Thanks.
Several things in your code may be source of crashing:
getModule(i) may return nullptr, see OMNeT++ Simulation API, so you should check in the code whether result is not nullptr.
gName1 and gName2 are not set!
Other issues:
instead of (Node*)mod use dynamic_cast<Node*)>(mod) and check whether results is not nullptr.
instead of strcmp(mod->getName(), "node") == 0 I advice using mod->isName("node") - see OMNeT++ Simulation API
if you want to obtain a module whose name is "node", you do not need to manually check the name of every module - there is a useful method getModuleByPath() see OMNeT++ Simulation Manual

(C++) Need help making splash screen for reprapdiscount smart controller 4x20 LCD display - EDITED

I recently purchased a delta 3d printer kit that uses the marlin software, MKS mini (kossel) main board (uses Arduino bootloader & Marlin Firmware), and reprapdiscount smart controller LCD display (4 rows x 20 characters).
I have almost zero programming experience, and I would like some help to create a "splash screen" that is called on boot only, then goes back to the status screen after a certain time. I have already scoured the internet on how to do this, but the only ones that had any viable options were for the FULL GRAPHICS version LCD display - which is not what I have. I have found the .cpp file used for this specific LCD display - however with my limited programming knowledge, I cannot figure out how to add a splash screen on start.
I'm pretty sure that I have to create a void function at the beginning of the menu implementation (see below), but i'm not sure what / how to call it so that it starts first, then switches to the status screen afterwards. I can write the pseudo code for it, but don't know the full code...
side-note: I just realized that in the menu items, it shows the reference variable of the text, which is actually contained in another file called language.h
PSEUDO CODE of what I would like it to do:
//start->boot printer
static void splashscreen()
{
/*splashlines are defined in language.h file*/
static void splashline1(); // hello
static void splashline2(); // world
static void splashline3(); // i'm
static void splashline4(); // here!
wait 3 seconds;
switch to -> static void lcd_status_screen();
}
Any help would be greatly appreciated!
Unfortunately the post is limited to 30,000 characters, and posting the original code will put me at over 50,000... so I will try to post
relevant code snippets:
THANKS IN ADVANCE!!
EDITED
~ LCD status screen code ~
#ifdef ULTIPANEL
static float manual_feedrate[] = MANUAL_FEEDRATE;
#endif // ULTIPANEL
/* !Configuration settings */
//Function pointer to menu functions.
typedef void (*menuFunc_t)();
uint8_t lcd_status_message_level;
char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG;
/** forward declerations **/
void copy_and_scalePID_i();
void copy_and_scalePID_d();
/* Different menus */
static void lcd_status_screen();
#ifdef ULTIPANEL
extern bool powersupply;
static void lcd_main_menu();
static void lcd_tune_menu();
static void lcd_prepare_menu();
static void lcd_move_menu();
static void lcd_control_menu();
static void lcd_control_temperature_menu();
static void lcd_control_temperature_preheat_pla_settings_menu();
static void lcd_control_temperature_preheat_abs_settings_menu();
static void lcd_control_motion_menu();
~ EDITED Start of coding ~
menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */
uint32_t lcd_next_update_millis;
uint8_t lcd_status_update_delay;
uint8_t lcdDrawUpdate = 2; /* Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets atleast 1 full redraw (first redraw is partial) */
//prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
menuFunc_t prevMenu = NULL;
uint16_t prevEncoderPosition;
//Variables used when editing values.
const char* editLabel;
void* editValue;
int32_t minEditValue, maxEditValue;
menuFunc_t callbackFunc;
// placeholders for Ki and Kd edits
float raw_Ki, raw_Kd;
/* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependend */
static void lcd_status_screen()
{
if (lcd_status_update_delay)
lcd_status_update_delay--;
else
lcdDrawUpdate = 1;
if (lcdDrawUpdate)
{
lcd_implementation_status_screen();
lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */
}
#ifdef ULTIPANEL
if (LCD_CLICKED)
{
currentMenu = lcd_main_menu;
encoderPosition = 0;
lcd_quick_feedback();
}
// Dead zone at 100% feedrate
if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
(feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
{
encoderPosition = 0;
feedmultiply = 100;
}
if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
{
feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
encoderPosition = 0;
}
else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
{
feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
encoderPosition = 0;
}
else if (feedmultiply != 100)
{
feedmultiply += int(encoderPosition);
encoderPosition = 0;
}
if (feedmultiply < 10)
feedmultiply = 10;
if (feedmultiply > 999)
feedmultiply = 999;
#endif//ULTIPANEL
}
As Joel Cornett suggested, look up the gaps in knowledge and ask specifically about those gaps. In that case, it seems what you need is the following:
How to code a timed pause for the "splash" to display.
Where to initialize the code you want (I think you may have overlooked it, as I don't think see it in the code you posted).
How to make the code proceed to the status screen without looping on itself.
Try to edit your post / split your questions into individual posts. You may get a better response rate from that.

Keyframing in 3DS MAX 2014 SDK c++

I want to ask you guys to help me with creating keyframes in Max SDK C++.
What I've done:
Created a Controller Plugin
Inside the getValue function I've done my translations via code.
I also wrote the setValue function.
Which I think manages keyframes and stores the controllers position in a given time in a given keyframe. In this way I achieved to be able to set keys manually, but I really would like, to work with the Auto Key turned on in Max.
On the other hand, I can't see the freshly added keys values. So please help me, how could I add keyframes?
Many Thanks:
Banderas
void maxProject3::GetValue(TimeValue t, void *ptr, Interval &valid, GetSetMethod method)
{
Point3 p3OurAbsValue(0, 0, 0);
tomb[0]=0;
//These positions stores my data they are globals
XPosition += (accX);
YPosition += (accY);
ZPosition += (accZ);
p3OurAbsValue.x = XPosition;
p3OurAbsValue.y = YPosition;
p3OurAbsValue.z = ZPosition;
valid.Set(t,t+1); //This answer is only valid at the calling time.
MatrixCtrl->GetValue(t, &p3OurAbsValue.y, valid, CTRL_RELATIVE);
if (method == CTRL_ABSOLUTE)
{
Point3* p3InVal = (Point3*)ptr;
*p3InVal = p3OurAbsValue;
}
else // CTRL_RELATIVE
{
//We do our translations on a Matrix
Matrix3* m3InVal = (Matrix3*)ptr;
//m3InVal->PreTranslate(p3OurAbsValue);
m3InVal->PreRotateX(rotX);
m3InVal->PreRotateY(rotY);
m3InVal->PreRotateZ(rotZ);
}
}
int maxProject3::NumSubs() {
return 1;
}
Animatable* maxProject3::SubAnim(int n) {
return MatrixCtrl;
}
void maxProject3::SetValue(TimeValue t, void *ptr, int commit, GetSetMethod method)
{
Matrix3* m3InVal = (Matrix3*)ptr;
MatrixCtrl->AddNewKey(t, ADDKEY_SELECT);
MatrixCtrl->SetValue(t, &m3InVal, commit, CTRL_RELATIVE);
}
To turn on the Auto key mode try using AnimateOn() before your transformation. Also add AnimateOff() to turn off the auto key mode in the end.
I did it in one of my project to create material id animation using auto key mode.
/** Auto key on*/
AnimateOn();
/** Creating material id animation */
for(int mtl_id = 1; mtl_id <= num_sub_mtl; ++mtl_id, time += time_step)
{
mtl_modifier->GetParamBlock()->SetValue(MATMOD_MATID,time,mtl_id);
}
/** Auto key off*/
AnimateOff();
Also as a suggestion, use the max script listener to know whats happening when the animation is created using 3ds Max GUI. This will help you to recreate the animation using Max SDK.

Buffer communication speed nightmare

I'm trying to use buffers to communicate between several 'layers' (threads) in my program and now that I have visual output of what's going on inside, I realize there's a devastating amount of time being eaten up in the process of using these buffers.
Here's some notes about what's going on in my code.
when the rendering mode is triggered in this thread, it begins sending as many points as it can to the layer (thread) below it
the points from the lower thread are then processed and returned to this thread via the output buffer of the lower thread
points received back are mapped (for now) as white pixels in the D3D surface
if I bypass the buffer and put the points directly into the surface pixels, it only takes about 3 seconds to do the whole job
if I hand the point down and then have the lower layer pass it right back up, skipping any actual number-crunching, the whole job takes about 30 minutes (which makes the whole program useless)
changing the size of my buffers has no noticeable effect on the speed
I was originally using MUTEXes in my buffers but have eliminated them in attempt the fix the problem
Is there something I can do differently to fix this speed problem I'm having?
...something to do with the way I'm handling these messages???
Here's my code
I'm very sorry that it's such a mess. I'm having to move way too fast on this project and I've left a lot of pieces laying around in comments where I've been experimenting.
DWORD WINAPI CONTROLSUBSYSTEM::InternalExProcedure(__in LPVOID lpSelf)
{
XMSG xmsg;
LPCONTROLSUBSYSTEM lpThis = ((LPCONTROLSUBSYSTEM)lpSelf);
BOOL bStall;
BOOL bRendering = FALSE;
UINT64 iOutstandingPoints = 0; // points that are out being tested
UINT64 iPointsDone = 0;
UINT64 iPointsTotal = 0;
BOOL bAssigning;
DOUBLE dNextX;
DOUBLE dNextY;
while(1)
{
if( lpThis->hwTargetWindow!=NULL && lpThis->d3ddev!=NULL )
{
lpThis->d3ddev->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
if(lpThis->d3ddev->BeginScene())
{
lpThis->d3ddev->StretchRect(lpThis->sfRenderingCanvas,NULL,lpThis->sfBackBuffer,NULL,D3DTEXF_NONE);
lpThis->d3ddev->EndScene();
}
lpThis->d3ddev->Present(NULL,NULL,NULL,NULL);
}
//bStall = TRUE;
// read input buffer
if(lpThis->bfInBuffer.PeekMessage(&xmsg))
{
bStall = FALSE;
if( HIBYTE(xmsg.wType)==HIBYTE(CONT_MSG) )
{
// take message off
lpThis->bfInBuffer.GetMessage(&xmsg);
// double check consistency
if( HIBYTE(xmsg.wType)==HIBYTE(CONT_MSG) )
{
switch(LOBYTE(xmsg.wType))
{
case SETRESOLUTION_MSG:
lpThis->iAreaWidth = (UINT)xmsg.dptPoint.X;
lpThis->iAreaHeight = (UINT)xmsg.dptPoint.Y;
lpThis->sfRenderingCanvas->Release();
if(lpThis->d3ddev->CreateOffscreenPlainSurface(
(UINT)xmsg.dptPoint.X,(UINT)xmsg.dptPoint.Y,
D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT,
&(lpThis->sfRenderingCanvas),
NULL)!=D3D_OK)
{
MessageBox(NULL,"Error resizing surface.","ERROR",MB_ICONERROR);
}
else
{
D3DLOCKED_RECT lrt;
if(D3D_OK == lpThis->sfRenderingCanvas->LockRect(&lrt,NULL,0))
{
lpThis->iPitch = lrt.Pitch;
VOID *data;
data = lrt.pBits;
ZeroMemory(data,lpThis->iPitch*lpThis->iAreaHeight);
lpThis->sfRenderingCanvas->UnlockRect();
MessageBox(NULL,"Surface Resized","yay",0);
}
else
{
MessageBox(NULL,"Error resizing surface.","ERROR",MB_ICONERROR);
}
}
break;
case SETCOLORMETHOD_MSG:
break;
case SAVESNAPSHOT_MSG:
lpThis->SaveSnapshot();
break;
case FORCERENDER_MSG:
bRendering = TRUE;
iPointsTotal = lpThis->iAreaHeight*lpThis->iPitch;
iPointsDone = 0;
MessageBox(NULL,"yay, render something!",":o",0);
break;
default:
break;
}
}// else, lost this message
}
else
{
if( HIBYTE(xmsg.wType)==HIBYTE(MATH_MSG) )
{
XMSG xmsg2;
switch(LOBYTE(xmsg.wType))
{
case RESETFRAME_MSG:
case ZOOMIN_MSG:
case ZOOMOUT_MSG:
case PANUP_MSG:
case PANDOWN_MSG:
case PANLEFT_MSG:
case PANRIGHT_MSG:
// tell self to start a render
xmsg2.wType = CONT_MSG|FORCERENDER_MSG;
if(lpThis->bfInBuffer.PutMessage(&xmsg2))
{
// pass it down
while(!lpThis->lplrSubordinate->PutMessage(&xmsg));
// message passed so pull it from buffer
lpThis->bfInBuffer.GetMessage(&xmsg);
}
break;
default:
// pass it down
if(lpThis->lplrSubordinate->PutMessage(&xmsg))
{
// message passed so pull it from buffer
lpThis->bfInBuffer.GetMessage(&xmsg);
}
break;
}
}
else if( lpThis->lplrSubordinate!=NULL )
// pass message down
{
if(lpThis->lplrSubordinate->PutMessage(&xmsg))
{
// message passed so pull it from buffer
lpThis->bfInBuffer.GetMessage(&xmsg);
}
}
}
}
// read output buffer from subordinate
if( lpThis->lplrSubordinate!=NULL && lpThis->lplrSubordinate->PeekMessage(&xmsg) )
{
bStall = FALSE;
if( xmsg.wType==(REPLY_MSG|TESTPOINT_MSG) )
{
// got point test back
D3DLOCKED_RECT lrt;
if(D3D_OK == lpThis->sfRenderingCanvas->LockRect(&lrt,NULL,0))
{
INT pitch = lrt.Pitch;
VOID *data;
data = lrt.pBits;
INT Y=dRound((xmsg.dptPoint.Y/(DOUBLE)100)*((DOUBLE)lpThis->iAreaHeight));
INT X=dRound((xmsg.dptPoint.X/(DOUBLE)100)*((DOUBLE)pitch));
// decide color
if( xmsg.iNum==0 )
((WORD *)data)[X+Y*pitch] = 0xFFFFFFFF;
else
((WORD *)data)[X+Y*pitch] = 0xFFFFFFFF;
// message handled so remove from buffer
lpThis->lplrSubordinate->GetMessage(&xmsg);
lpThis->sfRenderingCanvas->UnlockRect();
}
}
else if(lpThis->bfOutBuffer.PutMessage(&xmsg))
{
// message sent so pull the real one off the buffer
lpThis->lplrSubordinate->GetMessage(&xmsg);
}
}
if( bRendering && lpThis->lplrSubordinate!=NULL )
{
bAssigning = TRUE;
while(bAssigning)
{
dNextX = 100*((DOUBLE)(iPointsDone%lpThis->iPitch))/((DOUBLE)lpThis->iPitch);
dNextY = 100*(DOUBLE)((INT)(iPointsDone/lpThis->iPitch))/(DOUBLE)(lpThis->iAreaHeight);
xmsg.dptPoint.X = dNextX;
xmsg.dptPoint.Y = dNextY;
//
//xmsg.iNum = 0;
//xmsg.wType = REPLY_MSG|TESTPOINT_MSG;
//
xmsg.wType = MATH_MSG|TESTPOINT_MSG;
/*D3DLOCKED_RECT lrt;
if(D3D_OK == lpThis->sfRenderingCanvas->LockRect(&lrt,NULL,0))
{
INT pitch = lrt.Pitch;
VOID *data;
data = lrt.pBits;
INT Y=dRound((dNextY/(DOUBLE)100)*((DOUBLE)lpThis->iAreaHeight));
INT X=dRound((dNextX/(DOUBLE)100)*((DOUBLE)pitch));
((WORD *)data)[X+Y*pitch] = 0xFFFFFFFF;
lpThis->sfRenderingCanvas->UnlockRect();
}
iPointsDone++;
if( iPointsDone>=iPointsTotal )
{
MessageBox(NULL,"done rendering","",0);
bRendering = FALSE;
bAssigning = FALSE;
}
*/
if( lpThis->lplrSubordinate->PutMessage(&xmsg) )
{
bStall = FALSE;
iPointsDone++;
if( iPointsDone>=iPointsTotal )
{
MessageBox(NULL,"done rendering","",0);
bRendering = FALSE;
bAssigning = FALSE;
}
}
else
{
bAssigning = FALSE;
}
}
}
//if( bStall )
//Sleep(10);
}
return 0;
}
}
(still getting used to this forum's code block stuff)
Edit:
Here's an example that I perceive to be similar in concept, although this example consumes the messages it produces in the same thread.
#include <Windows.h>
#include "BUFFER.h"
int main()
{
BUFFER myBuffer;
INT jobsTotal = 1024*768;
INT currentJob = 0;
INT jobsOut = 0;
XMSG xmsg;
while(1)
{
if(myBuffer.PeekMessage(&xmsg))
{
// do something with message
// ...
// if successful, remove message
myBuffer.GetMessage(&xmsg);
jobsOut--;
}
while( currentJob<jobsTotal )
{
if( myBuffer.PutMessage(&xmsg) )
{
currentJob++;
jobsOut++;
}
else
{
// buffer is full at the moment
// stop for now and put more on later
break;
}
}
if( currentJob==jobsTotal && jobsOut==0 )
{
MessageBox(NULL,"done","",0);
break;
}
}
return 0;
}
This example also runs in about 3 seconds, as opposed to 30 minutes.
Btw, if anybody knows why visual studio keeps trying to make me say PeekMessageA and GetMessageA instead of the actual names I defined, that would be nice to know as well.
Locking and Unlocking an entire rect to change a single point is probably not very efficient, you might be better off generating a list of points you intend to modify and then locking the rect once, iterating over that list and modifying all the points, and then unlocking the rect.
When you lock the rect you are effectively stalling concurrent access to it, so its like a mutex for the GPU in that respect - then you only modify a single pixel. Doing this repeatedly for each pixel will constantly stall the GPU. You could use D3DLOCK_NOSYSLOCK to avoid this to some extent, but I'm not sure if it will play nicely in the larger context of your program.
I'm obviously not entirely sure what the goal of your algorithm is, but if you are trying to parallel process pixels on a d3d surface, then i think the best approach would be via a shader on the GPU.
Where you basically generate an array in system memory, populate it with "input" values on a per point/pixel basis, then generate a texture on a GPU from the array. Next you paint the texture to a full screen quad, and then render it with a pixel shader to some render target. The shader can be coded to process each point in whatever way you like, the GPU will take care of optimizing parallelization. Then you generate a new texture from that render target and then you copy that texture into a system memory array. And then you can extract all your outputs from that array. You can also apply multiple shaders to the render target result back into the render target to pipeline multiple transformations if needed.
A couple notes:
Don't write your own messape-passing code. It may be correct and slow, or fast and buggy. It takes a lot of experience to design code that's fast and then getting it bug-free is really hard, because debugging threaded code is hard. Win32 provides a couple of efficient threadsafe queues: SList and the window message queue.
Your design splits up work in the worst possible way. Passing information between threads is expensive even under the best circumstances, because it causes cache contention, both on the data and on the synchronization objects. It's MUCH better to split your work into distinct non-interacting (or minimize interaction) datasets and give each to a separate thread, that is then responsible for all stages of processing that dataset.
Don't poll.
That's likely to be the heart of the problem. You have a task continually calling peekmessage and probably finding nothing there. This will just eat all available CPU. Any task that wants to post messages is unlikely to receive any CPU time to acheive this.
I can't remember how you'd achieve this with the windows message queue (probably WaitMessage or some variant) but typically you might implement this with a counting semaphore. When the consumer wants data, it waits for the semaphore to be signalled. When the producer has data, it signals the semaphore.
I managed to resolve it by redesigning the whole thing
It now passes huge payloads instead of individual tasks
(I'm the poster)

c++ Problem with timer counter being shared between multiple instances of a class

I have a simple timer class in a game, intended to allow me to make an entity do something every so many seconds. It has two functions:
void Timer::GameTimer() // Gets time between frames
{
::ElapsedTime = Clock.GetElapsedTime();
Clock.Reset();
}
This just updates the ElapsedTime Global so that it can be grabbed by anything that needs it. It's placed inside the gameloop.
Then the important one:
bool Timer::tCounter(int total) // Returns true every 'total' seconds
{
static float ftime; // Variable to hold the mounting elapsed time
static int n; // Counter variable for true trigger
ftime += ElapsedTime;
int itime = (int)ftime; //Truncate
if(!(itime%total) && itime != 0)
{
n++;
}
else
{
n = 0;
}
if (n == 1)
{
return true;
}
else
{
return false;
}
}
Timer is instantiated inside the Entity class as Timer::Timer timer
The function is then called inside Entity::Update once per loop for every instance of the entity class in the game:
if (timer.tCounter(2))
{
Do stuff
}
The problem is it doesn't seem to count uniquely for each instance of Entity, resulting in only one doing stuff at a time and other weird stuff occasionally happening. The problem seems to be the static variables being shared. How do I ensure that this tCounter function holds unique variables for each instance that calls it?
static in this context means only one instance of something exists at a time and is initialized once.
The easiest fix to me would be to (not necessarily the best fix):
- Remove the static qualifier
- make ftime and n member variables of Timer
- Create an instance of Timer for each entity that you want to react to a timer.