Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <scene.hpp>
- //1 ship, 1 'skybox', 1 gear icon, 1 door, <bullet_count> bullets,
- //4 asteroids, 16 mini-asteroids, and 64 micro-asteroids
- #define bullet_count 8
- #define asteroid_count (4 + 4*4 + 4*4*4)
- MeshSimple* meshes[1 + 1 + 1 + 1 + bullet_count + asteroid_count];
- #define meshes_len (sizeof(meshes)/sizeof(MeshSimple*))
- #define bullet_offset 4
- #define asteroid_offset (bullet_offset+bullet_count)
- #define _mesh_ship (meshes[0])
- #define _mesh_skybox (meshes[1])
- #define _mesh_gear (meshes[2])
- #define _mesh_door (meshes[3])
- #define _mesh_bullet(which) (meshes[bullet_offset+(which)])
- #define _mesh_asteroid(which) (meshes[asteroid_offset+(which)])
- #define mesh_ship (*_mesh_ship)
- #define mesh_skybox (*_mesh_skybox)
- #define mesh_gear (*_mesh_gear)
- #define mesh_door (*_mesh_door)
- #define mesh_bullet(which) (*_mesh_bullet(which))
- #define mesh_asteroid(which) (*_mesh_asteroid(which))
- #define asteroid_normal(which) mesh_asteroid( which )
- #define asteroid_mini(which) mesh_asteroid(4+ (which))
- #define asteroid_micro(which) mesh_asteroid(4+16+(which))
- #define asteroid_menu asteroid_micro
- #define state_normal(which) state.asteroids[ which ]
- #define state_mini(which) state.asteroids[4+ (which)]
- #define state_micro(which) state.asteroids[4+16+(which)]
- #define bullet_size 0.25f
- #define nrml_siz 6.0f
- #define mini_siz (nrml_siz*0.75f)
- #define mcro_siz (nrml_siz*0.50f)
- #define menu_siz 0.50f
- #define skybox_bounds_formula (((CLIP_FAR/32) - 1.0f) * (0.5 + (float)cfg.num_asteroids/8))
- //application of values are as follows:
- //camera's current position = old*mod + new*(1.0f-mod)
- //old = camera's current position
- #define camera_mod 0.85f
- #define camera_lpf(_member) \
- camera_old._member*camera_mod + camera_new._member*(1.0f-camera_mod)
- Location camera_old;
- Location camera_cur; //subject to different rules to that of scene_camera
- Location camera_new;
- #define ship_camera_distance 1.3f
- #define ship_camera_y_offset 0.25f
- #define ship_camera_down_tilt 0.02f
- #define ship_decay_multiplier_a 0.88f
- #define ship_decay_multiplier_b 0.5f
- #define speed_modifier(v) ( (v) * (CLIP_FAR/768.0f) )
- #define bullet_speed speed_modifier(1.50f)
- #define ship_speed_x speed_modifier(0.20f)
- #define ship_speed_y speed_modifier(0.20f)
- #define ship_speed_z speed_modifier(0.30f)
- #define asteroid_speed speed_modifier(0.1)
- #define asteroid_rotation ((_2pi/60) * 1.0f) //speed_modifier isn't needed here
- //
- #define CFG_FILENAME "./config.bin"
- #define CFG_VERSION 12
- struct _cfg_s {
- unsigned short version = CFG_VERSION;
- bool maximized = false;
- bool fullscreen = false;
- float high_scores[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- #define BIND_COUNT 6
- unsigned short bind_right = SDL_SCANCODE_D;
- unsigned short bind_left = SDL_SCANCODE_A;
- unsigned short bind_forward = SDL_SCANCODE_W;
- unsigned short bind_back = SDL_SCANCODE_S;
- unsigned short bind_up = SDL_SCANCODE_LSHIFT;
- unsigned short bind_down = SDL_SCANCODE_LCTRL;
- float lastrand = 0.9f; //used to modify srand when starting a game
- float sensitivity = 0.8f; //mouse look sensitivity
- unsigned short win_w = WIN_W, win_h = WIN_H;
- char num_asteroids = 4; //# of normal asteroids that appear when game resets
- bool invert_y = false; //inverts vertical mouse input
- };
- _cfg_s cfg;
- //WEIRD POINTER STUFF LMAOOO
- unsigned short* bind_array = (unsigned short*)(&cfg.high_scores[3+1]);
- unsigned short bind_array_defaults[BIND_COUNT];
- const char* bind_names[] = {
- "right",
- "left",
- "forward",
- "back",
- "up",
- "down",
- };
- #define MENU_REBINDING -3
- #define MENU_DEAD -2
- #define MENU_PLAYING -1
- #define MENU_QUIT 0
- #define MENU_PLAY 1
- #define MENU_ASTEROIDS 2
- #define MENU_REBIND 3
- #define MENU_MAX MENU_REBIND
- struct bulletElement {
- Vec3 vel = {0,0,0};
- bool active = false;
- };
- enum asteroidTypeEnum { ATYPE_NORMAL = 0, ATYPE_MINI, ATYPE_MICRO, };
- struct asteroidElement {
- int children[4]; //indexes of children; set during init
- Location vel; //velocity
- char type = -1; //asteroidTypeEnum
- bool has_children = true;
- bool active = false;
- char _padding8;
- };
- struct _state_s {
- bulletElement bullets[bullet_count];
- int active_bullets = 0;
- asteroidElement asteroids[asteroid_count];
- int active_asteroids = 0;
- int menu = MENU_PLAY;
- int which_rebind = 0;
- bool pressed_right = false;
- bool pressed_left = false;
- bool pressed_forward = false;
- bool pressed_back = false;
- bool pressed_up = false;
- bool pressed_down = false;
- bool quit = false;
- bool cursorIsTrapped = false;
- float score = 0.0f;
- float skybox_bounds = skybox_bounds_formula;
- };
- _state_s state;
- bool* pressed_array = (bool*)(&state.which_rebind+1);
- const float asteroid_sizes[3] = { nrml_siz, mini_siz, mcro_siz };
- static inline bool keepInBounds(Location& loc){
- bool wrappedAround = false;
- if(fabsf(loc.x)>state.skybox_bounds){ loc.x = (1-2*(loc.x>=0))*state.skybox_bounds; wrappedAround = true; }
- if(fabsf(loc.y)>state.skybox_bounds){ loc.y = (1-2*(loc.y>=0))*state.skybox_bounds; wrappedAround = true; }
- if(fabsf(loc.z)>state.skybox_bounds){ loc.z = (1-2*(loc.z>=0))*state.skybox_bounds; wrappedAround = true; }
- return wrappedAround;
- }
- //bounces on edge instead of modulo
- static inline bool keepInBounds_asteroid(int which){
- bool bounced = false;
- asteroidElement& ast = state.asteroids[which];
- float bounce_dist = state.skybox_bounds - asteroid_sizes[(int)ast.type]/2;
- if(fabsf(mesh_asteroid(which).p.x)>=bounce_dist){ ast.vel.x = -ast.vel.x; bounced = true; }
- if(fabsf(mesh_asteroid(which).p.y)>=bounce_dist){ ast.vel.y = -ast.vel.y; bounced = true; }
- if(fabsf(mesh_asteroid(which).p.z)>=bounce_dist){ ast.vel.z = -ast.vel.z; bounced = true; }
- return bounced;
- }
- template<class T> inline T umod(T a, int b){
- a %= b;
- if(a < 0) a += b;
- return a;
- }
- #define SQR(thing) ((thing)*(thing))
- static inline float locHypot(const Location& loc){
- return sqrtf(SQR(loc.x)+SQR(loc.y)+SQR(loc.z));
- }
- static inline float locDistance(const Location& l_a, const Location& l_b){
- return sqrtf(SQR(l_b.x-l_a.x)+SQR(l_b.y-l_a.y)+SQR(l_b.z-l_a.z));
- }
- //assumes RAND_MAX is 32767
- static inline float randf(){ //0.0f -> 1.0f
- return (float)(rand()<<15|rand())/0x3fffffff;
- }
- static inline float randf2(){ //-1.0f -> 1.0f
- return randf()*2.0f - 1.0f;
- }
- void trapCursor(bool enable){
- if(enable == state.cursorIsTrapped) return;
- SDL_SetWindowTitle(canvas->getWin(), fstr(WIN_TITLE " %s", (enable) ? UNTRAP_PROMPT : TRAP_PROMPT));
- if(SDL_SetRelativeMouseMode((enable) ? SDL_TRUE : SDL_FALSE)<0) throw SDL_GetError();
- state.cursorIsTrapped = enable;
- }
- void setFullscreen(bool enable){
- SDL_SetWindowFullscreen(canvas->getWin(), (enable) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
- cfg.fullscreen = enable;
- }
- void mouseMoved(s32 dx, s32 dy);
- void mouseButton(u8 button, bool clicked);
- void mouseWheel(int amount);
- void keyPress(SDL_Keysym key, bool pressed, u16 modifiers);
- //returns false if state.quit gets flipped
- bool handleEvents(){
- SDL_Event evt;
- while(SDL_PollEvent(&evt))
- switch(evt.type){
- case SDL_QUIT: state.quit = true; SDL_ShowCursor(true); return false;
- case SDL_WINDOWEVENT: {
- switch(evt.window.event){
- case SDL_WINDOWEVENT_FOCUS_LOST: trapCursor(false); break;
- case SDL_WINDOWEVENT_RESIZED: cfg.win_w = evt.window.data1, cfg.win_h = evt.window.data2; break;
- case SDL_WINDOWEVENT_RESTORED: cfg.maximized = false; break;
- case SDL_WINDOWEVENT_MAXIMIZED: cfg.maximized = true; break;
- default: ;//Log("%X", evt.window.event);
- }
- } break;
- case SDL_KEYDOWN: {
- if(evt.key.repeat) break;
- if(evt.key.keysym.sym == SDLK_ESCAPE){ trapCursor(false); break; }
- if(evt.key.keysym.sym == SDLK_F11){ setFullscreen(!cfg.fullscreen); break; }
- } SDL_FALLTHROUGH;
- case SDL_KEYUP: {
- keyPress(evt.key.keysym,
- (evt.key.state == SDL_PRESSED) ? true : false,
- evt.key.keysym.mod);
- } break;
- case SDL_MOUSEBUTTONDOWN:{
- if(state.cursorIsTrapped)
- mouseButton(evt.button.button, evt.button.state == SDL_PRESSED);
- if(evt.button.button == SDL_BUTTON_LEFT)
- trapCursor(true);
- } break;
- case SDL_MOUSEMOTION: {
- if(cfg.invert_y) evt.motion.yrel = -evt.motion.yrel;
- if(state.cursorIsTrapped) mouseMoved(evt.motion.xrel, evt.motion.yrel);
- } break;
- case SDL_MOUSEWHEEL: {
- if(state.cursorIsTrapped)
- mouseWheel(evt.wheel.y);
- } break;
- default: ;//Log("%X", evt.type);
- }
- return !state.quit;
- }
- Vec3 rotatePRY(float pitch, float roll, float yaw,
- float x_0, float y_0, float z_0)
- {
- const float cosPitch = cosf(pitch);
- const float sinPitch = sinf(pitch);
- const float cosRoll = cosf(roll );
- const float sinRoll = sinf(roll );
- const float cosYaw = cosf(yaw );
- const float sinYaw = sinf(yaw );
- float y_1 = cosPitch*y_0 - sinPitch*z_0;
- float z_1 = sinPitch*y_0 + cosPitch*z_0;
- float x_2 = cosRoll*x_0 - sinRoll*y_1;
- float y_2 = sinRoll*x_0 + cosRoll*y_1;
- float x_3 = cosYaw*x_2 + sinYaw*z_1;
- float z_2 = -sinYaw*x_2 + cosYaw*z_1;
- return Vec3(x_3, y_2, z_2);
- }
- //motion is relative to camera's current direction
- static inline void moveCamera(float x_0, float y_0, float z_0){
- Vec3 motion = rotatePRY(-camera_cur.pitch,
- -camera_cur.roll,
- -camera_cur.yaw,
- x_0, y_0, z_0);
- camera_cur.x += motion.x;
- camera_cur.y += motion.y;
- camera_cur.z += motion.z;
- }
- bool bulletFire(){
- if(state.active_bullets >= bullet_count) return false; //max bullets reached
- int which = -1;
- for(int i=0; i<bullet_count; ++i){
- if(!state.bullets[i].active){ which = i; break; }
- }
- if(which == -1)
- throw "could not find empty spot in bullet queue, despite active bullets being < maximum"; //return false;
- Vec3 direction = rotatePRY(-camera_cur.pitch,
- -camera_cur.roll,
- -camera_cur.yaw,
- 0.0f, 0.0f, 1.0f);
- mesh_bullet(which).p.x = -camera_cur.x + direction.x;
- mesh_bullet(which).p.y = -camera_cur.y + direction.y;
- mesh_bullet(which).p.z = -camera_cur.z + direction.z;
- mesh_bullet(which).p.pitch = -camera_cur.pitch;
- mesh_bullet(which).p.roll = -camera_cur.roll;
- mesh_bullet(which).p.yaw = -camera_cur.yaw;
- state.bullets[which].vel = direction;
- state.bullets[which].vel *= bullet_speed;
- //lol
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
- state.bullets[which].active = true;
- #pragma GCC diagnostic pop
- ++state.active_bullets;
- return true;
- }
- void bulletMoveAll(){
- for(unsigned i=0; i<bullet_count; ++i){
- if(!state.bullets[i].active) continue;
- mesh_bullet(i).p.x += state.bullets[i].vel.x;
- mesh_bullet(i).p.y += state.bullets[i].vel.y;
- mesh_bullet(i).p.z += state.bullets[i].vel.z;
- if(keepInBounds(mesh_bullet(i).p)){
- mesh_bullet(i).p.y = CLIP_FAR*2;
- state.bullets[i].active = false;
- --state.active_bullets;
- }
- }
- }
- void asteroidCreate(int which, int parent = -1){
- asteroidElement& ast = state.asteroids[which];
- if(parent == -1){
- //move asteroid to a new location in-bounds that is far enough from the ship
- Location newloc = mesh_asteroid(which).p;
- float ast_size_mod = asteroid_sizes[(int)ast.type];
- do { //keep rolling for a new position until a suitable one is found
- newloc.x = randf2() * (state.skybox_bounds-ast_size_mod);
- newloc.y = randf2() * (state.skybox_bounds-ast_size_mod);
- newloc.z = randf2() * (state.skybox_bounds-ast_size_mod);
- } while( locDistance(newloc, camera_cur) < (state.skybox_bounds/3) );
- mesh_asteroid(which).p = newloc;
- } else {
- mesh_asteroid(which).p.x = mesh_asteroid(parent).p.x;
- mesh_asteroid(which).p.y = mesh_asteroid(parent).p.y;
- mesh_asteroid(which).p.z = mesh_asteroid(parent).p.z;
- }
- float max_type_speed = asteroid_speed *(1+ast.type);
- //float max_type_rotation = asteroid_rotation*(1+ast.type);
- ast.vel.x = randf2() * max_type_speed;
- ast.vel.y = randf2() * max_type_speed;
- ast.vel.z = randf2() * max_type_speed;
- ast.vel.pitch = randf2() * asteroid_rotation;
- ast.vel.roll = randf2() * asteroid_rotation;
- ast.active = true;
- ++state.active_asteroids;
- }
- void asteroidDestroy(int which){
- asteroidElement& ast = state.asteroids[which];
- ast.active = false;
- state.score += 1 + ast.type;
- if(ast.has_children){
- asteroidCreate(ast.children[0], which);
- asteroidCreate(ast.children[1], which);
- asteroidCreate(ast.children[2], which);
- asteroidCreate(ast.children[3], which);
- }
- mesh_asteroid(which).p.y = CLIP_FAR*2; //move asteroid mesh out of play area
- --state.active_asteroids;
- }
- void asteroidMoveAll(){
- for(unsigned i=0; i<asteroid_count; ++i){
- if(!state.asteroids[i].active) continue;
- mesh_asteroid(i).p.x += state.asteroids[i].vel.x;
- mesh_asteroid(i).p.y += state.asteroids[i].vel.y;
- mesh_asteroid(i).p.z += state.asteroids[i].vel.z;
- mesh_asteroid(i).p.pitch += state.asteroids[i].vel.pitch;
- mesh_asteroid(i).p.roll += state.asteroids[i].vel.roll;
- keepInBounds_asteroid(i);
- }
- }
- void checkForBulletHits(){
- for(unsigned b=0; b<bullet_count; ++b){
- if(!state.bullets[b].active) continue;
- Location bullet_loc = mesh_bullet(b).p;
- //checking the little asteroids first (as in, in reverse order)
- //will hopefully negate the usefulness of spam shooting a single asteroid a bit
- for(int a=(asteroid_count-1); a>=0; --a){
- if(!state.asteroids[a].active) continue;
- //*0.45f instead of *0.5f to account for inconsistent geometry
- float collide_dist = bullet_size/2 + asteroid_sizes[(int)state.asteroids[a].type]*0.45f;
- if(locDistance(bullet_loc,mesh_asteroid(a).p) < collide_dist){
- asteroidDestroy(a);
- mesh_bullet(b).p.y = CLIP_FAR*2;
- state.bullets[b].active = false;
- --state.active_bullets;
- break; //go to next bullet, since this one is now destroyed
- }
- }
- }
- }
- //
- void activateMenuItem(){
- switch(state.menu){
- case MENU_DEAD : state.menu = MENU_PLAY; break;
- case MENU_QUIT : state.quit = true; break;
- case MENU_PLAY : state.menu = MENU_PLAYING; break;
- case MENU_ASTEROIDS: cfg.num_asteroids = cfg.num_asteroids%4+1; break;
- case MENU_REBIND : state.menu = MENU_REBINDING; state.which_rebind = 0; break;
- default:;
- }
- }
- #define mdelta_divisor_a 200
- #define mdelta_divisor_b 200
- #define mdelta_divisor_c 1000
- void mouseMoved(s32 dx, s32 dy){
- if(state.menu != MENU_PLAYING) return;
- #define rotmod(value) fmodf(value, _2pi)
- #define rotclamp(value) CLAMP(value, -_pi, _pi)
- #define rotclamph(value) CLAMP(value, -(_pi/2), (_pi/2))
- camera_cur.yaw = rotmod(camera_cur.yaw -((float)dx/mdelta_divisor_a)*cfg.sensitivity);
- camera_cur.pitch = rotmod(camera_cur.pitch+((float)dy/mdelta_divisor_a)*cfg.sensitivity);
- mesh_ship.p.roll = rotclamph(mesh_ship.p.roll -((float)dx/mdelta_divisor_b)*cfg.sensitivity);
- mesh_ship.p.pitch = rotclamph(mesh_ship.p.pitch-((float)dy/mdelta_divisor_b)*cfg.sensitivity);
- }
- void mouseButton(u8 button, bool clicked){
- if(button == SDL_BUTTON_LEFT && clicked){
- if( state.menu == MENU_PLAYING) bulletFire();
- else if(state.menu >= 0) activateMenuItem();
- }
- }
- void mouseWheel(int amount){
- if(state.menu >= 0) state.menu = umod(state.menu+amount, MENU_MAX+1);
- }
- static inline bool bindingIsValid(SDL_Scancode scancode, unsigned index){
- if(index > INT_S32_MAX) //just in case
- throw "bindingIsValid(): index > 2147483647";
- //bindings shouldn't share the same scancode,
- //so check current bindings until right before current index (not BIND_COUNT)
- for(unsigned i=0; i<index; ++i) //loop shouldn't start at all if index is 0
- if(bind_array[i] == scancode) return false;
- return true;
- }
- void keyPress(SDL_Keysym key, bool pressed, u16 modifiers){
- //Log("0x%02X, %i, 0x%04X", key.scancode, pressed, modifiers);
- if(state.menu == MENU_PLAYING){
- for(unsigned i=0; i<BIND_COUNT; ++i){
- if(key.scancode == bind_array[i])
- pressed_array[i] = pressed;
- }
- if(pressed){
- if(key.sym == SDLK_SPACE ) bulletFire();
- if(key.sym == SDLK_BACKSPACE) state.menu = MENU_PLAY;
- }
- } else if(state.menu == MENU_REBINDING){
- if(!pressed) return;
- if(key.sym == SDLK_RETURN || key.sym == SDLK_SPACE) return;
- if( key.sym == SDLK_UP || key.sym == SDLK_DOWN ||
- key.sym == SDLK_LEFT || key.sym == SDLK_RIGHT )
- {
- return;
- }
- if(key.sym == SDLK_BACKSPACE){
- for(int i=0; i<BIND_COUNT; ++i) bind_array[i] = bind_array_defaults[i];
- state.menu = MENU_REBIND;
- return;
- }
- if(bindingIsValid(key.scancode, state.which_rebind)){
- bind_array[state.which_rebind] = key.scancode;
- ++state.which_rebind;
- }
- if(state.which_rebind >= BIND_COUNT) state.menu = MENU_REBIND;
- } else if(state.menu >= 0 || state.menu == MENU_DEAD){
- if(!pressed) return;
- if(key.sym == SDLK_RETURN || key.sym == SDLK_SPACE)
- activateMenuItem();
- if(state.menu < 0) return;
- if(key.scancode == cfg.bind_left || key.scancode == SDL_SCANCODE_LEFT){
- state.menu = umod(state.menu-1, MENU_MAX+1);
- } else if(key.scancode == cfg.bind_right || key.scancode == SDL_SCANCODE_RIGHT){
- state.menu = umod(state.menu+1, MENU_MAX+1);
- } else switch(state.menu){
- #ifdef _DEBUG
- case MENU_QUIT: {
- if(key.scancode == SDL_SCANCODE_RSHIFT) mesh_ship.p.yaw = 0.0f;
- } break;
- #endif
- case MENU_ASTEROIDS: {
- if(key.scancode == cfg.bind_back || key.scancode == SDL_SCANCODE_DOWN)
- cfg.num_asteroids = MAX(cfg.num_asteroids-1, 1);
- else if(key.scancode == cfg.bind_forward || key.scancode == SDL_SCANCODE_UP)
- cfg.num_asteroids = MIN(cfg.num_asteroids+1, 4);
- } break;
- default:;
- }
- } else {
- }
- }
- int sceneMain(int argc, char** argv){
- /************************************ INIT ************************************/
- _mesh_ship = new MeshSimple("ship.obj");
- _mesh_skybox = new MeshSimple("skybox.obj");
- _mesh_gear = new MeshSimple("gear.obj");
- _mesh_door = new MeshSimple("door.obj");
- for(unsigned i=0; i<bullet_count; ++i)
- _mesh_bullet(i) = new MeshSimple("bullet.obj");
- for(unsigned i=0; i<asteroid_count; ++i)
- _mesh_asteroid(i) = new MeshSimple("asteroid.obj");
- for(int i=0; i<BIND_COUNT; ++i)
- bind_array_defaults[i] = bind_array[i];
- cfg.version = CFG_VERSION;
- if(file::exists(CFG_FILENAME)){
- BinaryData _cfg_file(CFG_FILENAME);
- _cfg_s* cfg_file = (_cfg_s*)_cfg_file.data;
- //always make sure high score carries over, since i won't be changing its
- //placement between changes to the overall structure of _cfg_s
- cfg.high_scores[0] = cfg_file->high_scores[0];
- cfg.high_scores[1] = cfg_file->high_scores[1];
- cfg.high_scores[2] = cfg_file->high_scores[2];
- cfg.high_scores[3] = cfg_file->high_scores[3];
- if( _cfg_file.data_len == sizeof(cfg) &&
- cfg_file->version == cfg.version )
- {
- cfg = *cfg_file;
- }
- }
- sceneRebuild(meshes, meshes_len);
- for(unsigned i=0; i<bullet_count; ++i) mesh_bullet(i).p.scale = bullet_size;
- for(unsigned i=0; i< 4; ++i) asteroid_normal(i).p.scale = nrml_siz;
- for(unsigned i=0; i<16; ++i) asteroid_mini(i).p.scale = mini_siz;
- for(unsigned i=0; i<64; ++i) asteroid_micro(i).p.scale = mcro_siz;
- state.menu = -1;
- if(cfg.maximized) SDL_MaximizeWindow(canvas->getWin());
- else SDL_SetWindowSize(canvas->getWin(), cfg.win_w, cfg.win_h);
- setFullscreen(cfg.fullscreen);
- SDL_ShowWindow(canvas->getWin());
- canvas->clear();
- canvas->present(0);
- #define canvas_present(msDelay) canvas->present((unsigned)(MAX(1, ((msDelay)-(int)(SDL_GetTicks64()-startTime)) )))
- Uint64 startTime;
- SDL_RWops* cfg_file;
- float viewport_fov = 75; //degrees of vertical field of view
- float viewport_mod = tan(viewport_fov/(360.0f/_pi));
- SDL_Rect crosshair = {CNV_W/2-1, CNV_H/2-1, 2, 2};
- for(int n=0; n<4; ++n){
- state_normal(n).children[0] = 4 + n*4;
- state_normal(n).children[1] = state_normal(n).children[0] + 1;
- state_normal(n).children[2] = state_normal(n).children[0] + 2;
- state_normal(n).children[3] = state_normal(n).children[0] + 3;
- state_normal(n).type = ATYPE_NORMAL;
- state_normal(n).has_children = true;
- state_normal(n).active = false;
- }
- for(int m=0; m<16; ++m){
- state_mini(m).children[0] = 4 + 16 + m*4;
- state_mini(m).children[1] = state_mini(m).children[0] + 1;
- state_mini(m).children[2] = state_mini(m).children[0] + 2;
- state_mini(m).children[3] = state_mini(m).children[0] + 3;
- state_mini(m).type = ATYPE_MINI;
- state_mini(m).has_children = true;
- state_mini(m).active = false;
- }
- for(int u=0; u<64; ++u){
- state_micro(u).type = ATYPE_MICRO;
- state_micro(u).has_children = false;
- state_micro(u).active = false;
- }
- /**********************************/ _MENU: /**********************************/
- #define menu_mesh_spacing 3.0f
- memory::set(pressed_array, 0, sizeof(bool)*BIND_COUNT);
- memory::set(&scene_camera, 0, sizeof(scene_camera));
- scene_camera.scale = 1.0f/16;
- scene_camera.pitch = 0.3f;
- scene_camera.y = 0.25f;
- scene_camera.z = -0.25f;
- memory::set(&mesh_ship.p, 0, sizeof(mesh_ship.p));
- mesh_ship.p.scale = 1.0f;
- mesh_ship.p.x = menu_mesh_spacing*MENU_PLAY;
- mesh_ship.p.z = 1.0f;
- memory::set(&mesh_skybox.p, 0, sizeof(mesh_skybox.p));
- memory::set(&mesh_gear.p, 0, sizeof(mesh_gear.p));
- mesh_gear.p.scale = 1.0f;
- mesh_gear.p.x = menu_mesh_spacing*MENU_REBIND;
- mesh_gear.p.z = 1.0f;
- memory::set(&mesh_door.p, 0, sizeof(mesh_door.p));
- mesh_door.p.scale = 1.0f;
- mesh_door.p.x = menu_mesh_spacing*MENU_QUIT;
- mesh_door.p.z = 1.0f;
- for(unsigned i=0; i<bullet_count; ++i){
- mesh_bullet(i).p.y = CLIP_FAR*2;
- state.bullets[i].active = false;
- }
- state.active_bullets = 0;
- for(unsigned i=0; i<asteroid_count; ++i){
- mesh_asteroid(i).p.x = menu_mesh_spacing*MENU_ASTEROIDS;
- mesh_asteroid(i).p.y = CLIP_FAR*2;
- mesh_asteroid(i).p.z = 1.0f;
- mesh_asteroid(i).p.yaw = state.asteroids[i].vel.yaw = 0.0f;
- mesh_asteroid(i).p.pitch = state.asteroids[i].vel.pitch = 0.0f;
- mesh_asteroid(i).p.roll = state.asteroids[i].vel.roll = 0.0f;
- }
- const float old_scale[] = {
- asteroid_menu(0).p.scale,
- asteroid_menu(1).p.scale,
- asteroid_menu(2).p.scale,
- asteroid_menu(3).p.scale,
- };
- asteroid_menu(0).p.scale = menu_siz; //bottom-left
- asteroid_menu(0).p.x += -menu_siz/2; //
- asteroid_menu(0).p.y = -menu_siz/2; //
- asteroid_menu(1).p.scale = menu_siz; //bottom-right
- asteroid_menu(1).p.x += menu_siz/2; //
- asteroid_menu(1).p.y = -menu_siz/2; //
- asteroid_menu(2).p.scale = menu_siz; //top-left
- asteroid_menu(2).p.x += -menu_siz/2; //
- asteroid_menu(2).p.y = menu_siz/2; //
- asteroid_menu(3).p.scale = menu_siz; //top-right
- asteroid_menu(3).p.x += menu_siz/2; //
- asteroid_menu(3).p.y = menu_siz/2; //
- if(state.menu < 0) state.menu = MENU_PLAY;
- camera_old.x = menu_mesh_spacing * state.menu;
- camera_new.x = camera_old.x;
- scene_camera.x = camera_old.x;
- while(!state.quit && state.menu != MENU_PLAYING){
- startTime = SDL_GetTicks64();
- if(!handleEvents()) break;
- if(state.menu >= 0){
- mesh_ship.p.yaw += _2pi/60/8;
- mesh_gear.p.yaw = mesh_ship.p.yaw;
- mesh_door.p.yaw = mesh_ship.p.yaw;
- for(unsigned i=0; i<4; ++i)
- asteroid_menu(i).p.yaw = mesh_ship.p.yaw;
- camera_new.x = menu_mesh_spacing * state.menu;
- scene_camera.x = camera_lpf(x);
- camera_old.x = scene_camera.x;
- asteroid_menu(0).p.z = (cfg.num_asteroids >= 1) ? 1.0f : -100.0f;
- asteroid_menu(1).p.z = (cfg.num_asteroids >= 2) ? 1.0f : -100.0f;
- asteroid_menu(2).p.z = (cfg.num_asteroids >= 3) ? 1.0f : -100.0f;
- asteroid_menu(3).p.z = (cfg.num_asteroids >= 4) ? 1.0f : -100.0f;
- //putting this in this code block technically causes a graphical glitch
- //where the framebuffer elements related to geometry gradually fade
- //out when rebinding controls, but i'll include it until something
- //inexplicably breaks, just because the effect looks so cool
- scene_wka.setAll(scene_ori);
- for(unsigned i=0; i<meshes_len; ++i)
- if(meshes[i]) sceneApplyTransform(meshes[i]);
- sceneApplyTransform(nullptr);
- //(to fix this, simply move the previous 4 lines out of this code block)
- }
- canvas->clear();
- sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
- #define text_margin (16/(CNV_DIV))
- text_box(CENTER_TEXT, text_margin, 0, WIN_TITLE);
- switch(state.menu){
- case MENU_QUIT : {
- //text_box(CENTER_TEXT, CENTER_TEXT, 0, "(there's supposed to be a\nspinning door here, but i\nhaven't modeled that yet)");
- text_box(CENTER_TEXT, -text_margin-1, 0,
- " \n- QUIT GAME >\n");
- } break;
- case MENU_PLAY : {
- text_box(CENTER_TEXT, -text_margin-1, 0,
- " \n< START GAME >\n");
- textf_box(CENTER_TEXT, -text_margin-1 - 27 - 8,
- "high score (%i asteroid%s): %.1f",
- cfg.num_asteroids, (cfg.num_asteroids!=1)?"s":"", cfg.high_scores[cfg.num_asteroids-1]);
- } break;
- case MENU_ASTEROIDS: {
- textf_box(CENTER_TEXT, -text_margin-1,
- " ^\n< # OF ASTEROIDS: %i >\n V", cfg.num_asteroids);
- textf_box(CENTER_TEXT, -text_margin-1 - 27 - 8,
- "high score: %.1f", cfg.high_scores[cfg.num_asteroids-1]);
- } break;
- case MENU_REBIND : {
- text_box(CENTER_TEXT, -text_margin-1, 0,
- " \n< REBIND CONTROLS -\n");
- } break;
- case MENU_REBINDING: {
- textf_box(CENTER_TEXT, CENTER_TEXT,
- "Press a key for \"%s\"\n(backspace will reset all bindings to their defaults!)",
- bind_names[state.which_rebind]);
- } break;
- default:;
- }
- canvas_present(16);
- }
- if(state.quit) goto _QUIT;
- asteroid_menu(0).p.scale = old_scale[0];
- asteroid_menu(1).p.scale = old_scale[1];
- asteroid_menu(2).p.scale = old_scale[2];
- asteroid_menu(3).p.scale = old_scale[3];
- while(!state.cursorIsTrapped){
- if(!handleEvents()) break;
- text_box(CENTER_TEXT, CENTER_TEXT, 0, "(click in the window to start)");
- canvas->present(16);
- }
- srand((unsigned)( SDL_GetTicks64() + (unsigned)(cfg.lastrand*10000) ));
- cfg.lastrand = randf();
- if(!state.quit) goto _GAME;
- /**********************************/ _QUIT: /**********************************/
- cfg_file = SDL_RWFromFile(CFG_FILENAME, "wb");
- if(!cfg_file) throw SDL_GetError();
- if(SDL_RWwrite(cfg_file, &cfg, 1, sizeof(cfg))<sizeof(cfg)) throw SDL_GetError();
- if(SDL_RWclose(cfg_file)<0) throw SDL_GetError();
- for(unsigned i=0; i<meshes_len; ++i)
- SAFE_DELETE(meshes[i]);
- return 0;
- /**********************************/ _GAME: /**********************************/
- state.score = 0.0f;
- _reset_game:
- state.skybox_bounds = skybox_bounds_formula;
- mesh_skybox.p.scale = state.skybox_bounds*2;
- mesh_gear.p.scale = 0.0f;
- mesh_door.p.scale = 0.0f;
- asteroid_menu(0).p.y = CLIP_FAR*2;
- asteroid_menu(1).p.y = CLIP_FAR*2;
- asteroid_menu(2).p.y = CLIP_FAR*2;
- asteroid_menu(3).p.y = CLIP_FAR*2;
- memory::set(&camera_old, 0, sizeof(camera_old));
- memory::set(&camera_cur, 0, sizeof(camera_cur));
- memory::set(&camera_new, 0, sizeof(camera_new));
- memory::set(&mesh_ship.p, 0, sizeof(mesh_ship.p));
- mesh_ship.p.scale = 1.0f;
- scene_camera.yaw = 0.0f;
- scene_camera.pitch = ship_camera_down_tilt;
- scene_camera.roll = 0.0f;
- scene_camera.x = 0.0f;
- scene_camera.y = ship_camera_y_offset;
- scene_camera.z = -ship_camera_distance;
- unsigned ship_offset = mesh_ship.verts_len;
- state.active_asteroids = 0;
- for(int i=0; i<asteroid_count; ++i){
- mesh_asteroid(i).p.y = CLIP_FAR*2;
- state.asteroids[i].active = false;
- }
- for(int i=0; i<cfg.num_asteroids; ++i)
- asteroidCreate(i);
- _out_of_game_loop: //jumped to for the purpose of forcefully breaking the loop
- while(!state.quit && state.menu == MENU_PLAYING){
- startTime = SDL_GetTicks64();
- if(!handleEvents()) break;
- if(!state.cursorIsTrapped){
- text_box(CENTER_TEXT,CENTER_TEXT, 0, "paused");
- canvas->present(16);
- continue;
- }
- bulletMoveAll();
- asteroidMoveAll();
- //move ship
- Vec3 moveVector(0.0f, 0.0f, 0.0f);
- if(state.pressed_right ) moveVector.x += ship_speed_x;
- if(state.pressed_left ) moveVector.x -= ship_speed_x;
- if(state.pressed_forward) moveVector.z += ship_speed_z;
- if(state.pressed_back ) moveVector.z -= ship_speed_z;
- if(state.pressed_up ) moveVector.y += ship_speed_y;
- if(state.pressed_down ) moveVector.y -= ship_speed_y;
- moveCamera(-moveVector.x, -moveVector.y, -moveVector.z);
- keepInBounds(camera_cur);
- //break asteroids that are touching any active bullets
- checkForBulletHits();
- //'win' condition; reset game (without resetting score!)
- if(state.active_asteroids == 0) goto _reset_game;
- //since camera_cur is technically a world offset, the actual
- //player's placement is the direct opposite of that world offset
- Location negative_cur;
- negative_cur.x = -camera_cur.x;
- negative_cur.y = -camera_cur.y;
- negative_cur.z = -camera_cur.z;
- //check if player should be dead
- for(unsigned a=0; a<asteroid_count; ++a){
- if(!state.asteroids[a].active) continue;
- //*0.37f instead of *0.5f to account for inconsistent geometry
- float collide_dist = 0.5f + asteroid_sizes[(int)state.asteroids[a].type]*0.37f;
- if(locDistance(negative_cur, mesh_asteroid(a).p) < collide_dist){
- asteroidDestroy(a); //a neat touch
- state.menu = MENU_DEAD;
- goto _out_of_game_loop;
- }
- }
- mesh_ship.p.roll *= ship_decay_multiplier_a;
- mesh_ship.p.pitch *= ship_decay_multiplier_a;
- scene_wka.setAll(scene_ori);
- for(unsigned i=1; i<meshes_len; ++i)
- if(meshes[i]) sceneApplyTransform(meshes[i]);
- //rotate all but the ship's verts
- translateWka(camera_cur, ship_offset, LOOP_END_MAX);
- rotateWka(camera_cur, ship_offset, LOOP_END_MAX);
- meshTransform(mesh_ship);
- sceneApplyTransform(nullptr);
- canvas->clear();
- sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
- canvas->renderFillRect(&crosshair, 0xffffffff);
- #define brr_width 20
- #define brr_height 40
- #define brr_height_b (int)( (1.0f-((float)(state.active_bullets)/bullet_count))*brr_height )
- SDL_Rect bullets_remaining_rect = {CNV_W-brr_width, CNV_H-brr_height,
- brr_width, brr_height};
- canvas->renderFillRectBordered(bullets_remaining_rect);
- bullets_remaining_rect.w -= 2;
- bullets_remaining_rect.h = MAX(brr_height_b-2, 0);
- bullets_remaining_rect.x += 1;
- bullets_remaining_rect.y = CNV_H-bullets_remaining_rect.h-1;
- canvas->renderFillRect(&bullets_remaining_rect, 0x00ff00);
- textf(4-brr_width/2, 3-brr_height/2, "%u", bullet_count-state.active_bullets);
- textf_box(0,0, "(backspace returns\nto the main menu)");
- textf_box(CENTER_TEXT,0, "score: %.1f", state.score);
- #ifdef _DEBUG
- textf_box(0,-10-1, "active bullets: %i", state.bullets[0].active+state.bullets[1].active+state.bullets[2].active+state.bullets[3].active);
- textf_box(0,-1, "active asteroids: %i", state.active_asteroids);
- #endif
- canvas_present(16);
- }
- mesh_ship.p.y = CLIP_FAR*2;
- while(!state.quit && state.menu == MENU_DEAD){
- startTime = SDL_GetTicks64();
- if(!handleEvents()) break;
- //uncomment this if i end up wanting to continue animating scene after death
- /*
- bulletMoveAll();
- asteroidMoveAll();
- checkForBulletHits();
- scene_wka.setAll(scene_ori);
- for(unsigned i=0; i<meshes_len; ++i)
- if(meshes[i]) sceneApplyTransform(meshes[i]);
- translateWka(camera_cur, 0, LOOP_END_MAX);
- rotateWka(camera_cur, 0, LOOP_END_MAX);
- sceneApplyTransform(nullptr);
- */
- canvas->clear();
- //same visual bug with rebinding is utilized again here
- sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
- if(state.score <= cfg.high_scores[cfg.num_asteroids-1]){
- textf_box(CENTER_TEXT, CENTER_TEXT, "score: %.1f", state.score);
- } else {
- textf_box(CENTER_TEXT, CENTER_TEXT, "score: %.1f (new high score!)", state.score);
- }
- canvas_present(16);
- }
- //note: this will in theory save the high score,
- //even in the event of something like alt+f4 being pressed!
- if(state.score > cfg.high_scores[cfg.num_asteroids-1])
- cfg.high_scores[cfg.num_asteroids-1] = state.score;
- if(state.quit) goto _QUIT;
- else goto _MENU;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement