Huge refactoring v3

master
Vectozavr 2021-10-28 20:58:02 +07:00
parent 31722ca109
commit 870842b682
98 changed files with 1175 additions and 1163 deletions

View File

@ -1,11 +0,0 @@
//
// Created by Иван Ильин on 05.06.2021.
//
#include "Bonus.h"
Bonus::Bonus(const std::string &bonusName, const std::string &filename, const Vec3D &scale) {
_name = bonusName;
loadObj(filename, scale);
setCollider(false);
}

21
Bonus.h
View File

@ -1,21 +0,0 @@
//
// Created by Иван Ильин on 05.06.2021.
//
#ifndef SHOOTER_BONUS_H
#define SHOOTER_BONUS_H
#include "engine/World.h"
#include "Player.h"
class Bonus final : public RigidBody {
private:
std::string _name;
public:
explicit Bonus(const std::string &bonusName, const std::string& filename, const Vec3D& scale = Vec3D{1, 1, 1});
[[nodiscard]] std::string name() const { return _name; }
};
#endif //SHOOTER_3DZAVR_BONUS_H

View File

@ -22,8 +22,6 @@ add_executable(shooter
weapon/Shotgun.h
weapon/Gun.cpp
weapon/Gun.h
Bonus.cpp
Bonus.h
weapon/Gold_Ak47.h
weapon/Rifle.cpp
weapon/Rifle.h
@ -34,8 +32,8 @@ add_executable(shooter
ShooterConsts.h
# 3d engine:
engine/Consts.h
engine/Point4D.h
engine/Point4D.cpp
engine/Vec4D.h
engine/Vec4D.cpp
engine/Vec3D.cpp
engine/Vec3D.h
engine/Vec2D.cpp
@ -97,7 +95,7 @@ add_executable(shooter
engine/network/UDPConnection.h
engine/network/UDPSocket.cpp
engine/network/UDPSocket.h
engine/SoundController.cpp engine/SoundController.h)
engine/SoundController.cpp engine/SoundController.h ShooterMsgType.h ShooterMsgType.cpp)
if(APPLE OR UNIX)
include_directories(/usr/local/include)

View File

@ -6,13 +6,13 @@
#include <utility>
#include "engine/utils/Log.h"
#include "Bonus.h"
#include "engine/animation/Timeline.h"
#include "engine/animation/ATranslateToPoint.h"
#include "ShooterMsgType.h"
void Client::updatePacket() {
sf::Packet packet;
packet << MsgType::ClientUpdate << _player->position().x() << _player->position().y() << _player->position().z() << _player->angle().y() << _player->headAngle() << _player->playerName();
packet << MsgType::ClientUpdate << _player->position().x() << _player->position().y() << _player->position().z() << _player->angle().y() << _player->headAngle() << _player->playerNickName();
_socket.send(packet, _socket.serverId());
}
@ -24,8 +24,9 @@ void Client::processInit(sf::Packet& packet) {
while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> kills >> deaths)
{
if(targetId != _socket.ownId()) {
if(_spawnPlayerCallBack != nullptr)
if(_spawnPlayerCallBack != nullptr) {
_spawnPlayerCallBack(targetId);
}
_players[targetId]->translateToPoint(Vec3D{ buf[0], buf[1], buf[2]});
_players[targetId]->setHealth(buf[3]);
@ -42,24 +43,23 @@ void Client::processUpdate(sf::Packet& packet) {
while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> buf[5] >> playerName) {
if (_players.count(targetId)) {
std::string tagName = "Player_" + std::to_string(targetId);
std::string name = "Enemy_" + std::to_string(targetId);
// old approach (no animation):
//_players[targetId]->translateToPoint(Vec3D{buf[0], buf[1], buf[2]});
// new approach (linear extrapolational animations)
double duration = 1.0 / Consts::NETWORK_WORLD_UPDATE_RATE;
Timeline::animate(AnimationListTag(tagName + "_linearTranslation"), new ATranslateToPoint(_players[targetId], Vec3D{buf[0], buf[1], buf[2]}, duration, Animation::LoopOut::None, Animation::InterpolationType::linear));
_players[targetId]->translateToPoint(Vec3D{buf[0], buf[1], buf[2]});
_players[targetId]->setHealth(buf[3]);
_players[targetId]->rotateToAngle(Vec3D{0, buf[4], 0});
_players[targetId]->setPlayerName(playerName);
_players[targetId]->setPlayerNickName(playerName);
auto head = _players[targetId]->attached(ObjectNameTag("head"));
auto weapon = _players[targetId]->attached(ObjectNameTag("Weapon"));
auto head = _players[targetId]->attached(ObjectNameTag(name + "_head"));
auto weapon = _players[targetId]->attached(ObjectNameTag("Enemy_" + std::to_string(targetId) + "_weapon"));
if(head != nullptr) {
head->rotateLeft(buf[5] - _players[targetId]->headAngle());
}
if(weapon != nullptr) {
weapon->rotateLeft(-(buf[5] - _players[targetId]->headAngle()));
}
_players[targetId]->setHeadAngle(buf[5]);
} else if (targetId == _socket.ownId()) {
@ -73,8 +73,9 @@ void Client::processNewClient(sf::Packet& packet) {
packet >> targetId;
if(_spawnPlayerCallBack != nullptr)
if(_spawnPlayerCallBack != nullptr) {
_spawnPlayerCallBack(targetId);
}
}
void Client::processDisconnect(sf::Uint16 targetId) {
@ -85,23 +86,26 @@ void Client::processDisconnect(sf::Uint16 targetId) {
}
void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
void Client::processCustomPacket(sf::Packet& packet) {
sf::Uint16 buffId[2];
double dbuff[10];
std::string tmp, tmp2;
ShooterMsgType type;
packet >> type;
switch (type) {
case MsgType::Kill:
case ShooterMsgType::Kill:
packet >> buffId[0] >> buffId[1];
_lastEvent = "";
if(buffId[1] == _socket.ownId()) {
_player->addKill();
SoundController::playSound(SoundTag("kill"), ShooterConsts::KILL_SOUND);
_lastEvent += _player->playerName();
_lastEvent += _player->playerNickName();
}
else {
_players[buffId[1]]->addKill();
_lastEvent += _players[buffId[1]]->playerName();
_lastEvent += _players[buffId[1]]->playerNickName();
}
_lastEvent += " ~> ";
@ -112,45 +116,51 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
_player->initWeapons();
_player->setFullAbility();
SoundController::playSound(SoundTag("death"), ShooterConsts::DEATH_SOUND);
_lastEvent += _player->playerName();
_lastEvent += _player->playerNickName();
}
else {
_players[buffId[0]]->addDeath();
_lastEvent += _players[buffId[0]]->playerName();
_lastEvent += _players[buffId[0]]->playerNickName();
}
break;
case MsgType::FireTrace:
case ShooterMsgType::FireTrace:
packet >> dbuff[0] >> dbuff[1] >> dbuff[2] >> dbuff[3] >> dbuff[4] >> dbuff[5];
if(_addFireTraceCallBack != nullptr)
if(_addFireTraceCallBack != nullptr) {
_addFireTraceCallBack(Vec3D(dbuff[0], dbuff[1], dbuff[2]), Vec3D(dbuff[3], dbuff[4], dbuff[5]));
}
break;
case MsgType::InitBonuses:
case ShooterMsgType::InitBonuses:
while (packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2]) {
if(_addBonusCallBack != nullptr)
if(_addBonusCallBack != nullptr) {
_addBonusCallBack(tmp, Vec3D(dbuff[0], dbuff[1], dbuff[2]));
}
}
break;
case MsgType::AddBonus:
case ShooterMsgType::AddBonus:
packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2];
if(_addBonusCallBack != nullptr)
if(_addBonusCallBack != nullptr) {
_addBonusCallBack(tmp, Vec3D(dbuff[0], dbuff[1], dbuff[2]));
}
break;
case MsgType::RemoveBonus:
case ShooterMsgType::RemoveBonus:
packet >> tmp;
if(_removeBonusCallBack != nullptr)
if(_removeBonusCallBack != nullptr) {
_removeBonusCallBack(ObjectNameTag(tmp));
}
break;
case MsgType::ChangeWeapon:
case ShooterMsgType::ChangeWeapon:
packet >> buffId[0] >> tmp;
if(_changeEnemyWeaponCallBack != nullptr)
if(_changeEnemyWeaponCallBack != nullptr) {
_changeEnemyWeaponCallBack(tmp, buffId[0]);
}
break;
default:
Log::log("Client::processCustomPacket: unknown message type " + std::to_string(static_cast<int>(type)));
return;
}
}
@ -164,7 +174,7 @@ void Client::processDisconnected() {
void Client::damagePlayer(sf::Uint16 targetId, double damage) {
sf::Packet packet;
packet << MsgType::Damage << targetId << damage;
packet << MsgType::Custom << ShooterMsgType::Damage << targetId << damage;
_socket.sendRely(packet, _socket.serverId());
Log::log("Client: damagePlayer " + std::to_string(targetId) + " ( -" + std::to_string(damage) + "hp )");
@ -173,24 +183,25 @@ void Client::damagePlayer(sf::Uint16 targetId, double damage) {
void Client::addTrace(const Vec3D& from, const Vec3D& to) {
sf::Packet packet;
packet << MsgType::FireTrace << from.x() << from.y() << from.z() << to.x() << to.y() << to.z();
packet << MsgType::Custom << ShooterMsgType::FireTrace << from.x() << from.y() << from.z() << to.x() << to.y() << to.z();
_socket.send(packet, _socket.serverId());
}
void Client::takeBonus(const std::string& bonusName) {
sf::Packet packet;
packet << MsgType::RemoveBonus << bonusName;
packet << MsgType::Custom << ShooterMsgType::RemoveBonus << bonusName;
_socket.sendRely(packet, _socket.serverId());
if(_removeBonusCallBack != nullptr)
if(_removeBonusCallBack != nullptr) {
_removeBonusCallBack(ObjectNameTag(bonusName));
}
}
void Client::changeWeapon(const std::string &weaponName) {
sf::Packet packet;
packet << MsgType::ChangeWeapon << weaponName;
packet << MsgType::Custom << ShooterMsgType::ChangeWeapon << weaponName;
_socket.sendRely(packet, _socket.serverId());
}

View File

@ -39,7 +39,7 @@ public:
void processNewClient(sf::Packet& packet) override;
void processDisconnect(sf::Uint16 targetId) override;
void processCustomPacket(MsgType type, sf::Packet& packet) override;
void processCustomPacket(sf::Packet& packet) override;
void processDisconnected() override;

View File

@ -7,7 +7,7 @@
#include "engine/ResourceManager.h"
#include "engine/utils/Log.h"
Player::Player() {
Player::Player(ObjectNameTag name) : RigidBody(name) {
loadObj(ShooterConsts::CUBE_OBJ, Vec3D{0.5, 1.9, 0.5});
setAcceleration(Vec3D{0, -ShooterConsts::GRAVITY, 0});
setCollision(true);
@ -18,31 +18,39 @@ Player::Player() {
}
void Player::rotateWeaponsRelativePoint(const Vec3D& point4D, const Vec3D& v, double val) {
for(auto& weapon : _weapons)
for(auto& weapon : _weapons) {
weapon->rotateRelativePoint(point4D, v, val);
}
}
void Player::collisionWithObject(const ObjectNameTag& tag, std::shared_ptr<RigidBody> obj) {
if(tag.str().find("Bonus_gun") != std::string::npos)
if(tag.str().find("Bonus_gun") != std::string::npos) {
addWeapon(std::make_shared<Gun>());
}
if(tag.str().find("Bonus_shotgun") != std::string::npos)
if(tag.str().find("Bonus_shotgun") != std::string::npos) {
addWeapon(std::make_shared<Shotgun>());
}
if(tag.str().find("Bonus_ak47") != std::string::npos)
if(tag.str().find("Bonus_ak47") != std::string::npos) {
addWeapon(std::make_shared<Ak47>());
}
if(tag.str().find("Bonus_gold_ak47") != std::string::npos)
if(tag.str().find("Bonus_gold_ak47") != std::string::npos) {
addWeapon(std::make_shared<Gold_Ak47>());
}
if(tag.str().find("Bonus_rifle") != std::string::npos)
if(tag.str().find("Bonus_rifle") != std::string::npos) {
addWeapon(std::make_shared<Rifle>());
}
if(tag.str().find("Bonus_hill") != std::string::npos)
if(tag.str().find("Bonus_hill") != std::string::npos) {
setFullHealth();
}
if(tag.str().find("Bonus_ability") != std::string::npos)
if(tag.str().find("Bonus_ability") != std::string::npos) {
setFullAbility();
}
if(tag.str().find("Bonus") != std::string::npos) {
_takeBonusCallBack(tag.str());
@ -60,10 +68,10 @@ void Player::addWeapon(std::shared_ptr<Weapon> weapon) {
}
_weapons.push_back(weapon);
attach(weapon, ObjectNameTag(weapon->name()));
attach(weapon);
_weapons.back()->translate(position());
_weapons.back()->rotateRelativePoint(position() + Vec3D{0, 1.8, 0}, Vec3D{0, 1, 0}, _angle->y());
_weapons.back()->rotateRelativePoint(position() + Vec3D{0, 1.8, 0}, Vec3D{0, 1, 0}, _angle.y());
_weapons.back()->rotateRelativePoint(position() + Vec3D{0, 1.8, 0}, left(), headAngle());
_weapons.back()->setAddTraceCallBack(_addTraceCallBack);
@ -72,8 +80,9 @@ void Player::addWeapon(std::shared_ptr<Weapon> weapon) {
void Player::initWeapons() {
if(!_weapons.empty()) {
for(auto weapon : _weapons)
for(auto weapon : _weapons) {
unattach(ObjectNameTag(weapon->name()));
}
_removeWeaponCallBack(_weapons[_selectedWeapon]);
_weapons.clear();
@ -99,10 +108,11 @@ void Player::previousWeapon() {
if(_weapons.size() > 1) {
// change '_selectedWeapon'
_removeWeaponCallBack(_weapons[_selectedWeapon]);
if (_selectedWeapon > 0)
if (_selectedWeapon > 0) {
_selectedWeapon = (_selectedWeapon - 1) % _weapons.size();
else
} else {
_selectedWeapon = _weapons.size() - 1;
}
_addWeaponCallBack(_weapons[_selectedWeapon]);
Log::log("selectedWeapon " + std::to_string(_selectedWeapon));
SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND);

View File

@ -30,7 +30,7 @@ private:
std::vector<std::shared_ptr<Weapon>> _weapons;
size_t _selectedWeapon = 0;
std::string _name = ShooterConsts::PLAYER_NAME;
std::string _nickName = ShooterConsts::PLAYER_NAME;
std::function<void(sf::Uint16 targetId, double)> _damagePlayerCallBack;
std::function<void(const Vec3D&, const Vec3D&)> _addTraceCallBack;
@ -41,7 +41,7 @@ private:
std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> _rayCastFunction;
public:
Player();
explicit Player(ObjectNameTag name);
void setHealth(double h) { _health = h; }
void setAbility(double a) { _ability = a; }
@ -100,8 +100,8 @@ public:
void collisionWithObject(const ObjectNameTag& tag, std::shared_ptr<RigidBody> obj);
[[nodiscard]] std::string playerName() const { return _name; }
void setPlayerName(const std::string& name) { _name = name; }
[[nodiscard]] std::string playerNickName() const { return _nickName; }
void setPlayerNickName(const std::string& name) { _nickName = name; }
};

View File

@ -4,12 +4,10 @@
#include "PlayerController.h"
#include "engine/utils/Log.h"
#include "engine/animation/AFunction.h"
#include "engine/animation/AWait.h"
#include "engine/animation/ATranslate.h"
#include "engine/animation/ATranslateToPoint.h"
#include "engine/animation/Timeline.h"
#include "engine/animation/ARotate.h"
#include "ShooterConsts.h"
PlayerController::PlayerController(std::shared_ptr<Player> player,
@ -18,13 +16,14 @@ PlayerController::PlayerController(std::shared_ptr<Player> player,
void PlayerController::update() {
// friction
if(_player->inCollision())
_player->setVelocity(_player->velocity()*(1.0 - Time::deltaTime() * 2));
if(_player->inCollision()) {
_player->setVelocity(_player->velocity() * (1.0 - Time::deltaTime() * 2));
}
if(_isInSlowMo) {
if(_player->ability() > 0)
if(_player->ability() > 0) {
_player->setAbility(_player->ability() - Time::deltaTime());
else {
} else {
_player->setAbility(0);
_isInSlowMo = false;
_player->setVelocity(_player->velocity() * ShooterConsts::SLOW_MO_COEFFICIENT);
@ -45,52 +44,56 @@ void PlayerController::update() {
std::shared_ptr<Object> camera = _player->attached(ObjectNameTag("Camera"));
if(camera != nullptr && _inRunning && _player->inCollision()) {
if (!Timeline::isInAnimList(AnimationListTag("camera_hor_oscil"))) {
Timeline::animate(AnimationListTag("camera_hor_oscil"), new ATranslate(camera, -camera->left() / 6, 0.3,Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_hor_oscil"), new ATranslate(camera, -camera->left() / 6, 0.3,Animation::LoopOut::None, Animation::InterpolationType::Cos));
Timeline::animate(AnimationListTag("camera_hor_oscil"), new AWait(0));
Timeline::animate(AnimationListTag("camera_hor_oscil"), new ATranslate(camera, camera->left() / 6, 0.3, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_hor_oscil"), new ATranslate(camera, camera->left() / 6, 0.3, Animation::LoopOut::None, Animation::InterpolationType::Cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, -Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, -Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::Cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new AWait(0));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::Cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new AWait(0));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, -Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, -Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::Cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new AWait(0));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_vert_oscil"), new ATranslate(camera, Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::Cos));
Timeline::animate(AnimationListTag("camera_init"), new ATranslateToPoint( camera, _player->position() + Vec3D{0, 1.8, 0}, 0.3, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_init"), new ATranslateToPoint( camera, _player->position() + Vec3D{0, 1.8, 0}, 0.3, Animation::LoopOut::None, Animation::InterpolationType::Cos));
}
} else if(camera != nullptr && inRunning_old && !_inRunning) {
Timeline::deleteAnimationList(AnimationListTag("camera_hor_oscil"));
Timeline::deleteAnimationList(AnimationListTag("camera_vert_oscil"));
Timeline::deleteAnimationList(AnimationListTag("camera_init"));
Timeline::animate(AnimationListTag("camera_init"), new ATranslateToPoint( camera, _player->position() + Vec3D{0, 1.8, 0}, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
Timeline::animate(AnimationListTag("camera_init"), new ATranslateToPoint( camera, _player->position() + Vec3D{0, 1.8, 0}, 0.15, Animation::LoopOut::None, Animation::InterpolationType::Cos));
}
// Left and right
if (Keyboard::isKeyPressed(sf::Keyboard::A)) {
_player->translate(_player->left() * Time::deltaTime() * ShooterConsts::WALK_SPEED * coeff);
if(_player->inCollision())
_player->setVelocity(Vec3D{0,0,0});
if(_player->inCollision()) {
_player->setVelocity(Vec3D{0, 0, 0});
}
}
if (Keyboard::isKeyPressed(sf::Keyboard::D)) {
_player->translate(-_player->left() * Time::deltaTime() * ShooterConsts::WALK_SPEED * coeff);
if(_player->inCollision())
_player->setVelocity(Vec3D{0,0,0});
if(_player->inCollision()) {
_player->setVelocity(Vec3D{0, 0, 0});
}
}
// Forward and backward
if (Keyboard::isKeyPressed(sf::Keyboard::W)) {
_player->translate(_player->lookAt() * Time::deltaTime() * ShooterConsts::WALK_SPEED * coeff);
if(_player->inCollision())
_player->setVelocity(Vec3D{0,0,0});
if(_player->inCollision()) {
_player->setVelocity(Vec3D{0, 0, 0});
}
}
if (Keyboard::isKeyPressed(sf::Keyboard::S)) {
_player->translate(-_player->lookAt() * Time::deltaTime() * ShooterConsts::WALK_SPEED * coeff);
if(_player->inCollision())
_player->setVelocity(Vec3D{0,0,0});
if(_player->inCollision()) {
_player->setVelocity(Vec3D{0, 0, 0});
}
}
if (_player->ability() > 0 && !_isInSlowMo && Keyboard::isKeyPressed(sf::Keyboard::LShift)) {
@ -112,19 +115,24 @@ void PlayerController::update() {
bool shot = _player->fire();
if(shot) {
if(!_player->inCollision() && (_player->weaponName() == ObjectNameTag("shotgun")))
if(!_player->inCollision() && (_player->weaponName() == ObjectNameTag("weapon_shotgun"))) {
_player->addVelocity(-camera->lookAt() * 30 * coeff);
}
}
}
if (Keyboard::isKeyPressed(sf::Keyboard::Space) && _player->inCollision()) {
// if we just want to jump, we have to add particular speed
if (!_isSliding)
_player->addVelocity(Vec3D{ 0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * ShooterConsts::JUMP_HEIGHT) * coeff, 0 });
if (!_isSliding) {
_player->addVelocity(Vec3D{0, std::abs(_player->collisionNormal().y()) *
sqrt(2 * -_player->acceleration().y() * ShooterConsts::JUMP_HEIGHT) * coeff,
0});
// if we want to slide, we have to add speed * 60/fps to make it independent on frame rate
else
_player->addVelocity(Vec3D{ 0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * ShooterConsts::JUMP_HEIGHT) * coeff * Time::deltaTime() * 60, 0 });
} else {
_player->addVelocity(Vec3D{0, std::abs(_player->collisionNormal().y()) *
sqrt(2 * -_player->acceleration().y() * ShooterConsts::JUMP_HEIGHT) * coeff *
Time::deltaTime() * 60, 0});
}
_player->translate(Vec3D{ 0, Time::deltaTime() * ShooterConsts::WALK_SPEED * 2 * coeff, 0 });
_isSliding = true;
} else {
@ -140,16 +148,19 @@ void PlayerController::update() {
double rotationLeft = displacement.y() * ShooterConsts::MOUSE_SENSITIVITY;
// You can only see in range [-90 : 90] grad
if (_player->headAngle() + rotationLeft > Consts::PI / 2)
if (_player->headAngle() + rotationLeft > Consts::PI / 2) {
rotationLeft = Consts::PI / 2 - _player->headAngle();
if (_player->headAngle() + rotationLeft < -Consts::PI / 2)
}
if (_player->headAngle() + rotationLeft < -Consts::PI / 2) {
rotationLeft = -Consts::PI / 2 - _player->headAngle();
}
_player->setHeadAngle(_player->headAngle() + rotationLeft);
_player->rotateWeaponsRelativePoint(_player->position() + Vec3D{0, 1.8, 0}, _player->left(), rotationLeft);
if(camera != nullptr)
if(camera != nullptr) {
camera->rotateLeft(_player->headAngle() - camera->angleLeftUpLookAt().x());
}
if (_keyboard->isKeyTapped(sf::Keyboard::Right) || _keyboard->isKeyTapped(sf::Keyboard::E)) {
_player->nextWeapon();

View File

@ -106,7 +106,7 @@ Static Public Member Functions</h2></td></tr>
<tr class="memdesc:aa917c9435330e6e0368d3893672d1b74"><td class="mdescLeft">&#160;</td><td class="mdescRight">Get the joystick information. <a href="#aa917c9435330e6e0368d3893672d1b74">More...</a><br /></td></tr>
<tr class="separator:aa917c9435330e6e0368d3893672d1b74"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48">update</a> ()</td></tr>
<tr class="memdesc:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the states of all joysticks. <a href="#ab85fa9175b4edd3e5a07ee3cde0b0f48">More...</a><br /></td></tr>
<tr class="memdesc:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the states of all joysticks. <a href="#ab85fa9175b4edd3e5a07ee3cde0b0f48">More...</a><br /></td></tr>
<tr class="separator:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
@ -119,7 +119,7 @@ Static Public Member Functions</h2></td></tr>
<li>32 buttons per joystick (<a class="el" href="classsf_1_1Joystick.html#aee00dd432eacd8369d279b47c3ab4cc5a2f1b8a0a59f2c12a4775c0e1e69e1816" title="Maximum number of supported buttons. ">sf::Joystick::ButtonCount</a>) </li>
<li>8 axes per joystick (<a class="el" href="classsf_1_1Joystick.html#aee00dd432eacd8369d279b47c3ab4cc5accf3e487c9f6ee2f384351323626a42c" title="Maximum number of supported axes. ">sf::Joystick::AxisCount</a>)</li>
</ul>
<p>Unlike the keyboard or mouse, the state of joysticks is sometimes not directly available (depending on the OS), therefore an <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="Update the states of all joysticks. ">update()</a> function must be called in order to update the current state of joysticks. When you have a window with event handling, this is done automatically, you don't need to call anything. But if you have no window, or if you want to check joysticks state before creating one, you must call <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="Update the states of all joysticks. ">sf::Joystick::update</a> explicitly.</p>
<p>Unlike the keyboard or mouse, the state of joysticks is sometimes not directly available (depending on the OS), therefore an <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="ServerUpdate the states of all joysticks. ">update()</a> function must be called in order to update the current state of joysticks. When you have a window with event handling, this is done automatically, you don't need to call anything. But if you have no window, or if you want to check joysticks state before creating one, you must call <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="ServerUpdate the states of all joysticks. ">sf::Joystick::update</a> explicitly.</p>
<p>Usage example: </p><div class="fragment"><div class="line"><span class="comment">// Is joystick #0 connected?</span></div><div class="line"><span class="keywordtype">bool</span> connected = <a class="code" href="classsf_1_1Joystick.html#ac7d4e1923e9f9420174f26703ea63d6c">sf::Joystick::isConnected</a>(0);</div><div class="line"></div><div class="line"><span class="comment">// How many buttons does joystick #0 support?</span></div><div class="line"><span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> buttons = <a class="code" href="classsf_1_1Joystick.html#a4de9f445c6582bfe9f0873f695682885">sf::Joystick::getButtonCount</a>(0);</div><div class="line"></div><div class="line"><span class="comment">// Does joystick #0 define a X axis?</span></div><div class="line"><span class="keywordtype">bool</span> hasX = <a class="code" href="classsf_1_1Joystick.html#a268e8f2a11ae6af4a47c727cb4ab4d95">sf::Joystick::hasAxis</a>(0, <a class="code" href="classsf_1_1Joystick.html#a48db337092c2e263774f94de6d50baa7a95dc8b9bf7b0a2157fc67891c54c401e">sf::Joystick::X</a>);</div><div class="line"></div><div class="line"><span class="comment">// Is button #2 pressed on joystick #0?</span></div><div class="line"><span class="keywordtype">bool</span> pressed = <a class="code" href="classsf_1_1Joystick.html#ae0d97a4b84268cbe6a7078e1b2717835">sf::Joystick::isButtonPressed</a>(0, 2);</div><div class="line"></div><div class="line"><span class="comment">// What&#39;s the current position of the Y axis on joystick #0?</span></div><div class="line"><span class="keywordtype">float</span> position = <a class="code" href="classsf_1_1Joystick.html#aea4930193331df1851b709f3060ba58b">sf::Joystick::getAxisPosition</a>(0, <a class="code" href="classsf_1_1Joystick.html#a48db337092c2e263774f94de6d50baa7a51ef1455f7511ad4a78ba241d66593ce">sf::Joystick::Y</a>);</div></div><!-- fragment --><dl class="section see"><dt>See also</dt><dd><a class="el" href="classsf_1_1Keyboard.html" title="Give access to the real-time state of the keyboard. ">sf::Keyboard</a>, <a class="el" href="classsf_1_1Mouse.html" title="Give access to the real-time state of the mouse. ">sf::Mouse</a> </dd></dl>
<p class="definition">Definition at line <a class="el" href="Joystick_8hpp_source.html#l00041">41</a> of file <a class="el" href="Joystick_8hpp_source.html">Joystick.hpp</a>.</p>
@ -457,7 +457,7 @@ Static Public Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update the states of all joysticks. </p>
<p>ServerUpdate the states of all joysticks. </p>
<p>This function is used internally by SFML, so you normally don't have to call it explicitly. However, you may need to call it if you have no window yet (or no window at all): in this case the joystick states are not updated automatically. </p>
</div>

View File

@ -99,7 +99,7 @@ Public Member Functions</h2></td></tr>
<tr class="memdesc:a5da95ecdbce615a80bb78399012508cf"><td class="mdescLeft">&#160;</td><td class="mdescRight">Activate or deactivate the render-texture for rendering. <a href="#a5da95ecdbce615a80bb78399012508cf">More...</a><br /></td></tr>
<tr class="separator:a5da95ecdbce615a80bb78399012508cf"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:af92886d5faef3916caff9fa9ab32c555"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1RenderTexture.html#af92886d5faef3916caff9fa9ab32c555">display</a> ()</td></tr>
<tr class="memdesc:af92886d5faef3916caff9fa9ab32c555"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the contents of the target texture. <a href="#af92886d5faef3916caff9fa9ab32c555">More...</a><br /></td></tr>
<tr class="memdesc:af92886d5faef3916caff9fa9ab32c555"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the contents of the target texture. <a href="#af92886d5faef3916caff9fa9ab32c555">More...</a><br /></td></tr>
<tr class="separator:af92886d5faef3916caff9fa9ab32c555"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a6685315b5c4c25a5dcb75b4280b381ba"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classsf_1_1Vector2.html">Vector2u</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1RenderTexture.html#a6685315b5c4c25a5dcb75b4280b381ba">getSize</a> () const</td></tr>
<tr class="memdesc:a6685315b5c4c25a5dcb75b4280b381ba"><td class="mdescLeft">&#160;</td><td class="mdescRight">Return the size of the rendering region of the texture. <a href="#a6685315b5c4c25a5dcb75b4280b381ba">More...</a><br /></td></tr>
@ -376,7 +376,7 @@ Protected Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update the contents of the target texture. </p>
<p>ServerUpdate the contents of the target texture. </p>
<p>This function updates the target texture with what has been drawn so far. Like for windows, calling this function is mandatory at the end of rendering. Not calling it may leave the texture in an undefined state. </p>
</div>

View File

@ -403,7 +403,7 @@ Protected Member Functions</h2></td></tr>
</div><div class="memdoc">
<p>Copy the current contents of the window to an image. </p>
<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000005">Deprecated:</a></b></dt><dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="Update the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd></dl>
<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000005">Deprecated:</a></b></dt><dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="ServerUpdate the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd></dl>
<div class="fragment"><div class="line"><a class="code" href="classsf_1_1Vector2.html">sf::Vector2u</a> windowSize = window.<a class="code" href="classsf_1_1Window.html#a3969926741cbe83d7f9eeaf5333d4e71">getSize</a>();</div><div class="line"><a class="code" href="classsf_1_1Texture.html">sf::Texture</a> texture;</div><div class="line">texture.<a class="code" href="classsf_1_1Texture.html#a89b4c7d204acf1033c3a1b6e0a3ad0a3">create</a>(windowSize.<a class="code" href="classsf_1_1Vector2.html#a1e6ad77fa155f3753bfb92699bd28141">x</a>, windowSize.<a class="code" href="classsf_1_1Vector2.html#a420f2481b015f4eb929c75f2af564299">y</a>);</div><div class="line">texture.<a class="code" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963">update</a>(window);</div><div class="line"><a class="code" href="classsf_1_1Image.html">sf::Image</a> screenshot = texture.<a class="code" href="classsf_1_1Texture.html#a77e18a70de2e525ac5e4a7cd95f614b9">copyToImage</a>();</div></div><!-- fragment --><p>This is a slow operation, whose main purpose is to make screenshots of the application. If you want to update an image with the contents of the window and then use it for drawing, you should rather use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its update(Window&amp;) function. You can also draw things directly to a texture with the <a class="el" href="classsf_1_1RenderTexture.html" title="Target for off-screen 2D rendering into a texture. ">sf::RenderTexture</a> class.</p>
<dl class="section return"><dt>Returns</dt><dd><a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">Image</a> containing the captured contents </dd></dl>

View File

@ -108,28 +108,28 @@ Public Member Functions</h2></td></tr>
<tr class="memdesc:a77e18a70de2e525ac5e4a7cd95f614b9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Copy the texture pixels to an image. <a href="#a77e18a70de2e525ac5e4a7cd95f614b9">More...</a><br /></td></tr>
<tr class="separator:a77e18a70de2e525ac5e4a7cd95f614b9"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ae4eab5c6781316840b0c50ad08370963"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963">update</a> (const Uint8 *pixels)</td></tr>
<tr class="memdesc:ae4eab5c6781316840b0c50ad08370963"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the whole texture from an array of pixels. <a href="#ae4eab5c6781316840b0c50ad08370963">More...</a><br /></td></tr>
<tr class="memdesc:ae4eab5c6781316840b0c50ad08370963"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the whole texture from an array of pixels. <a href="#ae4eab5c6781316840b0c50ad08370963">More...</a><br /></td></tr>
<tr class="separator:ae4eab5c6781316840b0c50ad08370963"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a1352d8e16c2aeb4df586ed65dd2c36b9">update</a> (const Uint8 *pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the texture from an array of pixels. <a href="#a1352d8e16c2aeb4df586ed65dd2c36b9">More...</a><br /></td></tr>
<tr class="memdesc:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the texture from an array of pixels. <a href="#a1352d8e16c2aeb4df586ed65dd2c36b9">More...</a><br /></td></tr>
<tr class="separator:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:af9885ca00b74950d60feea28132d9691"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#af9885ca00b74950d60feea28132d9691">update</a> (const <a class="el" href="classsf_1_1Texture.html">Texture</a> &amp;texture)</td></tr>
<tr class="memdesc:af9885ca00b74950d60feea28132d9691"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of this texture from another texture. <a href="#af9885ca00b74950d60feea28132d9691">More...</a><br /></td></tr>
<tr class="memdesc:af9885ca00b74950d60feea28132d9691"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of this texture from another texture. <a href="#af9885ca00b74950d60feea28132d9691">More...</a><br /></td></tr>
<tr class="separator:af9885ca00b74950d60feea28132d9691"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a89beb474da1da84b5e38c9fc0b441fe4"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a89beb474da1da84b5e38c9fc0b441fe4">update</a> (const <a class="el" href="classsf_1_1Texture.html">Texture</a> &amp;texture, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a89beb474da1da84b5e38c9fc0b441fe4"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of this texture from another texture. <a href="#a89beb474da1da84b5e38c9fc0b441fe4">More...</a><br /></td></tr>
<tr class="memdesc:a89beb474da1da84b5e38c9fc0b441fe4"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of this texture from another texture. <a href="#a89beb474da1da84b5e38c9fc0b441fe4">More...</a><br /></td></tr>
<tr class="separator:a89beb474da1da84b5e38c9fc0b441fe4"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a037cdf171af0fb392d07626a44a4ea17"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a037cdf171af0fb392d07626a44a4ea17">update</a> (const <a class="el" href="classsf_1_1Image.html">Image</a> &amp;image)</td></tr>
<tr class="memdesc:a037cdf171af0fb392d07626a44a4ea17"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the texture from an image. <a href="#a037cdf171af0fb392d07626a44a4ea17">More...</a><br /></td></tr>
<tr class="memdesc:a037cdf171af0fb392d07626a44a4ea17"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the texture from an image. <a href="#a037cdf171af0fb392d07626a44a4ea17">More...</a><br /></td></tr>
<tr class="separator:a037cdf171af0fb392d07626a44a4ea17"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a87f916490b757fe900798eedf3abf3ba"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a87f916490b757fe900798eedf3abf3ba">update</a> (const <a class="el" href="classsf_1_1Image.html">Image</a> &amp;image, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a87f916490b757fe900798eedf3abf3ba"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the texture from an image. <a href="#a87f916490b757fe900798eedf3abf3ba">More...</a><br /></td></tr>
<tr class="memdesc:a87f916490b757fe900798eedf3abf3ba"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the texture from an image. <a href="#a87f916490b757fe900798eedf3abf3ba">More...</a><br /></td></tr>
<tr class="separator:a87f916490b757fe900798eedf3abf3ba"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5">update</a> (const <a class="el" href="classsf_1_1Window.html">Window</a> &amp;window)</td></tr>
<tr class="memdesc:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the texture from the contents of a window. <a href="#ad3cceef238f7d5d2108a98dd38c17fc5">More...</a><br /></td></tr>
<tr class="memdesc:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the texture from the contents of a window. <a href="#ad3cceef238f7d5d2108a98dd38c17fc5">More...</a><br /></td></tr>
<tr class="separator:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a154f246eb8059b602076009ab1cfd175"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a154f246eb8059b602076009ab1cfd175">update</a> (const <a class="el" href="classsf_1_1Window.html">Window</a> &amp;window, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a154f246eb8059b602076009ab1cfd175"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the texture from the contents of a window. <a href="#a154f246eb8059b602076009ab1cfd175">More...</a><br /></td></tr>
<tr class="memdesc:a154f246eb8059b602076009ab1cfd175"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the texture from the contents of a window. <a href="#a154f246eb8059b602076009ab1cfd175">More...</a><br /></td></tr>
<tr class="separator:a154f246eb8059b602076009ab1cfd175"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a0c3bd6825b9a99714f10d44179d74324"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a0c3bd6825b9a99714f10d44179d74324">setSmooth</a> (bool smooth)</td></tr>
<tr class="memdesc:a0c3bd6825b9a99714f10d44179d74324"><td class="mdescLeft">&#160;</td><td class="mdescRight">Enable or disable the smooth filter. <a href="#a0c3bd6825b9a99714f10d44179d74324">More...</a><br /></td></tr>
@ -193,7 +193,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
<div class="textblock"><p><a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">Image</a> living on the graphics card that can be used for drawing. </p>
<p><a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> stores pixels that can be drawn, with a sprite for example.</p>
<p>A texture lives in the graphics card memory, therefore it is very fast to draw a texture to a render target, or copy a render target to a texture (the graphics card can access both directly).</p>
<p>Being stored in the graphics card memory has some drawbacks. A texture cannot be manipulated as freely as a <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, you need to prepare the pixels first and then upload them to the texture in a single operation (see <a class="el" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963" title="Update the whole texture from an array of pixels. ">Texture::update</a>).</p>
<p>Being stored in the graphics card memory has some drawbacks. A texture cannot be manipulated as freely as a <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, you need to prepare the pixels first and then upload them to the texture in a single operation (see <a class="el" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963" title="ServerUpdate the whole texture from an array of pixels. ">Texture::update</a>).</p>
<p><a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> makes it easy to convert from/to <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, but keep in mind that these calls require transfers between the graphics card and the central memory, therefore they are slow operations.</p>
<p>A texture can be loaded from an image, but also directly from a file/memory/stream. The necessary shortcuts are defined so that you don't need an image first for the most common cases. However, if you want to perform some modifications on the pixels before creating the final texture, you can load your file to a <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, do whatever you need with the pixels, and then call <a class="el" href="classsf_1_1Texture.html#abec4567ad9856a3596dc74803f26fba2" title="Load the texture from an image. ">Texture::loadFromImage</a>.</p>
<p>Since they live in the graphics card memory, the pixels of a texture cannot be accessed without a slow copy first. And they cannot be accessed individually. Therefore, if you need to read the texture's pixels (like for pixel-perfect collisions), it is recommended to store the collision information separately, for example in an array of booleans.</p>
@ -886,7 +886,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update the whole texture from an array of pixels. </p>
<p>ServerUpdate the whole texture from an array of pixels. </p>
<p>The <em>pixel</em> array is assumed to have the same size as the <em>area</em> rectangle, and to contain 32-bits RGBA pixels.</p>
<p>No additional check is performed on the size of the pixel array, passing invalid arguments will lead to an undefined behavior.</p>
<p>This function does nothing if <em>pixels</em> is null or if the texture was not previously created.</p>
@ -943,7 +943,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of the texture from an array of pixels. </p>
<p>ServerUpdate a part of the texture from an array of pixels. </p>
<p>The size of the <em>pixel</em> array must match the <em>width</em> and <em>height</em> arguments, and it must contain 32-bits RGBA pixels.</p>
<p>No additional check is performed on the size of the pixel array or the bounds of the area to update, passing invalid arguments will lead to an undefined behavior.</p>
<p>This function does nothing if <em>pixels</em> is null or if the texture was not previously created.</p>
@ -976,7 +976,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of this texture from another texture. </p>
<p>ServerUpdate a part of this texture from another texture. </p>
<p>Although the source texture can be smaller than this texture, this function is usually used for updating the whole texture. The other overload, which has (x, y) additional arguments, is more convenient for updating a sub-area of this texture.</p>
<p>No additional check is performed on the size of the passed texture, passing a texture bigger than this texture will lead to an undefined behavior.</p>
<p>This function does nothing if either texture was not previously created.</p>
@ -1021,7 +1021,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of this texture from another texture. </p>
<p>ServerUpdate a part of this texture from another texture. </p>
<p>No additional check is performed on the size of the texture, passing an invalid combination of texture size and offset will lead to an undefined behavior.</p>
<p>This function does nothing if either texture was not previously created.</p>
<dl class="params"><dt>Parameters</dt><dd>
@ -1051,7 +1051,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update the texture from an image. </p>
<p>ServerUpdate the texture from an image. </p>
<p>Although the source image can be smaller than the texture, this function is usually used for updating the whole texture. The other overload, which has (x, y) additional arguments, is more convenient for updating a sub-area of the texture.</p>
<p>No additional check is performed on the size of the image, passing an image bigger than the texture will lead to an undefined behavior.</p>
<p>This function does nothing if the texture was not previously created.</p>
@ -1096,7 +1096,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of the texture from an image. </p>
<p>ServerUpdate a part of the texture from an image. </p>
<p>No additional check is performed on the size of the image, passing an invalid combination of image size and offset will lead to an undefined behavior.</p>
<p>This function does nothing if the texture was not previously created.</p>
<dl class="params"><dt>Parameters</dt><dd>
@ -1126,7 +1126,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update the texture from the contents of a window. </p>
<p>ServerUpdate the texture from the contents of a window. </p>
<p>Although the source window can be smaller than the texture, this function is usually used for updating the whole texture. The other overload, which has (x, y) additional arguments, is more convenient for updating a sub-area of the texture.</p>
<p>No additional check is performed on the size of the window, passing a window bigger than the texture will lead to an undefined behavior.</p>
<p>This function does nothing if either the texture or the window was not previously created.</p>
@ -1171,7 +1171,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of the texture from the contents of a window. </p>
<p>ServerUpdate a part of the texture from the contents of a window. </p>
<p>No additional check is performed on the size of the window, passing an invalid combination of window size and offset will lead to an undefined behavior.</p>
<p>This function does nothing if either the texture or the window was not previously created.</p>
<dl class="params"><dt>Parameters</dt><dd>

View File

@ -103,10 +103,10 @@ Public Member Functions</h2></td></tr>
<tr class="memdesc:a6c534536ed186a2ad65e75484c8abafe"><td class="mdescLeft">&#160;</td><td class="mdescRight">Return the vertex count. <a href="#a6c534536ed186a2ad65e75484c8abafe">More...</a><br /></td></tr>
<tr class="separator:a6c534536ed186a2ad65e75484c8abafe"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ad100a5f578a91c49a9009e3c6956c82d"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1VertexBuffer.html#ad100a5f578a91c49a9009e3c6956c82d">update</a> (const <a class="el" href="classsf_1_1Vertex.html">Vertex</a> *vertices)</td></tr>
<tr class="memdesc:ad100a5f578a91c49a9009e3c6956c82d"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the whole buffer from an array of vertices. <a href="#ad100a5f578a91c49a9009e3c6956c82d">More...</a><br /></td></tr>
<tr class="memdesc:ad100a5f578a91c49a9009e3c6956c82d"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the whole buffer from an array of vertices. <a href="#ad100a5f578a91c49a9009e3c6956c82d">More...</a><br /></td></tr>
<tr class="separator:ad100a5f578a91c49a9009e3c6956c82d"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ae6c8649a64861507010d21e77fbd53fa"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1VertexBuffer.html#ae6c8649a64861507010d21e77fbd53fa">update</a> (const <a class="el" href="classsf_1_1Vertex.html">Vertex</a> *vertices, std::size_t vertexCount, unsigned int offset)</td></tr>
<tr class="memdesc:ae6c8649a64861507010d21e77fbd53fa"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the buffer from an array of vertices. <a href="#ae6c8649a64861507010d21e77fbd53fa">More...</a><br /></td></tr>
<tr class="memdesc:ae6c8649a64861507010d21e77fbd53fa"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the buffer from an array of vertices. <a href="#ae6c8649a64861507010d21e77fbd53fa">More...</a><br /></td></tr>
<tr class="separator:ae6c8649a64861507010d21e77fbd53fa"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a41f8bbcf07f403e7fe29b1b905dc7544"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1VertexBuffer.html#a41f8bbcf07f403e7fe29b1b905dc7544">update</a> (const <a class="el" href="classsf_1_1VertexBuffer.html">VertexBuffer</a> &amp;vertexBuffer)</td></tr>
<tr class="memdesc:a41f8bbcf07f403e7fe29b1b905dc7544"><td class="mdescLeft">&#160;</td><td class="mdescRight">Copy the contents of another buffer into this buffer. <a href="#a41f8bbcf07f403e7fe29b1b905dc7544">More...</a><br /></td></tr>
@ -664,7 +664,7 @@ Static Private Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update the whole buffer from an array of vertices. </p>
<p>ServerUpdate the whole buffer from an array of vertices. </p>
<p>The <em>vertex</em> array is assumed to have the same size as the <em>created</em> buffer.</p>
<p>No additional check is performed on the size of the vertex array, passing invalid arguments will lead to undefined behavior.</p>
<p>This function does nothing if <em>vertices</em> is null or if the buffer was not previously created.</p>
@ -710,7 +710,7 @@ Static Private Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update a part of the buffer from an array of vertices. </p>
<p>ServerUpdate a part of the buffer from an array of vertices. </p>
<p><code>offset</code> is specified as the number of vertices to skip from the beginning of the buffer.</p>
<p>If <code>offset</code> is 0 and <code>vertexCount</code> is equal to the size of the currently created buffer, its whole contents are replaced.</p>
<p>If <code>offset</code> is 0 and <code>vertexCount</code> is greater than the size of the currently created buffer, a new buffer is created containing the vertex data.</p>

View File

@ -51,7 +51,7 @@
<dt><a class="anchor" id="_deprecated000004"></a>Member <a class="el" href="classsf_1_1RenderTexture.html#a0e945c4ce7703591c7f240b169744603">sf::RenderTexture::create</a> (unsigned int width, unsigned int height, bool depthBuffer)</dt>
<dd>Use <a class="el" href="classsf_1_1RenderTexture.html#a49b7b723a80f89bc409a942364351dc3" title="Create the render-texture. ">create(unsigned int, unsigned int, const ContextSettings&amp;)</a> instead. </dd>
<dt><a class="anchor" id="_deprecated000005"></a>Member <a class="el" href="classsf_1_1RenderWindow.html#a5a784b8a09bf4a8bc97ef9e0a8957c35">sf::RenderWindow::capture</a> () const</dt>
<dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="Update the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd>
<dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="ServerUpdate the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd>
<dt><a class="anchor" id="_deprecated000012"></a>Member <a class="el" href="classsf_1_1Shader.html#aa8618119ed4399df3fd33e78ee96b4fc">sf::Shader::setParameter</a> (const std::string &amp;name, const <a class="el" href="classsf_1_1Color.html" title="Utility class for manipulating RGBA colors. ">Color</a> &amp;color)</dt>
<dd>Use <a class="el" href="classsf_1_1Shader.html#abc1aee8343800680fd62e1f3d43c24bf" title="Specify value for vec4 uniform. ">setUniform(const std::string&amp;, const Glsl::Vec4&amp;)</a> instead. </dd>
<dt><a class="anchor" id="_deprecated000015"></a>Member <a class="el" href="classsf_1_1Shader.html#af06b4cba0bab915fa01032b063909044">sf::Shader::setParameter</a> (const std::string &amp;name, <a class="el" href="structsf_1_1Shader_1_1CurrentTextureType.html" title="Special type that can be passed to setUniform(), and that represents the texture of the object being ...">CurrentTextureType</a>)</dt>

File diff suppressed because one or more lines are too long

View File

@ -106,7 +106,7 @@ Static Public Member Functions</h2></td></tr>
<tr class="memdesc:aa917c9435330e6e0368d3893672d1b74"><td class="mdescLeft">&#160;</td><td class="mdescRight">Get the joystick information. <a href="#aa917c9435330e6e0368d3893672d1b74">More...</a><br /></td></tr>
<tr class="separator:aa917c9435330e6e0368d3893672d1b74"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48">update</a> ()</td></tr>
<tr class="memdesc:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the states of all joysticks. <a href="#ab85fa9175b4edd3e5a07ee3cde0b0f48">More...</a><br /></td></tr>
<tr class="memdesc:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the states of all joysticks. <a href="#ab85fa9175b4edd3e5a07ee3cde0b0f48">More...</a><br /></td></tr>
<tr class="separator:ab85fa9175b4edd3e5a07ee3cde0b0f48"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
@ -119,7 +119,7 @@ Static Public Member Functions</h2></td></tr>
<li>32 buttons per joystick (<a class="el" href="classsf_1_1Joystick.html#aee00dd432eacd8369d279b47c3ab4cc5a2f1b8a0a59f2c12a4775c0e1e69e1816" title="Maximum number of supported buttons. ">sf::Joystick::ButtonCount</a>) </li>
<li>8 axes per joystick (<a class="el" href="classsf_1_1Joystick.html#aee00dd432eacd8369d279b47c3ab4cc5accf3e487c9f6ee2f384351323626a42c" title="Maximum number of supported axes. ">sf::Joystick::AxisCount</a>)</li>
</ul>
<p>Unlike the keyboard or mouse, the state of joysticks is sometimes not directly available (depending on the OS), therefore an <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="Update the states of all joysticks. ">update()</a> function must be called in order to update the current state of joysticks. When you have a window with event handling, this is done automatically, you don't need to call anything. But if you have no window, or if you want to check joysticks state before creating one, you must call <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="Update the states of all joysticks. ">sf::Joystick::update</a> explicitly.</p>
<p>Unlike the keyboard or mouse, the state of joysticks is sometimes not directly available (depending on the OS), therefore an <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="ServerUpdate the states of all joysticks. ">update()</a> function must be called in order to update the current state of joysticks. When you have a window with event handling, this is done automatically, you don't need to call anything. But if you have no window, or if you want to check joysticks state before creating one, you must call <a class="el" href="classsf_1_1Joystick.html#ab85fa9175b4edd3e5a07ee3cde0b0f48" title="ServerUpdate the states of all joysticks. ">sf::Joystick::update</a> explicitly.</p>
<p>Usage example: </p><div class="fragment"><div class="line"><span class="comment">// Is joystick #0 connected?</span></div><div class="line"><span class="keywordtype">bool</span> connected = <a class="code" href="classsf_1_1Joystick.html#ac7d4e1923e9f9420174f26703ea63d6c">sf::Joystick::isConnected</a>(0);</div><div class="line"></div><div class="line"><span class="comment">// How many buttons does joystick #0 support?</span></div><div class="line"><span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> buttons = <a class="code" href="classsf_1_1Joystick.html#a4de9f445c6582bfe9f0873f695682885">sf::Joystick::getButtonCount</a>(0);</div><div class="line"></div><div class="line"><span class="comment">// Does joystick #0 define a X axis?</span></div><div class="line"><span class="keywordtype">bool</span> hasX = <a class="code" href="classsf_1_1Joystick.html#a268e8f2a11ae6af4a47c727cb4ab4d95">sf::Joystick::hasAxis</a>(0, <a class="code" href="classsf_1_1Joystick.html#a48db337092c2e263774f94de6d50baa7a95dc8b9bf7b0a2157fc67891c54c401e">sf::Joystick::X</a>);</div><div class="line"></div><div class="line"><span class="comment">// Is button #2 pressed on joystick #0?</span></div><div class="line"><span class="keywordtype">bool</span> pressed = <a class="code" href="classsf_1_1Joystick.html#ae0d97a4b84268cbe6a7078e1b2717835">sf::Joystick::isButtonPressed</a>(0, 2);</div><div class="line"></div><div class="line"><span class="comment">// What&#39;s the current position of the Y axis on joystick #0?</span></div><div class="line"><span class="keywordtype">float</span> position = <a class="code" href="classsf_1_1Joystick.html#aea4930193331df1851b709f3060ba58b">sf::Joystick::getAxisPosition</a>(0, <a class="code" href="classsf_1_1Joystick.html#a48db337092c2e263774f94de6d50baa7a51ef1455f7511ad4a78ba241d66593ce">sf::Joystick::Y</a>);</div></div><!-- fragment --><dl class="section see"><dt>See also</dt><dd><a class="el" href="classsf_1_1Keyboard.html" title="Give access to the real-time state of the keyboard. ">sf::Keyboard</a>, <a class="el" href="classsf_1_1Mouse.html" title="Give access to the real-time state of the mouse. ">sf::Mouse</a> </dd></dl>
<p class="definition">Definition at line <a class="el" href="Joystick_8hpp_source.html#l00041">41</a> of file <a class="el" href="Joystick_8hpp_source.html">Joystick.hpp</a>.</p>
@ -457,7 +457,7 @@ Static Public Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update the states of all joysticks. </p>
<p>ServerUpdate the states of all joysticks. </p>
<p>This function is used internally by SFML, so you normally don't have to call it explicitly. However, you may need to call it if you have no window yet (or no window at all): in this case the joystick states are not updated automatically. </p>
</div>

View File

@ -99,7 +99,7 @@ Public Member Functions</h2></td></tr>
<tr class="memdesc:a5da95ecdbce615a80bb78399012508cf"><td class="mdescLeft">&#160;</td><td class="mdescRight">Activate or deactivate the render-texture for rendering. <a href="#a5da95ecdbce615a80bb78399012508cf">More...</a><br /></td></tr>
<tr class="separator:a5da95ecdbce615a80bb78399012508cf"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:af92886d5faef3916caff9fa9ab32c555"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1RenderTexture.html#af92886d5faef3916caff9fa9ab32c555">display</a> ()</td></tr>
<tr class="memdesc:af92886d5faef3916caff9fa9ab32c555"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the contents of the target texture. <a href="#af92886d5faef3916caff9fa9ab32c555">More...</a><br /></td></tr>
<tr class="memdesc:af92886d5faef3916caff9fa9ab32c555"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the contents of the target texture. <a href="#af92886d5faef3916caff9fa9ab32c555">More...</a><br /></td></tr>
<tr class="separator:af92886d5faef3916caff9fa9ab32c555"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a6685315b5c4c25a5dcb75b4280b381ba"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classsf_1_1Vector2.html">Vector2u</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1RenderTexture.html#a6685315b5c4c25a5dcb75b4280b381ba">getSize</a> () const</td></tr>
<tr class="memdesc:a6685315b5c4c25a5dcb75b4280b381ba"><td class="mdescLeft">&#160;</td><td class="mdescRight">Return the size of the rendering region of the texture. <a href="#a6685315b5c4c25a5dcb75b4280b381ba">More...</a><br /></td></tr>
@ -376,7 +376,7 @@ Protected Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update the contents of the target texture. </p>
<p>ServerUpdate the contents of the target texture. </p>
<p>This function updates the target texture with what has been drawn so far. Like for windows, calling this function is mandatory at the end of rendering. Not calling it may leave the texture in an undefined state. </p>
</div>

View File

@ -403,7 +403,7 @@ Protected Member Functions</h2></td></tr>
</div><div class="memdoc">
<p>Copy the current contents of the window to an image. </p>
<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000005">Deprecated:</a></b></dt><dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="Update the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd></dl>
<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000005">Deprecated:</a></b></dt><dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="ServerUpdate the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd></dl>
<div class="fragment"><div class="line"><a class="code" href="classsf_1_1Vector2.html">sf::Vector2u</a> windowSize = window.<a class="code" href="classsf_1_1Window.html#a3969926741cbe83d7f9eeaf5333d4e71">getSize</a>();</div><div class="line"><a class="code" href="classsf_1_1Texture.html">sf::Texture</a> texture;</div><div class="line">texture.<a class="code" href="classsf_1_1Texture.html#a89b4c7d204acf1033c3a1b6e0a3ad0a3">create</a>(windowSize.<a class="code" href="classsf_1_1Vector2.html#a1e6ad77fa155f3753bfb92699bd28141">x</a>, windowSize.<a class="code" href="classsf_1_1Vector2.html#a420f2481b015f4eb929c75f2af564299">y</a>);</div><div class="line">texture.<a class="code" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963">update</a>(window);</div><div class="line"><a class="code" href="classsf_1_1Image.html">sf::Image</a> screenshot = texture.<a class="code" href="classsf_1_1Texture.html#a77e18a70de2e525ac5e4a7cd95f614b9">copyToImage</a>();</div></div><!-- fragment --><p>This is a slow operation, whose main purpose is to make screenshots of the application. If you want to update an image with the contents of the window and then use it for drawing, you should rather use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its update(Window&amp;) function. You can also draw things directly to a texture with the <a class="el" href="classsf_1_1RenderTexture.html" title="Target for off-screen 2D rendering into a texture. ">sf::RenderTexture</a> class.</p>
<dl class="section return"><dt>Returns</dt><dd><a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">Image</a> containing the captured contents </dd></dl>

View File

@ -108,28 +108,28 @@ Public Member Functions</h2></td></tr>
<tr class="memdesc:a77e18a70de2e525ac5e4a7cd95f614b9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Copy the texture pixels to an image. <a href="#a77e18a70de2e525ac5e4a7cd95f614b9">More...</a><br /></td></tr>
<tr class="separator:a77e18a70de2e525ac5e4a7cd95f614b9"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ae4eab5c6781316840b0c50ad08370963"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963">update</a> (const Uint8 *pixels)</td></tr>
<tr class="memdesc:ae4eab5c6781316840b0c50ad08370963"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the whole texture from an array of pixels. <a href="#ae4eab5c6781316840b0c50ad08370963">More...</a><br /></td></tr>
<tr class="memdesc:ae4eab5c6781316840b0c50ad08370963"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the whole texture from an array of pixels. <a href="#ae4eab5c6781316840b0c50ad08370963">More...</a><br /></td></tr>
<tr class="separator:ae4eab5c6781316840b0c50ad08370963"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a1352d8e16c2aeb4df586ed65dd2c36b9">update</a> (const Uint8 *pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the texture from an array of pixels. <a href="#a1352d8e16c2aeb4df586ed65dd2c36b9">More...</a><br /></td></tr>
<tr class="memdesc:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the texture from an array of pixels. <a href="#a1352d8e16c2aeb4df586ed65dd2c36b9">More...</a><br /></td></tr>
<tr class="separator:a1352d8e16c2aeb4df586ed65dd2c36b9"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:af9885ca00b74950d60feea28132d9691"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#af9885ca00b74950d60feea28132d9691">update</a> (const <a class="el" href="classsf_1_1Texture.html">Texture</a> &amp;texture)</td></tr>
<tr class="memdesc:af9885ca00b74950d60feea28132d9691"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of this texture from another texture. <a href="#af9885ca00b74950d60feea28132d9691">More...</a><br /></td></tr>
<tr class="memdesc:af9885ca00b74950d60feea28132d9691"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of this texture from another texture. <a href="#af9885ca00b74950d60feea28132d9691">More...</a><br /></td></tr>
<tr class="separator:af9885ca00b74950d60feea28132d9691"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a89beb474da1da84b5e38c9fc0b441fe4"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a89beb474da1da84b5e38c9fc0b441fe4">update</a> (const <a class="el" href="classsf_1_1Texture.html">Texture</a> &amp;texture, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a89beb474da1da84b5e38c9fc0b441fe4"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of this texture from another texture. <a href="#a89beb474da1da84b5e38c9fc0b441fe4">More...</a><br /></td></tr>
<tr class="memdesc:a89beb474da1da84b5e38c9fc0b441fe4"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of this texture from another texture. <a href="#a89beb474da1da84b5e38c9fc0b441fe4">More...</a><br /></td></tr>
<tr class="separator:a89beb474da1da84b5e38c9fc0b441fe4"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a037cdf171af0fb392d07626a44a4ea17"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a037cdf171af0fb392d07626a44a4ea17">update</a> (const <a class="el" href="classsf_1_1Image.html">Image</a> &amp;image)</td></tr>
<tr class="memdesc:a037cdf171af0fb392d07626a44a4ea17"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the texture from an image. <a href="#a037cdf171af0fb392d07626a44a4ea17">More...</a><br /></td></tr>
<tr class="memdesc:a037cdf171af0fb392d07626a44a4ea17"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the texture from an image. <a href="#a037cdf171af0fb392d07626a44a4ea17">More...</a><br /></td></tr>
<tr class="separator:a037cdf171af0fb392d07626a44a4ea17"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a87f916490b757fe900798eedf3abf3ba"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a87f916490b757fe900798eedf3abf3ba">update</a> (const <a class="el" href="classsf_1_1Image.html">Image</a> &amp;image, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a87f916490b757fe900798eedf3abf3ba"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the texture from an image. <a href="#a87f916490b757fe900798eedf3abf3ba">More...</a><br /></td></tr>
<tr class="memdesc:a87f916490b757fe900798eedf3abf3ba"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the texture from an image. <a href="#a87f916490b757fe900798eedf3abf3ba">More...</a><br /></td></tr>
<tr class="separator:a87f916490b757fe900798eedf3abf3ba"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5">update</a> (const <a class="el" href="classsf_1_1Window.html">Window</a> &amp;window)</td></tr>
<tr class="memdesc:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the texture from the contents of a window. <a href="#ad3cceef238f7d5d2108a98dd38c17fc5">More...</a><br /></td></tr>
<tr class="memdesc:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the texture from the contents of a window. <a href="#ad3cceef238f7d5d2108a98dd38c17fc5">More...</a><br /></td></tr>
<tr class="separator:ad3cceef238f7d5d2108a98dd38c17fc5"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a154f246eb8059b602076009ab1cfd175"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a154f246eb8059b602076009ab1cfd175">update</a> (const <a class="el" href="classsf_1_1Window.html">Window</a> &amp;window, unsigned int x, unsigned int y)</td></tr>
<tr class="memdesc:a154f246eb8059b602076009ab1cfd175"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the texture from the contents of a window. <a href="#a154f246eb8059b602076009ab1cfd175">More...</a><br /></td></tr>
<tr class="memdesc:a154f246eb8059b602076009ab1cfd175"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the texture from the contents of a window. <a href="#a154f246eb8059b602076009ab1cfd175">More...</a><br /></td></tr>
<tr class="separator:a154f246eb8059b602076009ab1cfd175"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a0c3bd6825b9a99714f10d44179d74324"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1Texture.html#a0c3bd6825b9a99714f10d44179d74324">setSmooth</a> (bool smooth)</td></tr>
<tr class="memdesc:a0c3bd6825b9a99714f10d44179d74324"><td class="mdescLeft">&#160;</td><td class="mdescRight">Enable or disable the smooth filter. <a href="#a0c3bd6825b9a99714f10d44179d74324">More...</a><br /></td></tr>
@ -193,7 +193,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
<div class="textblock"><p><a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">Image</a> living on the graphics card that can be used for drawing. </p>
<p><a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> stores pixels that can be drawn, with a sprite for example.</p>
<p>A texture lives in the graphics card memory, therefore it is very fast to draw a texture to a render target, or copy a render target to a texture (the graphics card can access both directly).</p>
<p>Being stored in the graphics card memory has some drawbacks. A texture cannot be manipulated as freely as a <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, you need to prepare the pixels first and then upload them to the texture in a single operation (see <a class="el" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963" title="Update the whole texture from an array of pixels. ">Texture::update</a>).</p>
<p>Being stored in the graphics card memory has some drawbacks. A texture cannot be manipulated as freely as a <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, you need to prepare the pixels first and then upload them to the texture in a single operation (see <a class="el" href="classsf_1_1Texture.html#ae4eab5c6781316840b0c50ad08370963" title="ServerUpdate the whole texture from an array of pixels. ">Texture::update</a>).</p>
<p><a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> makes it easy to convert from/to <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, but keep in mind that these calls require transfers between the graphics card and the central memory, therefore they are slow operations.</p>
<p>A texture can be loaded from an image, but also directly from a file/memory/stream. The necessary shortcuts are defined so that you don't need an image first for the most common cases. However, if you want to perform some modifications on the pixels before creating the final texture, you can load your file to a <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a>, do whatever you need with the pixels, and then call <a class="el" href="classsf_1_1Texture.html#abec4567ad9856a3596dc74803f26fba2" title="Load the texture from an image. ">Texture::loadFromImage</a>.</p>
<p>Since they live in the graphics card memory, the pixels of a texture cannot be accessed without a slow copy first. And they cannot be accessed individually. Therefore, if you need to read the texture's pixels (like for pixel-perfect collisions), it is recommended to store the collision information separately, for example in an array of booleans.</p>
@ -886,7 +886,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update the whole texture from an array of pixels. </p>
<p>ServerUpdate the whole texture from an array of pixels. </p>
<p>The <em>pixel</em> array is assumed to have the same size as the <em>area</em> rectangle, and to contain 32-bits RGBA pixels.</p>
<p>No additional check is performed on the size of the pixel array, passing invalid arguments will lead to an undefined behavior.</p>
<p>This function does nothing if <em>pixels</em> is null or if the texture was not previously created.</p>
@ -943,7 +943,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of the texture from an array of pixels. </p>
<p>ServerUpdate a part of the texture from an array of pixels. </p>
<p>The size of the <em>pixel</em> array must match the <em>width</em> and <em>height</em> arguments, and it must contain 32-bits RGBA pixels.</p>
<p>No additional check is performed on the size of the pixel array or the bounds of the area to update, passing invalid arguments will lead to an undefined behavior.</p>
<p>This function does nothing if <em>pixels</em> is null or if the texture was not previously created.</p>
@ -976,7 +976,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of this texture from another texture. </p>
<p>ServerUpdate a part of this texture from another texture. </p>
<p>Although the source texture can be smaller than this texture, this function is usually used for updating the whole texture. The other overload, which has (x, y) additional arguments, is more convenient for updating a sub-area of this texture.</p>
<p>No additional check is performed on the size of the passed texture, passing a texture bigger than this texture will lead to an undefined behavior.</p>
<p>This function does nothing if either texture was not previously created.</p>
@ -1021,7 +1021,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of this texture from another texture. </p>
<p>ServerUpdate a part of this texture from another texture. </p>
<p>No additional check is performed on the size of the texture, passing an invalid combination of texture size and offset will lead to an undefined behavior.</p>
<p>This function does nothing if either texture was not previously created.</p>
<dl class="params"><dt>Parameters</dt><dd>
@ -1051,7 +1051,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update the texture from an image. </p>
<p>ServerUpdate the texture from an image. </p>
<p>Although the source image can be smaller than the texture, this function is usually used for updating the whole texture. The other overload, which has (x, y) additional arguments, is more convenient for updating a sub-area of the texture.</p>
<p>No additional check is performed on the size of the image, passing an image bigger than the texture will lead to an undefined behavior.</p>
<p>This function does nothing if the texture was not previously created.</p>
@ -1096,7 +1096,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of the texture from an image. </p>
<p>ServerUpdate a part of the texture from an image. </p>
<p>No additional check is performed on the size of the image, passing an invalid combination of image size and offset will lead to an undefined behavior.</p>
<p>This function does nothing if the texture was not previously created.</p>
<dl class="params"><dt>Parameters</dt><dd>
@ -1126,7 +1126,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update the texture from the contents of a window. </p>
<p>ServerUpdate the texture from the contents of a window. </p>
<p>Although the source window can be smaller than the texture, this function is usually used for updating the whole texture. The other overload, which has (x, y) additional arguments, is more convenient for updating a sub-area of the texture.</p>
<p>No additional check is performed on the size of the window, passing a window bigger than the texture will lead to an undefined behavior.</p>
<p>This function does nothing if either the texture or the window was not previously created.</p>
@ -1171,7 +1171,7 @@ class&#160;</td><td class="memItemRight" valign="bottom"><b>RenderTarget</b></td
</table>
</div><div class="memdoc">
<p>Update a part of the texture from the contents of a window. </p>
<p>ServerUpdate a part of the texture from the contents of a window. </p>
<p>No additional check is performed on the size of the window, passing an invalid combination of window size and offset will lead to an undefined behavior.</p>
<p>This function does nothing if either the texture or the window was not previously created.</p>
<dl class="params"><dt>Parameters</dt><dd>

View File

@ -103,10 +103,10 @@ Public Member Functions</h2></td></tr>
<tr class="memdesc:a6c534536ed186a2ad65e75484c8abafe"><td class="mdescLeft">&#160;</td><td class="mdescRight">Return the vertex count. <a href="#a6c534536ed186a2ad65e75484c8abafe">More...</a><br /></td></tr>
<tr class="separator:a6c534536ed186a2ad65e75484c8abafe"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ad100a5f578a91c49a9009e3c6956c82d"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1VertexBuffer.html#ad100a5f578a91c49a9009e3c6956c82d">update</a> (const <a class="el" href="classsf_1_1Vertex.html">Vertex</a> *vertices)</td></tr>
<tr class="memdesc:ad100a5f578a91c49a9009e3c6956c82d"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update the whole buffer from an array of vertices. <a href="#ad100a5f578a91c49a9009e3c6956c82d">More...</a><br /></td></tr>
<tr class="memdesc:ad100a5f578a91c49a9009e3c6956c82d"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate the whole buffer from an array of vertices. <a href="#ad100a5f578a91c49a9009e3c6956c82d">More...</a><br /></td></tr>
<tr class="separator:ad100a5f578a91c49a9009e3c6956c82d"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ae6c8649a64861507010d21e77fbd53fa"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1VertexBuffer.html#ae6c8649a64861507010d21e77fbd53fa">update</a> (const <a class="el" href="classsf_1_1Vertex.html">Vertex</a> *vertices, std::size_t vertexCount, unsigned int offset)</td></tr>
<tr class="memdesc:ae6c8649a64861507010d21e77fbd53fa"><td class="mdescLeft">&#160;</td><td class="mdescRight">Update a part of the buffer from an array of vertices. <a href="#ae6c8649a64861507010d21e77fbd53fa">More...</a><br /></td></tr>
<tr class="memdesc:ae6c8649a64861507010d21e77fbd53fa"><td class="mdescLeft">&#160;</td><td class="mdescRight">ServerUpdate a part of the buffer from an array of vertices. <a href="#ae6c8649a64861507010d21e77fbd53fa">More...</a><br /></td></tr>
<tr class="separator:ae6c8649a64861507010d21e77fbd53fa"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a41f8bbcf07f403e7fe29b1b905dc7544"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classsf_1_1VertexBuffer.html#a41f8bbcf07f403e7fe29b1b905dc7544">update</a> (const <a class="el" href="classsf_1_1VertexBuffer.html">VertexBuffer</a> &amp;vertexBuffer)</td></tr>
<tr class="memdesc:a41f8bbcf07f403e7fe29b1b905dc7544"><td class="mdescLeft">&#160;</td><td class="mdescRight">Copy the contents of another buffer into this buffer. <a href="#a41f8bbcf07f403e7fe29b1b905dc7544">More...</a><br /></td></tr>
@ -664,7 +664,7 @@ Static Private Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update the whole buffer from an array of vertices. </p>
<p>ServerUpdate the whole buffer from an array of vertices. </p>
<p>The <em>vertex</em> array is assumed to have the same size as the <em>created</em> buffer.</p>
<p>No additional check is performed on the size of the vertex array, passing invalid arguments will lead to undefined behavior.</p>
<p>This function does nothing if <em>vertices</em> is null or if the buffer was not previously created.</p>
@ -710,7 +710,7 @@ Static Private Member Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Update a part of the buffer from an array of vertices. </p>
<p>ServerUpdate a part of the buffer from an array of vertices. </p>
<p><code>offset</code> is specified as the number of vertices to skip from the beginning of the buffer.</p>
<p>If <code>offset</code> is 0 and <code>vertexCount</code> is equal to the size of the currently created buffer, its whole contents are replaced.</p>
<p>If <code>offset</code> is 0 and <code>vertexCount</code> is greater than the size of the currently created buffer, a new buffer is created containing the vertex data.</p>

View File

@ -51,7 +51,7 @@
<dt><a class="anchor" id="_deprecated000004"></a>Member <a class="el" href="classsf_1_1RenderTexture.html#a0e945c4ce7703591c7f240b169744603">sf::RenderTexture::create</a> (unsigned int width, unsigned int height, bool depthBuffer)</dt>
<dd>Use <a class="el" href="classsf_1_1RenderTexture.html#a49b7b723a80f89bc409a942364351dc3" title="Create the render-texture. ">create(unsigned int, unsigned int, const ContextSettings&amp;)</a> instead. </dd>
<dt><a class="anchor" id="_deprecated000005"></a>Member <a class="el" href="classsf_1_1RenderWindow.html#a5a784b8a09bf4a8bc97ef9e0a8957c35">sf::RenderWindow::capture</a> () const</dt>
<dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="Update the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd>
<dd>Use a <a class="el" href="classsf_1_1Texture.html" title="Image living on the graphics card that can be used for drawing. ">sf::Texture</a> and its <a class="el" href="classsf_1_1Texture.html#ad3cceef238f7d5d2108a98dd38c17fc5" title="ServerUpdate the texture from the contents of a window. ">sf::Texture::update(const Window&amp;)</a> function and copy its contents into an <a class="el" href="classsf_1_1Image.html" title="Class for loading, manipulating and saving images. ">sf::Image</a> instead. </dd>
<dt><a class="anchor" id="_deprecated000012"></a>Member <a class="el" href="classsf_1_1Shader.html#aa8618119ed4399df3fd33e78ee96b4fc">sf::Shader::setParameter</a> (const std::string &amp;name, const <a class="el" href="classsf_1_1Color.html" title="Utility class for manipulating RGBA colors. ">Color</a> &amp;color)</dt>
<dd>Use <a class="el" href="classsf_1_1Shader.html#abc1aee8343800680fd62e1f3d43c24bf" title="Specify value for vec4 uniform. ">setUniform(const std::string&amp;, const Glsl::Vec4&amp;)</a> instead. </dd>
<dt><a class="anchor" id="_deprecated000015"></a>Member <a class="el" href="classsf_1_1Shader.html#af06b4cba0bab915fa01032b063909044">sf::Shader::setParameter</a> (const std::string &amp;name, <a class="el" href="structsf_1_1Shader_1_1CurrentTextureType.html" title="Special type that can be passed to setUniform(), and that represents the texture of the object being ...">CurrentTextureType</a>)</dt>

File diff suppressed because one or more lines are too long

View File

@ -4,13 +4,14 @@
#include "Server.h"
#include "engine/utils/Log.h"
#include "ShooterMsgType.h"
void Server::broadcast() {
sf::Packet updatePacket;
updatePacket << MsgType::Update;
updatePacket << MsgType::ServerUpdate;
for (auto& [playerId, player] : _players) {
updatePacket << playerId << player->position().x() << player->position().y() << player->position().z() << player->health() << player->angle().y() << player->headAngle() << player->playerName();
updatePacket << playerId << player->position().x() << player->position().y() << player->position().z() << player->health() << player->angle().y() << player->headAngle() << player->playerNickName();
}
for (auto& player : _players) {
@ -26,9 +27,8 @@ void Server::processConnect(sf::Uint16 targetId) {
// players init
extraPacket << MsgType::NewClient << targetId;
sendPacket1 << MsgType::Init << targetId;
_players.insert({ targetId, std::make_shared<Player>() });
for (const auto& [playerId, player] : _players)
{
_players.insert({ targetId, std::make_shared<Player>(ObjectNameTag("Player_" + std::to_string(targetId))) });
for (const auto& [playerId, player] : _players) {
sendPacket1 << playerId << player->position().x() << player->position().y() << player->position().z() << player->health() << player->kills() << player->deaths();
if (playerId != targetId)
_socket.sendRely(extraPacket, playerId);
@ -36,11 +36,12 @@ void Server::processConnect(sf::Uint16 targetId) {
_socket.sendRely(sendPacket1, targetId);
// bonuses init
sendPacket2 << MsgType::InitBonuses;
sendPacket2 << MsgType::Custom << ShooterMsgType::InitBonuses;
for(auto& [bonusName, bonusInfo] : _bonuses) {
if(bonusInfo->onTheMap)
if(bonusInfo->onTheMap) {
sendPacket2 << bonusName << bonusInfo->position.x() << bonusInfo->position.y() << bonusInfo->position.z();
}
}
_socket.sendRely(sendPacket2, targetId);
}
@ -53,7 +54,7 @@ void Server::processClientUpdate(sf::Uint16 senderId, sf::Packet& packet) {
_players.at(senderId)->translateToPoint(Vec3D{ buf[0], buf[1], buf[2] });
_players.at(senderId)->rotateToAngle(Vec3D{0, buf[3], 0});
_players.at(senderId)->setHeadAngle(buf[4]);
_players.at(senderId)->setPlayerName(playerName);
_players.at(senderId)->setPlayerNickName(playerName);
}
void Server::processDisconnect(sf::Uint16 senderId) {
@ -61,12 +62,13 @@ void Server::processDisconnect(sf::Uint16 senderId) {
sendPacket << MsgType::Disconnect << senderId;
_players.erase(senderId);
for (const auto& player : _players)
for (const auto& player : _players) {
_socket.sendRely(sendPacket, player.first);
}
}
void Server::processCustomPacket(MsgType type, sf::Packet& packet, sf::Uint16 senderId) {
void Server::processCustomPacket(sf::Packet& packet, sf::Uint16 senderId) {
sf::Packet sendPacket;
double dbuff[10];
sf::Uint16 targetId;
@ -74,34 +76,37 @@ void Server::processCustomPacket(MsgType type, sf::Packet& packet, sf::Uint16 se
std::string tmp;
double newHealth;
ShooterMsgType type;
packet >> type;
switch (type) {
case MsgType::Damage:
case ShooterMsgType::Damage:
packet >> targetId >> damage;
newHealth = _players[targetId]->health() - damage;
if(newHealth > 0) {
_players[targetId]->setHealth(newHealth);
}
else {
} else {
_players[targetId]->setFullHealth();
_players[targetId]->setFullAbility();
_players[targetId]->addDeath();
_players[senderId]->addKill();
sendPacket << MsgType::Kill << targetId << senderId;
sendPacket << MsgType::Custom << ShooterMsgType::Kill << targetId << senderId;
for (auto& player : _players)
_socket.sendRely(sendPacket, player.first);
}
break;
case MsgType::FireTrace:
case ShooterMsgType::FireTrace:
packet >> dbuff[0] >> dbuff[1] >> dbuff[2] >> dbuff[3] >> dbuff[4] >> dbuff[5];
sendPacket << MsgType::FireTrace << dbuff[0] << dbuff[1] << dbuff[2] << dbuff[3] << dbuff[4] << dbuff[5];
sendPacket << MsgType::Custom << ShooterMsgType::FireTrace << dbuff[0] << dbuff[1] << dbuff[2] << dbuff[3] << dbuff[4] << dbuff[5];
for (auto& player : _players) {
if(player.first != senderId)
if(player.first != senderId) {
_socket.send(sendPacket, player.first);
}
}
break;
case MsgType::RemoveBonus:
case ShooterMsgType::RemoveBonus:
packet >> tmp;
if(tmp.find("Bonus_hill") != std::string::npos) {
@ -113,23 +118,26 @@ void Server::processCustomPacket(MsgType type, sf::Packet& packet, sf::Uint16 se
_bonuses[tmp] = std::make_shared<BonusInfo>(BonusInfo{_bonuses[tmp]->position, Time::time(), false});
sendPacket << MsgType::RemoveBonus << tmp;
sendPacket << MsgType::Custom << ShooterMsgType::RemoveBonus << tmp;
for (auto& player : _players) {
if(player.first != senderId)
if(player.first != senderId) {
_socket.sendRely(sendPacket, player.first);
}
}
break;
case MsgType::ChangeWeapon:
case ShooterMsgType::ChangeWeapon:
packet >> tmp;
sendPacket << MsgType::ChangeWeapon << senderId << tmp;
sendPacket << MsgType::Custom << ShooterMsgType::ChangeWeapon << senderId << tmp;
for (auto& player : _players) {
if(player.first != senderId)
if(player.first != senderId) {
_socket.sendRely(sendPacket, player.first);
}
}
break;
default:
Log::log("Server::processCustomPacket: unknown message type " + std::to_string(static_cast<int>(type)));
return;
}
}
@ -166,9 +174,10 @@ void Server::updateInfo() {
for(auto& [bonusName, bonusInfo] : _bonuses) {
if(!bonusInfo->onTheMap && std::abs(Time::time() - bonusInfo->lastTake) > ShooterConsts::BONUS_RECHARGE_TIME) {
sf::Packet sendPacket;
sendPacket << MsgType::AddBonus << bonusName << bonusInfo->position.x() << bonusInfo->position.y() << bonusInfo->position.z();
for (const auto& player : _players)
sendPacket << MsgType::Custom << ShooterMsgType::AddBonus << bonusName << bonusInfo->position.x() << bonusInfo->position.y() << bonusInfo->position.z();
for (const auto& player : _players) {
_socket.sendRely(sendPacket, player.first);
}
bonusInfo = std::make_shared<BonusInfo>(BonusInfo{bonusInfo->position, bonusInfo->lastTake, true});
}
}

View File

@ -7,7 +7,6 @@
#include "engine/network/ServerUDP.h"
#include "Player.h"
#include "Bonus.h"
struct BonusInfo final {
const Vec3D position{};
@ -28,7 +27,7 @@ public:
void processClientUpdate(sf::Uint16 senderId, sf::Packet& packet) override;
void processDisconnect(sf::Uint16 senderId) override;
void processCustomPacket(MsgType type, sf::Packet& packet, sf::Uint16 senderId) override;
void processCustomPacket(sf::Packet& packet, sf::Uint16 senderId) override;
void processStop() override;

View File

@ -11,13 +11,13 @@
#include "engine/animation/Timeline.h"
#include "ShooterConsts.h"
#include "engine/SoundController.h"
#include "engine/animation/ATranslateToPoint.h"
using namespace std;
// Read server/client settings and start both.
// If client doesn't connect to the localhost - server doesn't start.
void Shooter::InitNetwork()
{
void Shooter::InitNetwork() {
std::string clientIp;
sf::Uint16 clientPort;
sf::Uint16 serverPort;
@ -58,7 +58,7 @@ void Shooter::InitNetwork()
}
client->connect(clientIp, clientPort);
player->setPlayerName(playerName);
player->setPlayerNickName(playerName);
// TODO: encapsulate call backs inside Client
client->setSpawnPlayerCallBack([this](sf::Uint16 id){ spawnPlayer(id); });
@ -74,11 +74,11 @@ void Shooter::start() {
setDebugText(false);
setUpdateWorld(false);
mouse->setMouseCursorVisible(true);
screen->setMouseCursorVisible(true);
world->loadMap(ShooterConsts::MAP_OBJ, Vec3D{5, 5, 5});
player = std::make_shared<Player>();
player = std::make_shared<Player>(ObjectNameTag("Player"));
player->scale(Vec3D(3, 1, 3));
playerController = std::make_shared<PlayerController>(player, keyboard, mouse);
@ -93,9 +93,9 @@ void Shooter::start() {
player->initWeapons();
camera->translateToPoint(player->position() + Vec3D{0, 1.8, 0});
player->attach(camera, ObjectNameTag("Camera"));
player->attach(camera);
world->addBody(player, ObjectNameTag("Player"));
world->addBody(player);
player->translate(Vec3D{0, 10, 0});
client = std::make_shared<Client>(player);
@ -104,24 +104,22 @@ void Shooter::start() {
// connecting to the server
InitNetwork();
// Waiting for connect and updating server if it's same window
while (client->isWorking() && !client->connected())
{
while (client->isWorking() && !client->connected()) {
client->update();
server->update();
Time::update();
}
// If connect fail - return to menu
if (!client->isWorking())
{
if (!client->isWorking()) {
inGame = false;
server->stop();
}
// windows init:
mainMenu.title("Main menu");
mainMenu.setTitle("Main menu");
mainMenu.setBackgroundTexture(ShooterConsts::MAIN_MENU_BACK, 1.1, 1.1, screen->width(), screen->height());
mainMenu.addButton(screen->width()/2, 200, 200, 20, [this] () { this->play(); SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND);}, "Server: " + client->ip().toString(), 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255});
mainMenu.addButton(screen->width()/2, 200, 200, 20, [this] () { this->play(); SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND);}, "Server: " + client->serverIp().toString(), 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255});
mainMenu.addButton(screen->width()/2, 350, 200, 20, [this] () { this->player->translateToPoint(Vec3D{0, 0, 0}); this->player->setVelocity({}); this->play(); SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND);}, "Respawn", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255});
mainMenu.addButton(screen->width()/2, 500, 200, 20, [this] () { client->disconnect(); server->stop(); this->exit();}, "Exit", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255});
@ -134,12 +132,13 @@ void Shooter::update() {
client->update();
// Check all input after this condition please
if (!screen->hasFocus())
if (!screen->hasFocus()) {
return;
}
if(keyboard->isKeyTapped(sf::Keyboard::Escape)) {
inGame = !inGame;
mouse->setMouseCursorVisible(!inGame);
screen->setMouseCursorVisible(!inGame);
}
if(inGame) {
@ -153,8 +152,9 @@ void Shooter::update() {
setUpdateWorld(inGame);
// background sounds and music control
if(SoundController::getStatus(SoundTag("background")) != sf::Sound::Status::Playing)
if(SoundController::getStatus(SoundTag("background")) != sf::Sound::Status::Playing) {
SoundController::playSound(SoundTag("background"), ShooterConsts::BACK_NOISE);
}
}
void Shooter::gui() {
@ -187,7 +187,7 @@ void Shooter::drawStatsTable() {
} );
for(auto& p : allPlayers) {
screen->drawText(std::to_string(i) + "\t" + p->playerName() + "\t" + std::to_string(p->kills()) + " / " + std::to_string(p->deaths()),
screen->drawText(std::to_string(i) + "\t" + p->playerNickName() + "\t" + std::to_string(p->kills()) + " / " + std::to_string(p->deaths()),
Vec2D{10, 15 + 35.0*i}, 25, sf::Color(0, 0, 0, 150));
i++;
}
@ -217,23 +217,21 @@ void Shooter::drawPlayerStats() {
screen->drawText(std::to_string((int)balance.first), Vec2D{150, static_cast<double>(screen->height() - 150)}, 100, sf::Color(0, 0, 0, 100));
screen->drawText(std::to_string((int)balance.second), Vec2D{50, static_cast<double>(screen->height() - 100)}, 50, sf::Color(0, 0, 0, 70));
//screen->drawText("KILLS: " + std::to_string(player->kills()) + " | " + "DEATHS: " + std::to_string(player->deaths()),
// Vec2D{10, 10},25, sf::Color(0, 0, 0, 100));
}
void Shooter::play() {
inGame = true;
mouse->setMouseCursorVisible(false);
screen->setMouseCursorVisible(false);
}
void Shooter::spawnPlayer(sf::Uint16 id) {
std::string name = "Enemy_" + std::to_string(id);
std::shared_ptr<Player> newPlayer = std::make_shared<Player>();
std::shared_ptr<Player> newPlayer = std::make_shared<Player>(ObjectNameTag(name));
newPlayer->setCollision(false);
client->addPlayer(id, newPlayer);
world->addBody(newPlayer, ObjectNameTag(name));
world->addBody(newPlayer);
newPlayer->setVisible(true);
newPlayer->setAcceleration(Vec3D{0, 0, 0});
@ -241,19 +239,19 @@ void Shooter::spawnPlayer(sf::Uint16 id) {
world->loadBody(ObjectNameTag(name + "_head"), ShooterConsts::CUBE_OBJ, Vec3D{0.7, 0.7, 0.7});
world->body(ObjectNameTag(name + "_head"))->translate(Vec3D{0, 2, 0});
world->body(ObjectNameTag(name + "_head"))->setCollider(false);
newPlayer->attach(world->body(ObjectNameTag(name + "_head")), ObjectNameTag("head"));
newPlayer->attach(world->body(ObjectNameTag(name + "_head")));
world->loadBody(ObjectNameTag(name + "_eye1"), ShooterConsts::CUBE_OBJ, Vec3D{0.2, 0.2, 0.05});
world->body(ObjectNameTag(name + "_eye1"))->translate(Vec3D{0.3, 2.1, 0.7});
world->body(ObjectNameTag(name + "_eye1"))->setCollider(false);
world->body(ObjectNameTag(name + "_eye1"))->setColor({147, 159, 255});
world->body(ObjectNameTag(name + "_head"))->attach(world->body(ObjectNameTag(name + "_eye1")), ObjectNameTag("eye1"));
world->body(ObjectNameTag(name + "_head"))->attach(world->body(ObjectNameTag(name + "_eye1")));
world->loadBody(ObjectNameTag(name + "_eye2"), ShooterConsts::CUBE_OBJ, Vec3D{0.2, 0.2, 0.05});
world->body(ObjectNameTag(name + "_eye2"))->translate(Vec3D{-0.3, 2.1, 0.7});
world->body(ObjectNameTag(name + "_eye2"))->setCollider(false);
world->body(ObjectNameTag(name + "_eye2"))->setColor({147, 159, 255});
world->body(ObjectNameTag(name + "_head"))->attach(world->body(ObjectNameTag(name + "_eye2")), ObjectNameTag("eye2"));
world->body(ObjectNameTag(name + "_head"))->attach(world->body(ObjectNameTag(name + "_eye2")));
changeEnemyWeapon("gun", id);
}
@ -264,12 +262,12 @@ void Shooter::removePlayer(sf::Uint16 id) {
world->removeBody(ObjectNameTag(name + "_head"));
world->removeBody(ObjectNameTag(name + "_eye1"));
world->removeBody(ObjectNameTag(name + "_eye2"));
world->removeBody(ObjectNameTag("enemyWeapon_" + std::to_string(id)));
world->removeBody(ObjectNameTag("Enemy_" + std::to_string(id) + "_weapon"));
}
void Shooter::addFireTrace(const Vec3D &from, const Vec3D &to) {
std::string traceName = "Client_fireTraces_" + std::to_string(fireTraces++);
world->addBody(std::make_shared<RigidBody>(Mesh::LineTo(from, to, 0.05)), ObjectNameTag(traceName));
world->addBody(std::make_shared<RigidBody>(Mesh::LineTo(ObjectNameTag(traceName), from, to, 0.05)));
world->body(ObjectNameTag(traceName))->setCollider(false);
Timeline::animate(AnimationListTag(traceName + "_fadeOut"), new AColor(world->body(ObjectNameTag(traceName)), {150, 150, 150, 0}));
@ -282,9 +280,13 @@ void Shooter::removeFireTrace(const ObjectNameTag& traceName) {
void Shooter::addBonus(const string &bonusName, const Vec3D &position) {
std::string name = bonusName.substr(6, bonusName.size()-3-5);
world->addBody(std::make_shared<Bonus>(bonusName, "obj/" + name + ".obj", Vec3D{3, 3, 3}), ObjectNameTag(bonusName));
ObjectNameTag nameTag(bonusName);
world->addBody(std::make_shared<RigidBody>(ObjectNameTag(bonusName), "obj/" + name + ".obj", Vec3D{3, 3, 3}));
world->body(ObjectNameTag(bonusName))->translateToPoint(position);
Timeline::animate(AnimationListTag(bonusName + "_rotation"), new ARotate(world->body(ObjectNameTag(bonusName)), Vec3D{0, 2*Consts::PI, 0}, 4, Animation::LoopOut::Continue, Animation::InterpolationType::linear));
world->body(ObjectNameTag(bonusName))->setCollider(false);
Timeline::animate(AnimationListTag(bonusName + "_rotation"), new ARotate(world->body(ObjectNameTag(bonusName)), Vec3D{0, 2*Consts::PI, 0}, 4, Animation::LoopOut::Continue, Animation::InterpolationType::Linear));
}
void Shooter::removeBonus(const ObjectNameTag &bonusName) {
@ -293,14 +295,15 @@ void Shooter::removeBonus(const ObjectNameTag &bonusName) {
}
void Shooter::addWeapon(std::shared_ptr<Weapon> weapon) {
world->addBody(weapon, ObjectNameTag("weapon_" + weapon->name().str()));
world->addBody(weapon);
if(client != nullptr)
if(client != nullptr) {
client->changeWeapon(weapon->name().str());
}
}
void Shooter::changeEnemyWeapon(const std::string& weaponName, sf::Uint16 enemyId) {
ObjectNameTag weaponTag("enemyWeapon_" + std::to_string(enemyId));
ObjectNameTag weaponTag("Enemy_" + std::to_string(enemyId) + "_weapon");
auto head = world->body(ObjectNameTag("Enemy_" + std::to_string(enemyId) + "_head"));
auto enemy = world->body(ObjectNameTag("Enemy_" + std::to_string(enemyId)));
@ -317,9 +320,9 @@ void Shooter::changeEnemyWeapon(const std::string& weaponName, sf::Uint16 enemyI
world->body(weaponTag)->rotate(Vec3D(0, Consts::PI + head->angle().y(), 0));
world->body(weaponTag)->rotateLeft(-head->angleLeftUpLookAt().x());
enemy->attach(world->body(weaponTag), ObjectNameTag("Weapon"));
enemy->attach(world->body(weaponTag));
}
void Shooter::removeWeapon(std::shared_ptr<Weapon> weapon) {
world->removeBody(ObjectNameTag("weapon_" + weapon->name().str()));
world->removeBody(weapon->name());
}

18
ShooterMsgType.cpp Normal file
View File

@ -0,0 +1,18 @@
//
// Created by Иван Ильин on 27.10.2021.
//
#include "ShooterMsgType.h"
sf::Packet& operator<<(sf::Packet& packet, ShooterMsgType type)
{
return packet << (sf::Uint16)type;
}
sf::Packet& operator>>(sf::Packet& packet, ShooterMsgType& type)
{
sf::Uint16 temp;
packet >> temp;
type = (ShooterMsgType)temp;
return packet;
}

24
ShooterMsgType.h Normal file
View File

@ -0,0 +1,24 @@
//
// Created by Иван Ильин on 27.10.2021.
//
#ifndef SHOOTER_SHOOTERMSGTYPE_H
#define SHOOTER_SHOOTERMSGTYPE_H
#include <SFML/Network.hpp>
enum class ShooterMsgType
{
Damage,
Kill,
FireTrace,
InitBonuses,
AddBonus,
RemoveBonus,
ChangeWeapon
};
sf::Packet& operator<<(sf::Packet& packet, ShooterMsgType type);
sf::Packet& operator>>(sf::Packet& packet, ShooterMsgType& type);
#endif //SHOOTER_SHOOTERMSGTYPE_H

View File

@ -4,7 +4,7 @@
#include "Camera.h"
#include "utils/Log.h"
#include "Consts.h"
#include <cmath>
std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mesh) {
@ -14,8 +14,9 @@ std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mes
return _triangles;
}
if(!mesh->isVisible())
if(!mesh->isVisible()) {
return this->_triangles;
}
// Model transform matrix: translate _tris in the origin of body.
Matrix4x4 M = Matrix4x4::Translation(mesh->position());
@ -26,11 +27,11 @@ std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mes
for(auto& t : mesh->triangles()) {
double dot = t.norm().dot((mesh->position() + Vec3D(t[0]) - position()).normalized());
if(dot > 0)
if(dot > 0) {
continue;
}
// It needs to be cleared because it's reused through iterations. Usually it doesn't free memory.
clippedTriangles.clear();
@ -39,15 +40,14 @@ std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mes
// 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
clippedTriangles.emplace_back(t * VM);
for(auto& plane : _clipPlanes)
{
while(!clippedTriangles.empty())
{
for(auto& plane : _clipPlanes) {
while(!clippedTriangles.empty()) {
std::vector<Triangle> clipResult = plane.clip(clippedTriangles.back());
clippedTriangles.pop_back();
for(auto & i : clipResult)
for(auto & i : clipResult) {
tempBuffer.emplace_back(i);
}
}
clippedTriangles.swap(tempBuffer);
}
@ -103,8 +103,7 @@ std::vector<std::shared_ptr<Triangle>> Camera::sorted() {
// Sort _tris from _back to front
// This is some replacement for Z-buffer
std::sort(_triangles.begin(), _triangles.end(), [](std::shared_ptr<Triangle> &t1, std::shared_ptr<Triangle> &t2)
{
std::sort(_triangles.begin(), _triangles.end(), [](std::shared_ptr<Triangle> &t1, std::shared_ptr<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()});

View File

@ -26,7 +26,7 @@ private:
double _aspect = 0;
public:
Camera() = default;
Camera() : Object(ObjectNameTag("Camera")) {};
Camera(const Camera& camera) = delete;
void init(int width, int height, double fov = 110.0, double ZNear = 0.1, double ZFar = 5000.0);

View File

@ -5,7 +5,7 @@
#ifndef SHOOTER_CONSTS_H
#define SHOOTER_CONSTS_H
#include <SFML/Graphics.hpp>
#include "Vec2D.h"
namespace Consts {
const int STANDARD_SCREEN_WIDTH = 1920;
@ -29,11 +29,15 @@ namespace Consts {
const double LARGEST_TIME_STEP = 1.0/15.0;
const double TAP_DELAY = 0.2;
const unsigned NETWORK_VERSION = 2U;
const Vec2D BEZIER[2] = {Vec2D{0.8, 0}, Vec2D{0.2, 1}};
const unsigned NETWORK_VERSION = 3U;
const int NETWORK_TIMEOUT = 5U;
const int NETWORK_WORLD_UPDATE_RATE = 30;
const double NETWORK_RELIABLE_RETRY_TIME = 1.0/20;
const uint16_t NETWORK_MAX_CLIENTS = 64;
}
#endif //SHOOTER_CONSTS_H

View File

@ -14,20 +14,11 @@ Engine::Engine() {
Timeline::init();
ResourceManager::init();
SoundController::init();
screen = std::make_shared<Screen>();
keyboard = std::make_shared<Keyboard>();
mouse = std::make_shared<Mouse>();
world = std::make_shared<World>();
camera = std::make_shared<Camera>();
}
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);
screen->attachMouse(mouse);
Log::log("Engine::create(): started engine (" + std::to_string(screenWidth) + "x" + std::to_string(screenHeight) + ") with title '" + name + "'.");
Time::update();
@ -65,11 +56,13 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name,
// clear triangles from previous frame
camera->clear();
// project triangles to the camera plane
for(auto & it : *world)
for(auto & it : *world) {
camera->project(it.second);
}
// draw triangles on the screen
for (auto &t : camera->sorted())
for (auto &t : camera->sorted()) {
screen->drawTriangle(*t);
}
_triPerSec = camera->buffSize() * Time::fps();
}

View File

@ -24,12 +24,12 @@ private:
void printDebugText() const;
protected:
std::shared_ptr<Screen> screen;
std::shared_ptr<Keyboard> keyboard;
std::shared_ptr<Mouse> mouse;
const std::shared_ptr<Screen> screen = std::make_shared<Screen>();
const std::shared_ptr<Keyboard> keyboard = std::make_shared<Keyboard>();
const std::shared_ptr<Mouse> mouse = std::make_shared<Mouse>(screen);
std::shared_ptr<World> world;
std::shared_ptr<Camera> camera;
const std::shared_ptr<World> world = std::make_shared<World>();
const std::shared_ptr<Camera> camera = std::make_shared<Camera>();
virtual void start() {};
virtual void update() {};

View File

@ -11,8 +11,9 @@ bool Keyboard::isKeyPressed(sf::Keyboard::Key key) {
}
bool Keyboard::isKeyTapped(sf::Keyboard::Key key) {
if (!Keyboard::isKeyPressed(key))
if (!Keyboard::isKeyPressed(key)) {
return false;
}
if(_tappedKeys.count(key) == 0) {
_tappedKeys.emplace(key, Time::time());

View File

@ -18,8 +18,8 @@ Matrix4x4 Matrix4x4::operator*(const Matrix4x4 &matrix4X4) const {
return result;
}
Point4D Matrix4x4::operator*(const Point4D &point4D) const {
return Point4D(
Vec4D Matrix4x4::operator*(const Vec4D &point4D) const {
return Vec4D(
_arr[0][0] * point4D.x() + _arr[0][1] * point4D.y() + _arr[0][2] * point4D.z() + _arr[0][3] * point4D.w(),
_arr[1][0] * point4D.x() + _arr[1][1] * point4D.y() + _arr[1][2] * point4D.z() + _arr[1][3] * point4D.w(),
_arr[2][0] * point4D.x() + _arr[2][1] * point4D.y() + _arr[2][2] * point4D.z() + _arr[2][3] * point4D.w(),
@ -38,12 +38,15 @@ Vec3D Matrix4x4::operator*(const Vec3D &vec) const {
Matrix4x4 Matrix4x4::Identity() {
Matrix4x4 result;
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
if(i == j)
for(int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (i == j) {
result._arr[j][i] = 1.0;
else
} else {
result._arr[j][i] = 0.0;
}
}
}
return result;
}
@ -51,9 +54,11 @@ Matrix4x4 Matrix4x4::Identity() {
Matrix4x4 Matrix4x4::Constant(double value) {
Matrix4x4 result;
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
for(int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
result._arr[j][i] = value;
}
}
return result;
}

View File

@ -6,7 +6,7 @@
#define ENGINE_MATRIX4X4_H
#include <array>
#include "Point4D.h"
#include "Vec4D.h"
#include "Vec3D.h"
class Matrix4x4 final {
@ -18,7 +18,7 @@ public:
Matrix4x4& operator=(const Matrix4x4& matrix4X4) = default;
[[nodiscard]] Matrix4x4 operator*(const Matrix4x4& matrix4X4) const;
[[nodiscard]] Point4D operator*(const Point4D& point4D) const;
[[nodiscard]] Vec4D operator*(const Vec4D& point4D) const;
[[nodiscard]] Vec3D operator*(const Vec3D& vec) const;
// Any useful matrix (static methods)

View File

@ -18,7 +18,7 @@ Mesh &Mesh::operator*=(const Matrix4x4 &matrix4X4) {
return *this;
}
Mesh &Mesh::loadObj(const std::string& filename, const Vec3D& scale) {
void Mesh::loadObj(const std::string& filename, const Vec3D& scale) {
auto objects = ResourceManager::loadObjects(filename);
for(auto& obj : objects) {
@ -27,19 +27,17 @@ Mesh &Mesh::loadObj(const std::string& filename, const Vec3D& scale) {
}
}
this->scale(scale);
return *this;
}
Mesh::Mesh(const std::string& filename, const Vec3D& scale){
Mesh::Mesh(ObjectNameTag nameTag, const std::string& filename, const Vec3D& scale) : Object(nameTag) {
loadObj(filename, scale);
}
Mesh::Mesh(const vector<Triangle> &tries) : _tris(tries) {
Mesh::Mesh(ObjectNameTag nameTag, const vector<Triangle> &tries) : Object(nameTag), _tris(tries) {
}
Mesh Mesh::Obj(const std::string& filename) {
return Mesh(filename);
Mesh Mesh::Obj(ObjectNameTag nameTag, const std::string& filename) {
return Mesh(std::move(nameTag), filename);
}
void Mesh::rotate(const Vec3D &r) {
@ -78,24 +76,24 @@ void Mesh::setColor(const sf::Color& c) {
setTriangles(newTriangles);
}
Mesh Mesh::LineTo(const Vec3D& from, const Vec3D& to, double line_width, const sf::Color& color) {
Mesh Mesh::LineTo(ObjectNameTag nameTag, const Vec3D& from, const Vec3D& to, double line_width, const sf::Color& color) {
Mesh line;
Mesh line(nameTag);
Vec3D v1 = (to - from).normalized();
Vec3D v2 = from.cross(from + Vec3D{1, 0, 0}).normalized();
Vec3D v3 = v1.cross(v2).normalized();
// from plane
Point4D p1 = (from - v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
Point4D p2 = (from - v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
Point4D p3 = (from + v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
Point4D p4 = (from + v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
Vec4D p1 = (from - v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
Vec4D p2 = (from - v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
Vec4D p3 = (from + v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
Vec4D p4 = (from + v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
// to plane
Point4D p5 = (to - v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
Point4D p6 = (to - v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
Point4D p7 = (to + v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
Point4D p8 = (to + v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
Vec4D p5 = (to - v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
Vec4D p6 = (to - v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
Vec4D p7 = (to + v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
Vec4D p8 = (to + v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
line._tris = std::move(std::vector<Triangle>{
@ -117,7 +115,7 @@ Mesh Mesh::LineTo(const Vec3D& from, const Vec3D& to, double line_width, const s
return line;
}
Mesh::Mesh(const Mesh &mesh) : _tris(mesh._tris), _color(mesh._color), _visible(mesh._visible) {
Mesh::Mesh(const Mesh &mesh) : Object(mesh.name()), _tris(mesh._tris), _color(mesh._color), _visible(mesh._visible) {
}

View File

@ -5,6 +5,7 @@
#ifndef ENGINE_MESH_H
#define ENGINE_MESH_H
#include <utility>
#include <vector>
#include "Triangle.h"
#include <SFML/Graphics.hpp>
@ -18,14 +19,14 @@ private:
Mesh& operator*=(const Matrix4x4& matrix4X4);
public:
Mesh() = default;
explicit Mesh(ObjectNameTag nameTag) : Object(std::move(nameTag)) {};
Mesh& operator=(const Mesh& mesh) = delete;
Mesh(const Mesh& mesh);
explicit Mesh(const std::vector<Triangle>& tries);
explicit Mesh(const std::string& filename, const Vec3D& scale = Vec3D{1, 1, 1});
explicit Mesh(ObjectNameTag nameTag, const std::vector<Triangle>& tries);
explicit Mesh(ObjectNameTag nameTag, const std::string& filename, const Vec3D& scale = Vec3D{1, 1, 1});
Mesh& loadObj(const std::string& filename, const Vec3D& scale = Vec3D{1, 1, 1});
void loadObj(const std::string& filename, const Vec3D& scale = Vec3D{1, 1, 1});
[[nodiscard]] std::vector<Triangle>const &triangles() const { return _tris; }
[[nodiscard]] std::vector<Triangle>& triangles() { return _tris; }
@ -51,8 +52,8 @@ public:
~Mesh() override;
Mesh static Obj(const std::string& filename);
Mesh static LineTo(const Vec3D& from, const Vec3D& to, double line_width = 0.1, const sf::Color& color = {150, 150, 150, 100});
Mesh static Obj(ObjectNameTag nameTag, const std::string& filename);
Mesh static LineTo(ObjectNameTag nameTag, const Vec3D& from, const Vec3D& to, double line_width = 0.1, const sf::Color& color = {150, 150, 150, 100});
};
#endif //INC_3DZAVR_MESH_H

View File

@ -4,15 +4,16 @@
#include "Mouse.h"
#include "utils/Time.h"
#include "Consts.h"
Vec2D Mouse::getMousePosition() const {
sf::Vector2<int> pos = sf::Mouse::getPosition(*_window);
sf::Vector2<int> pos = sf::Mouse::getPosition(*_screen->renderWindow());
return Vec2D(pos.x, pos.y);
}
Vec2D Mouse::getMouseDisplacement() const {
sf::Vector2<int> mousePos = sf::Mouse::getPosition(*_window);
sf::Vector2<int> center = sf::Vector2<int>(_window->getSize().x/2, _window->getSize().y/2);
sf::Vector2<int> mousePos = sf::Mouse::getPosition(*_screen->renderWindow());
sf::Vector2<int> center = sf::Vector2<int>(_screen->width()/2, _screen->height()/2);
sf::Vector2<int> displacement = mousePos - center;
//setMouseInCenter();
@ -20,7 +21,7 @@ Vec2D Mouse::getMouseDisplacement() const {
}
void Mouse::setMouseInCenter() const {
sf::Mouse::setPosition({ static_cast<int>(_window->getSize().x / 2), static_cast<int>(_window->getSize().y / 2) }, *_window);
sf::Mouse::setPosition({ static_cast<int>(_screen->width() / 2), static_cast<int>(_screen->height() / 2) }, *_screen->renderWindow());
}
bool Mouse::isButtonPressed(sf::Mouse::Button button) {
@ -28,8 +29,9 @@ bool Mouse::isButtonPressed(sf::Mouse::Button button) {
}
bool Mouse::isButtonTapped(sf::Mouse::Button button) {
if (!Mouse::isButtonPressed(button))
if (!Mouse::isButtonPressed(button)) {
return false;
}
if(_tappedButtons.count(button) == 0) {
_tappedButtons.emplace(button, Time::time());
@ -40,11 +42,3 @@ bool Mouse::isButtonTapped(sf::Mouse::Button button) {
}
return false;
}
void Mouse::setWindow(std::shared_ptr<sf::RenderWindow> window) {
_window = window;
}
void Mouse::setMouseCursorVisible(bool visible) {
_window->setMouseCursorVisible(visible);
}

View File

@ -6,18 +6,17 @@
#define SHOOTER_MOUSE_H
#include <memory>
#include <SFML/Graphics.hpp>
#include <utility>
#include "Screen.h"
#include "Vec2D.h"
class Mouse final {
private:
std::shared_ptr<sf::RenderWindow> _window;
const std::shared_ptr<Screen> _screen;
std::map<sf::Mouse::Button, double> _tappedButtons;
public:
Mouse() = default;
void setWindow(std::shared_ptr<sf::RenderWindow> window);
explicit Mouse(std::shared_ptr<Screen> screen) : _screen(std::move(screen)) {};
static bool isButtonPressed(sf::Mouse::Button button); // returns true if this _button is _pressed
bool isButtonTapped(sf::Mouse::Button button); // returns true if this _button is tapped and 1/5 sec passed (_button bouncing problem solved)
@ -25,7 +24,6 @@ public:
[[nodiscard]] Vec2D getMousePosition() const;
[[nodiscard]] Vec2D getMouseDisplacement() const;
void setMouseInCenter() const;
void setMouseCursorVisible(bool visible);
};

View File

@ -7,123 +7,155 @@
#include "utils/Log.h"
void Object::translate(const Vec3D &dv) {
_position = std::make_unique<Vec3D>(*_position + dv);
_position = _position + dv;
for(auto &[attachedName, attachedObject] : _attachedObjects)
attachedObject->translate(dv);
for(auto &[attachedName, attachedObject] : _attachedObjects) {
if(!attachedObject.expired()) {
attachedObject.lock()->translate(dv);
}
}
}
void Object::scale(const Vec3D &s) {
for(auto &[attachedName, attachedObject] : _attachedObjects)
attachedObject->scale(s);
for(auto &[attachedName, attachedObject] : _attachedObjects) {
if(!attachedObject.expired()) {
attachedObject.lock()->scale(s);
}
}
}
void Object::rotate(const Vec3D &r) {
_angle = std::make_unique<Vec3D>(*_angle + r);
_angle = _angle + r;
Matrix4x4 rotationMatrix = Matrix4x4::RotationZ(r.z())*Matrix4x4::RotationY(r.y())*Matrix4x4::RotationX(r.z());
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
_left = rotationMatrix * _left;
_up = rotationMatrix * _up;
_lookAt = rotationMatrix * _lookAt;
for(auto &[attachedName, attachedObject] : _attachedObjects)
attachedObject->rotateRelativePoint(position(), r);
for(auto &[attachedName, attachedObject] : _attachedObjects) {
if(!attachedObject.expired()) {
attachedObject.lock()->rotateRelativePoint(position(), r);
}
}
}
void Object::rotate(const Vec3D &v, double rv) {
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, rv);
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
_left = rotationMatrix * _left;
_up = rotationMatrix * _up;
_lookAt = rotationMatrix * _lookAt;
for(auto &[attachedName, attachedObject] : _attachedObjects)
attachedObject->rotateRelativePoint(position(), v, rv);
for(auto &[attachedName, attachedObject] : _attachedObjects) {
if(!attachedObject.expired()) {
attachedObject.lock()->rotateRelativePoint(position(), v, rv);
}
}
}
void Object::rotateRelativePoint(const Vec3D &s, const Vec3D &r) {
_angle = std::make_unique<Vec3D>(*_angle + r);
_angle = _angle + r;
// Translate XYZ by vector r1
Vec3D r1(*_position - s);
Vec3D r1(_position - s);
// In translated coordinate system we rotate body and position
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(r);
Vec3D r2(rotationMatrix*r1);
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
_left = rotationMatrix * _left;
_up = rotationMatrix * _up;
_lookAt = rotationMatrix * _lookAt;
// After rotation we translate XYZ by vector -r2 and recalculate position
_position = std::make_unique<Vec3D>(s + r2);
_position = s + r2;
for(auto &[attachedName, attachedObject] : _attachedObjects)
attachedObject->rotateRelativePoint(s, r);
for(auto &[attachedName, attachedObject] : _attachedObjects) {
if(!attachedObject.expired()) {
attachedObject.lock()->rotateRelativePoint(s, r);
}
}
}
void Object::rotateRelativePoint(const Vec3D &s, const Vec3D &v, double r) {
// Translate XYZ by vector r1
Vec3D r1(*_position - s);
Vec3D r1(_position - s);
// In translated coordinate system we rotate body and position
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, r);
Vec3D r2 = rotationMatrix*r1;
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
_left = rotationMatrix * _left;
_up = rotationMatrix * _up;
_lookAt = rotationMatrix * _lookAt;
// After rotation we translate XYZ by vector -r2 and recalculate position
_position = std::make_unique<Vec3D>(s + r2);
_position = s + r2;
for(auto &[attachedName, attachedObject] : _attachedObjects)
attachedObject->rotateRelativePoint(s, v, r);
for(auto &[attachedName, attachedObject] : _attachedObjects) {
if(!attachedObject.expired()) {
attachedObject.lock()->rotateRelativePoint(s, v, r);
}
}
}
void Object::rotateLeft(double rl) {
_angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{_angleLeftUpLookAt->x() + rl,
_angleLeftUpLookAt->y(),
_angleLeftUpLookAt->z()});
_angleLeftUpLookAt = Vec3D{_angleLeftUpLookAt.x() + rl,
_angleLeftUpLookAt.y(),
_angleLeftUpLookAt.z()};
rotate(Vec3D(*_left), rl);
rotate(Vec3D(_left), rl);
}
void Object::rotateUp(double ru) {
_angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{_angleLeftUpLookAt->x(),
_angleLeftUpLookAt->y() + ru,
_angleLeftUpLookAt->z()});
_angleLeftUpLookAt = Vec3D{_angleLeftUpLookAt.x(),
_angleLeftUpLookAt.y() + ru,
_angleLeftUpLookAt.z()};
rotate(Vec3D(*_up), ru);
rotate(Vec3D(_up), ru);
}
void Object::rotateLookAt(double rlAt) {
_angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{_angleLeftUpLookAt->x(),
_angleLeftUpLookAt->y(),
_angleLeftUpLookAt->z() + rlAt});
rotate(Vec3D(*_lookAt), rlAt);
_angleLeftUpLookAt = Vec3D{_angleLeftUpLookAt.x(),
_angleLeftUpLookAt.y(),
_angleLeftUpLookAt.z() + rlAt};
rotate(Vec3D(_lookAt), rlAt);
}
void Object::translateToPoint(const Vec3D &point) {
translate(point - *_position);
translate(point - _position);
}
void Object::rotateToAngle(const Vec3D &v) {
rotate(v - *_angle);
rotate(v - _angle);
}
std::shared_ptr<Object> Object::attached(const ObjectNameTag& tag) {
if(_attachedObjects.count(tag) == 0)
if(_attachedObjects.count(tag) == 0 || _attachedObjects.find(tag)->second.expired()) {
return nullptr;
return _attachedObjects.find(tag)->second;
}
return _attachedObjects.find(tag)->second.lock();
}
void Object::attach(std::shared_ptr<Object> object, const ObjectNameTag& tag) {
// TODO: solve problem with possible infinite recursive call chains
if(this != object.get())
_attachedObjects.emplace(tag, object);
else
bool Object::checkIfAttached(Object *obj) {
for(const auto& [nameTag, attachedObject] : _attachedObjects) {
if (obj == attachedObject.lock().get() || attachedObject.lock()->checkIfAttached(obj)) {
return true;
}
}
return false;
}
void Object::attach(std::shared_ptr<Object> object) {
if(this != object.get()) {
if(!object->checkIfAttached(this)) {
_attachedObjects.emplace(object->name(), object);
} else {
throw std::invalid_argument{"Object::attach: You tried to create infinite recursive call chains"};
}
} else {
throw std::invalid_argument{"Object::attach: You cannot attach object to itself"};
}
}
void Object::unattach(const ObjectNameTag& tag) {

View File

@ -24,18 +24,22 @@ public:
};
class Object {
private:
bool checkIfAttached(Object* obj);
const ObjectNameTag _nameTag;
protected:
std::unique_ptr<Vec3D> _left = std::make_unique<Vec3D>(Vec3D{1, 0, 0}); // internal X
std::unique_ptr<Vec3D> _up = std::make_unique<Vec3D>(Vec3D{0, 1, 0}); // internal Y
std::unique_ptr<Vec3D> _lookAt = std::make_unique<Vec3D>(Vec3D{0, 0, 1}); // internal Z
Vec3D _left {1, 0, 0}; // internal X
Vec3D _up {0, 1, 0}; // internal Y
Vec3D _lookAt {0, 0, 1}; // internal Z
std::map<ObjectNameTag, std::shared_ptr<Object>> _attachedObjects;
std::map<ObjectNameTag, std::weak_ptr<Object>> _attachedObjects;
std::unique_ptr<Vec3D> _position = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
std::unique_ptr<Vec3D> _angle = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
std::unique_ptr<Vec3D> _angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
Vec3D _position {0, 0, 0};
Vec3D _angle {0, 0, 0};
Vec3D _angleLeftUpLookAt{0, 0, 0};
public:
Object() = default;
Object(ObjectNameTag nameTag) : _nameTag(nameTag) {};
virtual void translate(const Vec3D& dv);
virtual void translateToPoint(const Vec3D& point);
@ -49,18 +53,20 @@ public:
void rotateUp(double ru);
void rotateLookAt(double rlAt);
[[nodiscard]] Vec3D position() const { return *_position; }
[[nodiscard]] Vec3D angle() const { return *_angle; }
[[nodiscard]] Vec3D angleLeftUpLookAt() const { return *_angleLeftUpLookAt; }
[[nodiscard]] Vec3D position() const { return _position; }
[[nodiscard]] Vec3D angle() const { return _angle; }
[[nodiscard]] Vec3D angleLeftUpLookAt() const { return _angleLeftUpLookAt; }
[[nodiscard]] Vec3D left() const { return *_left; }
[[nodiscard]] Vec3D up() const { return *_up; }
[[nodiscard]] Vec3D lookAt() const { return *_lookAt; }
[[nodiscard]] Vec3D left() const { return _left; }
[[nodiscard]] Vec3D up() const { return _up; }
[[nodiscard]] Vec3D lookAt() const { return _lookAt; }
void attach(std::shared_ptr<Object> object, const ObjectNameTag& tag);
void attach(std::shared_ptr<Object> object);
void unattach(const ObjectNameTag& tag);
std::shared_ptr<Object> attached(const ObjectNameTag& tag);
ObjectNameTag name() const { return _nameTag; }
virtual ~Object();
};

View File

@ -4,21 +4,19 @@
#include "Plane.h"
Plane::Plane(const Triangle& tri) : _triangle(tri), _n(tri.norm()), _p(tri[0]) {
Plane::Plane(const Triangle& tri) : _normal(tri.norm()), _point(tri[0]) {
}
Plane::Plane(const Vec3D &N, const Vec3D &P) : _n(N.normalized()), _p(P) {
Plane::Plane(const Vec3D &N, const Vec3D &P) : _normal(N.normalized()), _point(P) {
}
double Plane::distance(const Vec3D &point) const {
return point.dot(_n) - _p.dot(_n);
return point.dot(_normal) - _point.dot(_normal);
}
std::pair<Vec3D, double> Plane::intersection(const Vec3D &start, const Vec3D &end) const {
double s_dot_n = start.dot(_n);
double k = (s_dot_n - _p.dot(_n)) / (s_dot_n - end.dot(_n));
double s_dot_n = start.dot(_normal);
double k = (s_dot_n - _point.dot(_normal)) / (s_dot_n - end.dot(_normal));
Vec3D res = start + (end - start)*k;
return std::make_pair(res, k);
}

View File

@ -5,30 +5,28 @@
#ifndef ENGINE_PLANE_H
#define ENGINE_PLANE_H
#include "Point4D.h"
#include "Vec4D.h"
#include "Triangle.h"
class Plane final {
private:
// You can define plane by defining the points in 3D space
Triangle _triangle;
// Or by defining normal vector and one val laying on the plane
Vec3D _n = Vec3D{0, 0, 1};
Vec3D _p{};
const Vec3D _normal;
const Vec3D _point;
public:
// A plain with normal vector '_n' and val '_p' lays on the plane
Plane() = default;
Plane(const Vec3D& N, const Vec3D& P);
Plane() = delete;
Plane(const Plane& plane) = default;
// You can define plane by defining the points in 3D space
explicit Plane(const Triangle& tri);
// Or by defining normal vector and one val laying on the plane
Plane(const Vec3D& N, const Vec3D& P);
[[nodiscard]] double distance(const Vec3D& point4D) const;
// Point4D in space where line ('start' to 'end') intersects plain with normal vector '_n' and val '_p' lays on the plane
// Vec4D in space where line ('start' to 'end') intersects plain with normal vector '_n' and val '_p' lays on the plane
[[nodiscard]] std::pair<Vec3D, double> intersection(const Vec3D& start, const Vec3D& end) const;
[[nodiscard]] std::vector<Triangle> clip(const Triangle& tri) const;
[[nodiscard]] Vec3D N() const { return _n; }
[[nodiscard]] Vec3D P() const { return _p; }
[[nodiscard]] Vec3D N() const { return _normal; }
[[nodiscard]] Vec3D P() const { return _point; }
};

View File

@ -1,70 +0,0 @@
//
// Created by Иван Ильин on 12.01.2021.
//
#include "Point4D.h"
#include <cmath>
#include <stdexcept>
Point4D::Point4D (double x, double y, double z, double w) {
_arr_point[0] = x;
_arr_point[1] = y;
_arr_point[2] = z;
_arr_point[3] = w;
}
Point4D::Point4D(const Point4D &point4D) {
_arr_point[0] = point4D.x();
_arr_point[1] = point4D.y();
_arr_point[2] = point4D.z();
_arr_point[3] = point4D.w();
}
[[nodiscard]] Point4D Point4D::operator-() const {
return Point4D(-x(), -y(), -z(), -w());
}
bool Point4D::operator==(const Point4D& point4D) const {
return (*this - point4D).sqrAbs() < Consts::EPS;
}
bool Point4D::operator!=(const Point4D& point4D) const {
return !(*this == point4D);
}
// Operations with Point4D
Point4D Point4D::operator+(const Point4D& point4D) const {
return Point4D(x()+point4D.x(), y()+point4D.y(), z()+point4D.z(), w()+point4D.w());
}
Point4D Point4D::operator-(const Point4D& point4D) const {
return Point4D(*this) + -point4D;
}
Point4D Point4D::operator*(double number) const {
return Point4D(x()*number, y()*number, z()*number, w()*number);
}
Point4D Point4D::operator/(double number) const {
if(std::abs(number) > Consts::EPS)
return Point4D(*this)*(1.0/number);
else
throw std::domain_error{"Point4D::operator/(double number): division by zero"};
}
// Other useful methods
double Point4D::sqrAbs() const {
return x()*x() + y()*y() + z()*z();
}
double Point4D::abs() const {
return sqrt(sqrAbs());
}
Point4D Point4D::normalized() const {
double vecAbs = abs();
if(vecAbs > Consts::EPS)
return Point4D(*this)/abs();
else
return Point4D(1);
}

View File

@ -1,47 +0,0 @@
//
// Created by Иван Ильин on 12.01.2021.
//
#ifndef ENGINE_POINT4D_H
#define ENGINE_POINT4D_H
#include <array>
#include "Consts.h"
class Point4D final {
private:
std::array<double, 4> _arr_point{};
public:
Point4D () = default;
Point4D (const Point4D& point4D);
explicit Point4D (double x, double y = 0.0, double z = 0.0, double w = 0.0);
Point4D& operator=(const Point4D& point4D) = delete;
[[nodiscard]] double x() const { return _arr_point[0]; }
[[nodiscard]] double y() const { return _arr_point[1]; }
[[nodiscard]] double z() const { return _arr_point[2]; }
[[nodiscard]] double w() const { return _arr_point[3]; }
[[nodiscard]] Point4D operator-() const;
// Boolean operations
bool operator==(const Point4D& point4D) const;
bool operator!=(const Point4D& point4D) const;
// Operations with Point4D
[[nodiscard]] Point4D operator+(const Point4D& point4D) const;
[[nodiscard]] Point4D operator-(const Point4D& point4D) const;
// Operations with numbers
[[nodiscard]] Point4D operator*(double number) const;
[[nodiscard]] Point4D operator/(double number) const;
// Other useful methods
[[nodiscard]] double sqrAbs() const; // Returns squared vector length
[[nodiscard]] double abs() const; // Returns vector length
[[nodiscard]] Point4D normalized() const; // Returns normalized vector without changing
};
#endif //INC_3DZAVR_POINT4D_H

View File

@ -16,20 +16,23 @@ void ResourceManager::init() {
}
void ResourceManager::unloadTextures() {
for (auto & _texture : _instance->_textures)
for (auto & _texture : _instance->_textures) {
_texture.second.reset();
}
_instance->_textures.clear();
}
void ResourceManager::unloadSoundBuffers() {
for (auto & _soundBuffer : _instance->_soundBuffers)
for (auto & _soundBuffer : _instance->_soundBuffers) {
_soundBuffer.second.reset();
}
_instance->_soundBuffers.clear();
}
void ResourceManager::unloadFonts() {
for (auto & _font : _instance->_fonts)
for (auto & _font : _instance->_fonts) {
_font.second.reset();
}
_instance->_fonts.clear();
}
@ -51,18 +54,21 @@ void ResourceManager::free() {
}
std::shared_ptr<sf::Texture> ResourceManager::loadTexture(const std::string& filename) {
if(!_instance)
if(!_instance) {
return nullptr;
}
// If texture is already loaded - return pointer to it
auto it = _instance->_textures.find(filename);
if (it != _instance->_textures.end())
if (it != _instance->_textures.end()) {
return it->second;
}
// Otherwise - try to load it. If failure - return zero
std::shared_ptr<sf::Texture> texture(new sf::Texture);
if (!texture->loadFromFile(filename))
if (!texture->loadFromFile(filename)) {
return nullptr;
}
// If success - remember and return texture pointer
texture->setRepeated(true);
@ -72,18 +78,21 @@ std::shared_ptr<sf::Texture> ResourceManager::loadTexture(const std::string& fil
}
std::shared_ptr<sf::SoundBuffer> ResourceManager::loadSoundBuffer(const std::string& filename) {
if(!_instance)
if(!_instance) {
return nullptr;
}
// If sound buffer is already loaded - return pointer to it
auto it = _instance->_soundBuffers.find(filename);
if (it != _instance->_soundBuffers.end())
if (it != _instance->_soundBuffers.end()) {
return it->second;
}
// Otherwise - try to load it. If failure - return zero
std::shared_ptr<sf::SoundBuffer> soundBuffer(new sf::SoundBuffer);
if (!soundBuffer->loadFromFile(filename))
if (!soundBuffer->loadFromFile(filename)) {
return nullptr;
}
// If success - remember and return sound pointer
_instance->_soundBuffers.emplace(filename, soundBuffer);
@ -92,18 +101,21 @@ std::shared_ptr<sf::SoundBuffer> ResourceManager::loadSoundBuffer(const std::str
}
std::shared_ptr<sf::Font> ResourceManager::loadFont(const std::string& filename) {
if(!_instance)
if(!_instance) {
return nullptr;
}
// If font is already loaded - return pointer to it
auto it = _instance->_fonts.find(filename);
if (it != _instance->_fonts.end())
if (it != _instance->_fonts.end()) {
return it->second;
}
// Otherwise - try to load it. If failure - return zero
std::shared_ptr<sf::Font> font(new sf::Font);
if (!font->loadFromFile(filename))
if (!font->loadFromFile(filename)) {
return nullptr;
}
// If success - remember and return font pointer
_instance->_fonts.emplace(filename, font);
@ -122,18 +134,16 @@ std::vector<std::shared_ptr<Mesh>> ResourceManager::loadObjects(const std::strin
}
std::ifstream file(filename);
if (!file.is_open())
{
if (!file.is_open()) {
Log::log("Mesh::LoadObjects(): cannot load file from " + filename);
return objects;
}
std::vector<Point4D> verts{};
std::vector<Vec4D> verts{};
std::vector<Triangle> tris{};
sf::Color currentColor = sf::Color(255, 245, 194, 255);
while (!file.eof())
{
while (!file.eof()) {
char line[128];
file.getline(line, 128);
@ -143,14 +153,14 @@ std::vector<std::shared_ptr<Mesh>> ResourceManager::loadObjects(const std::strin
char junk;
if(line[0] == 'o') {
if(!tris.empty())
objects.push_back(std::make_shared<Mesh>(tris));
objects.push_back(std::make_shared<Mesh>(ObjectNameTag(filename + "_temp_obj_" + std::to_string(objects.size())), tris));
tris.clear();
}
if (line[0] == 'v')
{
double x, y, z;
s >> junk >> x >> y >> z;
verts.emplace_back(x, y, z, 1);
verts.emplace_back(x, y, z, 1.0);
}
if(line[0] == 'g') {
std::string matInfo;
@ -174,8 +184,11 @@ std::vector<std::shared_ptr<Mesh>> ResourceManager::loadObjects(const std::strin
}
}
if(!tris.empty())
objects.push_back(std::make_shared<Mesh>(tris));
if(!tris.empty()) {
objects.push_back(
std::make_shared<Mesh>(ObjectNameTag(filename + "_temp_obj_" + std::to_string(objects.size())), tris));
}
tris.clear();
file.close();

View File

@ -21,7 +21,6 @@ void Screen::open(int screenWidth, int screenHeight, const std::string &name, bo
settings.depthBits = 24;
settings.antialiasingLevel = 8;
_window = std::make_shared<sf::RenderWindow>();
_window->create(sf::VideoMode(_w, _h), name, style, settings);
_window->setVerticalSyncEnabled(verticalSync);
}
@ -88,6 +87,10 @@ void Screen::debugText(const std::string& text) {
_window->popGLStates();
}
void Screen::setMouseCursorVisible(bool visible) {
_window->setMouseCursorVisible(visible);
}
void Screen::drawTetragon(const Vec2D &p1, const Vec2D &p2, const Vec2D &p3, const Vec2D &p4, sf::Color color) {
sf::ConvexShape polygon;
polygon.setPointCount(4);
@ -131,10 +134,6 @@ void Screen::drawText(const sf::Text &text) {
_window->popGLStates();
}
void Screen::attachMouse(std::shared_ptr<Mouse> mouse) {
mouse->setWindow(_window);
}
// OpenGL functions
void Screen::glDrawMesh(GLfloat* geometry, GLfloat* view, size_t count) {
// OpenGL:

View File

@ -11,7 +11,6 @@
#include <SFML/Graphics.hpp>
#include <map>
#include "utils/Time.h"
#include "Mouse.h"
#include "Consts.h"
#include "Mesh.h"
#include "Camera.h"
@ -25,7 +24,7 @@ private:
sf::Color _background;
std::shared_ptr<sf::RenderWindow> _window;
const std::shared_ptr<sf::RenderWindow> _window = std::make_shared<sf::RenderWindow>();
public:
void open(int screenWidth = Consts::STANDARD_SCREEN_WIDTH, int screenHeight = Consts::STANDARD_SCREEN_HEIGHT, const std::string& name = Consts::PROJECT_NAME, bool verticalSync = true, sf::Color background = Consts::BACKGROUND_COLOR, sf::Uint32 style = sf::Style::Default);
@ -51,11 +50,13 @@ public:
void debugText(const std::string& text);
void attachMouse(std::shared_ptr<Mouse> mouse);
void setMouseCursorVisible(bool visible);
// OpenGL functions
void glDrawMesh(GLfloat* geometry, GLfloat* view, size_t count);
static GLfloat* glMeshToGLfloatArray(std::shared_ptr<Mesh> mesh, const Vec3D& cameraPosition);
[[nodiscard]] std::shared_ptr<sf::RenderWindow> renderWindow() { return _window; }
};

View File

@ -12,8 +12,9 @@ void SoundController::init() {
}
void SoundController::playSound(const SoundTag& soundTag, const std::string& filename) {
if(!_instance)
if(!_instance) {
return;
}
stopSound(soundTag);
_instance->_sounds.emplace(soundTag, sf::Sound(*ResourceManager::loadSoundBuffer(filename)));
@ -21,8 +22,9 @@ void SoundController::playSound(const SoundTag& soundTag, const std::string& fil
}
void SoundController::pauseSound(const SoundTag& soundTag) {
if(!_instance)
if(!_instance) {
return;
}
if(_instance->_sounds.count(soundTag) > 0) {
_instance->_sounds[soundTag].pause();
@ -30,8 +32,9 @@ void SoundController::pauseSound(const SoundTag& soundTag) {
}
void SoundController::stopSound(const SoundTag& soundTag) {
if(!_instance)
if(!_instance) {
return;
}
if(_instance->_sounds.count(soundTag) > 0) {
_instance->_sounds[soundTag].stop();
@ -40,12 +43,13 @@ void SoundController::stopSound(const SoundTag& soundTag) {
}
sf::Sound::Status SoundController::getStatus(const SoundTag& soundTag) {
if(_instance == nullptr)
if(_instance == nullptr) {
return sf::Sound::Status::Stopped;
}
if(_instance->_sounds.count(soundTag) > 0)
if(_instance->_sounds.count(soundTag) > 0) {
return _instance->_sounds[soundTag].getStatus();
else {
} else {
_instance->_sounds.erase(soundTag);
return sf::Sound::Status::Stopped;
}

View File

@ -3,21 +3,12 @@
//
#include "Triangle.h"
#include "Consts.h"
Triangle::Triangle () {
_points.emplace_back(Point4D(0, 0, 0, 1));
_points.emplace_back(Point4D(0, 0, 0, 1));
_points.emplace_back(Point4D(0, 0, 0, 1));
Triangle::Triangle(const Vec4D& p1, const Vec4D& p2, const Vec4D& p3, sf::Color color) : _color(color), _points{p1, p2, p3} {
}
Triangle::Triangle(const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color) : _color(color) {
_points.emplace_back(Point4D(p1));
_points.emplace_back(Point4D(p2));
_points.emplace_back(Point4D(p3));
}
Triangle::Triangle(const Triangle &triangle) : _points(triangle._points), _color(triangle._color) {
Triangle::Triangle(const Triangle &triangle) : _points{triangle._points[0], triangle._points[1], triangle._points[2]}, _color(triangle._color) {
}
Triangle Triangle::operator*(const Matrix4x4 &matrix4X4) const {
@ -30,13 +21,14 @@ Vec3D Triangle::norm() const {
Vec3D v2 = Vec3D(_points[2] - _points[0]);
Vec3D crossProduct = v1.cross(v2);
if(crossProduct.sqrAbs() > Consts::EPS)
if(crossProduct.sqrAbs() > Consts::EPS) {
return crossProduct.normalized();
else
} else {
return Vec3D(0);
}
}
Point4D Triangle::operator[](int i) const {
Vec4D Triangle::operator[](int i) const {
return _points[i];
}
@ -47,7 +39,8 @@ bool Triangle::isPointInside(const Vec3D &point) const {
double dot2 = (point - Vec3D(_points[1])).cross(Vec3D(_points[2] - _points[1])).dot(triangleNorm);
double dot3 = (point - Vec3D(_points[2])).cross(Vec3D(_points[0] - _points[2])).dot(triangleNorm);
if((dot1 >= 0 && dot2 >= 0 && dot3 >= 0) || (dot1 <= 0 && dot2 <= 0 && dot3 <= 0))
if((dot1 >= 0 && dot2 >= 0 && dot3 >= 0) || (dot1 <= 0 && dot2 <= 0 && dot3 <= 0)) {
return true;
}
return false;
}

View File

@ -5,7 +5,7 @@
#ifndef ENGINE_TRIANGLE_H
#define ENGINE_TRIANGLE_H
#include "Point4D.h"
#include "Vec4D.h"
#include "Vec3D.h"
#include "Matrix4x4.h"
#include <SFML/Graphics.hpp>
@ -13,14 +13,14 @@
class Triangle final {
private:
sf::Color _color;
std::vector<Point4D> _points;
Vec4D _points[3];
public:
Triangle ();
Triangle (const Triangle& triangle);
Triangle (const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color = {0, 0, 0});
Triangle& operator=(const Triangle&) = delete;
Triangle() : _points{Vec4D{}, Vec4D{}, Vec4D{}} {};
Triangle(const Triangle& triangle);
Triangle(const Vec4D& p1, const Vec4D& p2, const Vec4D& p3, sf::Color color = {0, 0, 0});
Triangle& operator=(const Triangle&) = default;
[[nodiscard]] Point4D operator[] (int i) const;
[[nodiscard]] Vec4D operator[] (int i) const;
[[nodiscard]] Vec3D norm() const;
// Operations with Matrix4x4

View File

@ -4,6 +4,7 @@
#include <cmath>
#include "Vec2D.h"
#include "Consts.h"
Vec2D::Vec2D(const Vec2D &vec) {
_arr_point[0] = vec.x();
@ -15,7 +16,7 @@ Vec2D::Vec2D (double x, double y) {
_arr_point[1] = y;
}
Vec2D::Vec2D(const Point4D &point4D) {
Vec2D::Vec2D(const Vec4D &point4D) {
_arr_point[0] = point4D.x();
_arr_point[1] = point4D.y();
}
@ -43,10 +44,11 @@ Vec2D Vec2D::operator*(double number) const {
}
Vec2D Vec2D::operator/(double number) const {
if(std::abs(number) > Consts::EPS)
return Vec2D(*this)*(1.0/number);
else
if(std::abs(number) > Consts::EPS) {
return Vec2D(*this) * (1.0 / number);
} else {
throw std::domain_error{"Vec2D::operator/(double number): division by zero"};
}
}
// Other useful methods
@ -60,10 +62,11 @@ double Vec2D::abs() const {
Vec2D Vec2D::normalized() const {
double vecAbs = abs();
if(vecAbs > Consts::EPS)
return Vec2D(*this)/abs();
else
if(vecAbs > Consts::EPS) {
return Vec2D(*this) / abs();
} else {
return Vec2D(0);
}
}
double Vec2D::dot(const Vec2D& vec) const {

View File

@ -5,9 +5,8 @@
#ifndef SHOOTER_VEC2D_H
#define SHOOTER_VEC2D_H
#include <array>
#include "Point4D.h"
#include "Vec4D.h"
class Vec2D final {
private:
@ -16,9 +15,9 @@ private:
public:
Vec2D () = default;
Vec2D (const Vec2D& vec);
explicit Vec2D (const Point4D& point4D);
explicit Vec2D (const Vec4D& point4D);
explicit Vec2D (double x, double y = 0.0);
Vec2D& operator=(const Vec2D&) = delete;
Vec2D& operator=(const Vec2D&) = default;
[[nodiscard]] double x() const { return _arr_point[0]; }
[[nodiscard]] double y() const { return _arr_point[1]; }

View File

@ -3,6 +3,7 @@
//
#include "Vec3D.h"
#include "Consts.h"
#include <cmath>
#include <stdexcept>
@ -12,7 +13,7 @@ Vec3D::Vec3D(const Vec3D &vec) {
_arr_point[2] = vec.z();
}
Vec3D::Vec3D (const Point4D& point4D) {
Vec3D::Vec3D (const Vec4D& point4D) {
_arr_point[0] = point4D.x();
_arr_point[1] = point4D.y();
_arr_point[2] = point4D.z();
@ -48,10 +49,11 @@ Vec3D Vec3D::operator*(double number) const {
}
Vec3D Vec3D::operator/(double number) const {
if(std::abs(number) > Consts::EPS)
return Vec3D(*this)*(1.0/number);
else
if(std::abs(number) > Consts::EPS) {
return Vec3D(*this) * (1.0 / number);
} else {
throw std::domain_error{"Vec3D::operator/(double number): division by zero"};
}
}
// Other useful methods
@ -65,10 +67,11 @@ double Vec3D::abs() const {
Vec3D Vec3D::normalized() const {
double vecAbs = abs();
if(vecAbs > Consts::EPS)
return Vec3D(*this)/abs();
else
if(vecAbs > Consts::EPS) {
return Vec3D(*this) / abs();
} else {
return Vec3D(1);
}
}
double Vec3D::dot(const Vec3D& vec) const {
@ -81,6 +84,6 @@ Vec3D Vec3D::cross(const Vec3D& vec) const {
x() * vec.y() - vec.x() * y()};
}
Point4D Vec3D::makePoint4D() const {
return Point4D(x(), y(), z(), 1.0);
Vec4D Vec3D::makePoint4D() const {
return Vec4D(x(), y(), z(), 1.0);
}

View File

@ -6,7 +6,7 @@
#define SHOOTER_VEC3D_H
#include <array>
#include "Point4D.h"
#include "Vec4D.h"
class Vec3D final {
private:
@ -15,9 +15,9 @@ private:
public:
Vec3D () = default;
Vec3D (const Vec3D& vec);
explicit Vec3D (const Point4D& vec);
explicit Vec3D (const Vec4D& vec);
explicit Vec3D (double x, double y = 0.0, double z = 0.0);
Vec3D& operator=(const Vec3D&) = delete;
Vec3D& operator=(const Vec3D&) = default;
[[nodiscard]] double x() const { return _arr_point[0]; }
[[nodiscard]] double y() const { return _arr_point[1]; }
@ -29,7 +29,7 @@ public:
bool operator==(const Vec3D& vec) const;
bool operator!=(const Vec3D& vec) const;
// Operations with Point4D
// Operations with Vec4D
[[nodiscard]] Vec3D operator+(const Vec3D& vec) const;
[[nodiscard]] Vec3D operator-(const Vec3D& vec) const;
@ -44,7 +44,7 @@ public:
[[nodiscard]] double sqrAbs() const; // Returns squared vector length
[[nodiscard]] double abs() const; // Returns vector length
[[nodiscard]] Vec3D normalized() const; // Returns normalized vector without changing
[[nodiscard]] Point4D makePoint4D() const;
[[nodiscard]] Vec4D makePoint4D() const;
};

73
engine/Vec4D.cpp Normal file
View File

@ -0,0 +1,73 @@
//
// Created by Иван Ильин on 12.01.2021.
//
#include "Vec4D.h"
#include "Consts.h"
#include <cmath>
#include <stdexcept>
Vec4D::Vec4D (double x, double y, double z, double w) {
_arr_point[0] = x;
_arr_point[1] = y;
_arr_point[2] = z;
_arr_point[3] = w;
}
Vec4D::Vec4D(const Vec4D &point4D) {
_arr_point[0] = point4D.x();
_arr_point[1] = point4D.y();
_arr_point[2] = point4D.z();
_arr_point[3] = point4D.w();
}
[[nodiscard]] Vec4D Vec4D::operator-() const {
return Vec4D(-x(), -y(), -z(), -w());
}
bool Vec4D::operator==(const Vec4D& point4D) const {
return (*this - point4D).sqrAbs() < Consts::EPS;
}
bool Vec4D::operator!=(const Vec4D& point4D) const {
return !(*this == point4D);
}
// Operations with Vec4D
Vec4D Vec4D::operator+(const Vec4D& point4D) const {
return Vec4D(x() + point4D.x(), y() + point4D.y(), z() + point4D.z(), w() + point4D.w());
}
Vec4D Vec4D::operator-(const Vec4D& point4D) const {
return Vec4D(*this) + -point4D;
}
Vec4D Vec4D::operator*(double number) const {
return Vec4D(x() * number, y() * number, z() * number, w() * number);
}
Vec4D Vec4D::operator/(double number) const {
if(std::abs(number) > Consts::EPS) {
return Vec4D(*this) * (1.0 / number);
} else {
throw std::domain_error{"Vec4D::operator/(double number): division by zero"};
}
}
// Other useful methods
double Vec4D::sqrAbs() const {
return x()*x() + y()*y() + z()*z();
}
double Vec4D::abs() const {
return sqrt(sqrAbs());
}
Vec4D Vec4D::normalized() const {
double vecAbs = abs();
if(vecAbs > Consts::EPS) {
return Vec4D(*this) / abs();
} else {
return Vec4D(1);
}
}

46
engine/Vec4D.h Normal file
View File

@ -0,0 +1,46 @@
//
// Created by Иван Ильин on 12.01.2021.
//
#ifndef ENGINE_POINT4D_H
#define ENGINE_POINT4D_H
#include <array>
class Vec4D final {
private:
std::array<double, 4> _arr_point{};
public:
Vec4D () = default;
Vec4D (const Vec4D& point4D);
explicit Vec4D (double x, double y = 0.0, double z = 0.0, double w = 0.0);
Vec4D& operator=(const Vec4D& point4D) = default;
[[nodiscard]] double x() const { return _arr_point[0]; }
[[nodiscard]] double y() const { return _arr_point[1]; }
[[nodiscard]] double z() const { return _arr_point[2]; }
[[nodiscard]] double w() const { return _arr_point[3]; }
[[nodiscard]] Vec4D operator-() const;
// Boolean operations
bool operator==(const Vec4D& point4D) const;
bool operator!=(const Vec4D& point4D) const;
// Operations with Vec4D
[[nodiscard]] Vec4D operator+(const Vec4D& point4D) const;
[[nodiscard]] Vec4D operator-(const Vec4D& point4D) const;
// Operations with numbers
[[nodiscard]] Vec4D operator*(double number) const;
[[nodiscard]] Vec4D operator/(double number) const;
// Other useful methods
[[nodiscard]] double sqrAbs() const; // Returns squared vector length
[[nodiscard]] double abs() const; // Returns vector length
[[nodiscard]] Vec4D normalized() const; // Returns normalized vector without changing
};
#endif //INC_3DZAVR_POINT4D_H

View File

@ -11,13 +11,13 @@
using namespace std;
void World::addBody(std::shared_ptr<RigidBody> body, const ObjectNameTag& tag) {
_objects.emplace(tag, body);
Log::log("World::addBody(): inserted body '" + tag.str() + "' with " + std::to_string(_objects[tag]->triangles().size()) + " tris.");
void World::addBody(std::shared_ptr<RigidBody> body) {
_objects.emplace(body->name(), body);
Log::log("World::addBody(): inserted body '" + body->name().str() + "' with " + std::to_string(_objects[body->name()]->triangles().size()) + " tris.");
}
void World::loadBody(const ObjectNameTag& tag, const string &filename, const Vec3D& scale) {
_objects.emplace(tag, std::make_shared<RigidBody>(Mesh(filename, scale)));
_objects.emplace(tag, std::make_shared<RigidBody>(Mesh(tag, filename, scale)));
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + tag.str() + "' with " + std::to_string(_objects[tag]->triangles().size()) + " tris.");
}
@ -30,20 +30,23 @@ IntersectionInformation World::rayCast(const Vec3D& from, const Vec3D& to, const
while (s >> t) tagsToSkip.push_back(t);
bool intersected = false;
std::unique_ptr<Vec3D> point = std::make_unique<Vec3D>();
std::unique_ptr<Triangle> triangle = std::make_unique<Triangle>();
Vec3D point{};
Triangle triangle;
std::string bodyName;
double minDistance = Consts::RAY_CAST_MAX_DISTANCE;
std::shared_ptr<RigidBody> intersectedBody = nullptr;
for(auto& [name, body] : _objects) {
// TODO: check this stuff:
//for (auto& escapeTag : tagsToSkip)
// if(name.str().find(escapeTag) != std::string::npos)
// continue;
if(name.str().find("Player") != std::string::npos || name.str().find("weapon") != std::string::npos)
if(name.str().find("Player") != std::string::npos || name.str().find("weapon") != std::string::npos) {
continue;
}
for(auto& tri : body->triangles()) {
Triangle tri_translated(tri[0] + body->position().makePoint4D(), tri[1] + body->position().makePoint4D(), tri[2] + body->position().makePoint4D());
@ -53,33 +56,32 @@ IntersectionInformation World::rayCast(const Vec3D& from, const Vec3D& to, const
double distance = (intersection.first - from).sqrAbs();
if(intersection.second > 0 && distance < minDistance && tri_translated.isPointInside(intersection.first)) {
minDistance = distance;
point = std::make_unique<Vec3D>(intersection.first);
triangle = std::make_unique<Triangle>(tri_translated);
point = intersection.first;
triangle = tri_translated;
bodyName = name.str();
intersected = true;
intersectedBody = body;
}
}
}
return IntersectionInformation{*point, sqrt(minDistance), *triangle, ObjectNameTag(bodyName), intersectedBody, intersected};
return IntersectionInformation{point, sqrt(minDistance), triangle, ObjectNameTag(bodyName), intersectedBody, intersected};
}
void World::loadMap(const std::string& filename, const Vec3D& scale) {
auto objs = ResourceManager::loadObjects(filename);
for(unsigned i = 0; i < objs.size(); i++) {
ObjectNameTag meshName = ObjectNameTag("map_" + to_string(i));
addBody(std::make_shared<RigidBody>(*objs[i]), meshName);
body(meshName)->scale(scale);
for(auto & i : objs) {
std::shared_ptr<RigidBody> obj = std::make_shared<RigidBody>(*i);
addBody(obj);
obj->scale(scale);
}
auto it = _objects.begin();
}
void World::removeBody(const ObjectNameTag& tag) {
if(_objects.erase(tag) > 0)
if(_objects.erase(tag) > 0) {
Log::log("World::removeBody(): removed body '" + tag.str() + "'");
else
} else {
Log::log("World::removeBody(): cannot remove body '" + tag.str() + "': body does not exist.");
}
}
void World::checkCollision(const ObjectNameTag& tag) {
@ -88,7 +90,6 @@ void World::checkCollision(const ObjectNameTag& tag) {
_objects[tag]->setInCollision(false);
for (auto it = _objects.begin(); it != _objects.end();) {
auto obj = it->second;
ObjectNameTag name = it->first;
it++;
@ -100,12 +101,13 @@ void World::checkCollision(const ObjectNameTag& tag) {
CollisionPoint epa = _objects[tag]->EPA(gjk.second, obj);
_objects[tag]->solveCollision(epa);
}
if (_objects[tag]->collisionCallBack() != nullptr)
if (_objects[tag]->collisionCallBack() != nullptr) {
_objects[tag]->collisionCallBack()(name, obj);
}
}
}
}
}
}
void World::update() {
@ -116,7 +118,8 @@ void World::update() {
}
std::shared_ptr<RigidBody> World::body(const ObjectNameTag& tag) {
if(_objects.count(tag) == 0)
if(_objects.count(tag) == 0) {
return nullptr;
}
return _objects.find(tag)->second;
}

View File

@ -28,7 +28,7 @@ public:
void checkCollision(const ObjectNameTag& tag);
void update();
void addBody(std::shared_ptr<RigidBody> mesh, const ObjectNameTag& tag);
void addBody(std::shared_ptr<RigidBody> mesh);
std::shared_ptr<RigidBody> body(const ObjectNameTag& tag);
void removeBody(const ObjectNameTag& tag);
void loadBody(const ObjectNameTag& tag, const std::string &filename, const Vec3D& scale = Vec3D{1, 1, 1});

View File

@ -5,38 +5,38 @@
#ifndef ENGINE_ACOLOR_H
#define ENGINE_ACOLOR_H
#include <utility>
#include "Animation.h"
#include "../Mesh.h"
class AColor final : public Animation {
private:
std::shared_ptr<Mesh> _mesh;
const std::weak_ptr<Mesh> _mesh;
sf::Color newColor;
sf::Color startColor;
sf::Color _startColor;
const sf::Color _newColor;
bool _started = false;
public:
AColor(std::shared_ptr<Mesh> mesh, const sf::Color &color, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::linear) {
_mesh = mesh;
_duration = duration;
_looped = looped;
_intType = interpolationType;
_waitFor = true;
newColor = color;
void update() override {
if(_mesh.expired()) {
stop();
return;
}
bool update() override {
if(!_started)
startColor = _mesh->color();
if(!_started) {
_started = true;
_startColor = _mesh.lock()->color();
}
Point4D start(startColor.r, startColor.g, startColor.b, startColor.a);
Point4D end(newColor.r, newColor.g, newColor.b, newColor.a);
Point4D mid = start + (end - start)*_p;
Vec4D start(_startColor.r, _startColor.g, _startColor.b, _startColor.a);
Vec4D end(_newColor.r, _newColor.g, _newColor.b, _newColor.a);
Vec4D mid = start + (end - start) * progress();
_mesh->setColor(sf::Color(static_cast<sf::Uint8>(mid.x()), static_cast<sf::Uint8>(mid.y()), static_cast<sf::Uint8>(mid.z()), static_cast<sf::Uint8>(mid.w())));
return updateState();
_mesh.lock()->setColor(sf::Color(static_cast<sf::Uint8>(mid.x()), static_cast<sf::Uint8>(mid.y()), static_cast<sf::Uint8>(mid.z()), static_cast<sf::Uint8>(mid.w())));
}
public:
AColor(std::weak_ptr<Mesh> mesh, const sf::Color &color, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Linear) : Animation(duration, looped, interpolationType), _mesh(std::move(mesh)), _newColor(color) {
}
};

View File

@ -2,34 +2,27 @@
// Created by Иван Ильин on 06.04.2021.
//
#include <utility>
#include "Animation.h"
#ifndef ENGINE_AFUNCTION_H
#define ENGINE_AFUNCTION_H
#include <utility>
#include "Animation.h"
class AFunction final : public Animation {
private:
int _calls = 0;
int _allCalls = 1;
std::function<void()> _callBack;
int _callsCounter = 0;
const int _allCalls = 1;
const std::function<void()> _callBack;
public:
explicit AFunction(std::function<void()> function, int calls = 1, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::linear) {
_callBack = std::move(function);
_allCalls = calls;
_duration = duration;
_looped = looped;
_intType = interpolationType;
}
bool update() override {
if(_allCalls != 0 && _p >= (double)(_calls + 1) / (_allCalls + 1)) {
_calls++;
void update() override {
if(_allCalls != 0 && progress() >= (double)(_callsCounter + 1) / (_allCalls + 1)) {
_callsCounter++;
_callBack();
}
return updateState();
}
public:
explicit AFunction(std::function<void()> function, int calls = 1, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Linear) : Animation(duration, looped, interpolationType), _callBack(std::move(function)), _allCalls(calls) {
}
};

View File

@ -5,25 +5,26 @@
#ifndef ENGINE_AROTATE_H
#define ENGINE_AROTATE_H
#include <utility>
#include "Animation.h"
#include "../Object.h"
class ARotate final : public Animation {
private:
std::shared_ptr<Object> _object;
const std::weak_ptr<Object> _object;
const Vec3D _rotationValue;
Vec3D value;
public:
ARotate(std::shared_ptr<Object> object, const Vec3D& r, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : value(r) {
_object = object;
_duration = duration;
_looped = looped;
_intType = interpolationType;
void update() override {
if(_object.expired()) {
stop();
return;
}
bool update() override {
_object->rotate(value * _dp);
return updateState();
_object.lock()->rotate(_rotationValue * dprogress());
}
public:
ARotate(std::weak_ptr<Object> object, const Vec3D& r, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped, interpolationType), _object(std::move(object)), _rotationValue(r) {
}
};

View File

@ -5,36 +5,32 @@
#ifndef ENGINE_ASCALE_H
#define ENGINE_ASCALE_H
#include "Animatable.h"
#include <utility>
#include "Animation.h"
#include "Mesh.h"
#include "../physics/RigidBody.h"
class AScale final : public Animation {
private:
std::shared_ptr<Mesh> _mesh;
const std::weak_ptr<RigidBody> _object;
const Vec3D _scalingValue;
Vec3D value;
std::vector<Triangle> triangles{};
public:
AScale(std::shared_ptr<Mesh> mesh, const Vec3D &s, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : value(s) {
_mesh = mesh;
_duration = duration;
_looped = looped;
_intType = interpolationType;
_waitFor = true;
void update() override {
if(_object.expired()) {
stop();
return;
}
bool update() override {
if(!_started)
triangles = _mesh->triangles();
std::vector<Triangle> newTriangles;
for(auto &t : triangles) {
newTriangles.emplace_back(t * Matrix4x4::Scale(Point4D{1, 1, 1} + (value - Point4D{1, 1, 1}) * _p));
for(auto &t : _object->triangles()) {
newTriangles.emplace_back(t * Matrix4x4::Scale(Vec3D{1, 1, 1} + (_scalingValue - Vec3D{1, 1, 1}) * progress()));
}
_mesh->setTriangles(newTriangles);
_object.lock()->setTriangles(newTriangles);
return updateState();
}
public:
AScale(std::weak_ptr<RigidBody> object, const Vec3D &s, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped, interpolationType), _object(object), _scalingValue(s) {
}
};
#endif //INC_3DZAVR_ASCALE_H

View File

@ -5,25 +5,26 @@
#ifndef ENGINE_ATRANSLATE_H
#define ENGINE_ATRANSLATE_H
#include <utility>
#include "Animation.h"
#include "../Object.h"
class ATranslate final : public Animation {
private:
std::shared_ptr<Object> _object;
const std::weak_ptr<Object> _object;
const Vec3D _translationValue;
Vec3D value;
public:
ATranslate(std::shared_ptr<Object> object, const Vec3D& t, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : value(t){
_object = object;
_duration = duration;
_looped = looped;
_intType = interpolationType;
void update() override {
if(_object.expired()) {
stop();
return;
}
bool update() override {
_object->translate(value * _dp);
return updateState();
_object.lock()->translate(_translationValue * dprogress());
}
public:
ATranslate(std::weak_ptr<Object> object, const Vec3D& t, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped, interpolationType), _object(std::move(object)), _translationValue(t){
}
};

View File

@ -5,30 +5,33 @@
#ifndef ENGINE_ATRANSLATETOPOINT_H
#define ENGINE_ATRANSLATETOPOINT_H
#include <utility>
#include "Animation.h"
#include "../Object.h"
class ATranslateToPoint final : public Animation {
private:
std::shared_ptr<Object> _object;
const std::weak_ptr<Object> _object;
const Vec3D _targetPoint;
Vec3D _translationValue;
Vec3D point;
std::unique_ptr<Vec3D> value;
public:
ATranslateToPoint(std::shared_ptr<Object> object, const Vec3D& p, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : point(p) {
_object = object;
_duration = duration;
_looped = looped;
_intType = interpolationType;
bool _started = false;
void update() override {
if(_object.expired()) {
stop();
return;
}
bool update() override {
if(!_started) {
value = std::make_unique<Vec3D>(point - _object->position());
_started = true;
_translationValue = _targetPoint - _object.lock()->position();
}
_object->translate(*value * _dp);
return updateState();
_object.lock()->translate(_translationValue * dprogress());
}
public:
ATranslateToPoint(std::weak_ptr<Object> object, const Vec3D& p, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped, interpolationType), _targetPoint(p), _object(object) {
}
};

View File

@ -8,15 +8,10 @@
#include "Animation.h"
class AWait final : public Animation {
private:
void update() override{}
public:
explicit AWait(double duration = 1) {
_duration = duration;
_intType = InterpolationType::linear;
_waitFor = true;
}
bool update() override {
return updateState();
explicit AWait(double duration = 1) : Animation(duration, LoopOut::None, InterpolationType::Linear, true) {
}
};

View File

@ -4,37 +4,44 @@
#include "Animation.h"
Animation::Animation(double duration, Animation::LoopOut looped, Animation::InterpolationType intType, bool waitFor) : _duration(duration), _looped(looped), _intType(intType), _waitFor(waitFor) {
}
bool Animation::updateState() {
if(!_started) {
_started = true;
return _duration != 0;
if(_finished || std::abs(_duration) < Consts::EPS) {
return false;
}
// linear normalized time:
_dtime = Time::deltaTime()/_duration;
_time += _dtime;
if(_looped == LoopOut::Continue && _time > 0.5)
if(_looped == LoopOut::Continue && _time > 0.5) {
_time = 0.5;
}
switch (_intType) {
case InterpolationType::bezier:
_p = Interpolation::Bezier(*_bezier[0], *_bezier[1], _time);
_dp = Interpolation::dBezier(*_bezier[0], *_bezier[1], _time, _dtime);
case InterpolationType::Bezier:
_progress = Interpolation::Bezier(Consts::BEZIER[0], Consts::BEZIER[1], _time);
_dprogress = Interpolation::dBezier(Consts::BEZIER[0], Consts::BEZIER[1], _time, _dtime);
break;
case InterpolationType::bouncing:
_p = Interpolation::Bouncing(_time);
_dp = Interpolation::dBouncing(_time, _dtime);
case InterpolationType::Bouncing:
_progress = Interpolation::Bouncing(_time);
_dprogress = Interpolation::dBouncing(_time, _dtime);
break;
case InterpolationType::linear:
_p = Interpolation::Linear(_time);
_dp = Interpolation::dLinear(_time, _dtime);
case InterpolationType::Linear:
_progress = Interpolation::Linear(_time);
_dprogress = Interpolation::dLinear(_time, _dtime);
break;
case InterpolationType::cos:
_p = Interpolation::Cos(_time);
_dp = Interpolation::dCos(_time, _dtime);
case InterpolationType::Cos:
_progress = Interpolation::Cos(_time);
_dprogress = Interpolation::dCos(_time, _dtime);
break;
default:
throw std::logic_error{"Animation::updateState: unknown interpolation type " + std::to_string(static_cast<int>(_intType))};
}
update();
return (_time < 1) || _looped == LoopOut::Cycle;
}

View File

@ -13,48 +13,45 @@
class Animation {
public:
enum class InterpolationType {
linear,
cos,
bezier,
bouncing
Linear,
Cos,
Bezier,
Bouncing
};
enum class LoopOut {
None,
Cycle,
Continue
};
protected:
double _time = 0; // normalized time (from 0 to 1)
private:
// normalized time (from 0 to 1)
double _time = 0;
double _dtime = 0;
double _duration = 0;
bool _started = false;
LoopOut _looped = LoopOut::None;
// _p - animation progress
double _p = 0;
double _dp = 0;
bool _finished = false;
InterpolationType _intType = InterpolationType::bezier;
std::unique_ptr<Vec2D> _bezier[2] = {std::make_unique<Vec2D>(Vec2D{0.8, 0}),
std::make_unique<Vec2D>(Vec2D{0.2, 1})};
double _progress = 0;
double _dprogress = 0;
// If '_waitFor' == true then we need to finish all animation before starting this one. (for example for a_wait() or a_scale())
bool _waitFor = false;
bool updateState();
public:
Animation() = default;
virtual ~Animation() = default;
void setBezierPoints(const Vec2D& p1, const Vec2D& p2) {
_bezier[0] = std::make_unique<Vec2D>(p1);
_bezier[1] = std::make_unique<Vec2D>(p2);
}
[[nodiscard]] bool waitFor() const { return _waitFor; }
const bool _waitFor = false;
const double _duration = 0;
const LoopOut _looped = LoopOut::None;
const InterpolationType _intType = InterpolationType::Bezier;
// You should override this method for your particular animation
virtual bool update() = 0;
virtual void update() = 0;
public:
Animation(double duration, LoopOut looped, InterpolationType intType, bool _waitFor = false);
virtual ~Animation() = default;
[[nodiscard]] bool waitFor() const { return _waitFor; }
bool updateState();
[[nodiscard]] double progress() const { return _progress; }
[[nodiscard]] double dprogress() const { return _dprogress; }
void stop() { _finished = true;}
};
#endif //INC_3DZAVR_ANIMATION_H

View File

@ -22,8 +22,6 @@ namespace Interpolation {
static double dBouncing(double t, double dt);
};
double Interpolation::Linear(double t) {
if(t < 0)
t = -t;

View File

@ -13,65 +13,74 @@ void Timeline::init() {
}
void Timeline::animate(const AnimationListTag& listName, Animation* anim) {
if(!_instance)
if(!_instance) {
return;
}
_instance->_animations[listName].emplace_back(anim);
}
void Timeline::deleteAllAnimations() {
if(!_instance)
if(!_instance) {
return;
}
for (auto& [listName, animationList] : _instance->_animations) {
auto it = animationList.begin();
while(it != animationList.end())
while(it != animationList.end()) {
delete *(it++);
}
animationList.clear();
}
_instance->_animations.clear();
}
void Timeline::deleteAnimationList(const AnimationListTag& listName) {
if(!_instance)
if(!_instance) {
return;
}
_instance->_animations[listName].clear();
_instance->_animations.erase(listName);
}
[[nodiscard]] bool Timeline::isInAnimList(const AnimationListTag& listName) {
if(!_instance)
if(!_instance) {
return false;
}
return !_instance->_animations[listName].empty();
}
void Timeline::update() {
if(!_instance)
if(!_instance) {
return;
}
for (auto& [listName, animationList] : _instance->_animations) {
if (animationList.empty())
if (animationList.empty()) {
continue;
}
auto it = animationList.begin();
// If it the front animation is 'a_wait()' we should wait until waiting time is over
if (it.operator*()->waitFor()) {
if (!it.operator*()->update())
if (!it.operator*()->updateState()) {
animationList.erase(it);
}
continue;
}
// Otherwise we iterate over all animation until we meet animations.end() or wait animation
while (!animationList.empty() && (it != animationList.end()) && (!it.operator*()->waitFor())) {
if (!it.operator*()->update())
if (!it.operator*()->updateState()) {
animationList.erase(it++);
else
} else {
it++;
}
}
}
}
void Timeline::free() {

View File

@ -9,8 +9,7 @@
void Button::select()
{
if (!_selected && !_pressed)
{
if (!_selected && !_pressed) {
_button.setTextureRect(sf::IntRect(_selectedState.tx, _selectedState.ty, _w, _h));
_selected = true;
}
@ -18,8 +17,7 @@ void Button::select()
void Button::unSelect()
{
if (_selected && !_pressed)
{
if (_selected && !_pressed) {
_button.setTextureRect(sf::IntRect(_usualState.tx, _usualState.ty, _w, _h));
_selected = false;
}
@ -27,20 +25,18 @@ void Button::unSelect()
void Button::press()
{
if (!_pressed)
{
if (!_pressed) {
_button.setTextureRect(sf::IntRect(_pressedState.tx, _pressedState.ty, _w, _h));
if(_checkBox)
if(_checkBox) {
_pressed = true;
//_clickSound.play();
_click();
}
else
{
_click();
} else {
_button.setTextureRect(sf::IntRect(_usualState.tx, _usualState.ty, _w, _h));
if(_checkBox)
if(_checkBox) {
_pressed = false;
}
}
}
void Button::init() {
@ -54,9 +50,6 @@ void Button::init() {
_text.setCharacterSize((unsigned int)(_h * _sy / 2));
_text.setFillColor(_textColor);
_text.setPosition((float)(_x - _text.getLocalBounds().width / 2), (float)(_y - _h * _sy / 2 + _text.getLocalBounds().height / 4));
//_clickSound.setBuffer(*ResourceManager::loadSoundBuffer(_clickSoundName));
//_clickSound.setVolume(15);
}
Button::Button(int x, int y, int width, int height, std::function<void()> click, std::string text, double sx,

View File

@ -16,26 +16,26 @@ struct tPos final {
class Button final {
private:
int _x{};
int _y{};
const int _x{};
const int _y{};
int _w{};
int _h{};
const int _w{};
const int _h{};
std::function<void()> _click;
const std::function<void()> _click;
std::string _textString;
const std::string _textString;
double _sx{};
double _sy{};
const double _sx{};
const double _sy{};
std::string _texture;
tPos _usualState{};
tPos _selectedState{};
tPos _pressedState{};
const std::string _texture;
const tPos _usualState{};
const tPos _selectedState{};
const tPos _pressedState{};
std::string _font;
sf::Color _textColor;
const std::string _font;
const sf::Color _textColor;
sf::Sprite _button;
sf::Text _text;

View File

@ -10,7 +10,7 @@
void Window::addButton(int x, int y, int w, int h, std::function<void()> click, const std::string &text, double sx, double sy,
const std::string &texture, tPos usualState, tPos selectedState, tPos pressedState,
const std::string& font, sf::Color textColor) {
_buttons.push_back(Button{x, y, w, h, std::move(click), text, sx, sy, texture, usualState, selectedState, pressedState, font, textColor});
_buttons.emplace_back(x, y, w, h, std::move(click), text, sx, sy, texture, usualState, selectedState, pressedState, font, textColor);
_buttons.back().init();
}
@ -20,7 +20,7 @@ void Window::update() {
_screen->drawSprite(_back);
Vec2D mousePos = _mouse->getMousePosition();
Vec2D dMousePos = mousePos - *_prevMousePosition;
Vec2D dMousePos = mousePos - _prevMousePosition;
_back.setPosition(_back.getPosition() - sf::Vector2f((float)(dMousePos.x() / 30), (float)(dMousePos.y() / 30)));
bool isPressed = _mouse->isButtonTapped(sf::Mouse::Left);
@ -40,7 +40,7 @@ void Window::update() {
}
}
_prevMousePosition = std::make_unique<Vec2D>(mousePos);
_prevMousePosition = mousePos;
}
void Window::setBackgroundTexture(const std::string &texture, double sx, double sy, int w, int h) {

View File

@ -20,12 +20,12 @@ private:
sf::Sprite _back;
std::unique_ptr<Vec2D> _prevMousePosition = std::make_unique<Vec2D>(Vec2D{0, 0});
Vec2D _prevMousePosition{0, 0};
std::shared_ptr<Screen> _screen;
std::shared_ptr<Mouse> _mouse;
public:
explicit Window(std::shared_ptr<Screen> screen, std::shared_ptr<Mouse> mouse, std::string name = "Menu", std::string backTexture = "") : _screen(screen), _mouse(mouse), _name(std::move(name)), _backTexture(std::move(backTexture)){}
explicit Window(std::shared_ptr<Screen> screen, std::shared_ptr<Mouse> mouse, std::string name = "Menu", std::string backTexture = "") : _screen(std::move(screen)), _mouse(std::move(mouse)), _name(std::move(name)), _backTexture(std::move(backTexture)){}
void addButton(int x, int y, int w, int h,
std::function<void()> click,
@ -33,8 +33,7 @@ public:
const std::string& texture = "", tPos usualState = {}, tPos selectedState = {}, tPos pressedState = {},
const std::string& font = Consts::MEDIUM_FONT, sf::Color textColor = {255, 255, 255});
[[nodiscard]] std::string title() const { return _name; }
void title(const std::string& title) { _name = title; }
void setTitle(const std::string& title) { _name = title; }
void setBackgroundTexture(const std::string& texture, double sx = 1, double sy = 1, int w = 1920, int h = 1080);

View File

@ -93,8 +93,7 @@ bool ClientUDP::process()
if (!connected() && type != MsgType::Init)
return true;
switch (type)
{
switch (type) {
// here we process any operations based on msg type
case MsgType::Init:
packet >> targetId;
@ -104,7 +103,7 @@ bool ClientUDP::process()
processInit(packet);
break;
case MsgType::Update:
case MsgType::ServerUpdate:
processUpdate(packet);
break;
@ -123,8 +122,14 @@ bool ClientUDP::process()
processDisconnect(targetId);
break;
case MsgType::Custom:
processCustomPacket(packet);
break;
case MsgType::Error:
Log::log("ClientUDP::process(): Error message");
break;
default:
processCustomPacket(type, packet);
Log::log("ClientUDP::process(): unknown message type " + std::to_string(static_cast<int>(type)));
}
return true;

View File

@ -31,8 +31,8 @@ public:
void disconnect();
void update();
[[nodiscard]] sf::IpAddress ip() const { return _ip; }
[[nodiscard]] sf::Uint16 port() const { return _port; }
[[nodiscard]] sf::IpAddress serverIp() const { return _ip; }
[[nodiscard]] sf::Uint16 serverPort() const { return _port; }
// virtual functions
virtual void updatePacket(){};
@ -42,7 +42,7 @@ public:
virtual void processNewClient(sf::Packet& packet){};
virtual void processDisconnect(sf::Uint16 targetId){};
virtual void processCustomPacket(MsgType type, sf::Packet& packet){};
virtual void processCustomPacket(sf::Packet& packet){};
virtual void processDisconnected(){};

View File

@ -18,18 +18,12 @@ enum class MsgType
Connect, // connection (client ---> server)
Disconnect, // disconnect (client <==> server)
Init, // initialization (client <--- server)
Update, // update (client <--- server)
ServerUpdate, // update (client <--- server)
ClientUpdate, // update (client ---> server)
NewClient, // add new client (client <--- server)
// custom
Damage,
Kill,
FireTrace,
InitBonuses,
AddBonus,
RemoveBonus,
ChangeWeapon,
// this is for higher level clients & servers
Custom,
};
sf::Packet& operator<<(sf::Packet& packet, MsgType type);

View File

@ -12,10 +12,10 @@ ReliableMsg::ReliableMsg(const ReliableMsg& msg) : packet(msg.packet), address(m
bool ReliableMsg::trySend(sf::UdpSocket& socket)
{
if (Time::time() - firstTry > Consts::NETWORK_TIMEOUT)
if (Time::time() - firstTry > Consts::NETWORK_TIMEOUT) {
return false;
if (Time::time() - lastTry > Consts::NETWORK_RELIABLE_RETRY_TIME)
{
}
if (Time::time() - lastTry > Consts::NETWORK_RELIABLE_RETRY_TIME) {
lastTry = Time::time();
socket.send(packet, address, port);
}

View File

@ -7,14 +7,13 @@
#include <SFML/Network.hpp>
class ReliableMsg final
{
class ReliableMsg final {
private:
sf::Packet packet;
sf::IpAddress address;
sf::Uint16 port;
const sf::IpAddress address;
const sf::Uint16 port;
const double firstTry;
double lastTry;
double firstTry;
public:
ReliableMsg(sf::Packet& packet, sf::IpAddress address, sf::Uint16 port);

View File

@ -7,32 +7,31 @@
#include "../utils/Log.h"
#include <cmath>
ServerUDP::ServerUDP() : _lastBroadcast(-std::numeric_limits<double>::max()), _working(false)
{
ServerUDP::ServerUDP() : _lastBroadcast(-std::numeric_limits<double>::max()), _working(false) {
// TODO: replace this with lambda:
_socket.setTimeoutCallback(std::bind(&ServerUDP::timeout, this, std::placeholders::_1));
}
bool ServerUDP::isWorking() const
{
bool ServerUDP::isWorking() const {
return _working;
}
bool ServerUDP::start(sf::Uint16 port)
{
bool ServerUDP::start(sf::Uint16 port) {
_working = _socket.bind(port);
if(_working)
if(_working) {
Log::log("ServerUDP::start(): the server was successfully started.");
else
} else {
Log::log("ServerUDP::start(): failed to start the server.");
}
return _working;
}
void ServerUDP::update()
{
if (!isWorking())
void ServerUDP::update() {
if (!isWorking()) {
return;
}
while (process());
@ -48,10 +47,8 @@ void ServerUDP::update()
updateInfo();
}
void ServerUDP::stop()
{
for (auto it = _clients.begin(); it != _clients.end();)
{
void ServerUDP::stop() {
for (auto it = _clients.begin(); it != _clients.end();) {
sf::Packet packet;
packet << MsgType::Disconnect << *it;
_socket.send(packet, *it);
@ -66,15 +63,15 @@ void ServerUDP::stop()
Log::log("ServerUDP::stop(): the server was killed.");
}
bool ServerUDP::timeout(sf::Uint16 playerId)
{
bool ServerUDP::timeout(sf::Uint16 playerId) {
sf::Packet packet;
packet << MsgType::Disconnect << playerId;
_clients.erase(playerId);
for (auto client : _clients)
for (auto client : _clients) {
_socket.sendRely(packet, client);
}
Log::log("ServerUDP::timeout(): client Id = " + std::to_string(playerId) + " disconnected due to timeout.");
processDisconnect(playerId);
@ -84,21 +81,20 @@ bool ServerUDP::timeout(sf::Uint16 playerId)
// Recive and process message.
// Returns true, if some message was received.
bool ServerUDP::process()
{
bool ServerUDP::process() {
sf::Packet packet;
sf::Packet sendPacket;
sf::Uint16 senderId;
MsgType type = _socket.receive(packet, senderId);
if (type == MsgType::Empty)
if (type == MsgType::Empty) {
return false;
}
switch (type) {
// here we process any operations based on msg type
case MsgType::Connect:
Log::log("ServerUDP::process(): client Id = " + std::to_string(senderId) + " connecting...");
processConnect(senderId);
@ -113,13 +109,20 @@ bool ServerUDP::process()
sendPacket << MsgType::Disconnect << senderId;
_clients.erase(senderId);
_socket.removeConnection(senderId);
for (auto client : _clients)
for (auto client : _clients) {
_socket.sendRely(sendPacket, client);
}
processDisconnect(senderId);
break;
case MsgType::Custom:
processCustomPacket(packet, senderId);
break;
case MsgType::Error:
Log::log("ServerUDP::process(): Error message");
break;
default:
processCustomPacket(type, packet, senderId);
Log::log("ServerUDP::process(): message type " + std::to_string(static_cast<int>(type)));
}
return true;

View File

@ -40,7 +40,7 @@ public:
virtual void processClientUpdate(sf::Uint16 senderId, sf::Packet& packet){};
virtual void processDisconnect(sf::Uint16 senderId){};
virtual void processCustomPacket(MsgType type, sf::Packet& packet, sf::Uint16 senderId){};
virtual void processCustomPacket(sf::Packet& packet, sf::Uint16 senderId){};
virtual void processStop(){};

View File

@ -8,37 +8,30 @@
UDPConnection::UDPConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port) : _id(id), _ip(ip), _port(port), lastMsg(Time::time()) {}
sf::Uint16 UDPConnection::id() const
{
sf::Uint16 UDPConnection::id() const {
return _id;
}
const sf::IpAddress& UDPConnection::ip() const
{
const sf::IpAddress& UDPConnection::ip() const {
return _ip;
}
sf::Uint16 UDPConnection::port() const
{
sf::Uint16 UDPConnection::port() const {
return _port;
}
bool UDPConnection::timeout() const
{
bool UDPConnection::timeout() const {
return Time::time() - lastMsg > Consts::NETWORK_TIMEOUT;
}
bool UDPConnection::same(sf::IpAddress& ip, sf::Uint16 port) const
{
bool UDPConnection::same(sf::IpAddress& ip, sf::Uint16 port) const {
return _ip == ip && _port == port;
}
void UDPConnection::update()
{
void UDPConnection::update() {
lastMsg = Time::time();
}
void UDPConnection::send(sf::UdpSocket& socket, sf::Packet& packet)
{
void UDPConnection::send(sf::UdpSocket& socket, sf::Packet& packet) {
socket.send(packet, _ip, _port);
}

View File

@ -9,9 +9,9 @@
class UDPConnection final {
private:
sf::Uint16 _id;
sf::IpAddress _ip;
sf::Uint16 _port;
const sf::Uint16 _id;
const sf::IpAddress _ip;
const sf::Uint16 _port;
double lastMsg;
public:

View File

@ -7,28 +7,23 @@
#include <algorithm>
#include "../Consts.h"
UDPSocket::UDPSocket() : _ownId(0), _nextRelyMsgId(0)
{
UDPSocket::UDPSocket() : _ownId(0), _nextRelyMsgId(0) {
_socket.setBlocking(false);
}
void UDPSocket::addConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port)
{
void UDPSocket::addConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port) {
_connections.insert({ id, UDPConnection(id, ip, port) });
}
void UDPSocket::removeConnection(sf::Uint16 id)
{
void UDPSocket::removeConnection(sf::Uint16 id) {
_connections.erase(id);
}
bool UDPSocket::bind(sf::Uint16 port)
{
bool UDPSocket::bind(sf::Uint16 port) {
return _socket.bind(port) == sf::Socket::Status::Done;
}
void UDPSocket::unbind()
{
void UDPSocket::unbind() {
sf::Packet packet;
packet << MsgType::Disconnect << _ownId;
@ -44,143 +39,133 @@ void UDPSocket::unbind()
setId(0);
}
void UDPSocket::setTimeoutCallback(std::function<bool(sf::Uint16)> callback)
{
void UDPSocket::setTimeoutCallback(std::function<bool(sf::Uint16)> callback) {
_timeoutCallback = std::move(callback);
}
void UDPSocket::clearTimeoutCallback()
{
_timeoutCallback = nullptr;
}
void UDPSocket::setId(sf::Uint16 id)
{
void UDPSocket::setId(sf::Uint16 id) {
_ownId = id;
}
sf::Uint16 UDPSocket::ownId() const
{
sf::Uint16 UDPSocket::ownId() const {
return _ownId;
}
sf::Uint16 UDPSocket::serverId() const
{
sf::Uint16 UDPSocket::serverId() const {
return _serverId;
}
void UDPSocket::sendRely(const sf::Packet& packet, const sf::IpAddress& ip, sf::Uint16 port)
{
void UDPSocket::sendRely(const sf::Packet& packet, const sf::IpAddress& ip, sf::Uint16 port) {
sf::Packet finalPacket;
finalPacket << _ownId << true << _nextRelyMsgId;
finalPacket.append(packet.getData(), packet.getDataSize());
_relyPackets.insert({ _nextRelyMsgId++, ReliableMsg(finalPacket, ip, port) });
}
void UDPSocket::sendRely(const sf::Packet& packet, sf::Uint16 id)
{
if (!_connections.count(id))
void UDPSocket::sendRely(const sf::Packet& packet, sf::Uint16 id) {
if (!_connections.count(id)) {
return;
}
this->sendRely(packet, _connections.at(id).ip(), _connections.at(id).port());
}
void UDPSocket::send(const sf::Packet& packet, const sf::IpAddress& ip, sf::Uint16 port)
{
void UDPSocket::send(const sf::Packet& packet, const sf::IpAddress& ip, sf::Uint16 port) {
sf::Packet finalPacket;
finalPacket << _ownId << false << _serverId;
finalPacket.append(packet.getData(), packet.getDataSize());
_socket.send(finalPacket, ip, port);
}
void UDPSocket::send(const sf::Packet& packet, sf::Uint16 id)
{
if (!_connections.count(id))
void UDPSocket::send(const sf::Packet& packet, sf::Uint16 id) {
if (!_connections.count(id)) {
return;
}
this->send(packet, _connections.at(id).ip(), _connections.at(id).port());
}
void UDPSocket::update()
{
for (auto it = _connections.begin(); it != _connections.end();)
{
if (!it->second.timeout())
void UDPSocket::update() {
for (auto it = _connections.begin(); it != _connections.end();) {
if (!it->second.timeout()) {
++it;
else
{
if (_timeoutCallback && !_timeoutCallback(it->first))
} else {
if (_timeoutCallback && !_timeoutCallback(it->first)) {
return;
}
_connections.erase(it++);
}
}
for (auto it = _relyPackets.begin(); it != _relyPackets.end();)
{
if (!it->second.trySend(_socket))
for (auto it = _relyPackets.begin(); it != _relyPackets.end();) {
if (!it->second.trySend(_socket)) {
_relyPackets.erase(it++);
else
} else {
++it;
}
}
for (auto it = _confirmTimes.begin(); it != _confirmTimes.end();)
{
if (Time::time() - it->second > Consts::NETWORK_TIMEOUT)
for (auto it = _confirmTimes.begin(); it != _confirmTimes.end();) {
if (Time::time() - it->second > Consts::NETWORK_TIMEOUT) {
_confirmTimes.erase(it++);
else
} else {
++it;
}
}
}
MsgType UDPSocket::receive(sf::Packet& packet, sf::Uint16& senderId)
{
MsgType UDPSocket::receive(sf::Packet& packet, sf::Uint16& senderId) {
// Receive message
sf::IpAddress ip;
sf::Uint16 port;
packet.clear();
if (_socket.receive(packet, ip, port) != sf::Socket::Status::Done)
if (_socket.receive(packet, ip, port) != sf::Socket::Status::Done) {
return MsgType::Empty;
}
// Read header
bool reply = false;
sf::Uint16 msgId = 0;
MsgType type;
senderId = 0;
if (!(packet >> senderId >> reply >> msgId >> type))
if (!(packet >> senderId >> reply >> msgId >> type)) {
return MsgType::Error;
if (_connections.count(senderId))
_connections.at(senderId).update();
if (type == MsgType::Confirm)
{
_relyPackets.erase(msgId);
return MsgType::Confirm;
}
if (type == MsgType::Connect)
{
if (_connections.count(senderId)) {
_connections.at(senderId).update();
}
if (type == MsgType::Confirm) {
_relyPackets.erase(msgId);
// you don't need this information on the highest levels
return MsgType::Empty;
}
if (type == MsgType::Connect) {
sf::Uint32 version = 0;
if (!(packet >> version) || version != Consts::NETWORK_VERSION)
if (!(packet >> version) || version != Consts::NETWORK_VERSION) {
return MsgType::Error;
}
sf::Uint16 tmp;
for (tmp = Consts::NETWORK_MAX_CLIENTS; tmp >= 1; tmp--)
{
if (!_connections.count(tmp))
for (tmp = Consts::NETWORK_MAX_CLIENTS; tmp >= 1; tmp--) {
if (!_connections.count(tmp)) {
senderId = tmp;
else
if (_connections.at(tmp).same(ip, port))
} else {
if (_connections.at(tmp).same(ip, port)) {
return MsgType::Error;
}
}
}
_connections.insert({ senderId, UDPConnection(senderId, ip, port) });
}
if (!_connections.count(senderId) || !_connections.at(senderId).same(ip, port) || reply && confirmed(msgId, senderId))
if (!_connections.count(senderId) || !_connections.at(senderId).same(ip, port) || reply && confirmed(msgId, senderId)) {
return MsgType::Error;
}
return type;
}
bool UDPSocket::confirmed(sf::Uint16 msgId, sf::Uint16 senderId)
{
bool UDPSocket::confirmed(sf::Uint16 msgId, sf::Uint16 senderId) {
sf::Packet confirmPacket;
confirmPacket << _ownId << false << msgId << MsgType::Confirm;
_connections.at(senderId).send(_socket, confirmPacket);

View File

@ -31,7 +31,6 @@ public:
bool bind(sf::Uint16 port);
void unbind();
void setTimeoutCallback(std::function<bool(sf::Uint16)> callback);
void clearTimeoutCallback();
void addConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port);
void removeConnection(sf::Uint16 id);

View File

@ -8,9 +8,14 @@
#include <iostream>
#include <cmath>
#include <fstream>
#include <utility>
#include "../Consts.h"
RigidBody::RigidBody(ObjectNameTag nameTag, const std::string &filename, const Vec3D &scale) : Mesh(std::move(nameTag), filename, scale) {
}
Vec3D RigidBody::_findFurthestPoint(const Vec3D& direction) {
std::shared_ptr<Vec3D> maxPoint = std::make_shared<Vec3D>(Vec3D{0, 0, 0});
Vec3D maxPoint{0, 0, 0};
double maxDistance = -std::numeric_limits<double>::max();
for(auto& tri : triangles()){
@ -20,12 +25,12 @@ Vec3D RigidBody::_findFurthestPoint(const Vec3D& direction) {
double distance = point.dot(direction.normalized());
if(distance > maxDistance) {
maxDistance = distance;
maxPoint = std::make_shared<Vec3D>(point);
maxPoint = point;
}
}
}
return *maxPoint;
return maxPoint;
}
Vec3D RigidBody::_support(std::shared_ptr<RigidBody> obj, const Vec3D& direction) {
@ -47,8 +52,8 @@ NextSimplex RigidBody::_nextSimplex(const Simplex &points) {
}
NextSimplex RigidBody::_lineCase(const Simplex& points) {
std::shared_ptr<Simplex> newPoints = std::make_shared<Simplex>(points);
std::shared_ptr<Vec3D> newDirection;
Simplex newPoints(points);
Vec3D newDirection;
Vec3D a = points[0];
Vec3D b = points[1];
@ -57,18 +62,18 @@ NextSimplex RigidBody::_lineCase(const Simplex& points) {
Vec3D ao = - a;
if (ab.dot(ao) > 0) {
newDirection = std::make_shared<Vec3D>(ab.cross(ao).cross(ab));
newDirection = ab.cross(ao).cross(ab);
} else {
newPoints = std::make_shared<Simplex>(Simplex{a});
newDirection = std::make_shared<Vec3D>(ao);
newPoints = Simplex{a};
newDirection = ao;
}
return NextSimplex{*newPoints, *newDirection, false};
return NextSimplex{newPoints, newDirection, false};
}
NextSimplex RigidBody::_triangleCase(const Simplex &points) {
std::shared_ptr<Simplex> newPoints = std::make_shared<Simplex>(points);
std::shared_ptr<Vec3D> newDirection;
Simplex newPoints(points);
Vec3D newDirection;
Vec3D a = points[0];
Vec3D b = points[1];
@ -82,8 +87,8 @@ NextSimplex RigidBody::_triangleCase(const Simplex &points) {
if (abc.cross(ac).dot(ao) > 0) {
if (ac.dot(ao) > 0) {
newPoints = std::make_shared<Simplex>(Simplex{ a, c });
newDirection = std::make_shared<Vec3D>(ac.cross(ao).cross(ac));
newPoints = Simplex{ a, c };
newDirection = ac.cross(ao).cross(ac);
}
else {
return _lineCase(Simplex { a, b });
@ -94,15 +99,15 @@ NextSimplex RigidBody::_triangleCase(const Simplex &points) {
}
else {
if (abc.dot(ao) > 0) {
newDirection = std::make_shared<Vec3D>(abc);
newDirection = abc;
} else {
newPoints = std::make_shared<Simplex>(Simplex{ a, c, b });
newDirection = std::make_shared<Vec3D>(-abc);
newPoints = Simplex{ a, c, b };
newDirection = -abc;
}
}
}
return NextSimplex{*newPoints, *newDirection, false};
return NextSimplex{newPoints, newDirection, false};
}
NextSimplex RigidBody::_tetrahedronCase(const Simplex &points) {
@ -145,34 +150,38 @@ std::pair<bool, Simplex> RigidBody::checkGJKCollision(std::shared_ptr<RigidBody>
// Get initial support point in any direction
std::shared_ptr<Vec3D> support = std::make_shared<Vec3D>(_support(obj, Vec3D{1, 0, 0}));
Vec3D support = _support(obj, Vec3D{1, 0, 0});
// Simplex is an array of points, max count is 4
std::shared_ptr<Simplex> points = std::make_shared<Simplex>();
points->push_front(*support);
Simplex points{};
points.push_front(support);
// New direction is towards the origin
std::shared_ptr<Vec3D> direction = std::make_shared<Vec3D>(-*support);
Vec3D direction = -support;
while (true) {
support = std::make_shared<Vec3D>(_support(obj, *direction));
int iters = 0;
while (iters++ < size() + obj->size()) {
support = _support(obj, direction);
if (support->dot(*direction) <= 0)
return std::make_pair(false, *points); // no collision
if (support.dot(direction) <= 0) {
return std::make_pair(false, points); // no collision
}
points->push_front(*support);
points.push_front(support);
NextSimplex nextSimplex = _nextSimplex(*points);
NextSimplex nextSimplex = _nextSimplex(points);
direction = std::make_shared<Vec3D>(nextSimplex.newDirection);
points = std::make_shared<Simplex>(nextSimplex.newSimplex);
direction = nextSimplex.newDirection;
points = nextSimplex.newSimplex;
if (nextSimplex.finishSearching) {
if(obj->isCollider())
if(obj->isCollider()) {
_inCollision = true;
return std::make_pair(true, *points);
}
return std::make_pair(true, points);
}
}
return std::make_pair(false, points);
}
CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj) {
@ -192,28 +201,27 @@ CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody>
};
auto faceNormals = _getFaceNormals(polytope, faces);
std::vector<std::shared_ptr<FaceNormal>> normals = faceNormals.first;
std::vector<FaceNormal> normals = faceNormals.first;
size_t minFace = faceNormals.second;
std::shared_ptr<Vec3D> minNormal = std::make_shared<Vec3D>(normals[minFace]->normal);
Vec3D minNormal = normals[minFace].normal;
double minDistance = std::numeric_limits<double>::max();
int iters = 0;
while (minDistance == std::numeric_limits<double>::max() && iters++ < size() + obj->size()) {
minNormal = std::make_shared<Vec3D>(normals[minFace]->normal);
minDistance = normals[minFace]->distance;
minNormal = normals[minFace].normal;
minDistance = normals[minFace].distance;
Vec3D support = _support(obj, *minNormal);
double sDistance = minNormal->dot(support);
Vec3D support = _support(obj, minNormal);
double sDistance = minNormal.dot(support);
if (std::abs(sDistance - minDistance) > Consts::EPA_EPS) {
minDistance = std::numeric_limits<double>::max();
std::vector<std::pair<size_t, size_t>> uniqueEdges;
for (size_t i = 0; i < normals.size(); i++) {
if (normals[i]->normal.dot(support) > 0) {
size_t f = i * 3;
size_t f = 0;
for (auto & normal : normals) {
if (normal.normal.dot(support) > 0) {
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 0, f + 1);
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 1, f + 2);
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 2, f + 0);
@ -221,7 +229,8 @@ CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody>
faces.erase(faces.begin() + f);
faces.erase(faces.begin() + f);
faces.erase(faces.begin() + f);
normals.erase(normals.begin() + i--);
} else {
f += 3;
}
}
@ -237,20 +246,21 @@ CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody>
auto newFaceNormals = _getFaceNormals(polytope, faces);
normals = newFaceNormals.first;
normals = std::move(newFaceNormals.first);
minFace = newFaceNormals.second;
}
}
_collisionNormal = minNormal;
if(std::abs(minDistance - std::numeric_limits<double>::max()) < Consts::EPS)
return CollisionPoint{*minNormal, 0};
if(std::abs(minDistance - std::numeric_limits<double>::max()) < Consts::EPS) {
return CollisionPoint{minNormal, 0};
}
return CollisionPoint{*minNormal, minDistance + Consts::EPA_EPS};
return CollisionPoint{minNormal, minDistance + Consts::EPA_EPS};
}
std::pair<std::vector<std::shared_ptr<FaceNormal>>, size_t> RigidBody::_getFaceNormals(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces) {
std::vector<std::shared_ptr<FaceNormal>> normals;
std::pair<std::vector<FaceNormal>, size_t> RigidBody::_getFaceNormals(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces) {
std::vector<FaceNormal> normals;
size_t nearestFaceIndex = 0;
double minDistance = std::numeric_limits<double>::max();
@ -259,16 +269,16 @@ std::pair<std::vector<std::shared_ptr<FaceNormal>>, size_t> RigidBody::_getFaceN
Vec3D b = polytope[faces[i + 1]];
Vec3D c = polytope[faces[i + 2]];
std::shared_ptr<Vec3D> normal = std::make_shared<Vec3D>((b - a).cross(c - a).normalized());
Vec3D normal = (b - a).cross(c - a).normalized();
double distance = normal->dot(a);
double distance = normal.dot(a);
if (distance < -Consts::EPS) {
normal = std::make_unique<Vec3D>(-*normal);
normal = -normal;
distance *= -1;
}
normals.emplace_back(std::make_shared<FaceNormal>(FaceNormal{*normal, distance}));
normals.emplace_back(FaceNormal{normal, distance});
if (distance < minDistance) {
nearestFaceIndex = i / 3;
@ -304,41 +314,29 @@ void RigidBody::solveCollision(const CollisionPoint& collision) {
Vec3D velocity_parallel = collision.normal * velocity().dot(collision.normal);
Vec3D velocity_perpendicular = velocity() - velocity_parallel;
if(velocity().dot(collision.normal) > 0)
if(velocity().dot(collision.normal) > 0) {
setVelocity(velocity_perpendicular);
}
translate(-collision.normal * collision.depth);
}
void RigidBody::updatePhysicsState() {
translate(*_velocity * Time::deltaTime());
_velocity = std::make_unique<Vec3D>(*_velocity + *_acceleration * Time::deltaTime());
translate(_velocity * Time::deltaTime());
_velocity = _velocity + _acceleration * Time::deltaTime();
}
void RigidBody::setVelocity(const Vec3D& velocity) {
_velocity = std::make_unique<Vec3D>(velocity);
_velocity = velocity;
}
void RigidBody::addVelocity(const Vec3D &velocity) {
_velocity = std::make_unique<Vec3D>(*_velocity + velocity);
_velocity = _velocity + velocity;
}
void RigidBody::setAcceleration(const Vec3D& acceleration) {
_acceleration = std::make_unique<Vec3D>(acceleration);
_acceleration = acceleration;
}
RigidBody::RigidBody(const Mesh &mesh) : Mesh(mesh) {
}
void RigidBody::makeLogObjPolytope(const std::vector<Vec3D> &polytope, const std::vector<size_t> &faces) {
std::fstream file("polytope_log.obj", std::ios::out);
for(auto &p : polytope)
file << "v " << p.x() << " " << p.y() << " " << p.z() << std::endl;
for(size_t i = 0; i < faces.size(); i += 3)
file << "f " << faces[i + 0]+1 << " " << faces[i + 1]+1 << " " << faces[i + 2]+1 << std::endl;
file.close();
}

View File

@ -5,6 +5,7 @@
#ifndef ENGINE_RIGIDBODY_H
#define ENGINE_RIGIDBODY_H
#include <utility>
#include <vector>
#include <memory>
#include <functional>
@ -40,29 +41,29 @@ private:
static NextSimplex _triangleCase(const Simplex& points);
static NextSimplex _tetrahedronCase(const Simplex& points);
static std::pair<std::vector<std::shared_ptr<FaceNormal>>, size_t> _getFaceNormals(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces);
static std::pair<std::vector<FaceNormal>, size_t> _getFaceNormals(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces);
static std::vector<std::pair<size_t, size_t>> _addIfUniqueEdge(const std::vector<std::pair<size_t, size_t>>& edges, const std::vector<size_t>& faces, size_t a, size_t b);
static void makeLogObjPolytope(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces);
protected:
std::unique_ptr<Vec3D> _velocity = std::make_unique<Vec3D>(Vec3D{0, 0, 0});;
std::unique_ptr<Vec3D> _acceleration = std::make_unique<Vec3D>(Vec3D{0, 0, 0});;
Vec3D _velocity{0, 0, 0};
Vec3D _acceleration{0, 0, 0};
bool _collision = false;
bool _isCollider = true;
bool _inCollision = false;
std::shared_ptr<Vec3D> _collisionNormal = std::make_unique<Vec3D>(Vec3D{0, 0, 0});;
Vec3D _collisionNormal{0, 0, 0};
public:
RigidBody() = default;
explicit RigidBody(ObjectNameTag nameTag) : Mesh(std::move(nameTag)) {};
explicit RigidBody(const Mesh& mesh);
RigidBody(ObjectNameTag nameTag, const std::string& filename, const Vec3D& scale = Vec3D{1, 1, 1});
[[nodiscard]] std::pair<bool, Simplex> checkGJKCollision(std::shared_ptr<RigidBody> obj);
[[nodiscard]] CollisionPoint EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj);
void solveCollision(const CollisionPoint& collision);
[[nodiscard]] Vec3D collisionNormal() const { return *_collisionNormal; }
[[nodiscard]] Vec3D collisionNormal() const { return _collisionNormal; }
[[nodiscard]] bool isCollision() const { return _collision; }
[[nodiscard]] bool inCollision() const {return _inCollision; }
@ -77,8 +78,8 @@ public:
void addVelocity(const Vec3D& velocity);
void setAcceleration(const Vec3D& acceleration);
[[nodiscard]] Vec3D velocity() const { return *_velocity; }
[[nodiscard]] Vec3D acceleration() const { return *_acceleration; }
[[nodiscard]] Vec3D velocity() const { return _velocity; }
[[nodiscard]] Vec3D acceleration() const { return _acceleration; }
[[nodiscard]] const std::function<void(const ObjectNameTag&, std::shared_ptr<RigidBody>)>& collisionCallBack() const { return _collisionCallBack; }
void setCollisionCallBack(const std::function<void(const ObjectNameTag& tag, std::shared_ptr<RigidBody>)>& f) { _collisionCallBack = f; }

View File

@ -8,11 +8,5 @@
using namespace std;
Ak47::Ak47(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::AK47_OBJ, Vec3D{3, 3, 3}, Vec3D{-2.2, 1.0, 1.3}, Vec3D{0, Consts::PI, 0}) {
fireSound = ShooterConsts::AK47_FIRE_SOUND;
reloadSound = ShooterConsts::AK47_RELOAD_SOUND;
_stockAmmo = ammo - _clipCapacity;
_fireDelay = 0.1;
Ak47::Ak47(const std::string& weaponName) : Weapon(100, 30, 3.0, 0.1, 300, 2.0, ShooterConsts::AK47_FIRE_SOUND, ShooterConsts::AK47_RELOAD_SOUND, weaponName, ShooterConsts::AK47_OBJ, Vec3D{3, 3, 3}, Vec3D{-2.2, 1.0, 1.3}, Vec3D{0, Consts::PI, 0}) {
}

View File

@ -9,7 +9,7 @@
class Ak47 final : public Weapon {
public:
explicit Ak47(int ammo = 100, const std::string& weaponName = "ak47");
explicit Ak47(const std::string& weaponName = "ak47");
};

View File

@ -10,18 +10,7 @@
class Gold_Ak47 final : public Weapon {
public:
explicit Gold_Ak47(int ammo = 200, const std::string& weaponName = "gold_ak47") : Weapon(weaponName, ShooterConsts::GOLD_AK47_OBJ, Vec3D{3, 3, 3}, Vec3D{-2.2, 1.0, 1.3}, Vec3D{0, Consts::PI, 0}) {
fireSound = ShooterConsts::GOLD_AK47_FIRE_SOUND;
reloadSound = ShooterConsts::GOLD_AK47_RELOAD_SOUND;
_initialPack = 200;
_spreading = 1.0;
_reloadTime = 1.5;
_clipCapacity = 60;
_stockAmmo = ammo - _clipCapacity;
_fireDelay = 0.05;
_damage = 600;
_clipAmmo = _clipCapacity;
explicit Gold_Ak47(const std::string& weaponName = "gold_ak47") : Weapon(200, 60, 1.5, 0.05, 600, 1.0, ShooterConsts::GOLD_AK47_FIRE_SOUND, ShooterConsts::GOLD_AK47_RELOAD_SOUND, weaponName, ShooterConsts::GOLD_AK47_OBJ, Vec3D{3, 3, 3}, Vec3D{-2.2, 1.0, 1.3}, Vec3D{0, Consts::PI, 0}) {
}
};

View File

@ -8,16 +8,5 @@
using namespace std;
Gun::Gun(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::GUN_OBJ, Vec3D{3, 3, 3}, Vec3D{-1.8, 1.3, 1.8}, Vec3D{0, Consts::PI, 0}) {
fireSound = ShooterConsts::GUN_FIRE_SOUND;
reloadSound = ShooterConsts::GUN_RELOAD_SOUND;
_initialPack = 30;
_clipCapacity = 6; // how much ammo can be stored in one clip
_stockAmmo = ammo - _clipCapacity; // how much ammo do you have in stock
_clipAmmo = _clipCapacity; // how much ammo do you have in current clip
_reloadTime = 2;
_fireDelay = 0.3; // time delay between fires
_damage = 800;
_spreading = 3.0;
Gun::Gun() : Weapon(30, 6, 2.0, 0.3, 800, 3.0, ShooterConsts::GUN_FIRE_SOUND, ShooterConsts::GUN_RELOAD_SOUND, "gun", ShooterConsts::GUN_OBJ, Vec3D{3, 3, 3}, Vec3D{-1.8, 1.3, 1.8}, Vec3D{0, Consts::PI, 0}) {
}

View File

@ -9,7 +9,7 @@
class Gun final : public Weapon {
public:
explicit Gun(int ammo = 30, const std::string& weaponName = "gun");
explicit Gun();
};

View File

@ -6,16 +6,5 @@
#include "Rifle.h"
#include "../ShooterConsts.h"
Rifle::Rifle(int ammo, const std::string &weaponName) : Weapon(weaponName, ShooterConsts::RIFLE_OBJ, Vec3D{3, 3, 3}, Vec3D{-2.3, 1, 1.3}, Vec3D{0, Consts::PI, 0}) {
fireSound = ShooterConsts::RIFLE_FIRE_SOUND;
reloadSound = ShooterConsts::RIFLE_RELOAD_SOUND;
_initialPack = 5;
_clipCapacity = 1; // how much ammo can be stored in one clip
_stockAmmo = ammo - _clipCapacity; // how much ammo do you have in stock
_clipAmmo = _clipCapacity; // how much ammo do you have in current clip
_reloadTime = 1;
_fireDelay = 1; // time delay between fires
_damage = 30000;
_spreading = 0.5;
Rifle::Rifle() : Weapon(5, 1, 1.0, 1.0, 30000, 0.5, ShooterConsts::RIFLE_FIRE_SOUND, ShooterConsts::RIFLE_RELOAD_SOUND, "rifle", ShooterConsts::RIFLE_OBJ, Vec3D{3, 3, 3}, Vec3D{-2.3, 1, 1.3}, Vec3D{0, Consts::PI, 0}) {
}

View File

@ -9,7 +9,7 @@
class Rifle final : public Weapon {
public:
explicit Rifle(int ammo = 5, const std::string& weaponName = "rifle");
explicit Rifle();
};

View File

@ -9,19 +9,7 @@
using namespace std;
Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::SHOTGUN_OBJ, Vec3D{3, 3, 3}, Vec3D{-1.95, 0.8, 1.5}, Vec3D{0, Consts::PI, 0}) {
fireSound = ShooterConsts::SHOTGUN_FIRE_SOUND;
reloadSound = ShooterConsts::SHOTGUN_RELOAD_SOUND;
//reloadSound.setVolume(30);
_initialPack = 15;
_clipCapacity = 1; // how much ammo can be stored in one clipx
_stockAmmo = ammo - _clipCapacity; // how much ammo do you have in stock
_clipAmmo = _clipCapacity; // how much ammo do you have in current clip
_reloadTime = 1;
_fireDelay = 1; // time delay between fires
_damage = 400;
_spreading = 5;
Shotgun::Shotgun(const std::string& weaponName) : Weapon(15, 1, 1.0, 1.0, 400, 5.0, ShooterConsts::SHOTGUN_FIRE_SOUND, ShooterConsts::SHOTGUN_RELOAD_SOUND, weaponName, ShooterConsts::SHOTGUN_OBJ, Vec3D{3, 3, 3}, Vec3D{-1.95, 0.8, 1.5}, Vec3D{0, Consts::PI, 0}) {
}
std::map<ObjectNameTag, double>
@ -30,9 +18,10 @@ Shotgun::processFire(std::function<IntersectionInformation(const Vec3D&, const V
for(int i = 0; i < 15; i++) {
std::map<ObjectNameTag, double> damaged = addTrace(rayCastFunction, position, direction);
for(auto& player : damaged)
for(auto& player : damaged) {
damagedPlayers[player.first] += player.second;
}
}
return damagedPlayers;
}

View File

@ -9,7 +9,7 @@
class Shotgun final : public Weapon {
public:
explicit Shotgun(int ammo = 15, const std::string& weaponName = "shotgun");
explicit Shotgun(const std::string& weaponName = "shotgun");
std::map<ObjectNameTag, double> processFire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) override;
};

View File

@ -7,15 +7,15 @@
#include "../engine/ResourceManager.h"
#include "../engine/utils/Log.h"
#include "../engine/animation/AColor.h"
#include "../engine/animation/AFunction.h"
#include "../ShooterConsts.h"
using namespace std;
Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, const Vec3D& scale, const Vec3D& t, const Vec3D& r) {
_name = weaponName;
Weapon::Weapon(int initialPack, int clipCapacity, double reloadTime, double fireDelay, double damage, double spreading, std::string fireSound, std::string reloadSound, const std::string& weaponName, const std::string& objFileName, const Vec3D& s, const Vec3D& t, const Vec3D& r) : RigidBody(ObjectNameTag("weapon_" + weaponName), weaponName), _initialPack(initialPack), _clipCapacity(clipCapacity), _reloadTime(reloadTime), _fireDelay(fireDelay), _damage(damage), _spreading(spreading), _fireSound(std::move(fireSound)), _reloadSound(std::move(reloadSound)) {
_stockAmmo = _initialPack - _clipCapacity;
_clipAmmo = _clipCapacity;
loadObj(objFileName, scale);
loadObj(objFileName, s);
setCollider(false);
rotate(r);
translate(t);
@ -24,12 +24,14 @@ Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, co
FireInformation Weapon::fire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
if(_clipAmmo == 0) {
reload();
if(_clipAmmo == 0)
if(_clipAmmo == 0) {
SoundController::playSound(SoundTag("noAmmo"), ShooterConsts::NO_AMMO_SOUND);
}
}
if(_clipAmmo <= 0 || std::abs(Time::time() - _lastFireTime) < _fireDelay || std::abs(Time::time() - _lastReloadTime) < _reloadTime)
if(_clipAmmo <= 0 || std::abs(Time::time() - _lastFireTime) < _fireDelay || std::abs(Time::time() - _lastReloadTime) < _reloadTime) {
return FireInformation{std::map<ObjectNameTag, double>(), false};
}
_lastFireTime = Time::time();
_clipAmmo--;
@ -38,15 +40,16 @@ FireInformation Weapon::fire(std::function<IntersectionInformation(const Vec3D&,
reload();
}
SoundController::playSound(SoundTag("fire"), fireSound);
SoundController::playSound(SoundTag("fire"), _fireSound);
Log::log("Weapon::fire (" + std::to_string(_stockAmmo) + " : " + std::to_string(_clipAmmo) + ")");
return FireInformation{processFire(std::move(rayCastFunction), position, direction), true};
}
void Weapon::reload() {
if (_stockAmmo == 0 || std::abs(Time::time() - _lastReloadTime) < _reloadTime)
if (_stockAmmo == 0 || std::abs(Time::time() - _lastReloadTime) < _reloadTime) {
return;
}
if(_clipCapacity - _clipAmmo <= _stockAmmo) {
_stockAmmo -= _clipCapacity - _clipAmmo;
_clipAmmo = _clipCapacity;
@ -55,7 +58,7 @@ void Weapon::reload() {
_stockAmmo = 0;
}
SoundController::playSound(SoundTag("reload"), reloadSound);
SoundController::playSound(SoundTag("reload"), _reloadSound);
Log::log("Weapon::reload (" + std::to_string(_stockAmmo) + " : " + std::to_string(_clipAmmo) + ")");
_lastReloadTime = Time::time();
}
@ -74,8 +77,9 @@ std::map<ObjectNameTag, double> Weapon::addTrace(std::function<IntersectionInfor
// damage player
auto rayCast = rayCastFunction(from, from + directionTo * ShooterConsts::FIRE_DISTANCE + randV);
if(rayCast.objectName.str().find("Enemy") != std::string::npos)
damagedPlayers[rayCast.objectName] += _damage/(1.0 + rayCast.distanceToObject);
if(rayCast.objectName.str().find("Enemy") != std::string::npos) {
damagedPlayers[rayCast.objectName] += _damage / (1.0 + rayCast.distanceToObject);
}
// add trace line
Vec3D lineFrom = position() + Vec3D(triangles().back()[0]);

View File

@ -15,56 +15,47 @@
#include "../engine/SoundController.h"
#include "../engine/Consts.h"
struct FireInformation {
struct FireInformation final {
const std::map<ObjectNameTag, double> damagedPlayers;
const bool shot;
};
class Weapon : public RigidBody {
protected:
int _initialPack = 100; // how much ammo do you have when you find the weapon
private:
const int _initialPack = 100; // how much ammo do you have when you find the weapon
const int _clipCapacity = 30; // how much ammo can be stored in one clip
int _stockAmmo; // how much ammo do you have in stock
int _clipAmmo; // how much ammo do you have in current clip
const double _reloadTime = 3.0;
const double _fireDelay = 0.1; // time delay between fires
const double _damage = 300;
const double _spreading = 2.0;
int _clipCapacity = 30; // how much ammo can be stored in one clip
int _stockAmmo = _initialPack - _clipCapacity; // how much ammo do you have in stock
int _clipAmmo = _clipCapacity; // how much ammo do you have in current clip
double _reloadTime = 3;
double _fireDelay = 0.1; // time delay between fires
double _damage = 300;
double _spreading = 2.0;
std::string _name = "Weapon";
const std::string _fireSound;
const std::string _reloadSound;
double _lastFireTime = std::numeric_limits<double>::min();
double _lastReloadTime = std::numeric_limits<double>::min();
std::string fireSound;
std::string reloadSound;
std::function<void(const Vec3D&, const Vec3D&)> _addTraceCallBack;
protected:
std::map<ObjectNameTag, double> addTrace(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
virtual std::map<ObjectNameTag, double> processFire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
public:
Weapon(const std::string& weaponName, const std::string& objFileName, const Vec3D& scale, const Vec3D& translate, const Vec3D& rotate);
Weapon(int initialPack, int clipCapacity, double reloadTime, double fireDelay, double damage, double spreading, std::string fireSound, std::string reloadSound, const std::string& weaponName, const std::string& objFileName, const Vec3D& s, const Vec3D& t, const Vec3D& r);
FireInformation fire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
void reload();
[[nodiscard]] std::pair<double, double> balance() const{ return std::make_pair(_clipAmmo, _stockAmmo); }
void setAddTraceCallBack(std::function<void(Vec3D, Vec3D)> add) {
_addTraceCallBack = std::move(add);
}
[[nodiscard]] ObjectNameTag name() const { return ObjectNameTag(_name); }
void setAddTraceCallBack(std::function<void(Vec3D, Vec3D)> add) { _addTraceCallBack = std::move(add); }
void addAmmo(int ammoAdd) { _stockAmmo += ammoAdd; }
[[nodiscard]] int initialPack() const {return _initialPack; }
[[nodiscard]] int initialPack() const { return _initialPack; }
};