compiles cleanly with -Wall -Wextra -Wconversion, not tested, but that shouldn't break anything :)
#include "Player.hh"
#include "Rope.hh"
#include "Engine.hh"
#include "Graphics.hh"
#include <math.h>
#include <stdexcept>
Rope::Rope(Player &player) :
PhysicsObject(player.state.world, ROPE_MASS, Vector(0,0), Vector(0,0), ROPE, false), player(player), state(ROPE_FOLDED)
{
// XXX: better shape
std::vector<Vector> shape(4);
shape[0] = Vector(-1, -1);
shape[1] = Vector(-1, 1);
shape[2] = Vector(1, 1);
shape[3] = Vector(1, -1);
setShape(shape);
}
void Rope::throwRope (void) {
state = ROPE_FLYING;
// XXX: this should probably be more dynamic?
length = ROPE_LENGTH;
// copy position + velocity from player
position = player.getPosition();
velocity = player.getVelocity() + player.getDirection() * ROPE_VELOCITY;
// we are FLYING
inAir = true;
// enable the physics object
enable();
// inform network
player.handleRopeState(state);
}
void Rope::onCollision (Vector collisionPoint, PhysicsObject *other) {
(void) other;
// attached to something!
state = ROPE_FIXED;
// Ropes location will be used as the pivot point, so move the location to the collisionPoint.
// Currently the position is something like one pixel away from the collisionPoint where there isn't ground.
this->position = collisionPoint;
// set player's pivot
player.setPivot(this);
// inform network
player.handleRopeState(state);
}
void Rope::release (void) {
// Remove the rope from the PhysicsWorld
disable();
state = ROPE_FOLDED;
// player doesn't have a pivot anymore
player.setPivot(NULL);
// inform network
player.handleRopeState(state);
}
void Rope::changeLength (float delta) {
// change length
length += delta;
// minimum length
if (length < 0)
length = 0;
// inform network
player.handleRopeLength(length);
}
RopeState Rope::getState (void) {
return state;
}
float Rope::getLength (void) {
return length;
}
void Rope::updateState (RopeState new_state, Vector position, Vector velocity, float new_length) {
// update physics enabled/disabled state
if (new_state == ROPE_FOLDED || new_state == ROPE_FIXED)
disable();
else // new_state == ROPE_FLYING
enable();
// update player.pivot
if (new_state == ROPE_FIXED)
player.setPivot(this);
else if (this->state == ROPE_FIXED)
player.setPivot(NULL);
// update position stuff
updatePhysics(position, velocity, true, FACING_RIGHT, 0);
// update vars
this->state = new_state;
this->length = new_length;
}
void Rope::updateLength (float length) {
// update length
this->length = length;
}
float Rope::getPivotForce (PhysicsObject *bob) {
if ((position - bob->getPosition()).length() >= length)
return ROPE_FORCE;
else
return 0;
}
void Rope::draw (Graphics *g, PixelCoordinate camera) {
if (state == ROPE_FOLDED)
return;
PixelCoordinate player_pos = player.getCoordinate() - camera;
PixelCoordinate self_pos = getCoordinate() - camera;
g->get_gc()->draw_line(
player_pos.x, player_pos.y,
self_pos.x, self_pos.y,
CL_Color::black
);
}
void Rope::tick (TimeMS dt) {
if (this->state == ROPE_FLYING) {
// super
PhysicsObject::tick(dt);
}
else if (this->state == ROPE_FIXED) {
// If there's not ground on the pivot point anymore, release the rope
if (!world.collides(position)) {
this->state = ROPE_FLYING;
player.handleRopeState(state);
}
}
else { // ROPE_FOLDED
// Rope shouldn't be ticking if it is folded, but this can still happen
// immediately after the rope has been released
}
}