bool PlayerCollisions::checkleft(CPlayer& player) { if (player.fy < 0.0f) return false; short tile_y = (short)player.fy / TILESIZE; if (tile_y < 0 || tile_y >= MAPHEIGHT) return false; short tile_y2 = ((short)player.fy + PH) / TILESIZE; if (tile_y2 < 0 || tile_y2 >= MAPHEIGHT) return false; short tile_x = player.ix / TILESIZE; if (tile_x < 0 || tile_x >= MAPWIDTH) return false; int topTile = g_map->map(tile_x, tile_y); int bottomTile = g_map->map(tile_x, tile_y2); IO_Block * topBlock = g_map->block(tile_x, tile_y); IO_Block * bottomBlock = g_map->block(tile_x, tile_y2); if ((topTile & tile_flag_solid) || (bottomTile & tile_flag_solid) || (topBlock && !topBlock->isTransparent() && !topBlock->isHidden()) || (bottomBlock && !bottomBlock->isTransparent() && !bottomBlock->isHidden())) { player.setXf((float)((tile_x << 5) + TILESIZE) + 0.2f); player.flipsidesifneeded(); return true; } return false; }
bool PlayerCollisions::checktop(CPlayer& player) { if (player.topY() < 0.0f) return false; short tile_y = player.topY() / TILESIZE; if (tile_y < 0 || tile_y >= MAPHEIGHT) return false; short tile_x_left = player.leftX() / TILESIZE; if (tile_x_left < 0 || tile_x_left >= MAPWIDTH) return false; short tile_x_right = -1; if (player.rightX() >= 640) tile_x_right = (player.rightX() - 640) / TILESIZE; else tile_x_right = player.rightX() / TILESIZE; if (tile_x_right < 0 || tile_x_right >= MAPWIDTH) return false; int leftTile = g_map->map(tile_x_left, tile_y); int rightTile = g_map->map(tile_x_right, tile_y); IO_Block * leftBlock = g_map->block(tile_x_left, tile_y); IO_Block * rightBlock = g_map->block(tile_x_right, tile_y); if ((leftTile & tile_flag_solid) || (rightTile & tile_flag_solid) || (leftBlock && !leftBlock->isTransparent() && !leftBlock->isHidden()) || (rightBlock && !rightBlock->isTransparent() && !rightBlock->isHidden())) { player.setYf((float)((tile_y << 5) + TILESIZE) + 0.2f); return true; } return false; }
void IO_MovingObject::collision_detection_map() { xf(fx + velx); flipsidesifneeded(); fPrecalculatedY = fy + vely; //Fixes weird float rounding error. Must be computed here before casting to int. Otherwise, this will miss the bottom collision, but then hit the side collision and the player can slide out of 1x1 spaces. float fPlatformVelX = 0.0f; float fPlatformVelY = 0.0f; float fTempY = fy; if(platform) { if(!onice) { fPlatformVelX = platform->fVelX; xf(fx + fPlatformVelX); flipsidesifneeded(); } fPlatformVelY = platform->fVelY; if(platform->fOldVelY < 0.0f) fy += platform->fOldVelY; fPrecalculatedY += platform->fOldVelY; } iHorizontalPlatformCollision = -1; iVerticalPlatformCollision = -1; g_map.movingPlatformCollision(this); fy = fTempY; if(fPrecalculatedY + collisionHeight < 0.0f) { // on top outside of the screen yf(fPrecalculatedY); vely = CapFallingVelocity(GRAVITATION + vely); if(!platform) { inair = true; onice = false; } return; } else if(fPrecalculatedY + collisionHeight >= 480.0f) { //on ground outside of the screen? yi(-collisionHeight); fOldY = fy - 1.0f; onice = false; return; } //Could be optimized with bit shift >> 5 short ty = (short)fy / TILESIZE; short ty2 = ((short)fy + collisionHeight) / TILESIZE; short tx = -1; //----------------------------------------------------------------- // x axis first (--) //----------------------------------------------------------------- if(fy + collisionHeight >= 0.0f) { if(velx + fPlatformVelX > 0.01f || iHorizontalPlatformCollision == 3) { //moving right if(fx + collisionWidth >= 640.0f) { tx = (short)(fx + collisionWidth - 640.0f) / TILESIZE; fOldX -= 640.0f; } else tx = ((short)fx + collisionWidth) / TILESIZE; IO_Block * topblock = g_map.block(tx, ty); IO_Block * bottomblock = g_map.block(tx, ty2); bool fTopBlockSolid = topblock && !topblock->isTransparent() && !topblock->isHidden(); bool fBottomBlockSolid = bottomblock && !bottomblock->isTransparent() && !bottomblock->isHidden(); if(fTopBlockSolid || fBottomBlockSolid) { bool processOtherBlock = true; if(fTopBlockSolid) //collide with top block { if(iHorizontalPlatformCollision == 3) { KillObjectMapHazard(); return; } topblock->collide(this, 1); flipsidesifneeded(); removeifprojectile(this, true, true); processOtherBlock = false; SideBounce(true); } if(processOtherBlock && fBottomBlockSolid) //then bottom { if(iHorizontalPlatformCollision == 3) { KillObjectMapHazard(); return; } bottomblock->collide(this, 1); flipsidesifneeded(); removeifprojectile(this, true, true); SideBounce(true); } } else if((g_map.map(tx, ty) & tile_flag_solid) || (g_map.map(tx, ty2) & tile_flag_solid)) { //collision on the right side. if(iHorizontalPlatformCollision == 3) { KillObjectMapHazard(); return; } xf((float)((tx << 5) - collisionWidth) - 0.2f); //move to the edge of the tile (tile on the right -> mind the object width) fOldX = fx; if(velx > 0.0f) velx = -velx; flipsidesifneeded(); removeifprojectile(this, true, true); SideBounce(true); } } else if(velx + fPlatformVelX < -0.01f || iHorizontalPlatformCollision == 1) { //moving left tx = (short)fx / TILESIZE; //Just in case fx < 0 and wasn't caught by flipsidesifneeded() if(tx < 0) tx = 0; IO_Block * topblock = g_map.block(tx, ty); IO_Block * bottomblock = g_map.block(tx, ty2); bool fTopBlockSolid = topblock && !topblock->isTransparent() && !topblock->isHidden(); bool fBottomBlockSolid = bottomblock && !bottomblock->isTransparent() && !bottomblock->isHidden(); if(fTopBlockSolid || fBottomBlockSolid) { bool processOtherBlock = true; if(fTopBlockSolid) //collide with top block { if(iHorizontalPlatformCollision == 1) { KillObjectMapHazard(); return; } topblock->collide(this, 3); flipsidesifneeded(); removeifprojectile(this, true, true); processOtherBlock = false; SideBounce(false); } if(processOtherBlock && fBottomBlockSolid) //then bottom { if(iHorizontalPlatformCollision == 1) { KillObjectMapHazard(); return; } bottomblock->collide(this, 3); flipsidesifneeded(); removeifprojectile(this, true, true); SideBounce(false); } } else if((g_map.map(tx, ty) & tile_flag_solid) || (g_map.map(tx, ty2) & tile_flag_solid)) { if(iHorizontalPlatformCollision == 1) { KillObjectMapHazard(); return; } xf((float)((tx << 5) + TILESIZE) + 0.2f); //move to the edge of the tile fOldX = fx; if(velx < 0.0f) velx = -velx; flipsidesifneeded(); removeifprojectile(this, true, true); SideBounce(false); } } } short txl = -1, txr = -1; txl = ix / TILESIZE; if(ix + collisionWidth >= 640) txr = (ix + collisionWidth - 640) / TILESIZE; else txr = (ix + collisionWidth) / TILESIZE; //----------------------------------------------------------------- // then y axis (|) //----------------------------------------------------------------- float fMovingUp = vely; if(platform) fMovingUp = vely + fPlatformVelY - bounce; if(fMovingUp < -0.01f) { ty = (short)(fPrecalculatedY) / TILESIZE; IO_Block * leftblock = g_map.block(txl, ty); IO_Block * rightblock = g_map.block(txr, ty); if(leftblock && !leftblock->isTransparent() && !leftblock->isHidden()) //then left { if(iVerticalPlatformCollision == 2) KillObjectMapHazard(); leftblock->collide(this, 0); return; } if(rightblock && !rightblock->isTransparent() && !rightblock->isHidden()) //then right { if(iVerticalPlatformCollision == 2) KillObjectMapHazard(); rightblock->collide(this, 0); return; } if((g_map.map(txl, ty) & tile_flag_solid) || (g_map.map(txr, ty) & tile_flag_solid)) { if(iVerticalPlatformCollision == 2) KillObjectMapHazard(); yf((float)((ty << 5) + TILESIZE) + 0.2f); fOldY = fy - 1.0f; if(vely < 0.0f) vely = -vely; } else { yf(fPrecalculatedY); vely += GRAVITATION; } if(!platform) { inair = true; onice = false; } } else { //moving down / on ground ty = ((short)fPrecalculatedY + collisionHeight) / TILESIZE; IO_Block * leftblock = g_map.block(txl, ty); IO_Block * rightblock = g_map.block(txr, ty); bool fLeftBlockSolid = leftblock && !leftblock->isTransparent() && !leftblock->isHidden(); bool fRightBlockSolid = rightblock && !rightblock->isTransparent() && !rightblock->isHidden(); if(fLeftBlockSolid || fRightBlockSolid) { bool processOtherBlock = true; if(fLeftBlockSolid) //collide with left block { processOtherBlock = leftblock->collide(this, 2); if(!platform) { inair = false; onice = false; } } if(processOtherBlock && fRightBlockSolid) //then right { rightblock->collide(this, 2); if(!platform) { inair = false; onice = false; } } if(iVerticalPlatformCollision == 0) KillObjectMapHazard(); return; } int leftTile = g_map.map(txl, ty); int rightTile = g_map.map(txr, ty); if((leftTile & tile_flag_solid_on_top) || (rightTile & tile_flag_solid_on_top)) { if((fOldY + collisionHeight) / TILESIZE < ty) { vely = BottomBounce(); yf((float)((ty << 5) - collisionHeight) - 0.2f); fOldY = fy - GRAVITATION; if(!platform) { inair = false; onice = false; } platform = NULL; if(iVerticalPlatformCollision == 0) KillObjectMapHazard(); return; } } bool fSuperDeathTileUnderObject = fObjectDiesOnSuperDeathTiles && (((leftTile & tile_flag_super_death_top) && (rightTile & tile_flag_super_death_top)) || ((leftTile & tile_flag_super_death_top) && !(rightTile & tile_flag_solid)) || (!(leftTile & tile_flag_solid) && (rightTile & tile_flag_super_death_top))); if(((leftTile & tile_flag_solid) || (rightTile & tile_flag_solid)) && !fSuperDeathTileUnderObject) { vely = BottomBounce(); yf((float)((ty << 5) - collisionHeight) - 0.2f); fOldY = fy; if(!platform) { inair = false; if((leftTile & tile_flag_ice && ((rightTile & tile_flag_ice) || rightTile == tile_flag_nonsolid || rightTile == tile_flag_gap)) || (rightTile & tile_flag_ice && ((leftTile & tile_flag_ice) || leftTile == tile_flag_nonsolid || leftTile == tile_flag_gap))) onice = true; else onice = false; } platform = NULL; if(iVerticalPlatformCollision == 0) KillObjectMapHazard(); } else if(fSuperDeathTileUnderObject) { KillObjectMapHazard(); return; } else { yf(fPrecalculatedY); vely = CapFallingVelocity(GRAVITATION + vely); if(!platform) inair = true; } } if(!platform && inair) onice = false; }
void PlayerWarpStatus::chooseWarpExit(CPlayer& player) { WarpExit * exit = g_map->getRandomWarpExit(warpconnection, warpid); assert(exit); player.setXi(exit->x); player.setYi(exit->y); player.fOldX = player.fx; player.fOldY = player.fy; player.oldvelx = player.velx; player.lockjump = false; player.ClearPowerupStates(); //Trigger block that we warp into short iCol = player.leftX() / TILESIZE; short iRow = player.topY() / TILESIZE; IO_Block* block = NULL; assert(exit->direction != WARP_EXIT_UNDEFINED); switch(exit->direction) { case WARP_EXIT_UP: player.state = player_exiting_warp_up; player.velx = 0.0f; player.vely = -4.0f; warpcounter = PH + PHOFFSET; warpplane = exit->warpy << 5; if (iRow - 1 >= 0) { block = g_map->block(iCol, iRow - 1); if (block && !block->isTransparent() && !block->isHidden()) block->triggerBehavior(); } break; case WARP_EXIT_RIGHT: player.state = player_exiting_warp_right; player.velx = 1.0f; player.vely = 1.0f; warpcounter = PW + PWOFFSET; warpplane = (exit->warpx << 5) + TILESIZE; if (iCol + 1 >= 20) iCol -= 20; block = g_map->block(iCol + 1, iRow); if (block && !block->isTransparent() && !block->isHidden()) block->triggerBehavior(); break; case WARP_EXIT_DOWN: player.state = player_exiting_warp_down; player.velx = 0.0f; player.vely = 1.1f; player.inair = true; warpcounter = TILESIZE - PHOFFSET; warpplane = (exit->warpy << 5) + TILESIZE; if (iRow + 1 < 15) { block = g_map->block(iCol, iRow + 1); if (block && !block->isTransparent() && !block->isHidden()) block->triggerBehavior(); } break; case WARP_EXIT_LEFT: player.state = player_exiting_warp_left; player.velx = -1.0f; player.vely = 1.0f; warpcounter = PW + PWOFFSET; warpplane = (exit->warpx << 5); if (iCol - 1 < 0) iCol += 20; block = g_map->block(iCol - 1, iRow); if (block && !block->isTransparent() && !block->isHidden()) block->triggerBehavior(); break; default: assert(false); break; } //Make player shielded when exiting the warp (if that option is turned on) if (game_values.shieldstyle > 0) { if (!player.isShielded() || player.shield.time_left() < game_values.shieldtime) { player.shield.reset(); } } //Lock the warp (if that option is turned on) if (game_values.warplocktime > 0) { if (game_values.warplockstyle == 1 || game_values.warplockstyle == 2) //Lock the warp exit exit->locktimer = game_values.warplocktime; } }