Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"kw32g\src\globals_audioManager.cpp":
- #include <globals.hpp>
- #include <tile.hpp>
- using namespace kit;
- #define AM_LOOP_WAIT 0050 //in milliseconds
- #define MUS_VOLUME 0.030f //default volume for music modules
- #define AMB_VOLUME 0.015f //default volume for ambient tracks
- #define AMB_FADE 1.000f //fade in/out of 1000ms
- //turbo janky setup because it turns out my mutexes
- //do not work at all across multiple threads (which makes them useless >:( )
- //(probably the reason i can't call gl_snd's
- //deconstructor without a crash!)
- #define AM_LOOP_START { \
- while(gl_audioManager_occ_sfx) time::sleep(0); \
- gl_audioManager_occ_thr = true; }
- #define AM_LOOP_END { \
- gl_audioManager_occ_thr = false; \
- time::sleep(AM_LOOP_WAIT); }
- #define STOPPED (0xFFFF)
- #define FAILURE (-1)
- //using gl_fstr outside the main thread causes conflicts, so here's another fstr
- FStr am_fstr;
- static inline void musicLoad(u16 id){
- try {
- gl_snd->musicLoadModule(am_fstr.fmt("dat/music/%s",gl_music[id]));
- } catch(const char* errorText){
- #ifdef _DEBUG
- _printf("ERROR LOADING MUSIC \"%s\": \"%s\"\n", am_fstr.ptr(), errorText);
- #else
- FStr am_fstr2; //2 formats are needed for this, so create yet another fstr
- am_fstr2.fmt("ERROR LOADING MUSIC \"%s\": \"%s\"", am_fstr.ptr(), errorText);
- showMessageBox(am_fstr2.ptr(),
- "NON-FATAL EXCEPTION OCCURRED! COMPLAIN TO THE DEV! (lol)",
- MSGBOX_ICN_ERROR);
- #endif
- }
- }
- //aliases & other variables
- #define musicRelease gl_snd->musicReleaseModule
- #define musicStop gl_snd->musicStop
- #define musicStart gl_snd->musicStart
- #define music_playing gl_snd->musicIsPlaying() //() intentionally used here
- #define music_id gl_scene.music
- static u16 music_id_prev = STOPPED;
- static bool music_stopping = false;
- #define startVol 0.00001f //can't be exactly 0 or else it stops immediately lol
- static inline s32 ambiencePlay(u16 id){
- s32 new_track = gl_snd->sfxPlay(gl_ambience[id], startVol,startVol);
- if(new_track != FAILURE)
- gl_snd->sfxSetVolumeDelta(new_track, AMB_FADE, AMB_FADE);
- return new_track;
- }
- //make sure not to never use SoundEffect here,
- //as that will lock up the audioManager thread!
- //(also, when stopping an sfx track to fit a new
- //ambience track, make sure to use stopForced!)
- #define sfxStopForced gl_snd->sfxStopForced
- #define ambienceFadeout(_track) gl_snd->sfxSetVolumeDelta(_track, -(AMB_FADE),-(AMB_FADE))
- #define ambience_a_id gl_scene.ambience_a
- #define ambience_b_id gl_scene.ambience_b
- static u16 ambience_a_id_prev = STOPPED;
- static u16 ambience_b_id_prev = STOPPED;
- //'which track is ambience_x assigned to?'
- static s32 ambience_a_track = -1;
- static s32 ambience_b_track = -1;
- static inline void update_music(){
- //if music isn't supposed to change at all right now
- //(including if music_id is the current one)
- if(!music_id || music_id == music_id_prev) return;
- if(!music_stopping){
- music_stopping = true;
- if(music_playing) musicStop();
- } else if(!music_playing){
- music_stopping = false;
- music_id_prev = music_id;
- musicRelease();
- //if music is supposed to change rather than completely stop
- if(music_id != STOPPED){
- musicLoad(music_id);
- musicStart();
- }
- }
- }
- #define ambience_id (*ambience_id_ptr)
- #define ambience_id_prev (*ambience_id_prev_ptr)
- #define ambience_track (*ambience_track_ptr)
- //+2 instead of +1, because there are 2 ambience tracks
- #define increment_ambience_track() ( ambience_track = (ambience_track+2)%SND_TRACK_COUNT )
- void update_ambience(bool update_a_instead_of_b){ //(not inlined)
- u16* ambience_id_ptr;
- u16* ambience_id_prev_ptr;
- s32* ambience_track_ptr;
- if(update_a_instead_of_b){
- ambience_id_ptr = &ambience_a_id;
- ambience_id_prev_ptr = &ambience_a_id_prev;
- ambience_track_ptr = &ambience_a_track;
- } else {
- ambience_id_ptr = &ambience_b_id;
- ambience_id_prev_ptr = &ambience_b_id_prev;
- ambience_track_ptr = &ambience_b_track;
- }
- //if ambience isn't supposed to change at all right now
- //(including if ambience_id is the current one)
- if(!ambience_id || ambience_id == ambience_id_prev) return;
- //fading out causes a track to stop automatically when its volume reaches 0,
- //so it's the most smooth way of stopping a track
- //(this will stop any sound effect that happens to be in this track,
- //whether or not it's an ambience track at the time! this should be
- //taken care of by the "ambience_track = -1", but jsyk yk?)
- if(ambience_track > -1) ambienceFadeout(ambience_track);
- if(ambience_id != STOPPED){
- s32 new_track = ambiencePlay(ambience_id);
- if(new_track == FAILURE){ //all tracks are occupied
- increment_ambience_track(); // =(t+1)%track_count
- sfxStopForced(ambience_track); //forcefully make room for ambient track
- //it should be impossible for it to fail this time (should...)
- ambience_track = ambiencePlay(ambience_id);
- } else { //track sucessfully started playing
- ambience_track = new_track;
- }
- } else {
- ambience_track = -1; //mark ambience as stopped
- }
- ambience_id_prev = ambience_id;
- }
- #define UPDATE_A true
- #define UPDATE_B false
- s32 audioManager(void* userdata){
- //libxmp's nearest-neighbor interpolation sounds fugly,
- //so force linear interpolation to be used instead
- gl_snd->musicSetUseNearest(false);
- gl_snd->musicSetVolumeForced(MUS_VOLUME, MUS_VOLUME);
- //this forces the module to loop
- //gl_snd->musicSetCheckLoop(false);
- //set the master volume for the ambience tracks specifically
- for(u32 i=1; i<(gl_ambience_len+1); ++i){
- gl_ambience[i]->volumeL = AMB_VOLUME;
- gl_ambience[i]->volumeR = AMB_VOLUME;
- }
- while(!gl_audioManager_exit){
- AM_LOOP_START
- update_music();
- update_ambience(UPDATE_A);
- update_ambience(UPDATE_B);
- AM_LOOP_END
- }
- return 0;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"kw32g\src\main.cpp":
- #include <globals.hpp>
- #include <player.hpp>
- #include <tile.hpp>
- #include <object.hpp>
- #include <save.hpp>
- #include <stdio.h>
- #include <stdlib.h>
- using namespace kit;
- /*
- might want to eventually refactor how edge transitions occur, as instead of
- teleporting to a fixed point once an edge is crossed, maybe it should be done
- as an offset to the current edge position, or the transition is handled
- within the move function itself at the exact point the edge is crossed
- keep track of which scenes are swapped so they can be reswapped
- refactor player movement to improve game feel
- make object that confuses the player for a certain number of ticks
- be able to change footstep sounds based on the tile type
- have area only accessible by run-jumping while teleporting
- add in cutscene image slideshow things
- be able to change scene after cutscene
- create player animation frame override
- add customizable friction coefficients for tilesets
- make sure to not use the result of fstr->fmt as a parameter to another call to fstr->fmt
- create vel_m to separate player movement velocity and normal velocity
- */
- int gameMain(int argc, char** argv){
- gl_player.sfx_footstep = gl_sfx[1];
- gl_player.sfx_jumping = gl_sfx[2];
- gl_player.sfx_landing = gl_sfx[3];
- attemptReset(true);
- bool run = true;
- f64 timeStart = time::getUptime();
- while(run){
- gl_frameTimer->setTimer((1.0/60)/TPF);
- resetEnvFlags();
- clearControlStates();
- if(!handleEvents()) break;
- if(!gl_player.dying){
- gl_player.vel.y += GRAVITY;
- gl_player.update();
- handleEdgeWrap();
- }
- drawStuff_and_processObjects();
- DBG_TXT( 0, ".pos = {%i, %i}", gl_player.pos.x, gl_player.pos.y);
- DBG_TXT( 1, ".vel = {%6.2f, %6.2f}", gl_player.vel.x, gl_player.vel.y);
- DBG_TXT( 2, ".acc = {%6.2f, %6.2f}", gl_player.acc.x, gl_player.acc.y);
- DBG_TXT( 3, ".ticksInAir = %u", gl_player.ticksInAir);
- //DBG_TXT( 4, ".runningState = %6.4f", gl_player.runningState);
- //DBG_TXT( 5, ".scale = %.2f", gl_player.scale);
- //DBG_TXT( 6, ".facingRight = %s", boolStr(gl_player.facingRight));
- //DBG_TXT( 7, ".enforceMaxVel = %s", boolStr(gl_player.enforceMaxVel));
- //DBG_TXT( 8, ".confused = %s", boolStr(gl_player.confused));
- //DBG_TXT( 9, ".first_jmp = %s", boolStr(gl_player.first_jmp));
- //DBG_TXT(10, ".second_jmp = %s", boolStr(gl_player.second_jmp));
- //DBG_TXT(11, ".has_dbljmp = %s", boolStr(gl_player.has_dbljmp));
- DBG_TXT( 5, "tick latency = %.2fms", (time::getUptime()-timeStart)*1000);
- DBG_TXT( 6, "scene id = %u", gl_scene.scene);
- if(gl_death_prog < DEATH_PROG_MAX) deathAnim();
- if(!handleEscExit()) break;
- gl_win->present(true);
- gl_frameTimer->wait();
- timeStart = time::getUptime();
- ++gl_tickCounter;
- }
- return 0;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"kw32g\src\object.cpp":
- #include <object.hpp>
- #include <player.hpp>
- #include <tile.hpp>
- #include <save.hpp>
- using namespace kit;
- #define GET_OBJ(_type) _type* obj = (_type*)_obj_a
- #define GET_DST(_obj_ptr) { _obj_ptr->x, _obj_ptr->y, _obj_ptr->size.x, _obj_ptr->size.y }
- #define OBJIMG(_index) gl_objImg[_index]
- #define OBJIMG_LEVER_WALL OBJIMG( 1) // 2x2, ??x??px
- #define OBJIMG_ABILITY_SHRINK OBJIMG( 2) //24x1, ??x??px, 13 ticks (~9.2fps)
- #define OBJIMG_ABILITY_DBLJMP OBJIMG( 3) //24x1, ??x??px, 13 ticks (~9.2fps)
- #define OBJIMG_ABILITY_SPEED OBJIMG( 4) //24x1, ??x??px, 13 ticks (~9.2fps)
- #define OBJIMG_ABILITY_REMOVER OBJIMG( 5) // 3x1, ??x??px
- #define OBJIMG_SIGNPOST_WOOD OBJIMG( 6) // 1x1, ??x??px
- #define OBJIMG_EASTER_EGG OBJIMG( 7) //12x1, ??x??px, 8 ticks (15 fps)
- #define OBJIMG_TELEPORTER_BACK OBJIMG( 8) //16x1, ??x??px, 8 ticks (15 fps)
- #define OBJIMG_TELEPORTER_FRONT OBJIMG( 9) //16x1, ??x??px, 8 ticks (15 fps)
- #define OBJIMG_DEATH_BALL OBJIMG(10) //17x1, 22x22px, 8 ticks (15 fps)
- #define TXTLINE(_index) gl_text_lines[_index]
- //copy original state of object data to the active scene
- void loadObjects(bool forced, u16 scene_id){
- if(!scene_id && !gl_scene.scene)
- throw "gl_scene.scene == 0 (loadScene(>0) before calling loadObjects()!)";
- if(!scene_id) scene_id = gl_scene.scene;
- if(scene_id > gl_scenes_len) throw "scene_id > gl_scenes_len";
- SceneDescriptor* scene_current = gl_scenes[scene_id];
- Object* objsCache = gl_objsCache[scene_id];
- Object* objs = scene_current->objs;
- u16 objs_len = scene_current->objs_len;
- if(!forced){ //only copy object data whose persistence flag is false
- for(u32 i=0; i<objs_len; ++i){
- if(!objsCache[i].persistent) objsCache[i] = objs[i];
- }
- } else { //otherwise, copy all objects in scene
- for(u32 i=0; i<objs_len; ++i){
- objsCache[i] = objs[i];
- }
- }
- }
- #define CHECK_TYPE_NULL 0
- bool processObjects(bool in_front, bool render_only){
- bool scene_changed = false;
- Object* objs = gl_objsCache[gl_scene.scene];
- u16 objs_len = gl_scenes[gl_scene.scene]->objs_len;
- Object* obj;
- #if CHECK_TYPE_NULL == 1
- #define TYPE_CHECK && obj->type != 0
- #else
- #define TYPE_CHECK
- #endif
- if(!in_front){
- for(u32 i=0; i<objs_len; ++i){
- obj = &objs[i];
- if(!obj->in_front /*&&*/ TYPE_CHECK)
- scene_changed |= obj->update(obj, render_only);
- }
- } else {
- for(u32 i=0; i<objs_len; ++i){
- obj = &objs[i];
- if(obj->in_front /*&&*/ TYPE_CHECK)
- scene_changed |= obj->update(obj, render_only);
- }
- }
- #undef TYPE_CHECK
- if(!render_only) return scene_changed;
- else return false;
- }
- bool obj_1lever(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_1lever); //obj = _obj_a
- shape::rect rect_dst = GET_DST(_obj_a);
- shape::rect rect_src(0,0, 8,24);
- bool scene_changed = false;
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- obj->img = OBJIMG_LEVER_WALL;
- if(!obj->sfx_id){ //use default sound effect
- obj->sfx = SFXPTR_ACTIVATE_1;
- } else if(obj->sfx_id <= gl_sfx_len){ //use specified sound effect
- obj->sfx = SFXPTR(obj->sfx_id);
- } else { //no sound effect found
- obj->sfx = nullptr;
- //tbd: warn about nonexistent sound effect
- }
- }
- //if player is touching the object
- if(rects_overlapping(gl_player.getRect(), rect_dst)){
- rect_src.y = 24; //highlighted
- //if player activates the lever
- if(!render_only && CTRLSTATE_GET(inst.down_p)){
- swapScene(obj->scene_old, obj->scene_new);
- obj->flipped ^= 1;
- scene_changed = true;
- SFXPTR_PLAY(obj->sfx);
- }
- }
- if(obj->flipped) rect_src.x = 8; //lever points down
- if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, 0xff00ff);
- return scene_changed;
- }
- bool obj_ability(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_ability); //obj = _obj_a
- shape::rect rect_dst = GET_DST(_obj_a);
- shape::rect rect_src(0,0, 24,24);
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- obj->frameCounter = 23; //will roll over to 0 this iteration
- //this implementation is quite strange but whatever it works like a charm
- switch(obj->which){
- case 0 : obj->img = OBJIMG_ABILITY_SHRINK;
- obj->has_ability = &gl_player.has_shrink; break;
- case 1 : obj->img = OBJIMG_ABILITY_DBLJMP;
- obj->has_ability = &gl_player.has_dbljmp; break;
- case 2 : obj->img = OBJIMG_ABILITY_SPEED;
- obj->has_ability = &gl_player.has_speed; break;
- default: obj->img = gl_tileset_missing;
- obj->has_ability = nullptr;
- }
- }
- //if player is touching the object (and everything else is valid)
- if(!render_only) //&&
- if(obj->has_ability != nullptr && !(*obj->has_ability) &&
- rects_overlapping(gl_player.getRect(), rect_dst))
- {
- *obj->has_ability = true;
- SFXPTR_PLAY(SFXPTR_ABILITY_PICKUP);
- }
- //pick which frame in the animation to use
- if(!render_only && obj->has_ability != nullptr){
- //increment animation's frame counter every 13 ticks, which makes for ~9.2fps
- if(!(gl_tickCounter%13)) obj->frameCounter = (obj->frameCounter+1)%24;
- if(*obj->has_ability) rect_src.y = 24; //otherwise it'll remain 0
- }
- rect_src.x = 24 * obj->frameCounter;
- //if the has_ability pointer is invalid, disable magenta transparency, since
- //the 'missing tile' bitmap uses the color magenta
- color::ARGB t_color = (obj->has_ability != nullptr) ? 0xff00ff : 0x80000000;
- if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, t_color);
- return false;
- }
- bool obj_ability_remover(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_ability_remover); //obj = _obj_a
- shape::rect rect_dst = GET_DST(_obj_a);
- shape::rect rect_src(24*obj->which,0, 24,24);
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- obj->img = OBJIMG_ABILITY_REMOVER;
- if(!obj->img) obj->img = gl_tileset_missing; //this shouldn't happen ever
- switch(obj->which){
- case 0 : obj->has_ability = &gl_player.has_shrink; break;
- case 1 : obj->has_ability = &gl_player.has_dbljmp; break;
- case 2 : obj->has_ability = &gl_player.has_speed; break;
- default: obj->has_ability = nullptr;
- }
- }
- //if player is touching the object (and everything else is valid)
- if(!render_only) //&&
- if(obj->has_ability != nullptr && (*obj->has_ability) &&
- rects_overlapping(gl_player.getRect(), rect_dst))
- {
- *obj->has_ability = false;
- SFXPTR_PLAY(SFXPTR_ABILITY_REMOVED);
- if(!obj->dontReset)
- switch(obj->which){
- //(case 0 should only fail if i place this object in a subtile-wide space)
- case 0 : gl_player.setScale(2.0f); break;
- //case 1 : //(not used)
- case 2 : gl_player.enforceMaxVel = true; break;
- default:;
- }
- }
- //if the has_ability pointer is invalid, disable magenta transparency, since
- //the 'missing tile' bitmap uses the color magenta
- color::ARGB t_color = (obj->has_ability != nullptr) ? 0xff00ff : 0x80000000;
- if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, t_color);
- return false;
- }
- bool obj_generic_sprite(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_generic_sprite); //obj = _obj_a
- shape::rect rect_dst = GET_DST(_obj_a);
- shape::rect rect_src(0,0, obj->w,obj->h);
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- //will roll over to 0 this iteration
- //(MAX is used here, otherwise it underflows to 255)
- obj->frameCounter = MAX(obj->numFrames,1)-1;
- if(obj->which <= gl_objImg_len) obj->img = OBJIMG(obj->which);
- if(!obj->img){
- //if i somehow have more than 65k object images,
- //i have bigger problems to worry about
- obj->which = KIT_U16_MAX;
- obj->img = gl_tileset_missing;
- }
- //if w/h are 0, then default the src size to the dst size
- if(!obj->w){
- obj->w = (u8)_obj_a->size.x;
- rect_src.w = obj->w;
- }
- if(!obj->h){
- obj->h = (u8)_obj_a->size.y;
- rect_src.h = obj->h;
- }
- }
- //pick which frame in the animation to use
- if(!render_only && obj->numFrames > 1){
- //increment animation's frame counter every tick_delay ticks
- if(!(gl_tickCounter%obj->tick_delay))
- obj->frameCounter = (obj->frameCounter+1)%obj->numFrames;
- //(which horizontal slot in the spritesheet to use, technically)
- rect_src.x = rect_src.w * obj->frameCounter;
- }
- color::ARGB t_color = (obj->which != KIT_U16_MAX) ? 0xff00ff : 0x80000000;
- if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, t_color);
- return false;
- }
- bool obj_msgbox(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_msgbox); //obj = _obj_a
- shape::rect rect_collider = GET_DST(_obj_a);
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- _obj_a->in_front = 1; //this object is always in front
- obj->init = true;
- if(obj->which <= gl_text_lines_len) obj->str = TXTLINE(obj->which);
- if(!obj->str) obj->str = TXTLINE(0); // = "<INVALID TEXT ID>"
- obj->str_size = get_text_size(obj->str);
- //if both pos_x&y are 0, draw text box just above the msgbox collider
- if(!obj->pos_x && !obj->pos_y){
- obj->pos_x = _obj_a->x + _obj_a->size.x/2;
- obj->pos_y = _obj_a->y - obj->str_size.y/2 - 10;
- } else {
- //otherwise, center the axis that is 0, if any
- if( !obj->pos_x) obj->pos_x = CANVSIZ_X/2;
- else if(!obj->pos_y) obj->pos_y = CANVSIZ_Y/2;
- }
- }
- if(obj->show_always ||
- rects_overlapping(gl_player.getRect(), rect_collider))
- {
- drawTextBox(obj->pos_x, obj->pos_y, obj->str, obj->str_size);
- }
- return false;
- }
- bool obj_save_interface(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_save_interface); //obj = _obj_a
- shape::rect rect_collider = GET_DST(_obj_a);
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- _obj_a->in_front = 1; //this object is always in front
- obj->init = true;
- //obj->touching = false; //might not need to set this
- obj->box_height = 0;
- }
- if(!render_only)
- if(rects_overlapping(gl_player.getRect(), rect_collider)){
- if((!obj->touching && obj->passive) || CTRLSTATE_GET(inst.down_p)){
- obj->touching = true;
- switch(obj->which){
- case 0 : {
- if(saveRead()){
- SFXPTR_PLAY(SFXPTR_DLELELE);
- return true;
- } else if(!obj->passive){
- SFXPTR_PLAY(SFXPTR_NOPE_1);
- }
- } break;
- case 1 : {
- if(!gl_saveRead_called){
- saveWrite();
- SFXPTR_PLAY(SFXPTR_FWSHWSHWSH);
- if(!obj->passive) obj->box_height = rect_collider.h;
- }
- } break;
- case 2 : {
- saveWipe();
- SFXPTR_PLAY(SFXPTR_DLELELE);
- } break;
- default:
- _printf("WARNING: save interface object has invalid .which member!");
- }
- }
- } else {
- obj->touching = false;
- }
- if(obj->box_height > 0){
- shape::rect rect_visual = rect_collider;
- rect_visual.h = obj->box_height;
- rect_visual.y += rect_collider.h - rect_visual.h;
- gl_win->drawRectangles(&rect_visual, 1, 0xffffff);
- drawTextBox(CANVSIZ_X/2, CANVSIZ_Y/2, "SAVING...");
- if(!render_only) --obj->box_height;
- }
- return false;
- }
- bool obj_teleporter(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_teleporter); //obj = _obj_a
- shape::rect rect_collider = GET_DST(_obj_a);
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- }
- if(!render_only)
- if(rects_overlapping(gl_player.getRect(), rect_collider)){
- if((!obj->touching && obj->passive) || CTRLSTATE_GET(inst.down_p)){
- obj->touching = true;
- SFXPTR_PLAY(SFXPTR_DLELELE);
- gl_player.pos.x = obj->pos_x;
- gl_player.pos.y = obj->pos_y;
- if(obj->scene){
- loadScene(obj->scene);
- return true;
- }
- }
- } else {
- obj->touching = false;
- }
- return false;
- }
- bool obj_death_zone(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_death_zone); //obj = _obj_a
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- obj->collider.x = _obj_a->x;
- obj->collider.y = _obj_a->y;
- obj->collider.w = _obj_a->size.x;
- obj->collider.h = _obj_a->size.y;
- }
- if(!render_only && !gl_player.dying &&
- rects_overlapping(gl_player.getRect(), obj->collider))
- {
- gl_player.kill();
- }
- return false;
- }
- //note: if i add add sfx to this, make sure not to
- //trigger it at the first waypoint, otherwise it
- //would occur the moment the scene loads!
- bool obj_death_ball(Object* _obj_a, bool render_only){
- GET_OBJ(_obj_death_ball); //obj = _obj_a
- if(!obj->init){
- _obj_a->persistent = 1; //this object is always persistent
- obj->init = true;
- if(obj->speed==0.0f) obj->speed = 1.0f/120; //a->b in ~1 second
- else if(obj->speed<0.0f) obj->speed = -obj->speed;
- if(!obj->a_x) obj->a_x = _obj_a->x;
- if(!obj->a_y) obj->a_y = _obj_a->y;
- obj->frameCounter = 16; //will roll over once this hits 17
- obj->img = OBJIMG_DEATH_BALL;
- }
- s16 a_x = obj->a_x;
- s16 a_y = obj->a_y;
- s16 b_x = obj->b_x;
- s16 b_y = obj->b_y;
- f32 t_value = obj->t_value;
- shape::rect rect_dst;
- rect_dst.w = _obj_a->size.x;
- rect_dst.h = _obj_a->size.y;
- if(t_value < 1.0f){ //a->b
- rect_dst.x = (s32)LERP(a_x, b_x, t_value );
- rect_dst.y = (s32)LERP(a_y, b_y, t_value );
- } else { // >= 1.0f; b->a
- rect_dst.x = (s32)LERP(b_x, a_x, t_value-1.0f);
- rect_dst.y = (s32)LERP(b_y, a_y, t_value-1.0f);
- }
- if(!render_only){
- shape::rect rect_player = gl_player.getRect();
- if(!gl_player.dying &&
- rects_overlapping(rect_player, rect_dst))
- {
- gl_player.kill();
- }
- t_value += obj->speed;
- obj->t_value = fmodf(t_value, 2.0f);
- if(!(gl_tickCounter%7)){
- obj->frameCounter += 1;
- obj->frameCounter %= 17;
- }
- }
- shape::rect rect_src(obj->frameCounter*22, 0, 22, 22);
- if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, 0xff00ff);
- return false;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"kw32g\src\player.cpp":
- #include <player.hpp>
- #include <tile.hpp>
- #include <math.h>
- using namespace kit;
- bool Player::setScale(f32 scale_new){
- f32 scale_old = scale;
- scale = MAX(scale_new, 0.2f); //for a minimum of 2x2 pixels
- shape::rect player_rect = getRect();
- shape::point delta;
- //player was probably pushed into the floor if the scale increased,
- //so attempt to move the player out of any potential subtiles
- if(subtiles_overlapping(player_rect, &delta))
- player_rect += delta;
- //if the previous movement didn't result in the
- //player entering empty space, return false
- if(subtiles_overlapping(player_rect, nullptr)){
- scale = scale_old; //(revert the scale back to what it was originally too)
- return false;
- } else { //otherwise, apply those movement changes to pos, and return true
- pos += delta;
- return true;
- }
- }
- #define SPRSHEET_ADJUST(_v) ((_v)*(8+1)) //8px +1 for one pixel of spacing
- shape::rect Player::blit(bool only_return_src_rect){
- shape::rect src(0,0, 8,8);
- if(confused ) src.y += SPRSHEET_ADJUST(1);
- if(!facingRight) src.y += SPRSHEET_ADJUST(2);
- if(!only_return_src_rect &&
- (!visible || scale<=0.0f))
- {
- return src;
- }
- shape::rect dst = getRect();
- if(MID_AIR){ //mid-air
- if(fabsf(vel.x) > PLAYER_NEUTRAL){ //going fast horizontally
- if(vel.y<=0) src.x = SPRSHEET_ADJUST(2); //-Y; back leg extended
- else src.x = SPRSHEET_ADJUST(8); //+Y; front leg extended
- } else { //going slow (or not at all) horizontally
- if( vel.y <-PLAYER_NEUTRAL) src.x = SPRSHEET_ADJUST(1); //-Y; back leg down
- else if(vel.y > PLAYER_NEUTRAL) src.x = SPRSHEET_ADJUST(4); //+Y; front leg down
- else src.x = SPRSHEET_ADJUST(7); //0Y; both legs up
- }
- } else { //on the ground
- if(vel.x < 0 && acc.x > 0){ //slowing down while moving left
- if(fabsf(vel.x) > PLAYER_NEUTRAL){ //going fast horizontally
- if(facingRight) src.x = SPRSHEET_ADJUST(2); //back leg extended
- else src.x = SPRSHEET_ADJUST(8); //front leg extended
- } else { //going slow (or not at all) horizontally
- if(facingRight) src.x = SPRSHEET_ADJUST(1); //back leg down
- else src.x = SPRSHEET_ADJUST(4); //front leg down
- }
- } else if(vel.x > 0 && acc.x < 0){ //slowing down while moving right
- if(fabsf(vel.x) > PLAYER_NEUTRAL){ //going fast horizontally
- if(facingRight) src.x = SPRSHEET_ADJUST(8); //front leg extended
- else src.x = SPRSHEET_ADJUST(2); //back leg extended
- } else { //going slow (or not at all) horizontally
- if(facingRight) src.x = SPRSHEET_ADJUST(4); //front leg down
- else src.x = SPRSHEET_ADJUST(1); //back leg down
- }
- } else if(fabsf(vel.x) > PLAYER_NEUTRAL){ //moving forward
- src.x = SPRSHEET_ADJUST(1 + RND(runningState)%6);
- } else if(acc.x < 0){ //standing still while accelerating left
- if(facingRight) src.x = SPRSHEET_ADJUST(4); //front leg down
- else src.x = SPRSHEET_ADJUST(1); //back leg down
- } else if(acc.x > 0){ //standing still while accelerating right
- if(facingRight) src.x = SPRSHEET_ADJUST(1); //back leg down
- else src.x = SPRSHEET_ADJUST(4); //front leg down
- } else { //standing still without acceleration
- src.x = SPRSHEET_ADJUST(0); //technically redundant, but left here for clarity
- }
- }
- //if enforceMaxVel is false, put a kind of highlight effect onto the player
- if(!enforceMaxVel && !only_return_src_rect){
- shape::rect highlight_dst = dst;
- shape::rect highlight_src = src;
- highlight_dst.x -= 1;
- highlight_dst.y -= 1;
- highlight_dst.w += 2;
- highlight_dst.h += 2;
- highlight_src.y += SPRSHEET_ADJUST(4);
- gl_spritesheetPlayer->blitRect(&highlight_dst, &highlight_src, 0xff00ff);
- }
- //0xff00ff for magenta as the transparency color
- if(!only_return_src_rect)
- gl_spritesheetPlayer->blitRect(&dst, &src, 0xff00ff);
- return src;
- }
- //acc, visible, and confused are not modified here
- void Player::update(){
- if(dying) return;
- if(going_left^going_right){
- if( going_left ) acc.x = -PLAYER_SPEED;
- else if(going_right) acc.x = PLAYER_SPEED;
- if(confused) acc.x = -acc.x;
- } else {
- acc.x = 0.0f;
- }
- vel.x += (MID_AIR) ? acc.x*PLAYER_AIR_FRICTION : acc.x;
- vel.y += acc.y;
- if(enforceMaxVel){
- vel.x = CLAMP(vel.x, -VELX_MAX, VELX_MAX);
- vel.y = CLAMP(vel.y, -VELY_MAX, VELY_MAX);
- }
- {
- shape::rect new_rect = move(vel.x, vel.y);
- shape::rect collider_ceiling = new_rect;
- shape::rect collider_floor = new_rect;
- shape::rect collider_left = new_rect;
- shape::rect collider_right = new_rect;
- collider_ceiling.y -= 1;
- collider_ceiling.h = 1;
- collider_floor.y += collider_floor.h;
- collider_floor.h = 1;
- if(vel.y<0.0f && subtiles_overlapping(collider_ceiling)){
- vel.y = fabsf(vel.y)/2;
- ++ticksInAir;
- } else if(vel.y>0.0f && subtiles_overlapping(collider_floor)){
- if(sfx_landing){
- sfx_landing->volL = (fabsf(vel.y)/VELY_MAX)*PLAYER_LANDING_VOLUME;
- sfx_landing->volR = sfx_landing->volL;
- play_sfx_landing(ticksInAir);
- }
- if(ticksInAir) runningState = 2.5f;
- ticksInAir = 0;
- first_jmp = false;
- second_jmp = false;
- vel.y = 0.0f;
- } else {
- ++ticksInAir;
- }
- collider_left.x -= 1;
- collider_left.w = 1;
- collider_right.x += collider_right.w;
- collider_right.w = 1;
- if(vel.x<0.0f && subtiles_overlapping(collider_left ) ||
- vel.x>0.0f && subtiles_overlapping(collider_right) )
- {
- vel.x = 0.0f;
- runningState = 0.0f;
- }
- }
- //manage horizontal velocity
- {
- if(fabsf(vel.x)<0.05f && acc.x==0) vel.x = 0.0f;
- //if on ground while moving horizontally
- if(ticksInAir <= 1 && vel.x != 0){
- facingRight = vel.x > 0;
- if(ticksInAir <= 1 && acc.x == 0){
- vel.x -= (vel.x>0) ? PLAYER_SPEED*PLAYER_GND_FRICTION
- : -PLAYER_SPEED*PLAYER_GND_FRICTION;
- }
- }
- }
- //handle incrementing run animations
- {
- f32 prevRunningState = runningState;
- if(fabsf(vel.x) > PLAYER_NEUTRAL) runningState += fabsf(vel.x)*PLAYER_RUN_MUL;
- else runningState = 0.0f;
- runningState = fmodf(fabsf(runningState), 6.0f);
- //used to indicate that a foot step sound effect should play
- //(1.5 instead of 2, since 1.5 would round up to integer state 2,
- //which is the actual moment that the foot would reach the ground)
- if(prevRunningState < 1.5f && runningState >= 1.5f && !MID_AIR)
- if((vel.x < 0.0f) == (acc.x < 0.0f)){
- play_sfx_footstep();
- }
- }
- }
- shape::rect Player::move(f32 deltaX, f32 deltaY){
- rem.x += CLAMP(deltaX, -CANVSIZ_X,CANVSIZ_X);
- rem.y += CLAMP(deltaY, -CANVSIZ_Y,CANVSIZ_Y);
- shape::point delta(RND(rem.x), RND(rem.y));
- if(!delta.x && !delta.y) return getRect();
- rem.x -= delta.x;
- rem.y -= delta.y;
- shape::rect current = getRect();
- shape::rect end = current;
- end += delta;
- shape::point newpos(current.x, current.y);
- //do a bresenham line to find the exact point of collision, before setting
- //pos to that (minus 1 step assuming a collision actually occurred)
- s32 d_x = abs(delta.x);
- s32 d_y = -abs(delta.y);
- s32 s_x = (delta.x >= 0) ? 1 : -1;
- s32 s_y = (delta.y >= 0) ? 1 : -1;
- s32 e_1 = d_x + d_y;
- while(true){
- newpos.x = current.x; //(assumes that player isn't colliding
- newpos.y = current.y; //with any subtiles initially)
- if(current.x == end.x && current.y == end.y) break;
- s32 e_2 = e_1<<1;
- if(e_2 >= d_y){
- if(current.x == end.x) break;
- e_1 += d_y;
- current.x += s_x;
- }
- if(e_2 <= d_x){
- if(current.y == end.y) break;
- e_1 += d_x;
- current.y += s_y;
- }
- if(subtiles_overlapping(current)) break;
- }
- pos.x = newpos.x + current.w/2;
- pos.y = newpos.y + current.h/2;
- return getRect();
- }
- void Player::kill(){
- if(dying) return;
- SFXPTR_PLAY(SFXPTR_DEATH);
- visible = false;
- dying = true;
- //this will reset the death animation effect,
- //which will run now that gl_player.dying is true
- gl_death_prog = 0.0f;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement