|
agersant
|
 |
« Reply #15 on: June 12, 2012, 12:21:49 PM » |
|
//Main loop static function update (e : Event) : Void { if (crashed) return; frameTick = clock.clock(); for (s in scenes) s.update(); for (s in screens) s.draw(); Bank.cleanXmlMaps(); }
|
|
|
|
|
Logged
|
|
|
|
|
Pishtaco
|
 |
« Reply #16 on: June 12, 2012, 12:46:58 PM » |
|
Kind of rambling: while (!game.quit_now) { game.updateState(dt); //use dt from last frame
//TODO - fix input dt - maybe have continuous and discrete input as separate functions? handleInput(game, dt); //use dt from last frame
current_time = stopwatch.microsec(); float actual_dt = cast(float)(current_time - last_time)/1000000; //microseconds to seconds last_time = current_time; float bounded_dt = min(actual_dt, 0.1);
game.updateGui(bounded_dt);
if (!game.paused) dt = game.updateModel(bounded_dt); else dt = game.updateModel(0);
game.updateView(dt); game.render();
Screen.setupPointSprites();
screen.setupOrthogonalProjection(); if (game.console_open) Console.drawFully(screen); if (game.show_framerate) Console.displayFPS(game.current_FPS, screen); game.current_FPS = FPSCounter.update(actual_dt);
//SDL_Delay(1); SDL_GL_SwapBuffers(); game.frame_counter += 1; Screen.switchTextureUnit(0); }
I think the "setupPointSprites" thing is there to work around some bug.
|
|
|
|
|
Logged
|
|
|
|
|
Evan Balster
|
 |
« Reply #17 on: June 12, 2012, 03:29:30 PM » |
|
My engine of three years' main loop: int Program::run() { //Main game loop graphics.gui.focusMode(GUI::FocEngine); while (go) { //Random number generator may need to update early for some reason random.update();
//Drop tasks if (keyboard.f8.pressed()) for (Tasks::iterator i = tasks.begin(); i != tasks.end(); ++i) dropTask(*i);
//---Game state update begins--- graphics.gui.focusMode(GUI::FocTask);
if (!pause || slow) { //Run tasks clock.benchStart(); for (Tasks::iterator i = tasks.begin(); i != tasks.end(); ++i) { (*i)->update(); } console.monitor() << L"Tasks: " << std::ceil(clock.benchStop() * 100.0f/.025f) << L"%\n"; slow = false; }
//Process added and dropped tasks for (Tasks::iterator i = dropTasks.begin(); i != dropTasks.end(); ++i) { bool found = false; for (Tasks::iterator j = tasks.begin(); j != tasks.end(); ++j) if (*i == *j) { delete *j; tasks.erase(j); found = true; break; } if (!found) reportWarning("Tried to drop non-existent task..."); } dropTasks.clear(); for (Tasks::iterator i = addTasks.begin(); i != addTasks.end(); ++i) { tasks.push_back(*i); } addTasks.clear();
//---Game state update is done--- graphics.gui.focusMode(GUI::FocEngine);
//Universe processes include cleaning up deleted entities. // If we do it between tasks and output, deleted objects disappear // more responsively and created ones appear immediately. universe.update();
//Audio processing (needs to follow the action closely) audio.update();
//Network processing (send information soon after frame) network.handleOutbound();
//Console comes after program elements, before graphics update if (pause) console.monitor() << (clock.interval(.9f, .1f) ? L"[PAUSED]\n" : L"\n"); if (!tasks.size() && !console.active()) console.introduce(); console.update();
//Likewise with GUI gui.update();
//Graphics processing graphics.update();
//Process program messages (may be a shut-down signal) update();
//Clock processes last (it regulates framerate) clock.update();
//Network processing (send information soon before frame) network.handleInbound();
//Player input close before tasks, for responsiveness player.update(); }
return 0; } The ordering of input, logic and output can have surprising results on gameplay latency, for the unaware. Here's my Clock module's update, since we're talking about framerate regulation too: void Clock::update() { //No benchmarking should occur during clock's operation. if (!bench.empty()) reportError("Benchmark stack not empty!");
//Console output of performance estimate float timeTaken = imp->currentTime() - frameStart; perf = .97f * perf + 3.0f*(timeTaken / frameLength); console.monitor() << std::ceil(perf) << L"% Time\n("; if (fpsLast < 10) console.monitor() << L"0"; console.monitor() << fpsLast << L" FPS)\n"; long secA = long(frameStart), secB;
// (snipped some bizarro iOS testing code from this post)
//Seed randomizer with time consumption random.cryptoSeed((Uint8*) &timeTaken, sizeof(float), 3, Randomizer::SRC_PLAYER);
//Advance time by one frame frameCount++; contextTime += timeStep; goalTime += timeStep;
//Regulate framerate. imp->waitUntil(goalTime);
//Note time after delay for next frame, and bound goal time. frameStart = imp->currentTime(); goalTime = min(max(goalTime, frameStart - frameLength), frameStart + frameLength);
//Framerate counting secB = long(frameStart); if (secA != secB) { fpsLast = fpsCount; fpsCount = 0; } ++fpsCount; } It's vsync-friendly due to the accumulator.
|
|
|
|
|
Logged
|
|
|
|
|
FuzzYspo0N
|
 |
« Reply #18 on: June 12, 2012, 03:37:43 PM » |
|
Evan linked me into this cool thread, I guess ill post ! void cCore::process() {
ptimer.start(); shuttingDown = false;
while(!shuttingDown) {
boost::this_thread::sleep( boost::posix_time::milliseconds( 1 ) );
deltaTime = dte - dts; dts = ptimer.getTime();
time->process(); events->process(); net->process(); Core::Script::process(); phoenix->process();
dte = ptimer.getTime();
} //end while
} //end process()
|
|
|
|
|
Logged
|
|
|
|
|
ThemsAllTook
|
 |
« Reply #19 on: June 12, 2012, 03:55:22 PM » |
|
A lot of what's been posted has some form of conditional that allows you to exit the run loop. Any reason you guys don't just call exit()? The OS will clean up everything for you, and probably do it quicker than if you tear things down yourself.
All of these have made sense to me until I got to Evan's. What's this Task mechanism you have in here? Some sort of cooperative multithreading? I can't figure out the purpose of graphics.gui.focusMode(), either.
|
|
|
|
|
Logged
|
|
|
|
|
zacaj
|
 |
« Reply #20 on: June 12, 2012, 03:58:08 PM » |
|
A lot of what's been posted has some form of conditional that allows you to exit the run loop. Any reason you guys don't just call exit()? The OS will clean up everything for you, and probably do it quicker than if you tear things down yourself.
I have read in multiple place people claiming that the OS will/won't do this, always seemingly expert/trustable people, so I thought I might as well play it safe and close everything. Plus, remembering to free everything when you exit the program will help you remember other in game places you've forgotten to free stuff
|
|
|
|
|
Logged
|
My twitter: @zacaj_Well let's just take a look at this "getting started" page and see-- Download and install cmake
Noooooooo
|
|
|
|
eigenbom
|
 |
« Reply #21 on: June 12, 2012, 04:00:13 PM » |
|
@kamac Yes I like pointers, how else do you get direct access to things?  This.. Root::Instance()->physicsSystem->doSomething();
.. is fairly clear to me. As long as you have a well-defined way of using them, they aren't too dangerous. @themsall Yeh my usual mode of operation is to code things directly in and then refactor them out, if I can't see clearly from the outset hows its going to be modularised. So all the loading screen code, for example, will eventually be smooshed into some sort of LoadingScreen class or something.  The ISystemBase is a necessary abstraction, as an entity stores a list of systems it belongs to, which are all of that type. Haha, the .Reset() .restart() is due to SFML changing APIs midway through my development.  And thanks for the note, but they are all low resolution timers, so their exact values don't matter. 
|
|
|
|
|
Logged
|
|
|
|
|
eigenbom
|
 |
« Reply #22 on: June 12, 2012, 04:05:30 PM » |
|
A lot of what's been posted has some form of conditional that allows you to exit the run loop. Any reason you guys don't just call exit()? The OS will clean up everything for you, and probably do it quicker than if you tear things down yourself.
Maybe: - You might want to save or flush data, or log statistics - It's good defensive programming to free all memory you've allocated - It provides a clear flow, you know that when your program exits it will run the last bit of code under the while loop, rather than exiting from deep within your program
|
|
|
|
|
Logged
|
|
|
|
|
pekuja
|
 |
« Reply #23 on: June 12, 2012, 04:32:04 PM » |
|
This is actually my first post here on TIGForums. Seemed like a fun thread to join. int ret=0; while (!s3eDeviceCheckQuitRequest() && !Game::quit) { Game::update(ret); Gfx::render(ret); Gfx::flip_buffers();
Input::update(); s3eDeviceYield(0); }
Hmm, I think that ret variable isn't even used anywhere. Leftovers from a previous state of the code.
|
|
|
|
|
Logged
|
|
|
|
|
BlueSweatshirt
|
 |
« Reply #24 on: June 12, 2012, 04:43:35 PM » |
|
void GameContext::gameLoop() {
m_window = new sf::RenderWindow(sf::VideoMode(m_win_width, m_win_height), m_win_title);
while(m_window->isOpen()) { sf::Event event; while(m_window->pollEvent(event)) { if (event.type == sf::Event::Closed) m_window->close(); if (event.type == sf::Event::Resized) setWindowSize(event.size.width, event.size.height); }
m_elapsed = m_clock.getElapsedTime(); m_clock.restart();
update();
m_window->clear(m_clearCol); render(); m_window->display();
}
m_running = false; delete m_window; if (m_thread) m_thread->terminate(); }
For the GameContext class in my framework/engine.
|
|
|
|
|
Logged
|
|
|
|
|
eigenbom
|
 |
« Reply #25 on: June 12, 2012, 04:45:37 PM » |
|
hey pekuja, welcome, and nice loop you've got there. is that for tiny hawk? 
|
|
|
|
|
Logged
|
|
|
|
Dovuro
Level 0
|
 |
« Reply #26 on: June 12, 2012, 04:46:51 PM » |
|
A lot of what's been posted has some form of conditional that allows you to exit the run loop. Any reason you guys don't just call exit()? The OS will clean up everything for you, and probably do it quicker than if you tear things down yourself. I have a loop exit condition in my game loop for iOS. When the user hits the home button, sending the app to the background, I exit out of the game loop. When the user resumes the app I start the game loop up again. I do this because iOS will sometimes opt to simply kill an app instead of suspend it if it doesn't stop doing work correctly while in the background. iOS will, for example, kill an app that attempts to make OpenGL calls while in the background. I also exit the game loop when they put their device into sleep mode, and start the loop again when they wake their phone back up. iOS won't kill an app for processing while the device is asleep, but it'll drain the battery unnecessarily, so stopping the loop is just a nice thing to do there.
|
|
|
|
|
Logged
|
|
|
|
|
pekuja
|
 |
« Reply #27 on: June 12, 2012, 05:05:45 PM » |
|
hey pekuja, welcome, and nice loop you've got there. is that for tiny hawk?  Yeah, that's the Tiny Hawk loop for iOS and Android, using Marmalade SDK. It's a bit different in the PSP version, but I don't know if it'd be ok to post that. Maybe if I took out the few PSP API calls I have in there.
|
|
|
|
|
Logged
|
|
|
|
|
Evan Balster
|
 |
« Reply #28 on: June 12, 2012, 05:11:41 PM » |
|
A lot of what's been posted has some form of conditional that allows you to exit the run loop. Any reason you guys don't just call exit()? The OS will clean up everything for you, and probably do it quicker than if you tear things down yourself.
A more philosophical answer: In C or Java, the destruction of an object is not typically a significant event. In C++, by contrast, everything has a very well-defined endpoint to its lifespan and a sequence of carefully-ordered events that happens there. This allows for constructs such as an object representing the period of time a mutex is locked, frames of a stack elsewhere in the program, or objects which perform and undo a modification to the filesystem at the beginning and end of their lifetime. (I do this in one program to automatically reload an autosave file if I've detected the last session ended abnormally) To simply exit() dispenses with this entire paradigm and all the strengths it can offer. The short answer, though, is "saving on exit". All of these have made sense to me until I got to Evan's. What's this Task mechanism you have in here? Some sort of cooperative multithreading? I can't figure out the purpose of graphics.gui.focusMode(), either.
A game or program running on the engine would be a Task. These can coexist, though I don't often do so. I manage their addition and removal from the system with careful timing for reasons I don't need to explain.  As for focusMode(), that's a bit obscure. The debug terminal (an overlay accessed with the ~ key) blocks keyboard and mouse button input to GUI objects and Tasks. GUI objects can block this focus to Tasks, as well. I put a bizarro masking system in place so that the press/release states would be properly triggered when the focus mode transitioned. (In case, say, the player was holding the "shoot" button when the console popped up, or lord knows what else)
|
|
|
|
|
Logged
|
|
|
|
|
Average Software
|
 |
« Reply #29 on: June 12, 2012, 06:06:03 PM » |
|
Not a lot to say really, it does what it does.
What's the language? I don't recognize it. Ada.
|
|
|
|
|
Logged
|
|
|
|
|