#include <SDL_image.h> #include <math.h> #include "Projectile.h" #include "Player.h" void Projectile::init(SDL_Surface* image, uint collWidth, uint collHeight, uint frameWidth, uint frameHeight, uint numFrames, uint animationSpeed, Sound* sound) { chart = image; this->sound = sound; this->numFrames = numFrames; this->animationSpeed = animationSpeed; this->spriteDeathList = spriteDeathList; setCollSize(collWidth, collHeight); setFrameSize(frameWidth, frameHeight); } // Note : if projectile did not come from player, then pass NULL to player parameter void Projectile::reset(Player* player, PVector<int> startPosition, PVector<double> startVelocity, bool useGravity, bool playerPickup, bool reverseAnimation) { this->player = player; this->useGravity = useGravity; this->playerPickup = playerPickup; this->reverseAnimation = reverseAnimation; velocity = startVelocity; position = (PVector<double>)startPosition; origY = startPosition.y; health = 1; inAir = true; active = true; frame = 0; animationCount = 0.0; wavyCount = PROJ_WAVY_FREQ * 3.14159265; // start wavyness at middle inflection point in sine wave // lower velocity slightly to account for wavyness(drunkeness) if (player != NULL) velocity.x *= 1.0 - player->getDrunkeness() / PROJ_WAVY_SPEED_SCALE; } // this is called first by other two update functions void Projectile::update(double delta) { if (!active) return; // update position if (useGravity) velocity.y += DAY_GRAVITY * delta; position += velocity * delta; // do animation if ( (animationCount += delta ) >= animationSpeed ) { animationCount = 0.0; if ( !reverseAnimation && ++frame >= (int)numFrames ) frame = 0; else if ( reverseAnimation && --frame < 0) frame = numFrames - 1; } } void Projectile::checkCollidables(std::vector<Collidable>& collArray) { Collidable box = getCollBox(); for (uint i = 0; i < collArray.size(); i++) { Collidable c(collArray[i]); if (!collArray[i].isLedge && checkBoxToBox(box, c)) { if (!playerPickup) hurt(NULL, HURT_BY_COLL); else inAir = false; sound->playBottleSmashEffect(); break; } } } // this is for projectiles from player void Projectile::updateFromPlayer(double delta, std::vector<Collidable>& collArray, std::vector<Sprite*>& enemyArray) { if (!active) return; // vary y position with player drunkeness wavyCount += delta; position.y = origY + sin(wavyCount / PROJ_WAVY_FREQ) * player->getDrunkeness() * PROJ_WAVY_AMP; // update position, check for collision with collidables update(delta); checkCollidables(collArray); // check for collision with enemies Collidable c = getCollBox(); for (uint i = 0; i < enemyArray.size(); i++) { if (!enemyArray[i]->isActive()) // dont check dead enemies continue; // apply a small trim to enemy bounding boxes so that we can control the "tightness" of all enemy collisions Collidable e = enemyArray[i]->getCollBox(); e.trim(ALL_ENEMY_TRIM); if (checkBoxToBox(c, e)) { enemyArray[i]->hurt(this, HURT_BY_PROJ); hurt(NULL, HURT_BY_ENEMY); sound->playBarKeepKickEffect(); active = false; return; } } } // this is for projectiles from enemies void Projectile::updateFromEnemy(double delta, std::vector<Collidable>& collArray, Player* player) { if (!active) return; if (inAir) update(delta); // check for collision with player Collidable c = getCollBox(); if (checkBoxToBox( c, player->getCollBox() )) { if ( !playerPickup || inAir ) { player->hurt(this, HURT_BY_PROJ); hurt(player, HURT_BY_PLAYER); } else { player->addToAmmoCount(BOSS_PROJ_AMMO); sound->playBeerEffect(); } active = false; } if (inAir) checkCollidables(collArray); } void Projectile::render(SDL_Surface* screen, int cameraX, SDL_Rect* clip) { if (!active) return; // check for going off-screen (must be done in render() so we can check against camera location) if ( (!playerPickup && (position.x + collWidth < cameraX || position.x > cameraX + SCREEN_WIDTH) || position.y + collHeight < 0 || position.y > SCREEN_HEIGHT)) { active = false; return; } // find clip for current frame SDL_Rect c = { frame * frameWidth, 0, frameWidth, frameHeight }; Sprite::render(screen, cameraX, &c); }