void Mario::bneut() { if (action != BNEUT) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 132, 133, 12, ANIM_LOOP, -1); delay = 60 / 12 * 2; dx = 0; action = BNEUT; } else if (PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 133 && delay == 1) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 134, 134, 10, ANIM_LOOP, -1); delay = 60 / 10 * 1; PA_FatPlaySfx("mariobneut"); int directionmodifier = 1; if (direction == RIGHT) directionmodifier = -1; Hitbox tempbox; tempbox.addCircle(createAtkbox(32, 32, 6, Knockback(-.25*directionmodifier, 0, 6), 10, 5)); Projectile p = Projectile(x, y, -2 * directionmodifier, 0, 120, FIREBALL, charnum, tempbox, stage, display); ((vector<Projectile>*)getProj())->push_back(p); } else if (PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 134 && delay == 1) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 135, 136, 12, ANIM_LOOP, -1); delay = 60 / 12 * 2; } else if (PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 136 && delay == 1) { fall(); } else if (aerial && checkFloorCollision()) dy = 0; }
bool Hitbox::collide(const Hitbox &a, const Hitbox &b) { //static method // // Debug // std::cerr<<"Collide:\n"; // std::printf("\ta: [%3.2f %3.2f] [%3.2f %3.2f]\n", a.min.x, a.min.y, a.max.x, a.max.y); // std::printf("\tb: [%3.2f %3.2f] [%3.2f %3.2f]\n", b.min.x, b.min.y, b.max.x, b.max.y); if (a.isNone() || b.isNone()) return false; // Hitboxes of area 0 don't collide with anything. if (a.max.x <= b.min.x) { // std::cerr<<"\ta left of b"<<std::endl; return false; } if (a.min.x >= b.max.x) { // std::cerr<<"\ta right of b"<<std::endl; return false; } if (a.max.y <= b.min.y) { // std::cerr<<"\ta above b"<<std::endl; return false; } if (a.min.y >= b.max.y) { // std::cerr<<"\ta below b"<<std::endl; return false; // return false; // a is completely left/right/above/below b } // std::cerr<<"\tcollision"<<std::endl; return true; // overlap }
void Window::drawHitbox(const Hitbox &box, sf::Color color) { if(showHitbox) { sf::Shape boxA = sf::Shape::Rectangle( box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), sf::Color(0, 0, 0, 0), 1.0f, color); app.Draw(boxA); } }
bool Entity::collide(Entity const& target) const { Hitbox *self; Hitbox *op; if ((self = getComponent<Hitbox>()) && (op = target.getComponent<Hitbox>())) { return (self->isInTouch(*op)); } return (false); }
bool Hitbox::isIntersectingWith(const Hitbox& other){ bool xOverlap = valueInRange(this->getX(),other.getX(), other.getX() + other.getWidth()) || valueInRange(other.getX(), this->getX(), this->getX() + this->getWidth()); bool yOverlap = valueInRange(this->getY(),other.getY(),other.getY() + other.getHeight()) || valueInRange(other.getY(), this->getY(), this->getY() + this->getHeight()); return xOverlap && yOverlap; }
void Ike::bup() { if (action != BUP) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 118, 122, 15, ANIM_LOOP, -1); delay = 60 / 15 * 5; setDirection(); dx = 0; if (aerial) dy = -gravity; else dy = 0; action = BUP; int directionmodifier = 1; if (direction == RIGHT) directionmodifier = -1; Hitbox tempbox; tempbox.addCircle(createAtkbox(32, 32, 15, Knockback(0, 0, 2), 3, -2)); Projectile p = Projectile(x, y, -.1 * directionmodifier, -4, 30, IKESWORD, charnum, tempbox, stage, display); ((vector<Projectile>*)getProj())->push_back(p); } else if (delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 122) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 127, 127, 15, ANIM_LOOP, -1); PA_FatPlaySfx("ikebup"); delay = 60 / 15 * 1; } else if (delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 127) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 128, 128, 15, ANIM_LOOP, -1); delay = 60 / 15 * 3; dy = -gravity - 6; aerial = true; } else if (delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 128) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 129, 134, 15, ANIM_LOOP, -1); delay = 60 / 15 * 6; dy = -gravity; } else if (PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 135 && checkFloorCollision()) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 136, 138, 15, ANIM_LOOP, -1); delay = 60 / 15 * 3; dy = 0; aerial = false; } else if (delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 138) { idle(); } else if ((delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 134) || (delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 135)) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 135, 135, 15, ANIM_LOOP, -1); delay = 60 / 15 * 1; dy = -gravity + 6; } }
void Kirby::bup() { if(action != BUP) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 190, 199, 20, ANIM_ONESHOT); AS_SoundQuickPlay(kirbybup1); aerial = true; delay = 60/20 * 10; dy = -6; dx = 0; fastfall = 0; DI = 0; setDirection(); action = BUP; } else { if(delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 199) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 200, 200, 20, ANIM_LOOP, -1); AS_SoundQuickPlay(kirbybup2); delay = 60/20 * 1; dy = 4; } else if(delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 200) { if(!checkFloorCollision()) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 200, 200, 20, ANIM_LOOP, -1); delay = 60/20 * 1; dy = 4; } else { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 201, 201, 20, ANIM_LOOP, -1); delay = 60/20 * 1; int directionmodifier = 1; if(direction ==RIGHT) directionmodifier = -1; Hitbox tempbox; tempbox.addCircle(createAtkbox(36, 805%64, 22, Knockback((-1*directionmodifier), -.5, 8), 24)); tempbox.addCircle(createAtkbox(30, 794%63, 22, Knockback((-1*directionmodifier), -.5, 8), 24)); tempbox.addCircle(createAtkbox(47, 812%64, 10, Knockback((-1*directionmodifier), -.5, 8), 24)); ((vector<Projectile>*)getProj())->push_back(Projectile(x, y, -5*directionmodifier, 0, 20, FINALCUTTER, charnum, tempbox, stage, display)); } } } }
void Mario::bdown() { if (action != BDOWN) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 149, 149, 20, ANIM_LOOP, -1); delay = 60 / 20 * 1; fluddcharge = 0; dx = 0; if (aerial) dy = -gravity / 2; else dy = 0; action = BDOWN; } else if (custom_action(ACTION_SPECIAL, PAD_RELEASED) && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 149) { PA_StartSpriteAnimEx(MAIN_SCREEN, SPRITENUM, 150, 150, 12, ANIM_LOOP, -1); delay = 60 / 12 * 1; int directionmodifier = 1; if (direction == RIGHT) directionmodifier = -1; Hitbox tempbox; tempbox.addCircle(createAtkbox(58, 32, 5, Knockback((-1*directionmodifier), -.5, 6), 60, 5)); ((vector<Projectile>*)getProj())->push_back(Projectile(x, y - 16, -5*directionmodifier, 0, 2*fluddcharge, FLUDDWATER, charnum, tempbox, stage, display)); fluddcharge = 0; } else if (PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 150) { if (delay == 1) { fall(); } } else if (delay == 1 && PA_GetSpriteAnimFrame(MAIN_SCREEN, SPRITENUM) == 149) { delay = 60 / 20 * 1; fluddcharge++; } else if (aerial && checkFloorCollision()) { dy = 0; } else { fluddcharge++; if (fluddcharge > 30) fluddcharge = 30; } }
// Check for collision, correct position if necessary // Colliding will stop the player and push them back. void Player::collideWithTile(World *ptr, int id){ if(ptr->world.find(id) == ptr->world.end()) return; //No such field on map Entity *entity = nullptr; if(ptr->world[id].find(LayerType::LAYER_STONES) != ptr->world[id].end()) entity = ptr->world[id][LayerType::LAYER_STONES]; else if(ptr->world[id].find(LayerType::LAYER_BLOCKS) != ptr->world[id].end()) entity = ptr->world[id][LayerType::LAYER_BLOCKS]; else return; //Field has no blocks and stones Hitbox self = getHitbox(); Hitbox block = entity->getHitbox(); if(Hitbox::collide(self, block)) { sf::Vector2f offset(0, 0); // calculate where to push the player if(goDown) offset.y = block.getMinY() - self.getMaxY() - 1; // Negative value -- push up and a little more if(goUp) offset.y = block.getMaxY() - self.getMinY() + 1; // Positive value -- push down if(goRight) offset.x = block.getMinX() - self.getMaxX() - 1; // push left if(goLeft) offset.x = block.getMaxX() - self.getMinX() + 1; // push right // Correct position and update player position += offset; update(0); // instant correction, no velocity // TODO: Going towards a wall causes player's sprite to derp out -- find out why // Lock further movement if(goDown) goDown = lockChangeDirection = false; if(goUp) goUp = lockChangeDirection = false; if(goRight) goRight = lockChangeDirection = false; if(goLeft) goLeft = lockChangeDirection = false; } }
Collision AnimationHitbox::CollisionType(RectangleShape* rectangle) const { if(!rectangle->IsHitbox()) return DAMAGE; Hitbox* h = (Hitbox*) rectangle; vec2f sprite_position; Sprite* a = h->CurrentSprite(sprite_position); // Calculate rectangle intersection between h and a // This is necessary because the animation rectangle could be smaller than h const vec2f& hpos = h->position(); const vec2f& apos = hpos + sprite_position; float x1f = std::max(hpos.x, apos.x); float y1f = std::max(hpos.y, apos.y); float x2f = std::min(hpos.x + h->width(), apos.x + a->width()); float y2f = std::min(hpos.y + h->height(), apos.y + a->height()); // Calculate the animation intersection x1f = std::max(position_.x, x1f); y1f = std::max(position_.y, y1f); int x2 = (int)(std::min(position_.x + width_, x2f) - position_.x); int y2 = (int)(std::min(position_.y + height_, y2f) - position_.y); int x1 = (int)(x1f - position_.x); int y1 = (int)(y1f - position_.y); int x_offset = (int)(position_.x - apos.x); int y_offset = (int)(position_.y - apos.y); const Pixelmap& h1 = *CurrentSprite()->hit_map(); const Pixelmap& h2 = *a->damage_map(); if(Debug::enabled) { h1.Print(); h2.Print(); // Print pixel collision info for(int i = y1; i < y2; ++i) { for(int j = x1; j < x2; ++j) { if(h1.map_[i][j] && h2.map_[i + y_offset][j + x_offset]) std::cout << 'X'; else if(h1.map_[i][j] || h2.map_[i + y_offset][j + x_offset]) std::cout << '1'; else std::cout << '0'; } std::cout << std::endl; } } for(int i = y1; i < y2; ++i) { for(int j = x1; j < x2; ++j) { // TODO: Check Attack and Shield map collisions if(h1.map_[i][j] && h2.map_[i+y_offset][j+x_offset]) return DAMAGE; } } return NONE; }
Hitbox::Hitbox(const Hitbox& original) { this->area = original.getArea(); }
Fighter* Projectile::checkHits(Fighter* other) { Hitbox temp = hit; Hitbox atkbox; vector<Circle> circles = temp.getCircles(); for (uint8 n = 0; n < circles.size(); n++) { Circle current = circles[n]; Circle newcircright(current.getX() + x, current.getY() + y, current.getRadius(), current.getKnockback(), current.damage); Circle newcircleft(64 - current.getX() + x, current.getY() + y, current.getRadius(), current.getKnockback(), current.damage); if (dx < 0) atkbox.addCircle(newcircright); else atkbox.addCircle(newcircleft); } if(TYPE == THUNDER1 || TYPE == THUNDER2 || TYPE == THUNDER3 || TYPE == THUNDER4) { vector<Projectile> projs = *((vector<Projectile>*)getProj()); for(int n = 0; n < (int)projs.size(); n++) { if(projs[n].owner == owner && (projs[n].TYPE == THUNDER1 || projs[n].TYPE == THUNDER2 || projs[n].TYPE == THUNDER3 || projs[n].TYPE == THUNDER4)) { if(!projs[n].enabled) enabled = false; } } } if (!enabled) { if(TYPE == THUNDER1 || TYPE == THUNDER2 || TYPE == THUNDER3 || TYPE == THUNDER4) { vector<Projectile> projs = *((vector<Projectile>*)getProj()); for(int n = 0; n < (int)projs.size(); n++) { if(projs[n].owner == owner && (projs[n].TYPE == THUNDER1 || projs[n].TYPE == THUNDER2 || projs[n].TYPE == THUNDER3 || projs[n].TYPE == THUNDER4)) { projs[n].enabled = false; } } } return other; } if (other -> respawntimer > 0) return other; if (other -> invincibility > 0) return other; if(atkbox.hits(other -> getAtkbox())) { if(atkbox.getHitCircle(other -> getAtkbox()).priority < other -> getAtkbox().getHitCircle(atkbox).priority) { if (dx < 0) other -> takeDamage(atkbox.getHitCircle(other -> getDefbox(PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM))), 1, owner, 0); else other -> takeDamage(atkbox.getHitCircle(other -> getDefbox(PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM))), -1, owner, 0); } else if(atkbox.getHitCircle(other -> getAtkbox()).priority == other -> getAtkbox().getHitCircle(atkbox).priority) { removeProj(num); } else { removeProj(num); return other; // they win priority } } else if(atkbox.hits(other -> getDefbox(PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM)))) { if(other -> MYCHAR == KIRBY && PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM) == 189) { if(TYPE != THUNDER1 && TYPE != THUNDER2 && TYPE != THUNDER3 && TYPE != THUNDER4 && TYPE != IKESWORD) removeProj(num); else atkbox.enabled = false; } else if (other -> action == AIRDODGE || other -> action == ROLL || other -> action == DODGE) { /*doesn't hit*/ } else if (other -> action == SHIELD) { other -> shieldstr -= (int)((atkbox.getHitCircle(other -> getDefbox(PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM))).damage)); if(TYPE != THUNDER1 && TYPE != THUNDER2 && TYPE != THUNDER3 && TYPE != THUNDER4 && TYPE != IKESWORD) removeProj(num); else atkbox.enabled = false; if(TYPE == THUNDER1 || TYPE == THUNDER2 || TYPE == THUNDER3 || TYPE == THUNDER4) { vector<Projectile> projs = *((vector<Projectile>*)getProj()); for(int n = 0; n < (int)projs.size(); n++) { if(projs[n].owner == owner && (projs[n].TYPE == THUNDER1 || projs[n].TYPE == THUNDER2 || projs[n].TYPE == THUNDER3 || projs[n].TYPE == THUNDER4)) projs[n].enabled = false; } } } else if(other -> COUNTER) { if(TYPE != THUNDER1 && TYPE != THUNDER2 && TYPE != THUNDER3 && TYPE != THUNDER4 && TYPE != IKESWORD) removeProj(num); else atkbox.enabled = false; other -> COUNTER = false; if(other -> MYCHAR == IKE && (PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM) == 139 || PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM) == 140)) { PA_StartSpriteAnimEx(MAIN_SCREEN, other -> SPRITENUM, 143, 144, 10, ANIM_LOOP, -1); other -> action = ATTACK; other -> delay = 60/10 * 2; other -> freeze(30); other -> dx = 0; PA_StartSpriteAnimEx(MAIN_SCREEN, other -> SPRITENUM, 139, 139, 1, ANIM_LOOP, -1); } if(TYPE == THUNDER1 || TYPE == THUNDER2 || TYPE == THUNDER3 || TYPE == THUNDER4) { vector<Projectile> projs = *((vector<Projectile>*)getProj()); for(int n = 0; n < (int)projs.size(); n++) { if(projs[n].owner == owner && (projs[n].TYPE == THUNDER1 || projs[n].TYPE == THUNDER2 || projs[n].TYPE == THUNDER3 || projs[n].TYPE == THUNDER4)) projs[n].enabled = false; } } } else if(other -> CAPE) { dx *= -1; owner = other -> charnum; vector<Circle> temp = hit.getCircles(); hit.reset(); for(int n = 0; n < (int)temp.size();n++) { hit.addCircle(Circle(temp[n].getX(), temp[n].getY(), temp[n].getRadius(), Knockback(temp[n].getKnockback().dx * -1, temp[n].getKnockback().dy, temp[n].getKnockback().length), temp[n].damage)); } if(dx > 0) PA_SetSpriteHflip(MAIN_SCREEN, num, 0); if(dx < 0) PA_SetSpriteHflip(MAIN_SCREEN, num, 1); } else if (other -> ABSORB && (TYPE != IKESWORD)) { other -> percentage -= atkbox.getHitCircle(other -> getDefbox(PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM))).damage; if(other -> percentage < 0) other -> percentage = 0; if(TYPE != THUNDER1 && TYPE != THUNDER2 && TYPE != THUNDER3 && TYPE != THUNDER4) removeProj(num); else atkbox.enabled = false; if(TYPE == THUNDER1 || TYPE == THUNDER2 || TYPE == THUNDER3 || TYPE == THUNDER4) { vector<Projectile> projs = *((vector<Projectile>*)getProj()); for(int n = 0; n < (int)projs.size(); n++) { if(projs[n].owner == owner && (projs[n].TYPE == THUNDER1 || projs[n].TYPE == THUNDER2 || projs[n].TYPE == THUNDER3 || projs[n].TYPE == THUNDER4)) projs[n].enabled = false; } } } else { other -> takeDamage(atkbox.getHitCircle(other -> getDefbox(PA_GetSpriteAnimFrame(MAIN_SCREEN, other -> SPRITENUM))), 1, owner, 0); if (TYPE != FINALCUTTER && TYPE != IKESWORD && TYPE != THUNDER1 && TYPE != THUNDER2 && TYPE != THUNDER3 && TYPE != THUNDER4) removeProj(num); else enabled = false; if(TYPE == THUNDER1 || TYPE == THUNDER2 || TYPE == THUNDER3 || TYPE == THUNDER4) { vector<Projectile> projs = *((vector<Projectile>*)getProj()); for(int n = 0; n < (int)projs.size(); n++) { if(projs[n].owner == owner && (projs[n].TYPE == THUNDER1 || projs[n].TYPE == THUNDER2 || projs[n].TYPE == THUNDER3 || projs[n].TYPE == THUNDER4)) projs[n].enabled = false; } } } } return other; }