Made Triangle immutable

Correct inheritance (Objects -> Mesh & Camera -> RigidBody)
Small code refactor
master
Vectozavr 2021-09-19 15:25:10 +07:00
parent 17a307c45e
commit be42d4d9bc
32 changed files with 569 additions and 685 deletions

View File

@ -8,7 +8,7 @@
#include "World.h"
#include "Player.h"
class Bonus : public Mesh {
class Bonus : public RigidBody {
protected:
std::string _name;
public:

View File

@ -15,27 +15,27 @@ void Client::updatePacket() {
void Client::spawnPlayer(sf::Uint16 id) {
std::string name = "Player_" + std::to_string(id);
_players.insert({ id, std::make_shared<Player>() });
(*_world).addMesh(_players[id], name);
(*_world).addBody(_players[id], name);
_players[id]->setVisible(true);
_players[id]->setAcceleration(Point4D{0, 0, 0});
// add head and other stuff:
_world->loadObj(name + "_head", "../obj/cube.obj", "",Point4D{0.7, 0.7, 0.7});
(*_world)[name + "_head"]->translate(Point4D{0, 2, 0});
(*_world)[name + "_head"]->setCollider(false);
_players[id]->attach((*_world)[name + "_head"]);
_world->loadBody(name + "_head", "../obj/cube.obj", "", Point4D{0.7, 0.7, 0.7});
_world->body(name + "_head")->translate(Point4D{0, 2, 0});
_world->body(name + "_head")->setCollider(false);
_players[id]->attach(_world->body(name + "_head"));
_world->loadObj(name + "_eye1", "../obj/cube.obj", "",Point4D{0.2, 0.2, 0.05});
(*_world)[name + "_eye1"]->translate(Point4D{0.3, 2.1, 0.7});
(*_world)[name + "_eye1"]->setCollider(false);
(*_world)[name + "_eye1"]->setColor({147, 159, 255});
(*_world)[name + "_head"]->attach((*_world)[name + "_eye1"]);
_world->loadBody(name + "_eye1", "../obj/cube.obj", "", Point4D{0.2, 0.2, 0.05});
_world->body(name + "_eye1")->translate(Point4D{0.3, 2.1, 0.7});
_world->body(name + "_eye1")->setCollider(false);
_world->body(name + "_eye1")->setColor({147, 159, 255});
_world->body(name + "_head")->attach(_world->body(name + "_eye1"));
_world->loadObj(name + "_eye2", "../obj/cube.obj", "",Point4D{0.2, 0.2, 0.05});
(*_world)[name + "_eye2"]->translate(Point4D{-0.3, 2.1, 0.7});
(*_world)[name + "_eye2"]->setCollider(false);
(*_world)[name + "_eye2"]->setColor({147, 159, 255});
(*_world)[name + "_head"]->attach((*_world)[name + "_eye2"]);
_world->loadBody(name + "_eye2", "../obj/cube.obj", "", Point4D{0.2, 0.2, 0.05});
_world->body(name + "_eye2")->translate(Point4D{-0.3, 2.1, 0.7});
_world->body(name + "_eye2")->setCollider(false);
_world->body(name + "_eye2")->setColor({147, 159, 255});
_world->body(name + "_head")->attach(_world->body(name + "_eye2"));
}
void Client::processInit(sf::Packet& packet) {
@ -64,7 +64,7 @@ void Client::processUpdate(sf::Packet& packet) {
_players[targetId]->setHealth(buf[3]);
_players[targetId]->rotateToAngle(Point4D{0, buf[4], 0});
(*_world)[name + "_head"]->rotate(Matrix4x4::RotationY(buf[4]) * Point4D{1, 0, 0},
_world->body(name + "_head")->rotate(Matrix4x4::RotationY(buf[4]) * Point4D{1, 0, 0},
buf[5] - _players[targetId]->headAngle());
_players[targetId]->setHeadAngle(buf[5]);
} else if (targetId == _socket.ownId()) {
@ -84,10 +84,10 @@ void Client::processNewClient(sf::Packet& packet) {
void Client::processDisconnect(sf::Uint16 targetId) {
if (targetId != _socket.ownId() && _players.count(targetId)) {
std::string name = "Player_" + std::to_string(targetId);
_world->removeMesh(name);
_world->removeMesh(name + "_head");
_world->removeMesh(name + "_eye1");
_world->removeMesh(name + "_eye2");
_world->removeBody(name);
_world->removeBody(name + "_head");
_world->removeBody(name + "_eye1");
_world->removeBody(name + "_eye2");
_players.erase(targetId);
}
@ -128,18 +128,19 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
p2 = Point4D(dbuff[3], dbuff[4], dbuff[5]);
tmp = "Client_fireTraces_" + std::to_string(fireTraces++);
_world->addMesh(std::make_shared<Mesh>(Mesh::LineTo(p1, p2, 0.05)), tmp);
(*_world)[tmp]->setCollider(false);
_world->addBody(std::make_shared<RigidBody>(RigidBody(Mesh::LineTo(p1, p2, 0.05))), tmp);
_world->body(tmp)->setCollider(false);
(*_world)[tmp]->a_color(tmp + "_fadeOut", {255, 255, 255, 0}, 1, Animation::None, Animation::linear);
(*_world)["Player_im"]->a_function(tmp + "delete", [this, tmp](){ deleteTrace(_world, tmp); }, 1, 2);
_world->body(tmp)->a_color(tmp + "_fadeOut", {255, 255, 255, 0}, 1, Animation::None, Animation::linear);
_world->body("Player_im")->a_function(tmp + "delete", [this, tmp](){ deleteTrace(_world, tmp); }, 1, 2);
break;
case MsgType::InitBonuses:
while (packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2]) {
tmp2 = tmp.substr(6, tmp.size()-3-5);
_world->addMesh(std::make_shared<Bonus>(tmp, "../obj/" + tmp2 + ".obj", "../obj/" + tmp2 + "_mat.txt", Point4D{3, 3, 3}), tmp);
(*_world)[tmp]->translateToPoint(Point4D(dbuff[0], dbuff[1], dbuff[2]));
_world->addBody(std::make_shared<Bonus>(tmp, "../obj/" + tmp2 + ".obj", "../obj/" + tmp2 + "_mat.txt",
Point4D{3, 3, 3}), tmp);
_world->body(tmp)->translateToPoint(Point4D(dbuff[0], dbuff[1], dbuff[2]));
}
break;
@ -147,13 +148,14 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2];
tmp2 = tmp.substr(6, tmp.size()-3-5);
_world->addMesh(std::make_shared<Bonus>(tmp, "../obj/" + tmp2 + ".obj", "../obj/" + tmp2 + "_mat.txt", Point4D{3, 3, 3}), tmp);
(*_world)[tmp]->translateToPoint(Point4D(dbuff[0], dbuff[1], dbuff[2]));
_world->addBody(std::make_shared<Bonus>(tmp, "../obj/" + tmp2 + ".obj", "../obj/" + tmp2 + "_mat.txt",
Point4D{3, 3, 3}), tmp);
_world->body(tmp)->translateToPoint(Point4D(dbuff[0], dbuff[1], dbuff[2]));
break;
case MsgType::RemoveBonus:
packet >> tmp;
_world->removeMesh(tmp);
_world->removeBody(tmp);
break;
}
}
@ -162,10 +164,10 @@ void Client::processDisconnected() {
for (auto it = _players.begin(); it != _players.end();) {
std::string name = "Player_" + std::to_string(it->first);
_world->removeMesh(name);
_world->removeMesh(name + "_head");
_world->removeMesh(name + "_eye1");
_world->removeMesh(name + "_eye2");
_world->removeBody(name);
_world->removeBody(name + "_head");
_world->removeBody(name + "_eye1");
_world->removeBody(name + "_eye2");
_players.erase(it++);
}
}
@ -187,7 +189,7 @@ void Client::addTrace(const Point4D& from, const Point4D& to) {
}
void Client::deleteTrace(std::shared_ptr<World> world, const std::string &traceName) {
world->removeMesh(traceName);
world->removeBody(traceName);
}
void Client::takeBonus(const std::string& bonusName) {

View File

@ -21,7 +21,7 @@ private:
void spawnPlayer(sf::Uint16 id);
public:
Client(std::shared_ptr<Player> player, std::shared_ptr<World> world) : _player(std::move(player)), _world(std::move(world)) {};
Client(std::shared_ptr<Player> player, std::shared_ptr<World> world) : _player(player), _world(world) {};
void updatePacket() override;

View File

@ -11,28 +11,28 @@ void Player::update() {
// friction
if(inCollision())
p_velocity = p_velocity - p_velocity*Time::deltaTime()*2;
_velocity = _velocity - _velocity * Time::deltaTime() * 2;
if(isInSlowMo) {
if(_isInSlowMo) {
if(_ability > 0)
_ability -= Time::deltaTime();
else {
_ability = 0;
isInSlowMo = false;
setVelocity(velocity()*slowMoCoefficient);
setAcceleration(p_acceleration*slowMoCoefficient*slowMoCoefficient);
slowMoSound.stop();
unSlowMoSound.play();
_isInSlowMo = false;
setVelocity(velocity() * _slowMoCoefficient);
setAcceleration(_acceleration * _slowMoCoefficient * _slowMoCoefficient);
_slowMoSound.stop();
_unSlowMoSound.play();
}
}
double coeff = isInSlowMo ? 1.0/slowMoCoefficient : 1.0;
double coeff = _isInSlowMo ? 1.0 / _slowMoCoefficient : 1.0;
bool inRunning_old = inRunning;
inRunning = _screen != nullptr && (Screen::isKeyPressed(sf::Keyboard::A) || Screen::isKeyPressed(sf::Keyboard::D) ||Screen::isKeyPressed(sf::Keyboard::W) || Screen::isKeyPressed(sf::Keyboard::S));
bool inRunning_old = _inRunning;
_inRunning = _screen != nullptr && (Screen::isKeyPressed(sf::Keyboard::A) || Screen::isKeyPressed(sf::Keyboard::D) || Screen::isKeyPressed(sf::Keyboard::W) || Screen::isKeyPressed(sf::Keyboard::S));
// in case when the camera is attached we make some animation during running
if(_camera != nullptr && inRunning && !_camera->isInAnim()) {
if(_camera != nullptr && _inRunning && !_camera->isInAnim()) {
_camera->a_translate("hor_oscil", -_camera->left()/12, 0.3/coeff, Animation::LoopOut::None, Animation::cos);
_camera->a_wait("hor_oscil", 0);
_camera->a_translate("hor_oscil", _camera->left()/12, 0.3/coeff, Animation::LoopOut::None, Animation::cos);
@ -47,7 +47,7 @@ void Player::update() {
_camera->a_translateToPoint("init", position() + Point4D{0, 1.8, 0}, 0.3/coeff, Animation::None, Animation::cos);
} else if(_camera != nullptr && inRunning_old && !inRunning) {
} else if(_camera != nullptr && inRunning_old && !_inRunning) {
_camera->a_stopAllAnimations();
_camera->a_translateToPoint("init", position() + Point4D{0, 1.8, 0}, 0.15/coeff, Animation::None, Animation::cos);
@ -58,55 +58,55 @@ void Player::update() {
if(_world != nullptr && _screen != nullptr && _camera != nullptr) {
// Left and right
if (Screen::isKeyPressed(sf::Keyboard::A)) {
translate(_camera->left() * Time::deltaTime() * walkSpeed * coeff);
translate(_camera->left() * Time::deltaTime() * _walkSpeed * coeff);
if(inCollision())
setVelocity(Point4D{0,0,0});
}
if (Screen::isKeyPressed(sf::Keyboard::D)) {
translate(-_camera->left() * Time::deltaTime() * walkSpeed * coeff);
translate(-_camera->left() * Time::deltaTime() * _walkSpeed * coeff);
if(inCollision())
setVelocity(Point4D{0,0,0});
}
// Forward and backward
if (Screen::isKeyPressed(sf::Keyboard::W)) {
translate(_camera->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * walkSpeed * coeff);
translate(_camera->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * _walkSpeed * coeff);
if(inCollision())
setVelocity(Point4D{0,0,0});
}
if (Screen::isKeyPressed(sf::Keyboard::S)) {
translate(-_camera->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * walkSpeed * coeff);
translate(-_camera->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * _walkSpeed * coeff);
if(inCollision())
setVelocity(Point4D{0,0,0});
}
if (_ability > 0 && !isInSlowMo && Screen::isKeyPressed(sf::Keyboard::LShift)) {
if (_ability > 0 && !_isInSlowMo && Screen::isKeyPressed(sf::Keyboard::LShift)) {
// slow mo
isInSlowMo = true;
setVelocity(velocity()/slowMoCoefficient);
setAcceleration(p_acceleration/(slowMoCoefficient*slowMoCoefficient));
unSlowMoSound.stop();
slowMoSound.play();
} else if (isInSlowMo && !Screen::isKeyPressed(sf::Keyboard::LShift)) {
isInSlowMo = false;
setVelocity(velocity()*slowMoCoefficient);
setAcceleration(p_acceleration*slowMoCoefficient*slowMoCoefficient);
slowMoSound.stop();
unSlowMoSound.play();
_isInSlowMo = true;
setVelocity(velocity() / _slowMoCoefficient);
setAcceleration(_acceleration / (_slowMoCoefficient * _slowMoCoefficient));
_unSlowMoSound.stop();
_slowMoSound.play();
} else if (_isInSlowMo && !Screen::isKeyPressed(sf::Keyboard::LShift)) {
_isInSlowMo = false;
setVelocity(velocity() * _slowMoCoefficient);
setAcceleration(_acceleration * _slowMoCoefficient * _slowMoCoefficient);
_slowMoSound.stop();
_unSlowMoSound.play();
}
if (Screen::isKeyPressed(sf::Keyboard::Space) && inCollision()) {
addVelocity(Point4D{0, std::abs(_collisionNormal.y())*sqrt(2 * g * jumpHeight)*coeff, 0});
translate(Point4D{0, Time::deltaTime() * walkSpeed * 2 * coeff, 0});
addVelocity(Point4D{0, std::abs(_collisionNormal.y()) * sqrt(2 * _g * _jumpHeight) * coeff, 0});
translate(Point4D{0, Time::deltaTime() * _walkSpeed * 2 * coeff, 0});
}
// Mouse movement
Point4D disp = _screen->getMouseDisplacement();
rotate(Point4D{0, -disp.x() / 1000.0, 0});
p_velocity = Matrix4x4::RotationY(-disp.x() / 1000.0)*p_velocity;
_velocity = Matrix4x4::RotationY(-disp.x() / 1000.0) * _velocity;
double rotationLeft = disp.y() / 1000.0;
@ -126,7 +126,7 @@ void Player::update() {
_selectedWeapon = (_selectedWeapon + 1) % _weapons.size();
_weapons[_selectedWeapon]->addToWorld(_world);
Log::log("selected _selectedWeapon " + std::to_string(_selectedWeapon));
changeWeaponSound.play();
_changeWeaponSound.play();
}
}
@ -140,7 +140,7 @@ void Player::update() {
_selectedWeapon = _weapons.size() - 1;
_weapons[_selectedWeapon]->addToWorld(_world);
Log::log("selected _selectedWeapon " + std::to_string(_selectedWeapon));
changeWeaponSound.play();
_changeWeaponSound.play();
}
}
@ -148,7 +148,7 @@ void Player::update() {
auto damagedPlayers = _weapons[_selectedWeapon]->fire(_world, _camera);
for(auto& damagedPlayer : damagedPlayers) {
sf::Uint16 targetId = std::stoi(damagedPlayer.first.substr(7));
damagePlayerCallBack(targetId, damagedPlayer.second);
_damagePlayerCallBack(targetId, damagedPlayer.second);
}
}
@ -156,11 +156,11 @@ void Player::update() {
_weapons[_selectedWeapon]->reload();
}
if (inRunning && inCollision() && walkSound.getStatus() != sf::Sound::Status::Playing) {
if (_inRunning && inCollision() && _walkSound.getStatus() != sf::Sound::Status::Playing) {
if ((position() - rayToFloor.first).abs() < 2) {
int soundNum = round((double) rand() / RAND_MAX * 5) + 1;
walkSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/stonestep" + std::to_string(soundNum) + ".ogg"));
walkSound.play();
_walkSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/stonestep" + std::to_string(soundNum) + ".ogg"));
_walkSound.play();
}
}
}
@ -248,7 +248,7 @@ void Player::drawStats() {
text_ammo2.setFillColor(sf::Color(0, 0, 0, 70));
_screen->window.draw(text_ammo2);
// text killSound/deathSound stats
// text _killSound/_deathSound stats
sf::Text text_kills(text_health);
text_kills.setStyle(sf::Text::Bold);
text_kills.setString("KILLS: " + std::to_string((int)_kills) + " | " + "DEATHS: " + std::to_string((int)_deaths));
@ -267,16 +267,16 @@ void Player::drawStats() {
}
void Player::playDeath() {
deathSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/classic_hurt.ogg"));
deathSound.play();
_deathSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/classic_hurt.ogg"));
_deathSound.play();
}
void Player::playKill() {
killSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/kill.ogg"));
killSound.play();
_killSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/kill.ogg"));
_killSound.play();
}
void Player::collisionWithObject(const std::string &objName, std::shared_ptr<Mesh> obj) {
void Player::collisionWithObject(const std::string &objName, std::shared_ptr<RigidBody> obj) {
if(objName.find("Bonus_gun") != std::string::npos)
addWeapon(std::make_shared<Gun>());
@ -299,13 +299,13 @@ void Player::collisionWithObject(const std::string &objName, std::shared_ptr<Mes
setFullAbility();
if(objName.find("Bonus") != std::string::npos) {
_world->removeMesh(objName);
takeBonusCallBack(objName);
_world->removeBody(objName);
_takeBonusCallBack(objName);
}
}
void Player::addWeapon(std::shared_ptr<Weapon> weapon) {
changeWeaponSound.play();
_changeWeaponSound.play();
if(!_weapons.empty()) {
for(auto& w : _weapons) {
@ -320,11 +320,11 @@ void Player::addWeapon(std::shared_ptr<Weapon> weapon) {
_weapons.back()->attachToPlayer(*this);
_weapons.back()->translate(position());
_weapons.back()->rotateRelativePoint(position() + Point4D{0, 1.8, 0}, Point4D{0, 1, 0}, p_angle.y());
_weapons.back()->rotateRelativePoint(position() + Point4D{0, 1.8, 0}, Point4D{0, 1, 0}, _angle.y());
_weapons.back()->rotateRelativePoint(position() + Point4D{0, 1.8, 0}, _camera->left(), _camera->angleLeftUpLookAt().x());
_weapons.back()->setAddTraceCallBack(addTraceCallBack);
changeWeaponSound.play();
_weapons.back()->setAddTraceCallBack(_addTraceCallBack);
_changeWeaponSound.play();
}
void Player::initWeapons() {

View File

@ -8,7 +8,6 @@
#include <SFML/Audio/Sound.hpp>
#include <utility>
#include <ResourceManager.h>
#include "Mesh.h"
#include "Camera.h"
#include "World.h"
#include "weapon/Ak47.h"
@ -17,7 +16,7 @@
#include "weapon/Gold_Ak47.h"
#include "weapon/Rifle.h"
class Player : public Mesh{
class Player : public RigidBody{
private:
double _healthMax = 100;
double _health = _healthMax;
@ -25,80 +24,80 @@ private:
double _abilityMax = 10;
double _ability = _abilityMax;
double jumpHeight = 3;
double walkSpeed = 10;
double _jumpHeight = 3;
double _walkSpeed = 10;
double _headAngle = 0;
unsigned _kills = 0;
unsigned _deaths = 0;
double g = 35;
double _g = 35;
double slowMoCoefficient = 5;
bool isInSlowMo = false;
double _slowMoCoefficient = 5;
bool _isInSlowMo = false;
std::shared_ptr<Camera> _camera;
std::shared_ptr<Screen> _screen;
std::shared_ptr<World> _world;
bool inRunning = false;
bool _inRunning = false;
// sounds
sf::Sound killSound;
sf::Sound deathSound;
sf::Sound walkSound;
sf::Sound changeWeaponSound;
sf::Sound slowMoSound;
sf::Sound unSlowMoSound;
sf::Sound fullHealthSound;
sf::Sound fullAbilitySound;
sf::Sound _killSound;
sf::Sound _deathSound;
sf::Sound _walkSound;
sf::Sound _changeWeaponSound;
sf::Sound _slowMoSound;
sf::Sound _unSlowMoSound;
sf::Sound _fullHealthSound;
sf::Sound _fullAbilitySound;
std::string _name = "im";
std::vector<std::shared_ptr<Weapon>> _weapons;
uint8_t _selectedWeapon = 0;
std::function<void(sf::Uint16 targetId, double)> damagePlayerCallBack;
std::function<void(const Point4D&, const Point4D&)> addTraceCallBack;
std::function<void(const std::string&)> takeBonusCallBack;
std::function<void(sf::Uint16 targetId, double)> _damagePlayerCallBack;
std::function<void(const Point4D&, const Point4D&)> _addTraceCallBack;
std::function<void(const std::string&)> _takeBonusCallBack;
public:
Player() {
loadObj("../obj/cube.obj", "", Point4D{0.5, 1.9, 0.5});
setAcceleration(Point4D{0, -g, 0});
setAcceleration(Point4D{0, -_g, 0});
setCollision(true);
setVisible(false);
setColor({240, 168, 168});
_changeWeaponSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/weapons/change_weapon.ogg"));
_slowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/slow_mo.ogg"));
_unSlowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/unslow_mo.ogg"));
_fullHealthSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/fullHealth.ogg"));
_fullAbilitySound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/fullAbility.ogg"));
setCollisionCallBack([this](const std::string& objName, std::shared_ptr<RigidBody> obj) {collisionWithObject(objName, obj);});
};
void update();
void attachCamera(std::shared_ptr<Camera> camera, std::shared_ptr<Screen> screen) {
_camera = std::move(camera);
_screen = std::move(screen);
_camera = camera;
_screen = screen;
_camera->translateToPoint(position() + Point4D{0, 1.8, 0});
this->attach(_camera);
}
void attachWorld(std::shared_ptr<World> world, const Point4D& pos = Point4D{0, 30, 0}) {
_world = std::move(world);
_world = world;
translate(pos);
initWeapons();
changeWeaponSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/weapons/change_weapon.ogg"));
slowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/slow_mo.ogg"));
unSlowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/unslow_mo.ogg"));
fullHealthSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/fullHealth.ogg"));
fullAbilitySound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/fullAbility.ogg"));
setCollisionCallBack([this](const std::string& objName, std::shared_ptr<Mesh> obj) {collisionWithObject(objName, std::move(obj));});
}
void setHealth(double h) {
@ -110,24 +109,24 @@ public:
void setFullHealth() {
_health = _healthMax;
fullHealthSound.play();
_fullHealthSound.play();
}
void setFullAbility() {
_ability = _abilityMax;
fullAbilitySound.play();
_fullAbilitySound.play();
}
void setDamagePlayerCallBack(std::function<void(sf::Uint16 targetId, double)> hit) {
damagePlayerCallBack = std::move(hit);
_damagePlayerCallBack = std::move(hit);
}
void setAddTraceCallBack(std::function<void(const Point4D&, const Point4D&)> add) {
addTraceCallBack = std::move(add);
_addTraceCallBack = std::move(add);
}
void setTakeBonusCallBack(std::function<void(const std::string&)> take) {
takeBonusCallBack = std::move(take);
_takeBonusCallBack = std::move(take);
}
[[nodiscard]] double health() const { return _health; }
@ -151,7 +150,7 @@ public:
void playDeath();
void playKill();
void collisionWithObject(const std::string& objName, std::shared_ptr<Mesh> obj);
void collisionWithObject(const std::string& objName, std::shared_ptr<RigidBody> obj);
void addWeapon(std::shared_ptr<Weapon> weapon);

View File

@ -5,25 +5,25 @@
#include "Camera.h"
#include "utils/Log.h"
std::vector<Triangle> &Camera::project(Mesh& mesh, Screen::ViewMode mode) {
std::vector<Triangle> &Camera::project(std::shared_ptr<Mesh> mesh) {
if(!ready) {
Log::log("Camera::project(): cannot project tris without camera initialization ( Camera::init() ) ");
return this->triangles;
if(!_ready) {
Log::log("Camera::project(): cannot project _tris without camera initialization ( Camera::init() ) ");
return this->_triangles;
}
if(!mesh.isVisible())
return this->triangles;
if(!mesh->isVisible())
return this->_triangles;
// Model transform matrix: translate tris in the origin of mesh.
Matrix4x4 M = Matrix4x4::Translation(mesh.position());
VM = V * M;
// Model transform matrix: translate _tris in the origin of body.
Matrix4x4 M = Matrix4x4::Translation(mesh->position());
Matrix4x4 VM = _V * M;
// We don't want to waste time re-allocating memory every time
std::vector<Triangle> clippedTriangles, tempBuffer;
for(auto& t : mesh.triangles()) {
for(auto& t : mesh->triangles()) {
double dot = t.norm().dot((mesh.position() + t[0] - p_position).normalized());
double dot = t.norm().dot((mesh->position() + t[0] - _position).normalized());
if(dot > 0)
continue;
@ -32,10 +32,10 @@ std::vector<Triangle> &Camera::project(Mesh& mesh, Screen::ViewMode mode) {
// It needs to be cleared because it's reused through iterations. Usually it doesn't free memory.
clippedTriangles.clear();
// In the beginning we need to to translate triangle from world coordinate to our camera system:
// After that we apply clipping for all planes from clipPlanes
// In the beginning we need to to translate drawTriangle from world coordinate to our camera system:
// After that we apply clipping for all planes from _clipPlanes
clippedTriangles.emplace_back(t * VM);
for(auto& plane : clipPlanes)
for(auto& plane : _clipPlanes)
{
while(!clippedTriangles.empty())
{
@ -51,60 +51,59 @@ std::vector<Triangle> &Camera::project(Mesh& mesh, Screen::ViewMode mode) {
}
for(auto& clippedTriangle : clippedTriangles) {
if(mode != Screen::ViewMode::Clipped) {
clippedTriangle.color = sf::Color(clippedTriangle.color.r * (0.3 * std::abs(dot) + 0.7),
clippedTriangle.color.g * (0.3 * std::abs(dot) + 0.7),
clippedTriangle.color.b * (0.3 * std::abs(dot) + 0.7),
(mode == Screen::ViewMode::Transparency ||
mode == Screen::ViewMode::Normals) ? 100 : clippedTriangle.color.a);
}
sf::Color color = clippedTriangle.color();
sf::Color ambientColor = sf::Color(color.r * (0.3 * std::abs(dot) + 0.7),
color.g * (0.3 * std::abs(dot) + 0.7),
color.b * (0.3 * std::abs(dot) + 0.7),
color.a);
// Finally its time to project our clipped colored triangle from 3D -> 2D
// Finally its time to project our clipped colored drawTriangle from 3D -> 2D
// and transform it's coordinate to screen space (in pixels):
clippedTriangle *= SP;
clippedTriangle = clippedTriangle * _SP;
clippedTriangle[0] = clippedTriangle[0] / clippedTriangle[0].w();
clippedTriangle[1] = clippedTriangle[1] / clippedTriangle[1].w();
clippedTriangle[2] = clippedTriangle[2] / clippedTriangle[2].w();
clippedTriangle = Triangle(clippedTriangle[0] / clippedTriangle[0].w(),
clippedTriangle[1] / clippedTriangle[1].w(),
clippedTriangle[2] / clippedTriangle[2].w(),
ambientColor);
triangles.emplace_back(clippedTriangle);
_triangles.emplace_back(clippedTriangle);
}
}
return this->triangles;
return this->_triangles;
}
void Camera::init(int width, int height, double fov, double ZNear, double ZFar) {
// We need to init camera only after creation or changing width, height, fov, ZNear or ZFar.
// Because here we calculate matrix that does not change during the motion of _objects or camera
w = width; h = height;
aspect = (double)width / (double)height;
P = Matrix4x4::Projection(fov, aspect, ZNear, ZFar);
S = Matrix4x4::ScreenSpace(width, height);
_w = width; _h = height;
_aspect = (double)width / (double)height;
_P = Matrix4x4::Projection(fov, _aspect, ZNear, ZFar);
_S = Matrix4x4::ScreenSpace(width, height);
SP = S * P; // screen-space-projections matrix
_SP = _S * _P; // screen-space-projections matrix
// This is planes for clipping tris.
// Motivation: we are not interest in tris that we cannot see.
clipPlanes.emplace_back(Plane(Point4D{0, 0, 1}, Point4D{0, 0, ZNear})); // near plane
clipPlanes.emplace_back(Plane(Point4D{0, 0, -1}, Point4D{0, 0, ZFar})); // far plane
// This is planes for clipping _tris.
// Motivation: we are not interest in _tris that we cannot see.
_clipPlanes.emplace_back(Plane(Point4D{0, 0, 1}, Point4D{0, 0, ZNear})); // near plane
_clipPlanes.emplace_back(Plane(Point4D{0, 0, -1}, Point4D{0, 0, ZFar})); // far plane
double thetta1 = M_PI*fov*0.5/180.0;
double thetta2 = atan(aspect*tan(thetta1));
clipPlanes.emplace_back(Plane(Point4D{-cos(thetta2), 0, sin(thetta2)}, Point4D{0, 0, 0})); // left plane
clipPlanes.emplace_back(Plane(Point4D{cos(thetta2), 0, sin(thetta2)}, Point4D{0, 0, 0})); // right plane
clipPlanes.emplace_back(Plane(Point4D{0, cos(thetta1), sin(thetta1)}, Point4D{0, 0, 0})); // down plane
clipPlanes.emplace_back(Plane(Point4D{0, -cos(thetta1), sin(thetta1)},Point4D{0, 0, 0})); // up plane
double thetta2 = atan(_aspect * tan(thetta1));
_clipPlanes.emplace_back(Plane(Point4D{-cos(thetta2), 0, sin(thetta2)}, Point4D{0, 0, 0})); // left plane
_clipPlanes.emplace_back(Plane(Point4D{cos(thetta2), 0, sin(thetta2)}, Point4D{0, 0, 0})); // right plane
_clipPlanes.emplace_back(Plane(Point4D{0, cos(thetta1), sin(thetta1)}, Point4D{0, 0, 0})); // down plane
_clipPlanes.emplace_back(Plane(Point4D{0, -cos(thetta1), sin(thetta1)}, Point4D{0, 0, 0})); // up plane
ready = true;
_ready = true;
Log::log("Camera::init(): camera successfully initialized.");
}
std::vector<Triangle> &Camera::sorted() {
// Sort tris from back to front
// Sort _tris from back to front
// This is some replacement for Z-buffer
std::sort(triangles.begin(), triangles.end(), [](Triangle &t1, Triangle &t2)
std::sort(_triangles.begin(), _triangles.end(), [](Triangle &t1, Triangle &t2)
{
std::vector<double> v_z1({t1[0].z(), t1[1].z(), t1[2].z()});
std::vector<double> v_z2({t2[0].z(), t2[1].z(), t2[2].z()});
@ -118,44 +117,44 @@ std::vector<Triangle> &Camera::sorted() {
return z1 > z2;
});
return triangles;
return _triangles;
}
void Camera::record() {
// Cleaning all tris and recalculation of View matrix
void Camera::clear() {
// Cleaning all _tris and recalculation of View matrix
// That is like preparation for new camera shot: we need to set
// the position of camera and insert new cartridge for photo.
triangles.clear();
V = Matrix4x4::View(p_left, p_up, p_lookAt, p_position);
_triangles.clear();
_V = Matrix4x4::View(_left, _up, _lookAt, _position);
}
void Camera::rotateX(double rx) {
p_angle = Point4D{p_angle.x() + rx, p_angle.y(), p_angle.z()};
p_left = Matrix4x4::RotationX(rx) * p_left;
p_up = Matrix4x4::RotationX(rx) * p_up;
p_lookAt = Matrix4x4::RotationX(rx) * p_lookAt;
_angle = Point4D{_angle.x() + rx, _angle.y(), _angle.z()};
_left = Matrix4x4::RotationX(rx) * _left;
_up = Matrix4x4::RotationX(rx) * _up;
_lookAt = Matrix4x4::RotationX(rx) * _lookAt;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), Point4D{rx, 0, 0});
}
void Camera::rotateY(double ry) {
p_angle = Point4D{p_angle.x(), p_angle.y() + ry, p_angle.z()};
p_left = Matrix4x4::RotationY(ry) * p_left;
p_up = Matrix4x4::RotationY(ry) * p_up;
p_lookAt = Matrix4x4::RotationY(ry) * p_lookAt;
_angle = Point4D{_angle.x(), _angle.y() + ry, _angle.z()};
_left = Matrix4x4::RotationY(ry) * _left;
_up = Matrix4x4::RotationY(ry) * _up;
_lookAt = Matrix4x4::RotationY(ry) * _lookAt;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), Point4D{0, ry, 0});
}
void Camera::rotateZ(double rz) {
p_angle = Point4D{p_angle.x(), p_angle.y(), p_angle.z() + rz};
p_left = Matrix4x4::RotationZ(rz) * p_left;
p_up = Matrix4x4::RotationZ(rz) * p_up;
p_lookAt = Matrix4x4::RotationZ(rz) * p_lookAt;
_angle = Point4D{_angle.x(), _angle.y(), _angle.z() + rz};
_left = Matrix4x4::RotationZ(rz) * _left;
_up = Matrix4x4::RotationZ(rz) * _up;
_lookAt = Matrix4x4::RotationZ(rz) * _lookAt;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), Point4D{0, 0, rz});
}
@ -167,69 +166,69 @@ void Camera::rotate(const Point4D& r) {
void Camera::rotate(const Point4D& v, double rv) {
p_left = Matrix4x4::Rotation(v, rv) * p_left;
p_up = Matrix4x4::Rotation(v, rv) * p_up;
p_lookAt = Matrix4x4::Rotation(v, rv) * p_lookAt;
_left = Matrix4x4::Rotation(v, rv) * _left;
_up = Matrix4x4::Rotation(v, rv) * _up;
_lookAt = Matrix4x4::Rotation(v, rv) * _lookAt;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), v, rv);
}
void Camera::rotateLeft(double rl) {
p_angleLeftUpLookAt = Point4D{p_angleLeftUpLookAt.x() + rl, p_angleLeftUpLookAt.y(), p_angleLeftUpLookAt.z()};
_angleLeftUpLookAt = Point4D{_angleLeftUpLookAt.x() + rl, _angleLeftUpLookAt.y(), _angleLeftUpLookAt.z()};
rotate(p_left, rl);
rotate(_left, rl);
for(auto attached : v_attached)
attached->rotateRelativePoint(position(), p_left, rl);
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), _left, rl);
}
void Camera::rotateUp(double ru) {
p_angleLeftUpLookAt = Point4D{p_angleLeftUpLookAt.x(), p_angleLeftUpLookAt.y() + ru, p_angleLeftUpLookAt.z()};
rotate(p_up, ru);
_angleLeftUpLookAt = Point4D{_angleLeftUpLookAt.x(), _angleLeftUpLookAt.y() + ru, _angleLeftUpLookAt.z()};
rotate(_up, ru);
for(auto attached : v_attached)
attached->rotateRelativePoint(position(), p_up, ru);
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), _up, ru);
}
void Camera::rotateLookAt(double rlAt) {
p_angleLeftUpLookAt = Point4D{p_angleLeftUpLookAt.x(), p_angleLeftUpLookAt.y(), p_angleLeftUpLookAt.z() + rlAt};
rotate(p_lookAt, rlAt);
_angleLeftUpLookAt = Point4D{_angleLeftUpLookAt.x(), _angleLeftUpLookAt.y(), _angleLeftUpLookAt.z() + rlAt};
rotate(_lookAt, rlAt);
for(auto attached : v_attached)
attached->rotateRelativePoint(position(), p_lookAt, rlAt);
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), _lookAt, rlAt);
}
void Camera::rotateRelativePoint(const Point4D &s, const Point4D &r) {
p_angle = p_angle + r;
_angle = _angle + r;
// Translate XYZ by vector r1
Point4D r1 = p_position - s;
Point4D r1 = _position - s;
// In translated coordinate system we rotate camera and position
Point4D r2 = Matrix4x4::Rotation(r)*r1;
rotate(r);
// After rotation we translate XYZ by vector -r2 and recalculate position
p_position = s + r2;
_position = s + r2;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(s, r);
}
void Camera::rotateRelativePoint(const Point4D &s, const Point4D &v, double r) {
// Translate XYZ by vector r1
Point4D r1 = p_position - s;
Point4D r1 = _position - s;
// In translated coordinate system we rotate camera and position
Point4D r2 = Matrix4x4::Rotation(v, r)*r1;
rotate(v, r);
// After rotation we translate XYZ by vector -r2 and recalculate position
p_position = s + r2;
_position = s + r2;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(s, v, r);
}
void Camera::translateToPoint(const Point4D &point) {
translate(point - p_position);
translate(point - _position);
}

View File

@ -12,29 +12,28 @@
class Camera : public Object, public Animatable{
private:
Point4D p_angleLeftUpLookAt;
Point4D _angleLeftUpLookAt;
Point4D p_left = Point4D{1, 0, 0, 0}; // internal X
Point4D p_up = Point4D{0, 1, 0, 0}; // internal Y
Point4D p_lookAt = Point4D{0, 0, 1, 0}; // internal Z
Point4D _left = Point4D{1, 0, 0, 0}; // internal X
Point4D _up = Point4D{0, 1, 0, 0}; // internal Y
Point4D _lookAt = Point4D{0, 0, 1, 0}; // internal Z
Matrix4x4 S; // screen space matrix
Matrix4x4 P; // projections matrix
Matrix4x4 V; // camera matrix
Matrix4x4 _S; // screen space matrix
Matrix4x4 _P; // projections matrix
Matrix4x4 _V; // camera matrix
double aspect = 0;
double _aspect = 0;
// To accelerate calculations we can use precalculated matrix that does not chance
Matrix4x4 SP; // screen-space-projections matrix
Matrix4x4 VM; // camera-model-animation matrix
Matrix4x4 _SP; // screen-space-projections matrix
std::vector<Triangle> triangles;
std::vector<Plane> clipPlanes;
std::vector<Triangle> _triangles;
std::vector<Plane> _clipPlanes;
bool ready = false;
bool _ready = false;
double w = 0;
double h = 0;
double _w = 0;
double _h = 0;
public:
Camera() = default;
Camera(const Camera& camera) = delete;
@ -42,28 +41,28 @@ public:
void init(int width, int height, double fov = 110.0, double ZNear = 0.1, double ZFar = 5000.0);
std::vector<Triangle>& project(Mesh& mesh, Screen::ViewMode mode);
std::vector<Triangle>& project(std::shared_ptr<Mesh> mesh);
void record();
void clear();
[[nodiscard]] int buffSize() const { return triangles.size(); }
[[nodiscard]] int buffSize() const { return _triangles.size(); }
std::vector<Triangle>& sorted();
[[nodiscard]] Point4D position() const override { return p_position; }
[[nodiscard]] Point4D angle() const override { return p_angle; }
[[nodiscard]] Point4D angleLeftUpLookAt() const { return p_angleLeftUpLookAt; }
[[nodiscard]] Point4D position() const override { return _position; }
[[nodiscard]] Point4D angle() const override { return _angle; }
[[nodiscard]] Point4D angleLeftUpLookAt() const { return _angleLeftUpLookAt; }
[[nodiscard]] Point4D eye() const { return p_position; }
[[nodiscard]] Point4D left() const { return p_left; }
[[nodiscard]] Point4D right() const { return -p_left; }
[[nodiscard]] Point4D up() const { return p_up; }
[[nodiscard]] Point4D down() const { return -p_up; }
[[nodiscard]] Point4D lookAt() const { return p_lookAt; }
[[nodiscard]] Point4D eye() const { return _position; }
[[nodiscard]] Point4D left() const { return _left; }
[[nodiscard]] Point4D right() const { return -_left; }
[[nodiscard]] Point4D up() const { return _up; }
[[nodiscard]] Point4D down() const { return -_up; }
[[nodiscard]] Point4D lookAt() const { return _lookAt; }
void translate(const Point4D& dv) override {
p_position = p_position + dv;
_position = _position + dv;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->translate(dv);
}
@ -80,9 +79,9 @@ public:
void rotateUp(double ru);
void rotateLookAt(double rlAt);
// Rotate mesh around XYZ by (r.x, r.y, r.z) radians relative val 'point4D'
// Rotate body around XYZ by (r.x, r.y, r.z) radians relative val 'point4D'
void rotateRelativePoint(const Point4D& s, const Point4D& r) override;
// Rotate mesh around normalised vector 'v' by 'r' radians relative val 'point4D'
// Rotate body around normalised vector 'v' by 'r' radians relative val 'point4D'
void rotateRelativePoint(const Point4D& s, const Point4D& v, double r) override;
};

View File

@ -15,6 +15,8 @@ Engine::Engine() {
}
void Engine::create(int screenWidth, int screenHeight, const std::string &name, bool verticalSync, sf::Color background, sf::Uint32 style) {
_name = name;
screen->open(screenWidth, screenHeight, name, verticalSync, background, style);
Log::log("Engine::create(): started engine (" + std::to_string(screenWidth) + " x " + std::to_string(screenHeight) + ") with name '" + name + "'.");
@ -28,67 +30,35 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name,
screen->clear();
Time::update();
screen->keyboardControl();
update(Time::deltaTime());
update();
world->garbageCollector();
/* Project all mesh
* Here we project all tris for each mesh from world._objects.
* Here we project all _tris for each body from world._objects.
* When we call camera.project(m.second),
*/
// sometimes we dont need to update physics world
// (for example in menu or while pause)
// hence we can set 'b_updateWorld' equal to false in setUpdateWorld(bool):
if(b_updateWorld) {
camera->record();
for (auto &m : world->objects()) {
m.second->a_update();
camera->project(*m.second, screen->mode());
m.second->updatePhysicsState();
// isCollision detection:
if (m.second->isCollision()) {
m.second->setInCollision(false);
m.second->setCollisionNormal(Point4D{0, 0, 0});
for (auto &obj : world->objects()) {
if(obj.first != m.first) {
std::pair<bool, Simplex> gjk = m.second->checkGJKCollision(obj.second);
if (gjk.first) {
if (obj.second->isCollider()) {
CollisionPoint epa = m.second->EPA(gjk.second, obj.second);
Solver::solveCollision(m.second, obj.second, epa);
}
if (m.second->collisionCallBack() != nullptr)
m.second->collisionCallBack()(obj.first, obj.second);
}
}
}
}
}
// draw projected mesh
for (auto &t : camera->sorted())
screen->triangle(t);
// hence we can set '_updateWorld' equal to false in setUpdateWorld(bool):
if(_updateWorld) {
camera->a_update();
camera->clear();
triPerSec = camera->buffSize() * Time::fps();
world->update();
world->projectObjectsInCamera(camera);
if (b_debugText) {
screen->debugText(name + "\n\n X: " +
std::to_string((camera->eye().x())) + "\n Y: " +
std::to_string((camera->eye().y())) + "\n Z: " +
std::to_string((camera->eye().z())) + "\n\n" +
std::to_string(screen->width()) + "x" +
std::to_string(screen->height()) + "\n" +
std::to_string(Time::fps()) +
" fps \n" + std::to_string((int) triPerSec) + " tris/s");
}
}
// draw projected body
for (auto &t : camera->sorted())
screen->drawTriangle(t);
_triPerSec = camera->buffSize() * Time::fps();
printDebugText();
gui();
}
screen->display();
}
exit();
@ -99,5 +69,18 @@ void Engine::exit() {
screen->close();
}
ResourceManager::unloadAllResources();
Log::log("Engine::exit(): exit engine (" + std::to_string(screen->width()) + " x " + std::to_string(screen->height()) + ") with name '" + screen->title() + "'.");
Log::log("Engine::exit(): exit engine (" + std::to_string(screen->width()) + " x " + std::to_string(screen->height()) + ") with name '" + screen->name() + "'.");
}
void Engine::printDebugText() const {
if (_debugText) {
screen->debugText(_name + "\n\n X: " +
std::to_string((camera->eye().x())) + "\n Y: " +
std::to_string((camera->eye().y())) + "\n Z: " +
std::to_string((camera->eye().z())) + "\n\n" +
std::to_string(screen->width()) + "x" +
std::to_string(screen->height()) + "\n" +
std::to_string(Time::fps()) +
" fps \n" + std::to_string((int) _triPerSec) + " _tris/s");
}
}

View File

@ -11,15 +11,19 @@
#include "utils/Log.h"
class Engine {
private:
std::string _name;
double _triPerSec = 0;
bool _debugText = true;
bool _updateWorld = true;
void printDebugText() const;
protected:
std::shared_ptr<Screen> screen;
std::shared_ptr<World> world;
std::shared_ptr<Camera> camera;
double triPerSec = 0;
bool b_debugText = true;
bool b_updateWorld = true;
public:
Engine();
@ -28,10 +32,11 @@ public:
void create(int screenWidth = 1920, int screenHeight = 1080, const std::string& name = "engine", bool verticalSync = true, sf::Color background = sf::Color(255, 255, 255), sf::Uint32 style = sf::Style::Default);
virtual void start() {};
virtual void update(double elapsedTime) {};
virtual void update() {};
void exit();
void debugText(bool value) { b_debugText = value; }
void setUpdateWorld(bool value) { b_updateWorld = value; }
void setDebugText(bool value) { _debugText = value; }
void setUpdateWorld(bool value) { _updateWorld = value; }
virtual void gui(){}
};

View File

@ -11,13 +11,9 @@
using namespace std;
Mesh Mesh::operator*(const Matrix4x4 &matrix4X4) const {
return Mesh(*this) *= matrix4X4;
}
Mesh &Mesh::operator*=(const Matrix4x4 &matrix4X4) {
for (auto& t : tris)
t *= matrix4X4;
for (auto& t : _tris)
t = t * matrix4X4;
return *this;
}
@ -27,7 +23,7 @@ Mesh &Mesh::loadObj(const std::string& filename, const std::string &materials, c
auto objects = Mesh::LoadObjects(filename, materials, scale);
for(auto& obj : objects) {
for (auto &tri : obj->triangles()) {
tris.push_back(tri);
_tris.push_back(tri);
}
}
return *this;
@ -38,10 +34,10 @@ Mesh::Mesh(const std::string& filename, const std::string &materials, const Poin
}
Mesh::Mesh(const vector<Triangle> &tries){
tris = tries;
_tris = tries;
}
Mesh::Mesh(const Mesh& mesh) : Animatable(mesh) {
Mesh::Mesh(const Mesh& mesh) {
*this = mesh;
}
@ -50,17 +46,17 @@ Mesh Mesh::Obj(const std::string& filename) {
}
void Mesh::rotate(const Point4D &r) {
p_angle = p_angle + r;
_angle = _angle + r;
*this *= Matrix4x4::Rotation(r);
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), r);
}
void Mesh::rotate(const Point4D &v, double r) {
*this *= Matrix4x4::Rotation(v, r);
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(position(), v, r);
}
@ -71,72 +67,71 @@ void Mesh::scale(const Point4D &s) {
}
void Mesh::translate(const Point4D &t) {
p_position = p_position + t;
_position = _position + t;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->translate(t);
}
Mesh &Mesh::operator=(const Mesh &mesh) {
tris = mesh.tris;
p_position = mesh.p_position;
c_color = mesh.c_color;
_tris = mesh._tris;
_position = mesh._position;
_color = mesh._color;
return *this;
}
void Mesh::rotateRelativePoint(const Point4D &s, const Point4D &r) {
p_angle = p_angle + r;
_angle = _angle + r;
// Translate XYZ by vector r1
Point4D r1 = p_position - s;
Point4D r1 = _position - s;
*this *= Matrix4x4::Translation(r1);
// In translated coordinate system we rotate mesh and position
// In translated coordinate system we rotate body and position
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(r);
Point4D r2 = rotationMatrix*r1;
*this *= rotationMatrix;
// After rotation we translate XYZ by vector -r2 and recalculate position
*this *= Matrix4x4::Translation(-r2);
p_position = s + r2;
_position = s + r2;
if(v_attached.empty())
if(_attachedObjects.empty())
return;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(s, r);
}
void Mesh::rotateRelativePoint(const Point4D &s, const Point4D &v, double r) {
// Translate XYZ by vector r1
Point4D r1 = p_position - s;
Point4D r1 = _position - s;
*this *= Matrix4x4::Translation(r1);
// In translated coordinate system we rotate mesh and position
// In translated coordinate system we rotate body and position
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, r);
Point4D r2 = rotationMatrix*r1;
*this *= rotationMatrix;
// After rotation we translate XYZ by vector -r2 and recalculate position
*this *= Matrix4x4::Translation(-r2);
p_position = s + r2;
_position = s + r2;
for(auto attached : v_attached)
for(auto attached : _attachedObjects)
attached->rotateRelativePoint(s, v, r);
}
void Mesh::translateToPoint(const Point4D &point) {
translate(point - p_position);
translate(point - _position);
}
void Mesh::setColor(sf::Color c) {
c_color = c;
for (auto& t : tris)
t.color = c_color;
_color = c;
for (auto& t : _tris)
t = Triangle(t[0], t[1], t[2], _color);
}
std::vector<std::shared_ptr<Mesh>>
Mesh::LoadObjects(const string &filename, const string &materials, const Point4D &scale) {
std::vector<std::shared_ptr<Mesh>> Mesh::LoadObjects(const string &filename, const string &materials, const Point4D &scale) {
std::vector<std::shared_ptr<Mesh>> objects;
map<string, sf::Color> maters;
@ -209,8 +204,7 @@ Mesh::LoadObjects(const string &filename, const string &materials, const Point4D
{
int f[3];
s >> junk >> f[0] >> f[1] >> f[2];
tris.emplace_back(verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1] );
tris.back().color = currentColor;
tris.emplace_back(verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1], currentColor);
}
}
@ -225,6 +219,7 @@ Mesh::LoadObjects(const string &filename, const string &materials, const Point4D
}
Mesh Mesh::LineTo(const Point4D& from, const Point4D& to, double line_width, sf::Color color) {
Mesh line;
Point4D v1 = (to - from).normalized();
@ -242,7 +237,7 @@ Mesh Mesh::LineTo(const Point4D& from, const Point4D& to, double line_width, sf:
Point4D p7 = to + v2 * line_width/2.0 + v3 * line_width/2.0;
Point4D p8 = to + v2 * line_width/2.0 - v3 * line_width/2.0;
line.tris = {
line._tris = {
{ p2, p4, p1 },
{ p2, p3, p4 },
{ p1, p6, p2 },
@ -259,5 +254,10 @@ Mesh Mesh::LineTo(const Point4D& from, const Point4D& to, double line_width, sf:
line.setColor(color);
for(auto& triangle : line._tris)
triangle = Triangle(Point4D{triangle[0].x(), triangle[0].y(), triangle[0].z(), 1},
Point4D{triangle[1].x(), triangle[1].y(), triangle[1].z(), 1},
Point4D{triangle[2].x(), triangle[2].y(), triangle[2].z(), 1}, line.color());
return line;
}

View File

@ -8,24 +8,16 @@
#include <vector>
#include "Triangle.h"
#include "animation/Animatable.h"
#include "physics/RigidBody.h"
#include <SFML/Graphics.hpp>
#include "Object.h"
class Mesh : public Object, public Animatable, public RigidBody {
class Mesh : public Object, public Animatable {
private:
// Operations with Matrix4x4
[[nodiscard]] Mesh operator*(const Matrix4x4& matrix4X4) const;
Mesh& operator*=(const Matrix4x4& matrix4X4);
protected:
std::vector<Triangle> tris;
std::vector<Triangle> _tris;
sf::Color _color = sf::Color(255, 245, 194);
bool _visible = true;
sf::Color c_color = sf::Color(255, 245, 194);
std::function<void(const std::string&, std::shared_ptr<Mesh>)> _collisionCallBack;
Mesh& operator*=(const Matrix4x4& matrix4X4);
public:
Mesh() = default;
@ -37,29 +29,29 @@ public:
Mesh& loadObj(const std::string& filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
[[nodiscard]] std::vector<Triangle>const &triangles() const { return tris; }
[[nodiscard]] std::vector<Triangle>& triangles() override { return tris; }
void setTriangles(const std::vector<Triangle>& t) override { tris = t; }
[[nodiscard]] std::vector<Triangle>const &triangles() const { return _tris; }
[[nodiscard]] std::vector<Triangle>& triangles() override { return _tris; }
void setTriangles(const std::vector<Triangle>& t) override { _tris = t; }
// Translate mesh
// Translate body
void translate(const Point4D& t) override;
void translateToPoint(const Point4D& point);
// Rotate mesh around XYZ axes
// Rotate body around XYZ axes
void rotate(const Point4D& r) override;
// Rotate mesh around normalised vector 'v' by 'r' radians
// Rotate body around normalised vector 'v' by 'r' radians
void rotate(const Point4D& v, double r) override;
// Rotate mesh around XYZ by (r.x, r.y, r.z) radians relative val 'point4D'
// Rotate body around XYZ by (r.x, r.y, r.z) radians relative val 'point4D'
void rotateRelativePoint(const Point4D& point4D, const Point4D& r) override;
// Rotate mesh around normalised vector 'v' by 'r' radians relative val 'point4D'
// Rotate body around normalised vector 'v' by 'r' radians relative val 'point4D'
void rotateRelativePoint(const Point4D& point4D, const Point4D& v, double r) override;
void scale(const Point4D& s);
void rotateToAngle(const Point4D& v) { rotate(v - p_angle); }
void rotateToAngle(const Point4D& v) { rotate(v - _angle); }
[[nodiscard]] Point4D position() const override { return p_position; }
[[nodiscard]] Point4D angle() const override { return p_angle; }
[[nodiscard]] Point4D position() const override { return _position; }
[[nodiscard]] Point4D angle() const override { return _angle; }
[[nodiscard]] sf::Color color() const override { return c_color; }
[[nodiscard]] sf::Color color() const override { return _color; }
void setColor(sf::Color c) override;
Mesh static Obj(const std::string& filename);
@ -69,9 +61,6 @@ public:
[[nodiscard]] bool isVisible() const { return _visible; }
std::vector<std::shared_ptr<Mesh>> static LoadObjects(const std::string& filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
[[nodiscard]] const std::function<void(const std::string&, std::shared_ptr<Mesh>)>& collisionCallBack() const { return _collisionCallBack; }
void setCollisionCallBack(const std::function<void(const std::string&, std::shared_ptr<Mesh>)>& f) { _collisionCallBack = f; }
};

View File

@ -11,10 +11,10 @@
class Object {
protected:
std::vector<std::shared_ptr<Object>> v_attached;
std::vector<std::shared_ptr<Object>> _attachedObjects;
Point4D p_position;
Point4D p_angle;
Point4D _position;
Point4D _angle;
public:
Object() = default;
@ -24,11 +24,11 @@ public:
virtual void rotate(const Point4D& v, double rv) {}
virtual void rotateRelativePoint(const Point4D& s, const Point4D& v, double r) {}
[[nodiscard]] Point4D position() const { return p_position; }
[[nodiscard]] Point4D angle() const { return p_angle; }
[[nodiscard]] Point4D position() const { return _position; }
[[nodiscard]] Point4D angle() const { return _angle; }
void attach(std::shared_ptr<Object> object) {
v_attached.push_back(std::move(object));
_attachedObjects.push_back(object);
}
};

View File

@ -5,35 +5,34 @@
#include "Plane.h"
Plane::Plane(const Triangle& tri) {
triangle = tri;
n = tri.norm();
p = tri[0];
_triangle = tri;
_n = tri.norm();
_p = tri[0];
}
Plane::Plane(const Point4D &N, const Point4D &P) {
n = N;
p = P;
_n = N.normalized();
_p = P;
}
Plane::Plane(const Plane &plane) {
triangle = plane.triangle;
n = plane.n;
p = plane.p;
_triangle = plane._triangle;
_n = plane._n;
_p = plane._p;
}
double Plane::distance(const Point4D &point4D) const {
return point4D.dot(n) - p.dot(n);
return point4D.dot(_n) - _p.dot(_n);
}
std::pair<Point4D, double> Plane::intersection(const Point4D &start, const Point4D &end) {
double s_dot_n = start.dot(n);
double k = (s_dot_n - p.dot(n))/(s_dot_n - end.dot(n));
std::pair<Point4D, double> Plane::intersection(const Point4D &start, const Point4D &end) const {
double s_dot_n = start.dot(_n);
double k = (s_dot_n - _p.dot(_n)) / (s_dot_n - end.dot(_n));
Point4D res = start + (end - start)*k;
return std::make_pair(res, k);
}
int Plane::clip(Triangle &tri, Triangle &additional_tri) {
n = n.normalized();
int Plane::clip(Triangle &tri, Triangle &additional_tri) const {
Point4D insidePoints[3]; int inside = 0;
Point4D outsidePoints[3]; int outside = 0;
@ -49,20 +48,14 @@ int Plane::clip(Triangle &tri, Triangle &additional_tri) {
}
if(inside == 0) {
tri.clip = Triangle::Skipped;
return 0;
}
if(inside == 1) {
std::pair<Point4D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
std::pair<Point4D, double> intersect2 = intersection(insidePoints[0], outsidePoints[1]);
tri[0] = insidePoints[0];
tri[1] = intersect1.first;
tri[2] = intersect2.first;
tri.clip = Triangle::Cropped;
tri = Triangle(insidePoints[0], intersect1.first, intersect2.first, tri.color());
return 1;
}
@ -71,20 +64,8 @@ int Plane::clip(Triangle &tri, Triangle &additional_tri) {
std::pair<Point4D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
std::pair<Point4D, double> intersect2 = intersection(insidePoints[1], outsidePoints[0]);
tri[0] = insidePoints[0];
tri[1] = intersect1.first;
tri[2] = insidePoints[1];
additional_tri[0] = intersect1.first;
additional_tri[1] = intersect2.first;
additional_tri[2] = insidePoints[1];
tri.clip = Triangle::Doubled;
additional_tri.clip = Triangle::Doubled;
tri = Triangle(insidePoints[0], intersect1.first, insidePoints[1], tri.color());
additional_tri = Triangle(intersect1.first, intersect2.first, insidePoints[1], tri.color());
return 2;
}

View File

@ -11,24 +11,24 @@
class Plane {
private:
// You can define plane by defining the points in 3D space
Triangle triangle;
Triangle _triangle;
// Or by defining normal vector and one val laying on the plane
Point4D n = Point4D{0, 0, 1, 0};
Point4D p{};
Point4D _n = Point4D{0, 0, 1, 0};
Point4D _p{};
public:
// A plain with normal vector 'n' and val 'p' lays on the plane
// A plain with normal vector '_n' and val '_p' lays on the plane
Plane() = default;
Plane(const Point4D& N, const Point4D& P);
Plane(const Plane& plane);
explicit Plane(const Triangle& tri);
[[nodiscard]] double distance(const Point4D& point4D) const;
// Point4D in space where line ('start' to 'end') intersects plain with normal vector 'n' and val 'p' lays on the plane
std::pair<Point4D, double> intersection(const Point4D& start, const Point4D& end);
int clip(Triangle& tri, Triangle& additional_tri);
// Point4D in space where line ('start' to 'end') intersects plain with normal vector '_n' and val '_p' lays on the plane
[[nodiscard]] std::pair<Point4D, double> intersection(const Point4D& start, const Point4D& end) const;
int clip(Triangle& tri, Triangle& additional_tri) const;
[[nodiscard]] Point4D N() const { return n; }
[[nodiscard]] Point4D P() const { return p; }
[[nodiscard]] Point4D N() const { return _n; }
[[nodiscard]] Point4D P() const { return _p; }
};

View File

@ -5,7 +5,7 @@
#include "ResourceManager.h"
#include <map>
#include <memory>
#include <iostream>
namespace ResourceManager
{
namespace
@ -13,7 +13,6 @@ namespace ResourceManager
std::map<std::string, std::shared_ptr<sf::Texture>> _textures;
std::map<std::string, std::shared_ptr<sf::Font>> _fonts;
std::map<std::string, std::shared_ptr<sf::SoundBuffer>> _soundBuffers;
std::map<std::string, std::shared_ptr<sf::Shader>> _shaders;
}
void unloadTextures()
@ -36,18 +35,11 @@ namespace ResourceManager
_fonts.clear();
}
void unloadShaders() {
for (auto& shader : _shaders)
shader.second.reset();
_shaders.clear();
}
void unloadAllResources()
{
unloadTextures();
unloadSoundBuffers();
unloadFonts();
unloadShaders();
}
std::shared_ptr<sf::Texture> loadTexture(const std::string& filename)
@ -103,21 +95,4 @@ namespace ResourceManager
return font;
}
std::shared_ptr<sf::Shader> loadShader(const std::string& filename, sf::Shader::Type type) {
// If Shader is already loaded - return pointer to it
auto it = _shaders.find(filename);
if (it != _shaders.end())
return it->second;
// Otherwise - try to load it. If failure - return zero
std::shared_ptr<sf::Shader> shader(new sf::Shader);
if (!shader->loadFromFile(filename, type))
return nullptr;
// If success - remember and return texture pointer
_shaders.emplace(filename, shader);
return shader;
}
}

View File

@ -25,7 +25,6 @@ namespace ResourceManager
std::shared_ptr<sf::Texture> loadTexture(const std::string& filename);
std::shared_ptr<sf::Font> loadFont(const std::string& filename);
std::shared_ptr<sf::SoundBuffer> loadSoundBuffer(const std::string& filename);
std::shared_ptr<sf::Shader> loadShader(const std::string& filename, sf::Shader::Type type);
};

View File

@ -11,15 +11,15 @@
void Screen::open(int screenWidth, int screenHeight, const std::string &name, bool verticalSync, sf::Color background, sf::Uint32 style) {
this->name = name;
w = screenWidth;
h = screenHeight;
this->background = background;
_name = name;
_w = screenWidth;
_h = screenHeight;
_background = background;
sf::ContextSettings settings;
settings.antialiasingLevel = 8;
window.create(sf::VideoMode(w, h), name, style, settings);
window.create(sf::VideoMode(_w, _h), name, style, settings);
window.setVerticalSyncEnabled(verticalSync);
}
@ -31,44 +31,29 @@ void Screen::display() {
}
}
std::string title = name + " (" + std::to_string(Time::fps()) + " fps)";
std::string title = _name + " (" + std::to_string(Time::fps()) + " fps)";
window.setTitle(title);
window.display();
}
void Screen::clear() {
window.clear(background);
window.clear(_background);
}
void Screen::triangle(const Triangle& triangle)
void Screen::drawTriangle(const Triangle& triangle)
{
if(vm == Frame || vm == Borders || vm == Xray || vm == Clipped || vm == Transparency || vm == Normals) {
sf::Vertex lines[4] =
{
sf::Vertex(sf::Vector2f(triangle[0].x(), triangle[0].y()), sf::Color(0, 0, 0, 255)),
sf::Vertex(sf::Vector2f(triangle[1].x(), triangle[1].y()), sf::Color(0, 0, 0, 255)),
sf::Vertex(sf::Vector2f(triangle[2].x(), triangle[2].y()), sf::Color(0, 0, 0, 255)),
sf::Vertex(sf::Vector2f(triangle[0].x(), triangle[0].y()), sf::Color(0, 0, 0, 255))
};
window.draw(lines, 4, sf::LineStrip);
}
if(vm == Frame || vm == Xray)
return; // no texture when we turn on Frame or Xray mode
sf::Vertex tris[3] =
{
sf::Vertex(sf::Vector2f(triangle[0].x(), triangle[0].y()), triangle.color),
sf::Vertex(sf::Vector2f(triangle[1].x(), triangle[1].y()), triangle.color),
sf::Vertex(sf::Vector2f(triangle[2].x(), triangle[2].y()), triangle.color)
sf::Vertex(sf::Vector2f(triangle[0].x(), triangle[0].y()), triangle.color()),
sf::Vertex(sf::Vector2f(triangle[1].x(), triangle[1].y()), triangle.color()),
sf::Vertex(sf::Vector2f(triangle[2].x(), triangle[2].y()), triangle.color())
};
window.draw(tris, 3, sf::Triangles);
}
void Screen::title(const std::string& title)
{
name = title;
void Screen::setName(const std::string& title) {
_name = title;
}
bool Screen::isOpen() {
@ -89,49 +74,28 @@ Point4D Screen::getMousePosition() const {
}
Point4D Screen::getMouseDisplacement() const {
sf::Vector2<int> disp = sf::Mouse::getPosition(window) - sf::Vector2<int>(w/2, h/2);
sf::Vector2<int> disp = sf::Mouse::getPosition(window) - sf::Vector2<int>(_w/2, _h/2);
setMouseInCenter();
return Point4D(disp.x, disp.y, 0, 0);
}
void Screen::setMouseInCenter() const {
sf::Mouse::setPosition({ w / 2, h / 2 }, window);
sf::Mouse::setPosition({ _w / 2, _h / 2 }, window);
}
void Screen::setMouseCursorVisible(bool visible) {
window.setMouseCursorVisible(visible);
}
void Screen::keyboardControl() {
// Check all input after this condition please
if (!window.hasFocus())
return;
if(isKeyTapped(sf::Keyboard::Num1))
setMode(ViewMode::Default);
if(isKeyTapped(sf::Keyboard::Num2))
setMode(ViewMode::Borders);
if(isKeyTapped(sf::Keyboard::Num3))
setMode(ViewMode::Transparency);
if(isKeyTapped(sf::Keyboard::Num4))
setMode(ViewMode::Frame);
if(isKeyTapped(sf::Keyboard::Num5))
setMode(ViewMode::Xray);
if(isKeyTapped(sf::Keyboard::Num6))
setMode(ViewMode::Clipped);
if(isKeyTapped(sf::Keyboard::Num7))
setMode(ViewMode::Normals);
}
bool Screen::isKeyTapped(sf::Keyboard::Key key) {
if (!Screen::isKeyPressed(key))
return false;
if(tappedKeys.count(key) == 0) {
tappedKeys.emplace(key, Time::time());
if(_tappedKeys.count(key) == 0) {
_tappedKeys.emplace(key, Time::time());
return true;
} else if((Time::time() - tappedKeys[key]) > 0.2) {
tappedKeys[key] = Time::time();
} else if((Time::time() - _tappedKeys[key]) > 0.2) {
_tappedKeys[key] = Time::time();
return true;
}
return false;
@ -145,11 +109,11 @@ bool Screen::isButtonTapped(sf::Mouse::Button button) {
if (!Screen::isButtonPressed(button))
return false;
if(tappedButtons.count(button) == 0) {
tappedButtons.emplace(button, Time::time());
if(_tappedButtons.count(button) == 0) {
_tappedButtons.emplace(button, Time::time());
return true;
} else if((Time::time() - tappedButtons[button]) > 0.2) {
tappedButtons[button] = Time::time();
} else if((Time::time() - _tappedButtons[button]) > 0.2) {
_tappedButtons[button] = Time::time();
return true;
}
return false;
@ -159,7 +123,7 @@ bool Screen::isButtonTapped(sf::Mouse::Button button) {
void Screen::debugText(const std::string& text) {
sf::Text t;
t.setFont(*ResourceManager::loadFont(font));
t.setFont(*ResourceManager::loadFont(_font));
t.setString(text);
t.setCharacterSize(30);
t.setFillColor(sf::Color::Black);

View File

@ -13,33 +13,18 @@
#include "utils/Time.h"
class Screen {
public:
enum ViewMode {
Default = 0,
Frame,
Borders,
Xray,
Clipped,
Transparency,
Normals
};
private:
int w = 1920;
int h = 1080;
int _w = 1920;
int _h = 1080;
std::string name;
std::string _name;
sf::Color background;
sf::Color _background;
Screen::ViewMode vm = Screen::ViewMode::Default;
std::map<sf::Keyboard::Key, double> _tappedKeys;
std::map<sf::Mouse::Button, double> _tappedButtons;
std::map<sf::Keyboard::Key, double> tappedKeys;
std::map<sf::Mouse::Button, double> tappedButtons;
std::string font = "../engine/fonts/Roboto-Thin.ttf";
int frame = 0;
int scene = 0; // the number of scene
std::string _font = "../engine/fonts/Roboto-Thin.ttf";
public:
sf::RenderWindow window;
@ -49,10 +34,10 @@ public:
void display();
void clear();
void triangle(const Triangle& triangle );
void drawTriangle(const Triangle& triangle);
void title(const std::string& title);
std::string title() const { return name; };
void setName(const std::string& title);
std::string name() const { return _name; };
bool isOpen();
@ -72,11 +57,6 @@ public:
void setMouseInCenter() const;
void setMouseCursorVisible(bool visible);
void setMode(ViewMode mode) { vm = mode; }
[[nodiscard]] ViewMode mode() const { return vm; }
void keyboardControl();
void debugText(const std::string& text);
};

View File

@ -5,76 +5,55 @@
#include "Triangle.h"
Triangle::Triangle () {
p[0] = Point4D{0,0,0,1};
p[1] = Point4D{0,0,0,1};
p[2] = Point4D{0,0,0,1};
_p[0] = Point4D{0, 0, 0, 1};
_p[1] = Point4D{0, 0, 0, 1};
_p[2] = Point4D{0, 0, 0, 1};
}
Triangle::Triangle(const Point4D& p1, const Point4D& p2, const Point4D& p3, double w) {
p[0] = Point4D{p1.x(), p1.y(), p1.z(), w};
p[1] = Point4D{p2.x(), p2.y(), p2.z(), w};
p[2] = Point4D{p3.x(), p3.y(), p3.z(), w};
Triangle::Triangle(const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color) {
_p[0] = p1;
_p[1] = p2;
_p[2] = p3;
_color = color;
}
Triangle Triangle::operator*(const Matrix4x4 &matrix4X4) const {
return Triangle(*this) *= matrix4X4;
}
Triangle res(*this);
Triangle &Triangle::operator*=(const Matrix4x4 &matrix4X4) {
p[0] = matrix4X4 * p[0];
p[1] = matrix4X4 * p[1];
p[2] = matrix4X4 * p[2];
res._p[0] = matrix4X4 * _p[0];
res._p[1] = matrix4X4 * _p[1];
res._p[2] = matrix4X4 * _p[2];
return *this;
return res;
}
Point4D Triangle::norm() const {
Point4D v1 = p[1] - p[0];
Point4D v2 = p[2] - p[0];
Point4D v1 = _p[1] - _p[0];
Point4D v2 = _p[2] - _p[0];
return v1.cross3D(v2).normalized();
}
Point4D Triangle::operator[](int i) const {
return p[i];
}
Point4D &Triangle::operator[](int i) {
return p[i];
}
Point4D Triangle::pos() const {
return (p[0] + p[1] + p[2])/3.0;
return _p[i];
}
Triangle::Triangle(const Triangle &triangle) {
clip = triangle.clip;
color = triangle.color;
p[0] = triangle[0];
p[1] = triangle[1];
p[2] = triangle[2];
_color = triangle._color;
_p[0] = triangle[0];
_p[1] = triangle[1];
_p[2] = triangle[2];
}
bool Triangle::isPointInside(const Point4D &point) const {
Point4D triangleNorm = norm();
double dot1 = (point - p[0]).cross3D(p[1] - p[0]).dot(triangleNorm);
double dot2 = (point - p[1]).cross3D(p[2] - p[1]).dot(triangleNorm);
double dot3 = (point - p[2]).cross3D(p[0] - p[2]).dot(triangleNorm);
double dot1 = (point - _p[0]).cross3D(_p[1] - _p[0]).dot(triangleNorm);
double dot2 = (point - _p[1]).cross3D(_p[2] - _p[1]).dot(triangleNorm);
double dot3 = (point - _p[2]).cross3D(_p[0] - _p[2]).dot(triangleNorm);
if((dot1 >= 0 && dot2 >= 0 && dot3 >= 0) || (dot1 <= 0 && dot2 <= 0 && dot3 <= 0))
return true;
return false;
}
Triangle &Triangle::operator=(const Triangle &triangle) {
if(&triangle != this) {
clip = triangle.clip;
color = triangle.color;
p[0] = triangle[0];
p[1] = triangle[1];
p[2] = triangle[2];
}
return *this;
}

View File

@ -10,34 +10,25 @@
#include <SFML/Graphics.hpp>
class Triangle {
private:
sf::Color _color;
Point4D _p[3];
public:
// This is for clipping debug: you can distinguish how this triangle was clipped
enum ClipMode {
None = 0,
Cropped,
Doubled,
Skipped
};
ClipMode clip = None;
sf::Color color;
Point4D p[3];
Triangle ();
Triangle (const Triangle& triangle);
Triangle (const Point4D& p1, const Point4D& p2, const Point4D& p3, double w = 1);
Triangle& operator=(const Triangle& triangle);
Triangle (const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color = {0, 0, 0});
[[nodiscard]] Point4D operator[] (int i) const;
[[nodiscard]] Point4D& operator[] (int i);
[[nodiscard]] Point4D norm() const;
// Operations with Matrix4x4
[[nodiscard]] Triangle operator*(const Matrix4x4& matrix4X4) const;
Triangle& operator*=(const Matrix4x4& matrix4X4);
[[nodiscard]] Point4D pos() const;
[[nodiscard]] bool isPointInside(const Point4D& point) const;
[[nodiscard]] sf::Color color() const { return _color; }
};

View File

@ -2,35 +2,27 @@
// Created by Иван Ильин on 13.01.2021.
//
#include <fstream>
#include <sstream>
#include "World.h"
#include "utils/Log.h"
#include "Plane.h"
#include "physics/Solver.h"
using namespace std;
void World::addMesh(std::shared_ptr<Mesh> mesh, const string &name) {
_objects.emplace(name, mesh);
Log::log("World::addMesh(): inserted mesh '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " tris.");
void World::addBody(std::shared_ptr<RigidBody> body, const string &name) {
_objects.emplace(name, body);
Log::log("World::addBody(): inserted body '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " _tris.");
}
void World::loadObj(const string &name, const string &filename,const std::string &materials, const Point4D& scale) {
_objects.emplace(name, std::make_shared<Mesh>(filename, materials, scale));
Log::log("World::loadObj(): inserted mesh from " + filename + " with name '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " tris.");
void World::loadBody(const string &name, const string &filename, const std::string &materials, const Point4D& scale) {
_objects.emplace(name, std::make_shared<RigidBody>(Mesh(filename, materials, scale)));
Log::log("World::loadBody(): inserted body from " + filename + " with name '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " _tris.");
}
void World::removeMesh(const string &name) {
void World::removeBody(const string &name) {
_objToRemove.push_back(name);
}
std::shared_ptr<Mesh> World::operator[](const string &name) {
if(_objects.count(name) == 0)
Log::log("World::operator[]: mesh '" + name + "' does not exist.");
return _objects.find(name)->second;
}
std::pair<Point4D, string> World::rayCast(const Point4D& from, const Point4D& to) {
std::pair<Point4D, string> result{Point4D{0, 0,0, -1}, ""};
@ -41,7 +33,7 @@ std::pair<Point4D, string> World::rayCast(const Point4D& from, const Point4D& to
continue;
for(auto& tri : object.second->triangles()) {
Triangle tri_translated(tri[0] + object.second->position(), tri[1] + object.second->position(), tri[2] + object.second->position(), 0);
Triangle tri_translated(tri[0] + object.second->position(), tri[1] + object.second->position(), tri[2] + object.second->position());
Plane plane(tri_translated);
auto intersection = plane.intersection(from, to);
@ -59,23 +51,63 @@ void World::loadMap(const string &filename, const string &name, const Point4D &s
auto objs = Mesh::LoadObjects(filename, materials, scale);
for(int i = 0; i < objs.size(); i++) {
string meshName = name + "_" + to_string(i);
addMesh(objs[i], meshName);
addBody(std::make_shared<RigidBody>(*objs[i]), meshName);
}
}
void World::garbageCollector() {
for(auto& obj : _objToRemove) {
if(_objects.erase(obj) > 0)
Log::log("World::garbageCollector(): removed mesh '" + obj + "'");
Log::log("World::garbageCollector(): removed body '" + obj + "'");
else
Log::log("World::garbageCollector(): cannot remove mesh '" + obj + "': mesh does not exist.");
Log::log("World::garbageCollector(): cannot remove body '" + obj + "': body does not exist.");
}
_objToRemove.clear();
}
void World::removeMeshInstantly(const string &name) {
void World::removeBodyInstantly(const string &name) {
if(_objects.erase(name) > 0)
Log::log("World::removeMeshInstantly(): removed mesh '" + name + "'");
Log::log("World::removeBodyInstantly(): removed body '" + name + "'");
else
Log::log("World::removeMeshInstantly(): cannot remove mesh '" + name + "': mesh does not exist.");
Log::log("World::removeBodyInstantly(): cannot remove body '" + name + "': body does not exist.");
}
void World::checkCollision(const std::string& body) {
if (_objects[body]->isCollision()) {
_objects[body]->setInCollision(false);
for (auto &obj : _objects) {
if(obj.first != body) {
std::pair<bool, Simplex> gjk = _objects[body]->checkGJKCollision(obj.second);
if (gjk.first) {
if (obj.second->isCollider()) {
CollisionPoint epa = _objects[body]->EPA(gjk.second, obj.second);
Solver::solveCollision(_objects[body], obj.second, epa);
}
if (_objects[body]->collisionCallBack() != nullptr)
_objects[body]->collisionCallBack()(obj.first, obj.second);
}
}
}
}
}
void World::update() {
for (auto &m : _objects) {
m.second->a_update();
m.second->updatePhysicsState();
checkCollision(m.first);
}
}
void World::projectObjectsInCamera(std::shared_ptr<Camera> camera) {
for (auto &m : _objects)
camera->project(m.second);
}
std::shared_ptr<RigidBody> World::body(const string &name) {
if(_objects.count(name) == 0)
Log::log("World::body: mesh '" + name + "' does not exist.");
return _objects.find(name)->second;
}

View File

@ -6,25 +6,26 @@
#define ENGINE_WORLD_H
#include <map>
#include "Mesh.h"
#include "Camera.h"
#include "physics/RigidBody.h"
class World {
private:
std::map<std::string, std::shared_ptr<Mesh>> _objects;
std::map<std::string, std::shared_ptr<RigidBody>> _objects;
std::vector<std::string> _objToRemove;
public:
World() = default;
[[nodiscard]] std::shared_ptr<Mesh> operator[] (const std::string& name);
void checkCollision(const std::string& body);
void update();
void projectObjectsInCamera(std::shared_ptr<Camera> camera);
[[nodiscard]] std::map<std::string, std::shared_ptr<Mesh>>& objects() { return _objects; }
void addMesh(std::shared_ptr<Mesh> mesh, const std::string& name = "");
void removeMesh(const std::string& name);
void removeMeshInstantly(const std::string& name);
void addBody(std::shared_ptr<RigidBody> mesh, const std::string& name = "");
std::shared_ptr<RigidBody> body(const std::string& name);
void removeBody(const std::string& name);
void removeBodyInstantly(const std::string& name);
void garbageCollector();
void loadObj(const std::string &name, const std::string &filename,const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
void loadBody(const std::string &name, const std::string &filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
// rayCast returns pair of Point4D and std::string:
// 1) Point4D is point of collision (the last coordinate is -1 if there are no collisions)

View File

@ -34,7 +34,7 @@ protected:
double _duration = 0;
bool _started = false;
LoopOut _looped = None;
// p - animation progress
// _p - animation progress
double _p = 0;
double _dp = 0;

View File

@ -16,7 +16,7 @@ void Window::addButton(int x, int y, int w, int h, std::function<void()> click,
void Window::update(std::shared_ptr<Screen> screen) {
screen->title(s_name);
screen->setName(s_name);
screen->window.draw(back);
Point4D mousePos = screen->getMousePosition();

View File

@ -13,7 +13,8 @@ Point4D RigidBody::_findFurthestPoint(const Point4D& direction) {
Point4D maxPoint = {};
auto maxDistance = (double)-INFINITY;
for(auto& tri : triangles()){
for(auto point : tri.p){
for(int i = 0; i < 3; i++){
Point4D point = tri[i];
point = point + position();
@ -302,18 +303,22 @@ void RigidBody::AddIfUniqueEdge(std::vector<std::pair<size_t, size_t>>& edges, c
}
void RigidBody::updatePhysicsState() {
translate(p_velocity * Time::deltaTime());
p_velocity = p_velocity + p_acceleration * Time::deltaTime();
translate(_velocity * Time::deltaTime());
_velocity = _velocity + _acceleration * Time::deltaTime();
}
void RigidBody::setVelocity(const Point4D& velocity) {
p_velocity = velocity;
_velocity = velocity;
}
void RigidBody::addVelocity(const Point4D &velocity) {
p_velocity = p_velocity + velocity;
_velocity = _velocity + velocity;
}
void RigidBody::setAcceleration(const Point4D& acceleration) {
p_acceleration = acceleration;
_acceleration = acceleration;
}
RigidBody::RigidBody(const Mesh &mesh) : Mesh(mesh) {
}

View File

@ -10,6 +10,7 @@
#include "../utils/Point4D.h"
#include "../Triangle.h"
#include "Simplex.h"
#include "Mesh.h"
struct CollisionPoint {
Point4D a; // Furthest point of a into b
@ -19,20 +20,13 @@ struct CollisionPoint {
bool hasCollision;
};
class RigidBody {
protected:
Point4D p_velocity;
Point4D p_acceleration;
bool _collision = false;
bool _isCollider = true;
bool _inCollision = false;
Point4D _collisionNormal;
class RigidBody : public Mesh {
private:
Point4D _findFurthestPoint(const Point4D& direction);
Point4D _support(std::shared_ptr<RigidBody> obj, const Point4D& direction);
std::function<void(const std::string&, std::shared_ptr<RigidBody>)> _collisionCallBack;
static bool _nextSimplex(Simplex& points, Point4D& direction);
static bool _line(Simplex& points, Point4D& direction);
static bool _triangle(Simplex& points, Point4D& direction);
@ -41,9 +35,19 @@ protected:
static std::pair<std::vector<Point4D>, size_t> GetFaceNormals(const std::vector<Point4D>& polytope, const std::vector<size_t>& faces);
static void AddIfUniqueEdge(std::vector<std::pair<size_t, size_t>>& edges, const std::vector<size_t>& faces, size_t a, size_t b);
protected:
Point4D _velocity;
Point4D _acceleration;
bool _collision = false;
bool _isCollider = true;
bool _inCollision = false;
Point4D _collisionNormal;
public:
RigidBody() = default;
virtual ~RigidBody() = default;
explicit RigidBody(const Mesh& mesh);
std::pair<bool, Simplex> checkGJKCollision(std::shared_ptr<RigidBody> obj);
CollisionPoint EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj);
@ -56,19 +60,16 @@ public:
void setCollision(bool c) { _collision= c; }
void setCollider(bool c) { _isCollider = c; }
[[nodiscard]] virtual std::vector<Triangle>& triangles() = 0;
[[nodiscard]] virtual Point4D position() const = 0;
virtual void translate(const Point4D& dv) = 0;
virtual void rotate(const Point4D& r) = 0;
void updatePhysicsState();
void setVelocity(const Point4D& velocity);
void addVelocity(const Point4D& velocity);
void setAcceleration(const Point4D& acceleration);
[[nodiscard]] Point4D velocity() const { return p_velocity; }
[[nodiscard]] Point4D velocity() const { return _velocity; }
[[nodiscard]] const std::function<void(const std::string&, std::shared_ptr<RigidBody>)>& collisionCallBack() const { return _collisionCallBack; }
void setCollisionCallBack(const std::function<void(const std::string&, std::shared_ptr<RigidBody>)>& f) { _collisionCallBack = f; }
};

View File

@ -46,7 +46,7 @@ Point4D Point4D::operator-(const Point4D& point4D) const {
double Point4D::dot(const Point4D& point4D) const
{
return point4D.x() * x() + point4D.y() * y() + point4D.z() * z() + point4D.w() * w();
return point4D.x() * x() + point4D.y() * y() + point4D.z() * z();
}
[[nodiscard]] Point4D Point4D::cross3D(const Point4D& point4D) const {
return Point4D {y() * point4D.z() - point4D.y() * z(),

View File

@ -75,7 +75,7 @@ public:
Shooter() = default;
void start() override;
void update(double elapsedTime) override;
void update() override;
void gui() override;
@ -84,7 +84,7 @@ public:
void Shooter::start() {
// This code executed once in the beginning:
debugText(false);
setDebugText(false);
screen->setMouseCursorVisible(true);
@ -100,7 +100,7 @@ void Shooter::start() {
setUpdateWorld(false);
world->addMesh(player, player->name());
world->addBody(player, player->name());
player->setDamagePlayerCallBack([this] (sf::Uint16 targetId, double damage) { client->damagePlayer(targetId, damage); });
player->setTakeBonusCallBack([this] (const string& bonusName) { client->takeBonus(bonusName); });
@ -132,7 +132,7 @@ void Shooter::start() {
}
}
void Shooter::update(double elapsedTime) {
void Shooter::update() {
// This code executed every time step:
server->update();
@ -148,7 +148,7 @@ void Shooter::update(double elapsedTime) {
}
if(inGame) {
screen->title("Shooter");
screen->setName("Shooter");
player->update();
} else {
mainMenu.update(screen);
@ -166,8 +166,6 @@ void Shooter::update(double elapsedTime) {
void Shooter::gui() {
if(inGame) {
// aim
sf::Sprite sprite;
sprite.setTexture(*ResourceManager::loadTexture("../textures/gui.png"));
sprite.setTextureRect(sf::IntRect(243, 3, 9, 9));
@ -178,7 +176,6 @@ void Shooter::gui() {
// health player stats
player->drawStats();
}
}
void Shooter::play() {

View File

@ -41,12 +41,12 @@ Shotgun::processFire(std::shared_ptr<World> world, std::shared_ptr<Camera> camer
string traceName = _name + "_trace_nr_" + std::to_string(fireTraces++);
Point4D from = _objects[_name + "_" + to_string(9)]->position() +
_objects[_name + "_" + to_string(9)]->triangles()[0][0];
world->addMesh(make_shared<Mesh>(Mesh::LineTo(from, to, 0.05)), traceName);
(*world)[traceName]->setCollider(false);
world->addBody(make_shared<RigidBody>(Mesh::LineTo(from, to, 0.05)), traceName);
world->body(traceName)->setCollider(false);
// remove trace line after some time
(*world)[traceName]->a_color("color_trace", {255, 255, 255, 0}, 1, Animation::None, Animation::linear);
(*world)["map_0"]->a_function(traceName + "delete", [world, traceName]() { deleteTrace(world, traceName); },
world->body(traceName)->a_color("color_trace", {255, 255, 255, 0}, 1, Animation::None, Animation::linear);
world->body("map_0")->a_function(traceName + "delete", [world, traceName]() { deleteTrace(world, traceName); },
1, 2);
addTraceCallBack(from, to);
}

View File

@ -14,13 +14,16 @@ Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, co
auto objs = Mesh::LoadObjects(objFileName, matFileName, scale);
for(int i = 0; i < objs.size(); i++) {
string meshName = _name + "_" + to_string(i);
objs[i]->setCollider(false);
RigidBody obj(*objs[i]);
obj.setCollider(false);
//transforms
objs[i]->rotate(rotate);
objs[i]->translate(translate);
obj.rotate(rotate);
obj.translate(translate);
_objects.insert({meshName, objs[i]});
_objects.insert({meshName, std::make_shared<RigidBody>(obj)});
}
noAmmoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/weapons/no_ammo.ogg"));
}
@ -62,13 +65,13 @@ void Weapon::reload() {
void Weapon::addToWorld(shared_ptr<World> world) {
for(auto& obj : _objects) {
world->addMesh(obj.second, obj.first);
world->addBody(obj.second, obj.first);
}
}
void Weapon::removeFromWorld(shared_ptr<World> world) {
for(auto& obj : _objects) {
world->removeMeshInstantly(obj.first);
world->removeBodyInstantly(obj.first);
}
}
@ -90,7 +93,7 @@ void Weapon::translate(const Point4D &point4D) {
}
void Weapon::deleteTrace(shared_ptr<World> world, const std::string& traceName) {
world->removeMesh(traceName);
world->removeBody(traceName);
}
void Weapon::rotateRelativePoint(const Point4D &point4D, const Point4D &v, double val) {
@ -114,12 +117,12 @@ std::map<std::string, double> Weapon::processFire(shared_ptr<World> world, share
Point4D to = rayCast.first.w() == -1 ? camera->position() + camera->lookAt() * 1000 + randV: rayCast.first;
string traceName = _name + "_trace_nr_" + std::to_string(fireTraces++);
Point4D from = _objects[_name + "_" + to_string(_objects.size()-1)]->position() + _objects[_name + "_" + to_string(_objects.size()-1)]->triangles()[0][0];
world->addMesh(make_shared<Mesh>(Mesh::LineTo(from, to, 0.05)), traceName);
(*world)[traceName]->setCollider(false);
world->addBody(make_shared<RigidBody>(Mesh::LineTo(from, to, 0.05)), traceName);
world->body(traceName)->setCollider(false);
// remove trace line after some time
(*world)[traceName]->a_color("color_trace", {255, 255, 255, 0}, 1, Animation::None, Animation::linear);
(*world)["Player_im"]->a_function(traceName + "delete", [world, traceName](){deleteTrace(world, traceName); }, 1, 2);
world->body(traceName)->a_color("color_trace", {255, 255, 255, 0}, 1, Animation::None, Animation::linear);
world->body("Player_im")->a_function(traceName + "delete", [world, traceName](){deleteTrace(world, traceName); }, 1, 2);
addTraceCallBack(from, to);

View File

@ -28,7 +28,7 @@ protected:
double _spreading = 2.0;
std::string _name = "Weapon_name";
std::map<std::string, std::shared_ptr<Mesh>> _objects;
std::map<std::string, std::shared_ptr<RigidBody>> _objects;
double _lastFireTime = -INFINITY;
double _lastReloadTime = -INFINITY;