Advertisement
Kitomas

things changed in platformer 2024-08-02

Aug 2nd, 2024
243
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.79 KB | None | 0 0
  1. #include <player.hpp>
  2. #include <tile.hpp>
  3.  
  4. #include <math.h>
  5.  
  6. using namespace kit;
  7.  
  8.  
  9.  
  10.  
  11.  
  12. shape::fpoint curve_point(0.75f, 0.05f);
  13. f32 hvel_speed = .15;
  14.  
  15. #define INTERP_FPOINT(_a, _b, _t) \
  16.   shape::fpoint( LERP((_a).x,(_b).x,(_t)), LERP((_a).y,(_b).y,(_t)) )
  17.  
  18. shape::fpoint movement_bezier(f32 t){
  19.   shape::fpoint p_b = curve_point;
  20.  
  21.   shape::fpoint p_a(0.0f      , 0.0f      );
  22.   shape::fpoint p_c(1.0f-p_b.x, 1.0f-p_b.y);
  23.   shape::fpoint p_d(1.0f      , 1.0f      );
  24.  
  25.   shape::fpoint p_ab = INTERP_FPOINT(p_a, p_b, t);
  26.   shape::fpoint p_bc = INTERP_FPOINT(p_b, p_c, t);
  27.   shape::fpoint p_cd = INTERP_FPOINT(p_c, p_d, t);
  28.  
  29.   shape::fpoint p_abc = INTERP_FPOINT(p_ab, p_bc, t);
  30.   shape::fpoint p_bcd = INTERP_FPOINT(p_bc, p_cd, t);
  31.  
  32.   shape::fpoint p_abcd = INTERP_FPOINT(p_abc, p_bcd, t);
  33.  
  34.   return p_abcd;
  35.  
  36. }
  37.  
  38.  
  39. static f32 _get_movement_mul(f32 v, bool accelerating){
  40.   //gl_player.enforceMaxVel = false;
  41.   f32  v_old = v;
  42.   v = fabsf(v);
  43.  
  44.   //do a bezier curve thing
  45.   if(gl_player.enforceMaxVel){
  46.     v = MIN(v, 1.0f); //now v is 0.0f -> 1.0f
  47.     v = movement_bezier(v).y;
  48.  
  49.   }
  50.  
  51.   return v * ((v_old<0.0f) ? -1.0f : 1.0f );
  52.  
  53. }
  54.  
  55.  
  56.  
  57.  
  58.  
  59. //assumes n >= 0
  60. static inline void _put_closer_to_0(f32& v, f32 n){
  61.   if(     v < 0) v += n;
  62.   else if(v > 0) v -= n;
  63. }
  64.  
  65.  
  66.  
  67.  
  68.  
  69. bool Player::setScale(f32 scale_new){
  70.   f32 scale_old = scale;
  71.   scale = MAX(scale_new, 0.2f); //for a minimum of 2x2 pixels
  72.  
  73.   shape::rect player_rect = getRect();
  74.   shape::point delta;
  75.  
  76.   //player was probably pushed into the floor if the scale increased,
  77.    //so attempt to move the player out of any potential subtiles
  78.   if(subtiles_overlapping(player_rect, &delta))
  79.     player_rect += delta;
  80.  
  81.   //if the previous movement didn't result in the
  82.    //player entering empty space, return false
  83.   if(subtiles_overlapping(player_rect, nullptr)){
  84.     scale = scale_old; //(revert the scale back to what it was originally too)
  85.     return false;
  86.  
  87.   } else { //otherwise, apply those movement changes to pos, and return true
  88.     pos += delta;
  89.     return true;
  90.  
  91.   }
  92.  
  93. }
  94.  
  95.  
  96.  
  97.  
  98.  
  99. #define SPRSHEET_ADJUST(_v) ((_v)*(8+1)) //8px +1 for one pixel of spacing
  100.  
  101. shape::rect Player::blit(bool only_return_src_rect){
  102.   shape::rect src(0,0, 8,8);
  103.   if(confused    ) src.y += SPRSHEET_ADJUST(1);
  104.   if(!facingRight) src.y += SPRSHEET_ADJUST(2);
  105.  
  106.   if(!only_return_src_rect &&
  107.      (!visible || scale<=0.0f))
  108.   {
  109.     return src;
  110.   }
  111.  
  112.   shape::rect dst = getRect();
  113.   shape::fpoint rvel = get_rvel();
  114.  
  115.  
  116.  
  117.   if(MID_AIR){ //mid-air
  118.     if(fabsf(rvel.x) > PLAYER_NEUTRAL){ //going fast horizontally
  119.       if(rvel.y<=0) src.x = SPRSHEET_ADJUST(2); //-Y; back leg extended
  120.       else           src.x = SPRSHEET_ADJUST(8); //+Y; front leg extended
  121.     } else { //going slow (or not at all) horizontally
  122.       if(     rvel.y <-PLAYER_NEUTRAL) src.x = SPRSHEET_ADJUST(1); //-Y; back leg down
  123.       else if(rvel.y > PLAYER_NEUTRAL) src.x = SPRSHEET_ADJUST(4); //+Y; front leg down
  124.       else                              src.x = SPRSHEET_ADJUST(7); //0Y; both legs up
  125.     }
  126.  
  127.   } else { //on the ground
  128.       if(rvel.x < 0  &&  hacc > 0){ //slowing down while moving left
  129.         if(fabsf(rvel.x) > PLAYER_NEUTRAL){ //going fast horizontally
  130.           if(facingRight) src.x = SPRSHEET_ADJUST(2); //back leg extended
  131.           else            src.x = SPRSHEET_ADJUST(8); //front leg extended
  132.         } else { //going slow (or not at all) horizontally
  133.           if(facingRight) src.x = SPRSHEET_ADJUST(1); //back leg down
  134.           else            src.x = SPRSHEET_ADJUST(4); //front leg down
  135.         }
  136.  
  137.       } else if(rvel.x > 0  &&  hacc < 0){ //slowing down while moving right
  138.         if(fabsf(rvel.x) > PLAYER_NEUTRAL){ //going fast horizontally
  139.           if(facingRight) src.x = SPRSHEET_ADJUST(8); //front leg extended
  140.           else            src.x = SPRSHEET_ADJUST(2); //back leg extended
  141.         } else { //going slow (or not at all) horizontally
  142.           if(facingRight) src.x = SPRSHEET_ADJUST(4); //front leg down
  143.           else            src.x = SPRSHEET_ADJUST(1); //back leg down
  144.         }
  145.  
  146.       } else if(fabsf(rvel.x) > PLAYER_NEUTRAL){ //moving forward
  147.         src.x = SPRSHEET_ADJUST(1 + RND(runningState)%6);
  148.  
  149.       } else if(hacc < 0){ //standing still while accelerating left
  150.         if(facingRight) src.x = SPRSHEET_ADJUST(4); //front leg down
  151.         else            src.x = SPRSHEET_ADJUST(1); //back leg down
  152.  
  153.       } else if(hacc > 0){ //standing still while accelerating right
  154.         if(facingRight) src.x = SPRSHEET_ADJUST(1); //back leg down
  155.         else            src.x = SPRSHEET_ADJUST(4); //front leg down
  156.  
  157.       } else { //standing still without acceleration
  158.         src.x = SPRSHEET_ADJUST(0); //technically redundant, but left here for clarity
  159.  
  160.       }
  161.  
  162.   }
  163.  
  164.  
  165.  
  166.   //if enforceMaxVel is false, put a kind of highlight effect onto the player
  167.   if(!enforceMaxVel && !only_return_src_rect){
  168.     shape::rect highlight_dst = dst;
  169.     shape::rect highlight_src = src;
  170.  
  171.     highlight_dst.x -= 1;
  172.     highlight_dst.y -= 1;
  173.     highlight_dst.w += 2;
  174.     highlight_dst.h += 2;
  175.  
  176.     highlight_src.y += SPRSHEET_ADJUST(4);
  177.  
  178.     gl_spritesheetPlayer->blitRect(&highlight_dst, &highlight_src, 0xff00ff);
  179.  
  180.   }
  181.  
  182.  
  183.  
  184.   //0xff00ff for magenta as the transparency color
  185.   if(!only_return_src_rect)
  186.     gl_spritesheetPlayer->blitRect(&dst, &src, 0xff00ff);
  187.  
  188.   return src;
  189.  
  190. }
  191.  
  192.  
  193.  
  194.  
  195.  
  196. //visible, and confused are not modified here
  197. void Player::update(){
  198.   if(dying) return;
  199.  
  200.   bool accelerating = going_left^going_right;
  201.  
  202.   if(accelerating){
  203.     if(     going_left ) hacc = -1;
  204.     else if(going_right) hacc =  1;
  205.     if(confused) hacc = -hacc;
  206.  
  207.     f32 acc_x = hvel_speed*hacc;
  208.     if(enforceMaxVel)
  209.       hvel += (MID_AIR) ? acc_x*PLAYER_AIR_FRICTION : acc_x;
  210.     else
  211.       hvel += (MID_AIR) ? acc_x*PLAYER_AIR_FRICTION*0.1f : acc_x*0.1f;
  212.  
  213.   } else { //decelerate
  214.     if(enforceMaxVel)
  215.       _put_closer_to_0(hvel, hvel_speed);
  216.  
  217.     if(fabsf(hvel) < PLAYER_NEUTRAL){
  218.       hacc = 0;
  219.       hvel = 0.0f;
  220.       runningState = 0.0f;
  221.     }
  222.  
  223.   }
  224.  
  225.   if(enforceMaxVel){
  226.     hvel  = CLAMP( hvel,     -1.0f,     1.0f);
  227.     vel.y = CLAMP(vel.y, -PLAYER_VELY_MAX, PLAYER_VELY_MAX);
  228.   }
  229.  
  230.   _hvel = _get_movement_mul(hvel, accelerating) * PLAYER_VELX_MAX;
  231.  
  232.  
  233.  
  234.   shape::fpoint rvel = get_rvel();
  235.  
  236.   shape::rect new_rect = getRect();
  237.  
  238.   shape::rect collider_ceiling, collider_floor;
  239.   shape::rect collider_left    = new_rect;
  240.   shape::rect collider_right   = new_rect;
  241.  
  242.   collider_left.x  -= 1;
  243.   collider_left.w   = 1;
  244.   collider_right.x += collider_right.w;
  245.   collider_right.w  = 1;
  246.  
  247.   //touching a wall
  248.   if((rvel.x<0.0f && subtiles_overlapping(collider_left )) ||
  249.      (rvel.x>0.0f && subtiles_overlapping(collider_right))  )
  250.   {
  251.     _hvel = hvel = 0.0f;
  252.     runningState = 0.0f;
  253.     rvel = get_rvel();
  254.  
  255.   }
  256.  
  257.  
  258.   //update position
  259.   {
  260.     new_rect = move(rvel.x, rvel.y);
  261.  
  262.     collider_ceiling = new_rect;
  263.     collider_floor   = new_rect;
  264.     collider_left    = new_rect;
  265.     collider_right   = new_rect;
  266.  
  267.  
  268.     collider_ceiling.y -= 1;
  269.     collider_ceiling.h  = 1;
  270.     collider_floor.y   += collider_floor.h;
  271.     collider_floor.h    = 1;
  272.  
  273.     //touching the ceiling
  274.     if(vel.y<0.0f && subtiles_overlapping(collider_ceiling)){
  275.       vel.y = fabsf(vel.y)/2;
  276.       ++ticksInAir;
  277.  
  278.     //touching the floor
  279.     } else if(vel.y>0.0f && subtiles_overlapping(collider_floor)){
  280.       if(sfx_landing){
  281.         sfx_landing->volL = (fabsf(vel.y)/PLAYER_VELY_MAX)*PLAYER_LANDING_VOLUME;
  282.         sfx_landing->volR = sfx_landing->volL;
  283.         play_sfx_landing(ticksInAir);
  284.       }
  285.       if(ticksInAir) runningState = 2.5f;
  286.       ticksInAir = 0;
  287.       first_jmp  = false;
  288.       second_jmp = false;
  289.       vel.y = 0.0f;
  290.  
  291.     //mid-air
  292.     } else {
  293.       ++ticksInAir;
  294.  
  295.     }
  296.  
  297.  
  298.     collider_left.x  -= 1;
  299.     collider_left.w   = 1;
  300.     collider_right.x += collider_right.w;
  301.     collider_right.w  = 1;
  302.  
  303.     //touching a wall
  304.     if(       rvel.x<0.0f && subtiles_overlapping(collider_left)){
  305.       hvel = vel.x = 0.0f;
  306.       runningState = 0.0f;
  307.  
  308.     } else if(rvel.x>0.0f && subtiles_overlapping(collider_right)){
  309.       hvel = vel.x = 0.0f;
  310.       runningState = 0.0f;
  311.  
  312.     }
  313.   }
  314.  
  315.  
  316.  
  317.   //manage horizontal velocity
  318.   {
  319.     if(fabsf(hvel)<PLAYER_NEUTRAL && !hacc){
  320.       hvel = 0.0f;
  321.       runningState = 0.0f;
  322.     }
  323.  
  324.     //if on ground while moving horizontally (referring to rvel.x)
  325.     if(ticksInAir <= 1  &&  fabsf(rvel.x) > 0.0f){
  326.       facingRight  =  rvel.x >= 0.0f;
  327.       vel.x *= PLAYER_GND_FRICTION;
  328.       if(fabsf(vel.x)<PLAYER_NEUTRAL) vel.x = 0.0f;
  329.     }
  330.   }
  331.  
  332.  
  333.   //handle incrementing run animations
  334.   {
  335.     f32 prevRunningState = runningState;
  336.  
  337.     if(fabsf(_hvel) >= PLAYER_NEUTRAL) runningState += fabsf(_hvel)*PLAYER_RUN_MUL;
  338.     else                               runningState  = 0.0f;
  339.     runningState = fmodf(fabsf(runningState), 6.0f);
  340.  
  341.     //used to indicate that a foot step sound effect should play
  342.      //(1.5 instead of 2, since 1.5 would round up to integer state 2,
  343.      //which is the actual moment that the foot would reach the ground)
  344.     if(prevRunningState < 1.5f  &&  runningState >= 1.5f  &&  !MID_AIR)
  345.       if((_hvel < 0.0f) == (hacc < 0)){
  346.         play_sfx_footstep();
  347.       }
  348.   }
  349. }
  350.  
  351.  
  352.  
  353.  
  354.  
  355. shape::rect Player::move(f32 deltaX, f32 deltaY){
  356.   rem.x += CLAMP(deltaX, -CANVSIZ_X,CANVSIZ_X);
  357.   rem.y += CLAMP(deltaY, -CANVSIZ_Y,CANVSIZ_Y);
  358.  
  359.   shape::point delta(RND(rem.x), RND(rem.y));
  360.   if(!delta.x && !delta.y) return getRect();
  361.  
  362.   rem.x -= delta.x;
  363.   rem.y -= delta.y;
  364.   shape::rect current = getRect();
  365.   shape::rect end     = current;
  366.   end += delta;
  367.   shape::point newpos(current.x, current.y);
  368.  
  369.  
  370.  
  371.   //do a bresenham line to find the exact point of collision, before setting
  372.    //pos to that (minus 1 step assuming a collision actually occurred)
  373.   s32 d_x =  abs(delta.x);
  374.   s32 d_y = -abs(delta.y);
  375.   s32 s_x = (delta.x >= 0) ? 1 : -1;
  376.   s32 s_y = (delta.y >= 0) ? 1 : -1;
  377.   s32 e_1 = d_x + d_y;
  378.  
  379.   while(true){
  380.     newpos.x = current.x; //(assumes that player isn't colliding
  381.     newpos.y = current.y;  //with any subtiles initially)
  382.  
  383.     if(current.x == end.x  &&  current.y == end.y) break;
  384.  
  385.     s32 e_2 = e_1<<1;
  386.  
  387.     if(e_2 >= d_y){
  388.       if(current.x == end.x) break;
  389.       e_1 += d_y;
  390.       current.x += s_x;
  391.     }
  392.  
  393.     if(e_2 <= d_x){
  394.       if(current.y == end.y) break;
  395.       e_1 += d_x;
  396.       current.y += s_y;
  397.     }
  398.  
  399.     if(subtiles_overlapping(current)) break;
  400.  
  401.   }
  402.  
  403.  
  404.   pos.x = newpos.x + current.w/2;
  405.   pos.y = newpos.y + current.h/2;
  406.  
  407.   return getRect();
  408.  
  409. }
  410.  
  411.  
  412.  
  413.  
  414.  
  415. void Player::kill(){
  416.   if(dying) return;
  417.   SFXPTR_PLAY(SFXPTR_DEATH);
  418.  
  419.   visible = false;
  420.   dying   = true;
  421.  
  422.   //this will reset the death animation effect,
  423.    //which will run now that gl_player.dying is true
  424.   gl_death_prog = 0.0f;
  425.  
  426. }
  427.  
  428.  
  429.  
  430.  
  431.  
  432. #define MCSIZE 96
  433.  
  434. #define INTERP_FPOINT(_a, _b, _t) \
  435.   shape::fpoint( LERP((_a).x,(_b).x,(_t)), LERP((_a).y,(_b).y,(_t)) )
  436.  
  437. shape::fpoint movement_bezier(f32 t);
  438.  
  439. extern shape::fpoint curve_point;
  440. extern f32 hvel_speed;
  441.  
  442.  
  443. //whatever
  444. static inline shape::point mcCoord(shape::fpoint& fpnt, shape::rect& rct){
  445.   shape::point pnt((s32)(       fpnt.x *(rct.w-1) ),
  446.                    (s32)( (1.0f-fpnt.y)*(rct.h-1) ));
  447.   pnt.x += rct.x;
  448.   pnt.y += rct.y;
  449.   return pnt;
  450.  
  451. }
  452.  
  453.  
  454. //whatever
  455. void drawMovementCurve(shape::rect rect = {CANVSIZ_X-MCSIZE, CANVSIZ_Y-MCSIZE,
  456.                                                      MCSIZE,           MCSIZE})
  457. {
  458.   shape::fpoint cBL((f32)(rect.x       ), (f32)(rect.y+rect.h));
  459.   shape::fpoint cTR((f32)(rect.x+rect.w), (f32)(rect.y       ));
  460.  
  461.  
  462.   shape::fpoint hvel0 = movement_bezier(fabsf(gl_player.hvel));
  463.   shape::fpoint hvel1(hvel0.x, 0.0f);
  464.  
  465.   shape::point hvel[2];
  466.   hvel[0] = mcCoord(hvel0, rect);
  467.   hvel[1] = mcCoord(hvel1, rect);
  468.  
  469.  
  470.   //black background
  471.   gl_win->drawRectangles(&rect, 1, 0x000000);
  472.  
  473.  
  474.   shape::point bcurve[4];
  475.   bcurve[0] = mcCoord(shape::fpoint(0.0f,0.0f), rect);
  476.   bcurve[1] = mcCoord(curve_point, rect);
  477.   bcurve[2] = mcCoord(shape::fpoint(1.0f-curve_point.x, 1.0f-curve_point.y), rect);
  478.   bcurve[3] = mcCoord(shape::fpoint(1.0f,1.0f), rect);
  479.  
  480.   shape::rect bpoint = { bcurve[1].x-2, bcurve[1].y-2 };
  481.   bpoint.w = bpoint.h = 4;
  482.  
  483.   //curve settings
  484.   gl_win->drawLines(bcurve, 4, 0x008E4E);
  485.   gl_win->drawRectangles(&bpoint, 1, 0x008E4E);
  486.  
  487.  
  488.   //hvel line
  489.   gl_win->drawLines(hvel, 2, 0xDB3D42);
  490.  
  491.  
  492.   //the actual curve
  493.   shape::point p[2] = { {0,0}, {rect.x, rect.y+rect.h-1} };
  494.   for(f32 t=0.0f; t<1.0f; t+=(3.0f/MCSIZE)){
  495.     shape::fpoint p1 = movement_bezier(t);
  496.     p[0] = p[1];
  497.     p[1] = mcCoord(p1, rect);
  498.     gl_win->drawLines(p, 2, 0x006FAF);
  499.  
  500.   }
  501.  
  502.   p[0] = p[1];
  503.   p[1] = shape::point(rect.x+rect.w-1, rect.y);
  504.   gl_win->drawLines(p, 2, 0x006FAF);
  505.  
  506.  
  507. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement