// compute 1/30th of a second void update_sim() { //printf("Sim Update\n" ); if (!g_game.currLevel) { // no level loaded, don't update return; } // move aim thinggy based on cfHeading g_game.aimdir += g_game.cfAimDir * 10.0f; if (g_game.aimdir < 0.0f) g_game.aimdir += 360.0f; if (g_game.aimdir > 360.0f) g_game.aimdir -= 360.0f; // update power charge if (g_game.isCharging) { g_game.charge_amt += SIM_STEP; if (g_game.charge_amt > 2.0f) { g_game.charge_amt = 2.0f; fire_shot(); g_game.isCharging = false; } } // update any moving nodes bool needCleanup = false; g_game.isUpdating = false; for (size_t ndx=0; ndx < g_game.currLevel->m_nodes.size(); ndx++) { KNode &n = g_game.currLevel->m_nodes[ndx]; if (n.v > MIN_VEL) { // flag that something is being updated g_game.isUpdating = true; // update in kudzu space (bad) //n.pos += (n.dir * n.v); vec3f pos2; vec3f pos, dir, nrm, nrm2, bary,b2; KSimTri tri; if (!g_game.currLevel->getSimInfo( n.pos, n.dir, pos, nrm, dir, tri, bary ) ) { // node went out of bounds, mark it for // removal needCleanup = true; n.erase_flag = true; } else { n.erase_flag = false; // update vec3f oldpos = pos; pos = pos + dir * (n.v * SIM_STEP); // Add a bunch every BUNCH_SPC float d = prmath::Length( pos - oldpos ); n.bdist += d; if (n.bdist > BUNCH_SPC) { n.bdist -= BUNCH_SPC; KBunch b; b.pos = n.pos; b.pos3 = oldpos; b.age = 0.0f; g_game.currLevel->m_bunches.push_back( b ); } // make pos2 a little further for boundry crossing thing pos2 = pos + dir * (n.v * (SIM_STEP*5)); // remember pos3 n.pos3 = pos; // convert pos back to uv space b2 = tri.pos2bary( pos ); n.pos = tri.bary2uv( b2 ); // apply drag n.v -= 0.02; // if new pos is outside of triangle, // update dir so it will still appear straight if ((b2.x < 0) || (b2.y < 0) || (b2.z < 0)) { // b2 went outside of tri, get the new tri g_game.currLevel->getSimInfo( n.pos, n.dir, pos, nrm2, dir, tri, bary ); // find what uv's the new tri would give for the old position b2 = tri.pos2bary( pos2 ); vec2f uv2 = tri.bary2uv( b2 ); // get new heading from uv2 -> uv, if triangles // are near flat float olddir = n.dir; float ang = acos( prmath::DotProduct( nrm, nrm2 )); printf("Angle: %f\n", R2D*ang ); if (ang < D2R*45 ) { n.dir = R2D * atan2( uv2.y - n.pos.y, uv2.x - n.pos.x ); printf("DBG: Adjusting: Old dir was %f new dir %f\n", olddir, n.dir ); } else { // give the angle a random nudge to hide the // distortion in mapping n.dir += (((float)rand() / (float)RAND_MAX)- 0.5f) * 45.0; printf("DBG: Jittering: Old dir was %f new dir %f\n", olddir, n.dir ); } } // kill anything that runs into a bunch for (int i=0; i < g_game.currLevel->m_bunches.size(); i++) { // ignore freshly planted bunches if (g_game.currLevel->m_bunches[i].age < 2.0f) continue; float d = prmath::Length(n.pos3 - g_game.currLevel->m_bunches[i].pos3); if (d < BUNCH_SPC* 0.5) { printf("KILL node %d Dist %f %f\n", ndx, d, BUNCH_SPC*0.25 ); n.erase_flag = true; needCleanup = true; break; } } } // end of update } else { // node is stationary if (n.explode_flag) { needCleanup = true; n.erase_flag = true; } } } // end of node loop // safety: kill any bunches next to a not moving node std::vector<KBunch> newbunch; for (int i=0; i < g_game.currLevel->m_bunches.size(); i++) { KBunch &b = g_game.currLevel->m_bunches[i]; bool touching = false; for (int j=0; j < g_game.currLevel->m_nodes.size(); j++) { KNode &n = g_game.currLevel->m_nodes[j]; // skip moving nodes if (n.v > MIN_VEL) continue; if (prmath::Length( b.pos3 - n.pos3 ) < BUNCH_SPC * 0.55 ) { touching = true; break; } } if (!touching) { newbunch.push_back( b ); } } g_game.currLevel->m_bunches = newbunch; // age all of the bunches for (int i=0; i < g_game.currLevel->m_bunches.size(); i++) { g_game.currLevel->m_bunches[i].age += SIM_STEP; } // rebuild node list if there were baddies if (needCleanup) { // reset active node to 0 g_game.activeNode = 0; // Remove any nodes with the erase_flag set std::vector<KNode> newlist; for (int i=0; i < g_game.currLevel->m_nodes.size(); i++) { KNode &n = g_game.currLevel->m_nodes[i]; if (!n.erase_flag) { newlist.push_back( n ); } } g_game.currLevel->m_nodes = newlist; } }
// main loop int main( int argc, char *argv[] ) { if ( SDL_Init(SDL_INIT_NOPARACHUTE |SDL_INIT_VIDEO |SDL_INIT_JOYSTICK) < 0 ) { fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); exit(1); } if( SDL_SetVideoMode( 800, 600, 16, SDL_OPENGL /*| SDL_FULLSCREEN */ ) == 0 ) { fprintf(stderr, "Unable to set video mode: %s\n", SDL_GetError()); exit(1); } SDL_WM_SetCaption( "Kudzu Commander", NULL ); while (1) { SDL_Event event; /* Grab all the events off the queue. */ while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: switch( event.key.keysym.sym ) { case SDLK_ESCAPE: do_quit(); break; case SDLK_SPACE: if (!g_game.isUpdating) { g_game.isCharging = true; g_game.charge_amt = 0.0; } break; case SDLK_RETURN: // EXPLODE node // don't fire a shot until current one is done, // and can't explode if there is only one node left if ((!g_game.isUpdating) && (g_game.currLevel->m_nodes.size() > 1 )) { // TODO: energy system int num_explode = 20; for (int i = 0; i < num_explode; i++ ) { KNode n; n.pos = g_game.GetActNode().pos; n.dir = ((float)i / float(num_explode)) * 360.0f; n.v = 2.0; n.bdist = ( (float)rand() / (float)RAND_MAX) * BUNCH_SPC; n.explode_flag = true; g_game.currLevel->m_nodes.push_back( n ); } g_game.GetActNode().erase_flag = true; g_game.activeNode = 0; } break; case SDLK_s: //ilutGLScreenie(); break; case SDLK_1: g_dbg.drawGameView = !g_dbg.drawGameView; printf("Game View is now: %s\n", g_dbg.drawGameView?"enabled":"disabled" ); break; case SDLK_2: g_dbg.drawDbgView = !g_dbg.drawDbgView; printf("Debug View is now: %s\n", g_dbg.drawDbgView?"enabled":"disabled" ); break; case SDLK_3: g_dbg.drawSimView = !g_dbg.drawSimView; printf("Sim View is now: %s\n", g_dbg.drawSimView?"enabled":"disabled" ); break; case SDLK_l: { // init level printf("Init level\n"); g_game.currLevel = new KLevel(); // TODO: load this from a level info file g_game.currLevel->loadSimMesh( "./gamedata/house_sim.obj" ); //g_game.currLevel->loadSimMesh( "./gamedata/grid_sim.obj" ); // staring node KNode n; n.pos = vec2f( 0.1f, 0.5f ); n.pos3 = g_game.currLevel->k2pos( n.pos ); n.erase_flag = false; n.explode_flag = false; g_game.currLevel->m_nodes.push_back( n ); } break; case SDLK_q: if (g_game.currLevel) { g_dbg.dbgTriNdx--; if (g_dbg.dbgTriNdx < 0 ) { g_dbg.dbgTriNdx = g_game.currLevel->m_tri.size()-1; } printf("Triangle %d, links ab %d bc %d ca %d\n", g_dbg.dbgTriNdx, g_game.currLevel->m_tri[g_dbg.dbgTriNdx].ablink, g_game.currLevel->m_tri[g_dbg.dbgTriNdx].bclink, g_game.currLevel->m_tri[g_dbg.dbgTriNdx].calink ); } break; case SDLK_w: if (g_game.currLevel) { g_dbg.dbgTriNdx++; if (g_dbg.dbgTriNdx >= g_game.currLevel->m_tri.size() ) { g_dbg.dbgTriNdx = 0; } } break; case SDLK_UP: if (g_game.currLevel) { g_game.activeNode++; if (g_game.activeNode == g_game.currLevel->m_nodes.size()) { g_game.activeNode = 0; } } break; case SDLK_DOWN: if (g_game.currLevel) { g_game.activeNode--; if (g_game.activeNode < 0) { g_game.activeNode = g_game.currLevel->m_nodes.size() - 1; } } break; default: break; } break; case SDL_KEYUP: switch( event.key.keysym.sym ) { case SDLK_SPACE: if ((!g_game.isUpdating) && (g_game.isCharging)) { fire_shot(); } break; } case SDL_MOUSEMOTION: if (SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(3)) { // dragging RMB printf("Dragging %d %d\n", event.motion.xrel, event.motion.yrel ); g_cam.heading += -((float)event.motion.xrel / 800.0f) * 90.0f; printf("g_cam.heading %f\n", g_cam.heading ); if (g_cam.heading < 0.0f) g_cam.heading += 360.0f; if (g_cam.heading > 360.0f) g_cam.heading -= 360.0f; g_cam.recalc(); } // update mouse pos on sim view if ( (g_dbg.drawSimView) || (g_dbg.drawDbgView) ) { g_dbg.mx = (float)(event.motion.x - 110) / 580.0; g_dbg.my = 1.0f - ((float)(event.motion.y - 10) / 580.0); } break; case SDL_MOUSEBUTTONDOWN: if (event.button.button==4) { // wheel up g_cam.dist *= ZOOM_AMT; g_cam.recalc(); } else if (event.button.button==5) { // wheel down g_cam.dist *= (1.0f / ZOOM_AMT); g_cam.recalc(); } else if (event.button.button==2) { if ((g_dbg.mx >= 0.0) && (g_dbg.mx <= 1.0) && (g_dbg.my >= 0.0) && (g_dbg.my <= 1.0) ) { g_dbg.dbgBaryCursor = vec2f( g_dbg.mx, g_dbg.my ); } } printf("Mouse button %d pressed at (%d,%d)\n", event.button.button, event.button.x, event.button.y); break; case SDL_QUIT: /* Handle quit requests (like Ctrl-c). */ do_quit(); break; } } // Continuous (not one shot) keypresses g_game.cfAimDir = 0.0f; Uint8 *keys; keys = SDL_GetKeyState(NULL); if (keys[SDLK_LEFT] && !keys[SDLK_RIGHT]) { g_game.cfAimDir = 1.0; } if (!keys[SDLK_LEFT] && keys[SDLK_RIGHT]) { g_game.cfAimDir = -1.0; } // Update game loop static Uint32 last_tick=0, sim_ticks = 0; Uint32 tick; tick = SDL_GetTicks(); Uint32 deltaT; // get elapsed time if (last_tick==0) { deltaT = 0; } else { deltaT = tick - last_tick; } last_tick = tick; // update every SIM_FRAME_TIME ticks sim_ticks += deltaT; while (sim_ticks > SIM_FRAME_TIME) { sim_ticks -= SIM_FRAME_TIME; update_sim(); } // Redraw the screen redraw(); } return 0; }
void act(gamedata &g, int jx, int jy, bool jb){ // Reset hidden/afterburner status g.p().hide = false; g.p().boost = false; g.p().gunthreat = 0; switch(g.p().state){ case 0: // OK planes switch(g.p().land){ case 0: // Stationary on runway // Check for mission 0 and mission 1 wins if (((g.mission == 0) || (g.mission == 1)) && (!g.p().drak) && (g.p().score >= g.targetscore)){ g.winner = g.p().side; } // Start Engine if (jy == -1){ g.p().s = 0.3*GAME_SPEED*GAME_SPEED; g.p().land = 1; if ((g.p().control) > 0){ g.sound.volume(g.p().control-1, 0.0); g.sound.loop(g.p().control-1, g.p().enginesample); } } break; case 1: // Taking off plane if (jy == -1){ g.p().s = dlimit(g.p().s + 0.3*GAME_SPEED*GAME_SPEED, 0.0, 6.0*GAME_SPEED); } // Take off plane if ((jx == -1) && (g.p().s > 2.0*GAME_SPEED) && (g.base[g.p().side].planed == 13)){ g.p().d++; g.p().rotate = g.p().maxrotate; g.p().land = 2; } if ((jx == 1) && (g.p().s > 2.0*GAME_SPEED) && (g.base[g.p().side].planed == 5)){ g.p().d--; g.p().rotate = g.p().maxrotate; g.p().land = 2; } // Off end of runway if (abs(int(g.p().x - g.base[g.p().side].planex)) > g.base[g.p().side].runwaylength){ g.p().land = 2; } break; case 2: // flying // Navigate plane if ((g.p().rotate == 0) && (jx !=0)){ g.p().d = wrap(g.p().d-jx,1,17); g.p().rotate = g.p().maxrotate; }else{ if (g.p().rotate > 0){ g.p().rotate--; } } // Acceleration / Afterburner Controls { double acceleration = g.accel[g.p().d] * GAME_SPEED * GAME_SPEED; if (g.p().burner){ if (jy == -1){ acceleration += 0.3*GAME_SPEED*GAME_SPEED; g.p().boost = true; } if ((g.p().s > 6.0*GAME_SPEED) && (jy != -1)){ acceleration -= 0.3*GAME_SPEED*GAME_SPEED; } g.p().s = dlimit(g.p().s + acceleration, 0.0, 12.0*GAME_SPEED); }else{ g.p().s = dlimit(g.p().s + acceleration, 0.0, 6.0*GAME_SPEED); } } // Stealth Controls if ((jy == -1) && (jx == 0) && (!jb) && (g.p().stealth)){ g.p().hide = true; } // Check for shotfire if (g.p().shotdelay == 0){ if ((jb) && (g.p().ammo > 0)){ fire_shot(g.p(), g.shot, g.sound, g.xmove, g.ymove); } // Check for bombdrop if ((jy == 1) && (g.p().bombs > 0)){ drop_bomb(g.p(), g.fall, g.sound, g.bombimage); } }else{ g.p().shotdelay--; } break; case 3: // Landing plane if ((((g.p().x - g.base[g.p().side].planex) < 2.0) && (g.base[g.p().side].planed == 13)) || (((g.p().x - g.base[g.p().side].planex) > -2.0) && (g.base[g.p().side].planed == 5))){ g.p().land = 0; g.p().x = g.base[g.p().side].planex; g.p().y = g.base[g.p().side].planey; g.p().d = g.base[g.p().side].planed; g.p().xs = 0; g.p().ys = 0; g.p().s = 0; g.p().ammo = g.p().maxammo; g.p().bombs = g.p().maxbombs; g.p().coms = 0; g.p().targetx = 0; g.p().targety = 0; g.p().cruiseheight = 0; } break; } // Set speed for planes g.p().xs = g.p().s * g.xmove[g.p().d]; g.p().ys = g.p().s * g.ymove[g.p().d]; // Check for stall if ((g.p().s < 1.0*GAME_SPEED) && (g.p().land == 2)){ g.p().state = 1; if ((g.p().control) > 0){ g.sound.stop(g.p().control-1); g.sound.play(SOUND_STALL); } } if (g.p().y < 0){ g.p().y = 0; g.p().ys = 0; g.p().state = 1; if ((g.p().control) > 0){ g.sound.stop(g.p().control-1); g.sound.play(SOUND_STALL); } } break; case 1: // Stalling planes // Navigate plane if ((g.p().rotate == 0) && (jx !=0)){ g.p().d = wrap(g.p().d-jx,1,17); g.p().rotate = g.p().maxrotate; }else{ if (g.p().rotate > 0){ g.p().rotate--; } } // Check for shotfire if (g.p().shotdelay == 0){ if ((jb) && (g.p().ammo > 0)){ fire_shot(g.p(), g.shot, g.sound, g.xmove, g.ymove); } // Check for bombdrop if ((jy == 1) && (g.p().bombs > 0)){ drop_bomb(g.p(), g.fall, g.sound, g.bombimage); } }else{ g.p().shotdelay--; } // Gravity and drag g.p().ys += 0.1 * GAME_SPEED * GAME_SPEED; if (fabs(g.p().xs) > 0.02 * GAME_SPEED * GAME_SPEED){ g.p().xs -= g.p().xs / fabs(g.p().xs) * 0.02 * GAME_SPEED * GAME_SPEED; } // Recover from Stall if ((g.p().ys > 3.0 * GAME_SPEED) && (g.p().d == 9)){ g.p().s = dlimit(g.p().ys, 3.0*GAME_SPEED, 6.0*GAME_SPEED); g.p().state = 0; g.p().xs = g.p().s * g.xmove[g.p().d]; g.p().ys = g.p().s * g.ymove[g.p().d]; g.p().coms = 0; if ((g.p().control) > 0){ double volume = g.p().s / (6.0*GAME_SPEED); g.sound.volume(g.p().control-1, volume * 0.5); g.sound.loop(g.p().control-1, g.p().enginesample); } } break; case 2: // Dead planes // Gravity and drag g.p().ys += 0.1 * GAME_SPEED * GAME_SPEED; if (fabs(g.p().xs) > 0.02 * GAME_SPEED * GAME_SPEED){ g.p().xs -= g.p().xs/ fabs(g.p().xs) * 0.02 * GAME_SPEED * GAME_SPEED; } // Smoking plane g.p().crash++; if (g.p().crash == int(5/GAME_SPEED)){ g.p().crash = 0; smoketype newsmoke; newsmoke.x = int(g.p().x); newsmoke.y = g.p().y; newsmoke.time = 0; g.smoke.add(newsmoke); } break; case 3: // Crashed planes g.p().crash++; if (g.p().crash == int(70/GAME_SPEED)){ if (!g.p().drak){ // Respawn plane to runway g.p().land = 0; g.p().state = 0; g.p().rotate = 0; g.p().crash = 0; g.p().x = g.base[g.p().side].planex; g.p().y = g.base[g.p().side].planey; g.p().d = g.base[g.p().side].planed; g.p().xs = 0; g.p().ys = 0; g.p().s = 0; g.p().ammo = g.p().maxammo; g.p().bombs = g.p().maxbombs; g.p().coms = 0; g.p().targetx = 0; g.p().targety = 0; g.p().cruiseheight = 0; }else{ // Expunge drak g.p().state = 4; } } break; case 4: // Expunged drak fighter (NB: shouldn't get here!) break; } // Move the planes g.p().x += g.p().xs; g.p().y += g.p().ys; // Control Engine Volume if ((g.p().control) > 0){ if ((g.p().state == 0) && (g.p().land > 0)){ double volume = g.p().s / (6.0*GAME_SPEED); g.sound.volume(g.p().control-1, volume * 0.5); if ((g.p().boost) && (g.p().enginesample == SOUND_JET)){ g.p().enginesample = SOUND_BURNER; g.sound.loop(g.p().control-1,SOUND_BURNER); } if ((!g.p().boost) && (g.p().enginesample == SOUND_BURNER)){ g.p().enginesample = SOUND_JET; g.sound.loop(g.p().control-1,SOUND_JET); } }else{ g.sound.stop(g.p().control-1); } } if (g.p().state < 3) detect_collisions(g); }