#include "Mine.h" #include "TextureManager.h" #include "ParticleManager.h" #include "SoundManager.h" #include <iostream> using namespace sf; const float MINE_RADIUS = 2.0f, MAX_DAMAGE = 40.0f, // maximum amount of damage mine does to player DAMAGE_FALL_OFF = 1.5f, // larger = damage dealt to player is even lower when further away (1.0 = straight meters to damage conversion) MAX_PUSH = 70.0f, MAX_PUSH_DIST = 30.0f, MAX_VELOCITY = 4.0f, MAX_ANGULAR_VELOCITY = 25.0f, MINE_ACTIVE_DIST = 150.0f, MINE_ACTIVE_DIST_SQUARED = MINE_ACTIVE_DIST * MINE_ACTIVE_DIST; Mine::Mine() { type = MINE; mineState = MINE_NEEDS_TO_SPAWN; mineShape.setRadius(MINE_RADIUS); mineShape.setPointCount(15); Texture* mineTexture = TextureManager::LoadAndRetrieveTexture("Assets\\mine.png"); mineShape.setTexture(mineTexture); mineShape.setOrigin(MINE_RADIUS, MINE_RADIUS); } Mine::~Mine() { } void Mine::Load(PhysicsManager* physics, PlayerShip* playerShip, const Vector2f &position) { this->physics = physics; this->playerShip = playerShip; physicsBody = physics->AddMine(this, position, MINE_RADIUS); mineState = MINE_NORMAL; // give it a small random velocity Vector2f vel(randFloat() - 0.5f, randFloat() - 0.5f); vel = getNormalized(vel) * randFloat(MAX_VELOCITY); physicsBody->SetLinearVelocity(getB2Vector(vel)); float angular = randFloat(MAX_ANGULAR_VELOCITY); physicsBody->SetAngularVelocity(getRadians(rand() % 2 == 0 ? angular : -angular)); } void Mine::Update(float delta) { if (mineState == MINE_EXPLODING) { physics->RemoveBody(physicsBody); mineState = MINE_NEEDS_TO_SPAWN; return; } if (mineState == MINE_NEEDS_TO_SPAWN) return; float dist = getDistanceSquared(getPosition(), playerShip->getPosition()); bool lessThan = dist < MINE_ACTIVE_DIST_SQUARED; if (physicsBody->IsActive()) { if (!lessThan) physicsBody->SetActive(false); } else if (lessThan) physicsBody->SetActive(true); // get new position & rotation from box2D if (physicsBody->IsActive()) { mineShape.setPosition(getPosition()); mineShape.setRotation(getRotation()); } } void Mine::Draw(RenderWindow* Window) { if (mineState == MINE_NORMAL && isVisible(Window)) Window->draw(mineShape); } bool Mine::isVisible(RenderWindow* Window) { Vector2f wp = Window->getView().getCenter(); // center of screen Vector2f ws = Window->getView().getSize(); // width & height of screen in world coordinates ws += Vector2f(MINE_RADIUS * 2.0f, MINE_RADIUS * 2.0f); FloatRect wr(wp.x - ws.x / 2.0f, wp.y - ws.y / 2.0f, ws.x, ws.y); if ( wr.contains(getPosition()) ) return true; else return false; } void Mine::handleCollision(GameObject* objectHit, const sf::Vector2f& contactPoint) { if (mineState != MINE_NORMAL) return; if (objectHit->getType() == ASTEROID || objectHit->getType() == PLAYER_SHIP || objectHit->getType() == MINE) { // find distance to player double dist = getLength(playerShip->getPosition() - getPosition()); if (dist < 4.0f) dist = 0.0f; // calculate damage int damage = max(0, (int)(MAX_DAMAGE - dist*DAMAGE_FALL_OFF)); playerShip->updateHealth(damage); // std::cout << "mine damage to player = " << damage << "\n"; // bump player if (dist < MAX_PUSH_DIST) { float speed = (float)((MAX_PUSH_DIST - dist) / MAX_PUSH_DIST) * MAX_PUSH; std::cout << "mine push player speed = " << speed << "\n"; b2Vec2 dir = getB2Vector( getNormalized(playerShip->getPosition() - getPosition()) * speed ); playerShip->getPhysicsBody()->ApplyLinearImpulse(dir, playerShip->getPhysicsBody()->GetWorldCenter()); } mineState = MINE_EXPLODING; if (getDistance(playerShip->getPosition(), getPosition()) < 200.0f) { ParticleManager::addMineExplosionParticle(getPosition()); SoundManager::play(SoundManager::EXPLOSION_LARGE); } } }