/**
* Triangles
* Copyright (C) 2016 POSITIVE MENTAL ATTITUDE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include "Player.hpp"
#include "Assets.hpp"
Player::Player():
Triangle(),
InputTarget(_inputMap),
Collidable(),
_movement(0.f),
_movementSpeed(2.f),
_movementMomentum(0.f),
_movementAcceleration(10.f),
_movementSuppresion(10.f),
_rotation(0.f),
_rotationSpeed(0.6f),
_rotationMomentum(0.f),
_rotationAcceleration(38.f),
_rotationSuppresion(20.f),
_hit(false),
_dead(false),
_particleSystem(1920, 1080)
{
/**
* Default binding
*/
if(sf::Joystick::isConnected(0))
{
_inputMap.map(1, Input(sf::Joystick::Axis::Y, false));
_inputMap.map(2, Input(sf::Joystick::Axis::Y, true));
_inputMap.map(3, Input(sf::Joystick::Axis::Z, false));
_inputMap.map(4, Input(sf::Joystick::Axis::Z, true));
_inputMap.map(5, Input(7));
}
else
{
_inputMap.map(1, Input(sf::Keyboard::W));
_inputMap.map(2, Input(sf::Keyboard::S));
_inputMap.map(3, Input(sf::Keyboard::A));
_inputMap.map(4, Input(sf::Keyboard::D));
_inputMap.map(5, Input(sf::Keyboard::Space));
}
/**
* Input lambdas
*/
bind(1, [this](const sf::Event&, float power)
{
_movement += power;
});
bind(2, [this](const sf::Event&, float power)
{
_movement -= power * 0.8f;
});
bind(3, [this](const sf::Event&, float power)
{
_rotation -= power;
});
bind(4, [this](const sf::Event&, float power)
{
_rotation += power;
});
bind(5, [this](const sf::Event&, float)
{
if(_bulletTimer.getElapsedTime().asMilliseconds() > 1500)
{
// Does not check if _context != nullptr
// so please do remember to call setContext().
_bullets.emplace_back(getRotation(), getPosition(),
_context->assets->loadSound("data/audio/Shotgun.ogg"),
_context->assets->loadSound("data/audio/Bomb.ogg"),
_context->foreground);
_bullets.back().setTexture(_innerTexture);
_bulletTimer.restart();
_movementMomentum -= 3.f;
}
});
/**
* Particles
*/
_particleSystem.setDissolutionRate(255.f);
/**
* Technical
*/
genCollisionBox("data/hitbox/Player.png", sf::Vector2f(71.f, 100.f));
_bullets.reserve(10);
_bulletTimer.restart();
_durability = 0.99f;
}
void Player::setContext(Context* context)
{
_context = context;
_glass.setBuffer(_context->assets->loadSound("data/audio/GlassHit.ogg"));
_deathSound.setBuffer(_context->assets->loadSound("data/audio/GlassRekt.ogg"));
}
bool Player::isDead()
{
return _dead;
}
void Player::setTexture(sf::Texture& texture)
{
_innerTexture = texture;
_image = texture.copyToImage();
_texture = &_innerTexture;
vertexFit();
unsigned pointCount = 0;
for(unsigned i = 0; i < _image.getSize().x; ++i)
for(unsigned j = 0; j < _image.getSize().y; ++j)
if(_image.getPixel(i, j).a > 0)
++pointCount;
setPointCount(pointCount);
}
bool Player::checkCollision(Foreground& foreground)
{
updateTransform(getTransform());
int k = pixelPerfect(foreground);
if(k == -1)
{
if(_glass.getStatus() != sf::Sound::Status::Playing)
_glass.setVolume(0.f);
_hit = false;
return false;
}
float i = 10.f;
while(k != -1)
{
sf::Vector2f pos = _cmap[k];
sf::Vector2f center = sf::Vector2f(_image.getSize().x / 2.f, 100.f);
if(center.x + pos.x >= 0 && center.x + pos.x < _image.getSize().x and center.y + pos.y >= 0 && center.y + pos.y < _image.getSize().y)
_image.setPixel(center.x + pos.x, center.y + pos.y, sf::Color(0, 0, 0, 0));
for(int i = -1; i <= 1; i++)
for(int j = -1; j <= 1; j++)
{
if(i == 0 && j == 0)
continue;
if(pos.x + center.x + i < 0 || pos.y + center.y + j < 0 or pos.x + center.x + i > _image.getSize().x || pos.y + center.y + j > _image.getSize().y)
continue;
if(_image.getPixel(pos.x + center.x + i, pos.y + center.y + j).a > 0)
{
sf::Vector2f vec;
vec.x = pos.x + i;
vec.y = pos.y + j;
if(std::find(_cmap.begin(), _cmap.end(), vec) == _cmap.end())
if(std::find(_cbanned.begin(), _cbanned.end(), vec) == _cbanned.end())
_cmap.push_back(vec);
}
}
_cmap.erase(_cmap.begin() + k);
_cbanned.push_back(pos);
k = pixelPerfect(foreground);
if(i < 100.f) i += 0.1f;
}
if(i > _glass.getVolume())
_glass.setVolume(i);
if(_glass.getStatus() != sf::Sound::Status::Playing) _glass.play();
_innerTexture.loadFromImage(_image);
_hit = true;
if(_pointCount * _durability < _cbanned.size())
{
_dead = true;
_deathSound.play();
return true;
}
else
return false;
}
void Player::keyboardControls(sf::Time delta)
{
float seconds = delta.asSeconds();
const double degree = 3.14159265358 / 180.;
if(_hit)
{
if(_movement > 0 || _movementMomentum > 0)
_movementMomentum -= seconds * 15.f;
if(_movement < 0 || _movementMomentum < 0)
_movementMomentum += seconds * 15.f;
_movement *= 0.6f;
}
_movementMomentum += _movementAcceleration * seconds * _movement;
if(_movement == 0.f)
{
if(_movementMomentum > _movementSuppresion * seconds)
_movementMomentum -= _movementSuppresion * seconds;
else if(_movementMomentum < -_movementSuppresion * seconds)
_movementMomentum += _movementSuppresion * seconds;
else
_movementMomentum = 0.f;
}
sf::Vector2f movement;
movement.x = std::sin(getRotation() * degree) * 60.f * _movementSpeed * _movementMomentum * seconds;
movement.y = -std::cos(getRotation() * degree) * 60.f * _movementSpeed * _movementMomentum * seconds;
move(movement);
_particleSystem.fuel(movement.x * 20.f, getRotation());
_particleSystem.fuel(movement.y * 20.f, getRotation());
_movement = 0.f;
_rotationMomentum += _rotationAcceleration * seconds * _rotation;
if(_rotationMomentum > _rotationSuppresion * seconds)
_rotationMomentum -= _rotationSuppresion * seconds;
else if(_rotationMomentum < -_rotationSuppresion * seconds)
_rotationMomentum += _rotationSuppresion * seconds;
else
_rotationMomentum = 0.f;
float rotation = 90.f * _rotationSpeed * _rotationMomentum * seconds;
rotate(rotation);
_rotation = 0.f;
}
void Player::padControls(sf::Time delta)
{
float seconds = delta.asSeconds();
const double degree = 3.14159265358 / 180.;
sf::Vector2f v = sf::Vector2f(
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::X) / 100.f,
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::Y) / 100.f);
float curr = getRotation();
static float supposed;
if(v.x != 0 or v.y != 0)
supposed = atan2(v.x, -v.y) / degree;
if(supposed < 0.f)
supposed += 360.f;
float c = supposed - curr;
if(curr > 180.f && supposed < 180.f)
{
float a = (supposed - curr);
float b = (supposed - curr + 360.f);
if(std::fabs(a) < std::fabs(b))
c = a;
else
c = b;
}
if(curr < 180.f && supposed > 180.f)
{
float a = (supposed - curr);
float b = (supposed - curr - 360.f);
if(std::fabs(a) < std::fabs(b))
c = a;
else
c = b;
}
if(v.x != 0 or v.y != 0)
{
if(c > 0.f)
_rotationMomentum += _rotationAcceleration * seconds;
else if(c < 0.f)
_rotationMomentum -= _rotationAcceleration * seconds;
}
if(_rotationMomentum > _rotationSuppresion * seconds)
_rotationMomentum -= _rotationSuppresion * seconds;
else if(_rotationMomentum < -_rotationSuppresion * seconds)
_rotationMomentum += _rotationSuppresion * seconds;
else
_rotationMomentum = 0.f;
float rotation = 90.f * _rotationSpeed * _rotationMomentum * seconds;
rotate(rotation);
if((v.x != 0 || v.y != 0) && c < 1.f)
_movement = std::fabs(v.x + v.y);
if(_hit)
{
if(_movement > 0 || _movementMomentum > 0)
_movementMomentum -= seconds * 15.f;
if(_movement < 0 || _movementMomentum < 0)
_movementMomentum += seconds * 15.f;
_movement *= 0.6f;
}
_movementMomentum += _movementAcceleration * seconds * _movement;
if(_movement == 0.f)
{
if(_movementMomentum > _movementSuppresion * seconds)
_movementMomentum -= _movementSuppresion * seconds;
else if(_movementMomentum < -_movementSuppresion * seconds)
_movementMomentum += _movementSuppresion * seconds;
else
_movementMomentum = 0.f;
}
sf::Vector2f movement;
movement.x = std::sin(getRotation() * degree) * 60.f * _movementSpeed * _movementMomentum * seconds;
movement.y = -std::cos(getRotation() * degree) * 60.f * _movementSpeed * _movementMomentum * seconds;
move(movement);
_particleSystem.fuel(movement.x * 20.f, getRotation());
_particleSystem.fuel(movement.y * 20.f, getRotation());
_movement = 0.f;
}
void Player::update(sf::Time delta)
{
//if(sf::Joystick::isConnected(0))
//padControls(delta);
//else
keyboardControls(delta);
for(unsigned i = 0; i < _bullets.size(); ++i)
{
_bullets[i].update(delta);
if(_bullets[i].isDead())
_bullets.erase(_bullets.begin() + i);
}
_particleSystem.setPosition(getPosition());
_particleSystem.clear();
_particleSystem.update(delta);
_particleSystem.render();
}
void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(_particleSystem.getSprite());
for(unsigned i = 0; i < _bullets.size(); ++i)
target.draw(_bullets[i]);
states.transform *= getTransform();
if(_texture != nullptr)
states.texture = (_texture);
target.draw(_vertices, states);
}