Jump to content

Mumbles

Members
  • Posts

    691
  • Joined

  • Last visited

Everything posted by Mumbles

  1. In 2.2x it was available as a CPP file. But it's not guaranteed to be the same in 2.3 onwards
  2. I'll remember you said that...
  3. I don't see why hidden would mean exemption from collisions. In half life they used to place invisible ramps on staircases so you could walk up them without the "climbing effect" which Valve considered disorientating. Is there no way to edit collision pairs between groups in LE 3? LE2 had it, but I suspect only because it was a part of Newton.
  4. Glancing back to old TGC times, I would have thought showcase forum would be better suited to actual completed products that you want to show off. Maybe there should be an completely dedicated work in progress board here.
  5. The command I remember is AppSuspended() returns 1 if the window is inactive (you have Alt-Tabbed away), 0 if the window is active
  6. Source code if you really want it, but really, everything is in the one source file. It's all in the last post, but that scroll bar makes it a bit harder to read... Minor typo, but not serious. the int main has it's first value of "int argcn". It shouldn't say 'n' at the end, but there's no way I'm editing that post, otherwise I'd have to format that big block of code all over again - no thanks.
  7. You want a timer that automatically calls a function when it reaches zero? That's soooo simple, all you need all you need is some uh, basic knowledge of multithreading and function pointers Basically, I have a struct that contains: a number of milliseconds to run for, a control bool to abort the timer (set it to false at any time, when the timer next hits zero, it won't do anything, and will instead end the thread) a number of timer to run the timer, (0 for unlimited) Then a function pointer to the function it will call and a void pointer containing the parameters to pass to the function Then there is a function called TimerThreadFunction, but you never call this yourself. When you call StartTimerThread, that will call _beginthreadex which spawns a new thread, the entry point (like your main() is TimerThreadFunction. It uses the struct (pass is by pointer) to determine how long it would wait for, which function it should run when finished, and how many times it should run the timer. When it has run enough times (or if you set the stop timer value to true in your main loop), it will end the thread. PrintToScreen() and ChangeVarVal are two different functions that the timers can use. The way I designed it, any void function with a void * parameter can be called by the timer thread. PrintToScreen shows the timer working totally multithreaded. ChangeVarVal just changes a bool value, and we check this value in the main loop, this is more suitable if for LE 2 commands, since you cannot call them inside another thread Finally, there is the main function, which just shows it in action. First, it does PrintToScreen multithreaded, then it does ChangeVarVal single threaded, then it does PrintToScreen multithreaded again, but with an infinite count, and the main loop aborts the timer after a short time... #include <iostream> #include <process.h> #include <windows.h> struct ThreadLaunchArgs { unsigned int WaitMillis; bool StopTimer; unsigned int RepeatCount; //0 = infinite... can only be stopped with the above bool void (*FuncToCall)(void *); void * FuncToCallArgs; }; unsigned __stdcall TimerThreadFunction( void * ArgList ) { ThreadLaunchArgs * ArgsList = ( ThreadLaunchArgs * ) ArgList; if( ArgsList->RepeatCount != 0) { for ( unsigned int CurrentRepeat = 0 ; CurrentRepeat < ArgsList->RepeatCount ; CurrentRepeat += 1) { Sleep( ArgsList->WaitMillis ); if ( !ArgsList->StopTimer ) ArgsList->FuncToCall( ArgsList->FuncToCallArgs ); else CurrentRepeat = ArgsList->RepeatCount; } } else { while ( !ArgsList->StopTimer ) { Sleep( ArgsList->WaitMillis); if ( !ArgsList->StopTimer ) ArgsList->FuncToCall( ArgsList->FuncToCallArgs ); } } _endthreadex( 0 ); return 0; } HANDLE StartTimerThread(ThreadLaunchArgs * TimerArgs) { HANDLE hThread; unsigned threadID; hThread = (HANDLE)_beginthreadex( NULL, 0, &TimerThreadFunction, TimerArgs, 0, &threadID ); return hThread; } void PrintToScreen ( void * MillisDelay ) { unsigned int * Value = (unsigned int *) MillisDelay; std::cout << "Fire and forget timer, with delay of " << *Value << " millis has expired!\n"; return; } void ChangeVarVal ( void * Flag ) { bool * Value = (bool *) Flag; *Value = true; return; } int main( int argcn, char* argv[]) { unsigned int NumRepeats = 10, TimerMillis = 2000; ThreadLaunchArgs * TimerArgs = (ThreadLaunchArgs *) malloc (sizeof (ThreadLaunchArgs)); TimerArgs->FuncToCall = &PrintToScreen; TimerArgs->FuncToCallArgs = &TimerMillis; TimerArgs->RepeatCount = NumRepeats; TimerArgs->StopTimer = false; TimerArgs->WaitMillis = TimerMillis; //Fire and forget timer - will automatically call the selected function when the timer expires HANDLE FirstTimerThreadHandle = StartTimerThread(TimerArgs); Sleep(5000);//Main thread does nothing for 30 seconds - notice how the console window still fills up //For 20 seconds, the counter will work, then for the next 10, nothing will happen. //You can make things interesting by sleeping for less timer, like only 5 seconds //Perhaps we don't want to work multithreaded... Maybe we are calling LE 2 commands, which won't work in another thread. We'll operate psuedo single threaded instead //The second thread will set a flag value. We check it in this thread's loop, and when it's true, we do "stuff" bool * TimerFlag = new bool(); *TimerFlag = false; ThreadLaunchArgs * SecondTimerArgs = (ThreadLaunchArgs *) malloc (sizeof (ThreadLaunchArgs)); SecondTimerArgs->FuncToCall = &ChangeVarVal; SecondTimerArgs->FuncToCallArgs = TimerFlag; SecondTimerArgs->RepeatCount = NumRepeats; SecondTimerArgs->StopTimer = false; SecondTimerArgs->WaitMillis = TimerMillis; unsigned int CurrentRepeatCount = 0; //Monitored timer - will still count but it will instead set a value that we must check in this thread HANDLE SecondTimerThreadHandle = StartTimerThread(SecondTimerArgs); while( CurrentRepeatCount < 10 ) { if( *TimerFlag ) { *TimerFlag = false; CurrentRepeatCount += 1; std::cout << "Monitored timer, with delay of " << TimerMillis << " millis has expired!\n"; } } //In the final example, the timer repeats forever, and we stop it ourself with the bool value ThreadLaunchArgs * ThirdTimerArgs = (ThreadLaunchArgs *) malloc (sizeof (ThreadLaunchArgs)); ThirdTimerArgs->FuncToCall = &PrintToScreen;; ThirdTimerArgs->FuncToCallArgs = &TimerMillis; ThirdTimerArgs->RepeatCount = NumRepeats; ThirdTimerArgs->StopTimer = false; ThirdTimerArgs->WaitMillis = TimerMillis; HANDLE ThirdTimerThreadHandle = StartTimerThread(ThirdTimerArgs); Sleep(20000); ThirdTimerArgs->StopTimer = true; WaitForSingleObject(FirstTimerThreadHandle,INFINITE); CloseHandle(FirstTimerThreadHandle); //It has a return value, but if it fails, just end the process anyway... WaitForSingleObject(SecondTimerThreadHandle,INFINITE); CloseHandle(SecondTimerThreadHandle); WaitForSingleObject(ThirdTimerThreadHandle,INFINITE); CloseHandle(ThirdTimerThreadHandle); delete TimerFlag; //These three could have been done better as an array, but it's just a "simple" example //As could the HANDLE variables for each thread free(ThirdTimerArgs); free(SecondTimerArgs); free(TimerArgs); return 0; }
  8. It says that every time any exception is thrown, and where nothing catches it... Knowing what type of exception to catch (and where it is in the code) could be a nightmare to find...
  9. Remember that this user doesn't own a copy of the engine just yet. So even if they can sell, it's inherently untested...
  10. Ever since you mentioned it to me, one thing I've always done is include those three runtime DLLs in the working directory. No reaon to install the entire lot when it only needs those 3 right? Unless 2010 and newer or so much different from 2008.
  11. I didn't find that happened. Started at 145 fps, still there 5 minutes later. Kill all the goblins, come back and it's now 175...
  12. That's weird. I'm pretty sure I don't have the 2010 runtimes installed, and yet it ran fine. Are the 2008 runtimes (.NET 3.5) sufficient? And yes, very nice... $500 nice? Personal opinion, not really.
  13. You've started early... Side effects of sniffing too much stamp glue
  14. Could you copy and paste what it says? Because only your first account will be able to access the rest of the boards or download files, etc. Also what browser are you using?
  15. Maybe that's a limitation of the "trial version" Besides, what do you mean when you say: ?
  16. There is no default gravity in Newton. Real Newton that is, Likewise, it's also possible to adjust the mass matrix, which I assume would make gravity work correctly for a plane. void ApplyGravity(const NewtonBody * body, const Entity * ent) { float * NewForce = (float*) malloc(3 * sizeof(float)); NewForce[0] = 0.0f; NewForce[1] = GRAVITY_FORCE * ent->GetGravityMultiplier(); NewForce[2] = 0.0f; NewtonBodyAddForce(body,NewForce); free(NewForce); } //callback signature provided by Newton. Most of this code is just copied straight from the tutorial... because it works. void ApplyForceOnlyCallback (const NewtonBody * body, dFloat timestep, int threadIndex) { Entity * ent = (Entity *) NewtonBodyGetUserData(body); dFloat Ixx, Iyy, Izz, mass; NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz); TVec3 ForceToAdd = ent->GetForce(); TVec3 InternalForce = ent->GetSelfForce(); TVec3 CombinedForce = GetCombinedForce(ForceToAdd,InternalForce); ApplyForce(body,ent,CombinedForce); if(ent->GravityEnabled()) { ApplyGravity(body,ent); } ent->ClearForces(); } Of course, I never touch the mass matrix because it works fine for me, and messing about with things I don't know could, well, cause planes to fall out of the sky... But really, it should just be a case of modifying Ixx, Iyy and Izz. Don't ask what to though, because I don't know...
  17. Well, since that's not the way I handle it, I don't know what the second problem would be caused by, but at least the first one was found. Delete an actor and null it in the main code by all means (whether it'd good practice or not is purely personal opinion), but make sure any other class using that specific actor has it's pointer nulled too. Since for Projectile, the Actor pointer is private access, it just needs a member function to null it (which for what its worth, is what I'd call a stray pointer. Not exactly hidden, but one that should have been updated but wasn't) Beyond that, I've no idea if I've been helpful earlier, but I don't think I'm particularly helpful now at this stage, sorry.
  18. Maybe it's just my way of thinking. But I know in my project I have a base "GameEntity" class (which I think translates to your Actor class), that has a protected constructor. The way I'm set up, there is no reason for me to be creating these entities. A light, a door, a character, a weapon etc - they're all types of entities, and they inherit from it, so they can call the constructor themselves when they need it. If it were my project, it's likely that the Actor would not have a public constructor, and any type of Actor would either be a derived class, or a friend class. That doesn't mean there can't be a list of Actors available to read in the main gameplay class (or namespace as I have it), it's just that if I want to add an object to it, I have to create one of these special types instead. I can't see why you would want to delete a projectile's associated actor but not delete the rest of the projectile. Now obviously I'm sure you don't want to reveal too much about your game, because surprises are nice - but personally, I would just delete the entire projectile, which would delete its actor as part of its clean up. Now please don't take this as a lecture, because I'm sure of the two of us, you'd normally be the one teaching me...
  19. Note my proposed change to your Actor Projectile (whoops) class, and where it is deleted in main... Yes, we deleted a in _tmain before. but as far as p was concerned, it was still there... class Actor { private: int i; public: Actor() { i = 50; } void Increase() { i++; } }; class Projectile { private: Actor* _actor; public: Projectile(Actor* actor) { _actor = actor; } void Update() { if(_actor) _actor->Increase(); } void DeleteActor(void) { delete _actor; _actor = 0;//This is what we weren't doing before, hence why the if would still run } }; int main(int argc, char * argv[]) { Actor* a = new Actor(); Projectile p(a); //delete a; p.DeleteActor(); //Presumably, your projectile class could be in charge of allocating its own Actors in the same way, but would obviously need a rewritten constructor a = 0; //Ideally, your projectile class does do it's own allocation and destruction. If it "new"s its Actor, then this isn't necessary p.Update(); return 0; }
  20. Yes I must have been sniffing permanent markers earlier because I was sure that p(a) was valid, but sure enough the compiler didn't like it. There may not be a difference but the way I look it, the cast means I'm still pointing to a pointer, rather than pointing to a pointer's address, which perhaps it's just me, but that sounds wrong.
  21. OK yep, not quite what I was thinking, but does this work? class Actor { private: int i; public: Actor() { i = 50; } void Increase() { i++; } }; class Projectile { private: Actor** _actor; public: Projectile(Actor** actor) { _actor = actor; } void Update() { if(_actor[0]) _actor[0]->Increase(); } }; int main(int argc, char * argv[]) { Actor * a = new Actor(); Projectile p((Actor**)a); delete a; a = 0; p.Update(); return 0; }
  22. You have changed _actor's definition from Actor** to Actor * Put it back to Actor** but leave Projectile p(a); as it is.
  23. Basically, every red should be paired off with a blue, but your Projectile::_actor has two reds instead
  24. OK, let's start at _tmain... I'm going to show where I've allocated memory but with low numbers just for example. Remember, we can't normally choose where our variables are allocated. Addresses in red, their values in blue. New variable a located at memory position 100 (for example). It is a pointer, so we create an Actor object at 150 for example. value of _tmain::a is therefore 150 New variable p located at memory position 200. It is not a pointer or a primitive, so it has no value of it's own. p has a pointer member _actor, it is stored at 210, it has no value at this time _tmain:._actor is located at 210, the constructor for _tmain: has assigned it a value of 100, this would probably be better as 150, by leaving off the & sign a has been deleted. Value at 100 is now 0 p.update has been called. Value of p::_actor checked. It is 100, so it is valid. We attempt to call a function - but this object instance is not there. Runtime error Now, if Projectile::_actor was assigned 150 by the constructor rather than 100 by simply passed a, rather than address of a. Then when a is deleted in _tmain, Update's if check would return a value of 0, not 100 and thus refuse to run the block. edit: emoticons disabled
  25. But you can't delete where _tmain::a's pointer is located in memory because you didn't allocate it. That was allocated implicitly when it was created. You can delete the object it points to but not the pointer itself. That will be lost when it falls out of scope same as any other variable, although what it points to stays valid until explicitly deleted - hence what memory leaks are.
×
×
  • Create New...