Explanation or source code for Quote's movement?

May 29, 2014 at 2:53 AM
Junior Member
"Fresh from the Bakery"
Join Date: May 29, 2014
Location:
Posts: 10
I'd love the source code (c++) for Quote's movement, or at least explain how it works on a technical level.

It's not the actual platforming that I care for, it's the way Quote seems to cut corners sometimes, adjust position to fit into a gap, or try to reach a destination just to slip and fall back down.

I've been trying to recreate that movement but it's just... Ludicrously hard when taking in all other factors. Especially how Quote seems to fall off ledges 2 pixels before he really should (according to hitbox), he falls down 1 pixel and goes 2 left/right when near ledge. But when I put that in, my Quote has a hard time getting up 3 block high jumps without falling back down. Fucking tedious.

So; What is Quote's REAL hitbox? (The one in the table has to be lying. Just has to be.)
Does it ever change? How does he do all that corner cutting?
 
May 29, 2014 at 2:57 AM
Perpetually out of it
"Big Joe Tire and Battery Restaurant! Opening Soon! Eat at Big Joes!"
Join Date: Oct 6, 2013
Location: Absent
Posts: 490
Age: 24
You'll get no specific answers regarding the source code from me, but the corner cutting (if you can call it that) isn't entirely due to the hitbox, I'd think it's more relevant to Quote's jump physics and forward momentum. I could easily be wrong though, this is an assumption, after all.
 
May 29, 2014 at 3:07 AM
Junior Member
"Fresh from the Bakery"
Join Date: May 29, 2014
Location:
Posts: 10

Oh. Nadojin.




Code:
void PInitRepel(void)
{
const int s = SPR_MYCHAR;
int i;
player->nrepel_l = sprites[s].block_l.count;
player->nrepel_r = sprites[s].block_r.count;
player->nrepel_d = sprites[s].block_d.count;
player->nrepel_u = sprites[s].block_u.count;

for(i=0;i<player->nrepel_l;i++)
{
  player->repel_l[i].x = sprites[s].block_l[i].x + 1;
  player->repel_l[i].y = sprites[s].block_l[i].y;
}

for(i=0;i<player->nrepel_r;i++)
{
  player->repel_r[i].x = sprites[s].block_r[i].x - 1;
  player->repel_r[i].y = sprites[s].block_r[i].y;
}

for(i=0;i<player->nrepel_d;i++)
{
  player->repel_d[i].x = sprites[s].block_d[i].x;
  player->repel_d[i].y = sprites[s].block_d[i].y - 1;
}

for(i=0;i<player->nrepel_u;i++)
{
  player->repel_u[i].x = sprites[s].block_u[i].x;
  player->repel_u[i].y = sprites[s].block_u[i].y + 1;
}
}
// the player's block points are assymetrical--block u/d are closer together than block l/r.
// So it's quite possible to get e.g. your blockl points embedded in a wall by
// falling off the top of it. This function implements a SMB1-style "repel" that
// allows this to happen but then pushes the player out of the block over the next
// few frames.
void PDoRepel(void)
{
// since this function is called from the aftermove, regular player->blockl etc
// won't be updated until the following frame, so we always check the attributes
// directly here.
static const int REPEL_SPEED = (1<<CSF);

if (settings->enable_debug_keys && inputs[DEBUG_MOVE_KEY])
  return;

// pushes player out of walls if he become embedded in them, ala Super Mario 1.
// this can happen for example because his R,L block points are further out than
// his D block points so it's possible to fall really close to a block and
// embed the R or L points further into the block than they should be
if (player->CheckAttribute(player->repel_r, player->nrepel_r, TA_SOLID_PLAYER))
{
  if (!player->CheckAttribute(&sprites[player->sprite].block_l, TA_SOLID_PLAYER))
  {
   player->x -= REPEL_SPEED;
   //debug("REPEL [to left]");
  }
}

if (player->CheckAttribute(player->repel_l, player->nrepel_l, TA_SOLID_PLAYER))
{
  if (!player->CheckAttribute(&sprites[player->sprite].block_r, TA_SOLID_PLAYER))
  {
   player->x += REPEL_SPEED;
   //debug("REPEL [to right]");
  }
}

// vertical repel doesn't happen normally, but if we get embedded in a
// block somehow, it can happen.
/*
// do repel down
if (player->CheckAttribute(player->repel_u, player->nrepel_u, TA_SOLID_PLAYER))
{
  if (!player->CheckAttribute(&sprites[player->sprite].block_d, TA_SOLID_PLAYER))
  {
   player->y += REPEL_SPEED;
   //debug("REPEL [down]");
  }
}

// do repel up
if (player->CheckAttribute(player->repel_d, player->nrepel_d, TA_SOLID_PLAYER))
{
  if (!player->CheckAttribute(&sprites[player->sprite].block_u, TA_SOLID_PLAYER))
  {
   player->y -= REPEL_SPEED;
   //debug("REPEL [up]");
  }
}
*/
}


Can't make sense of this code. Too many undefined variables and meanings.

I don't even know if this is the right code.
 
May 29, 2014 at 3:18 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
I think what you're really after is the tile collision

this isn't exactly how cave story does it but it's from my engine which is basically a rip-off of cave story.
Code:
void Player::tileSolid(int x, int y)
{
    int result = 0;
    int scaleFactor = PXSCALE;
    int pxPerTile = 0x20;

    Rect playerRect = {xPos - hitRect.left, yPos - hitRect.up,
                        xPos + hitRect.right, yPos + hitRect.down};
    Rect tileRect = {(x * pxPerTile) * scaleFactor,
                    (y * pxPerTile - 8) * scaleFactor,
                    (x * pxPerTile + 16) * scaleFactor,
                    (y * pxPerTile + 8) * scaleFactor};
    if (rectOverlap(playerRect, tileRect)) {
        xPos = ((x * pxPerTile + 16) * scaleFactor) + hitRect.right;
        if (xVel <= -0x180)
            xVel = -0x180;
        if (!(keyHeld & KEYLEFT) && xVel <= 0)
            xVel = 0;
        if (canGrabWall()) {
            stateFlags |= 0x20; //wallhang left
            //state = PSTATE_WALL_TRANS;
        }
        result |= LEFT;
    }
    tileRect.left = (x * pxPerTile - 16) * scaleFactor;
    //tileRect.up = (y * pxPerTile + 4) * scaleFactor;
    tileRect.right = (x * pxPerTile) * scaleFactor;
    //tileRect.down = (y * pxPerTile - 4) * scaleFactor;
    if (rectOverlap(playerRect, tileRect)) {
        xPos = ((x * pxPerTile - 16) * scaleFactor) - hitRect.right;
        if (xVel >= 0x180)
            xVel = 0x180;
        if (!(keyHeld & KEYRIGHT) && xVel >= 0)
            xVel = 0;
        if (canGrabWall()) {
            stateFlags |= 0x40; //wallhang right
            //state = PSTATE_WALL_TRANS;
        }
        result |= RIGHT;
    }

    tileRect.left = (x * pxPerTile - 10) * scaleFactor;
    tileRect.up = (y * pxPerTile) * scaleFactor;
    tileRect.right = (x * pxPerTile + 10) * scaleFactor;
    tileRect.down = (y * pxPerTile + 16) * scaleFactor;
    if (rectOverlap(playerRect, tileRect)) {
        yPos = ((y * pxPerTile + 16) * scaleFactor) + hitRect.up;
        if ((stateFlags & 2) == 0)
            if (yVel <= -0x200)
                headBump();
        if (yVel <= 0)
            yVel = 0;
        result |= UP;
    }

    //tileRect.left = (x * pxPerTile + 5) * scaleFactor;
    tileRect.up = (y * pxPerTile - 16) * scaleFactor;
    //tileRect.right = (x * pxPerTile - 5) * scaleFactor;
    tileRect.down = (y * pxPerTile) * scaleFactor;
    if (rectOverlap(playerRect, tileRect)) {
        yPos = ((y * pxPerTile - 16) * scaleFactor) - hitRect.down;
        if (yVel > 0x400)
            playSound(SFX_fx_thud);
        if (yVel > 0)
            yVel = 0;
        result |= DOWN;
    }
    collision |= result;
}
 
May 29, 2014 at 3:42 AM
Junior Member
"Fresh from the Bakery"
Join Date: May 29, 2014
Location:
Posts: 10
So it just checks if it's inside any blocks and then it makes it go to the block's side?
 
May 29, 2014 at 3:54 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
yeah pretty much
some velocity cancelling in certain cases
 
May 29, 2014 at 4:00 AM
Junior Member
"Fresh from the Bakery"
Join Date: May 29, 2014
Location:
Posts: 10
What's the hitbox?
.....-16.......
-5 .........5
........0
 
May 29, 2014 at 4:11 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
there are four, one for each side of the square

p184481-0-g4lwudr.png

you'll note the upper and lower are slightly wider, this is because quote is skinnier than he is tall so he might fall through otherwise.
 
Top