OpenGL graphics acceleration support!

master
Vectozavr 2021-10-22 23:42:32 +07:00
parent 22c18968f6
commit e471795290
24 changed files with 307 additions and 74 deletions

View File

@ -112,4 +112,20 @@ if (SFML_FOUND)
include_directories(${SFML_INCLUDE_DIR})
endif()
target_link_libraries(shooter sfml-audio sfml-network sfml-graphics sfml-window sfml-system)
target_link_libraries(shooter sfml-audio sfml-network sfml-graphics sfml-window sfml-system)
# OpenGL part
if (APPLE OR UNIX)
set(GLEW_H /usr/local/Cellar/glew/2.1.0/include/GL)
set(GLFW_H /usr/local/Cellar/glfw/3.2.1/include/GLFW)
include_directories(${GLEW_H} ${GLFW_H})
set(GLEW_LINK /usr/local/Cellar/glew/2.1.0/lib/libGLEW.2.1.dylib)
set(GLFW_LINK /usr/local/Cellar/glfw/3.2.1/lib/libglfw.3.dylib)
link_libraries(${OPENGL} ${GLEW_LINK} ${GLFW_LINK})
target_link_libraries(shooter "-framework OpenGL")
target_link_libraries(shooter "-framework GLUT")
else()
endif()

View File

@ -8,7 +8,7 @@
#include "engine/utils/Log.h"
Player::Player() {
loadObj(ShooterConsts::CUBE_OBJ, Vec3D{0.5, 1.9, 0.5});
loadObj(ShooterConsts::CUBE_OBJ, Vec3D{1.5, 1.9, 1.5});
setAcceleration(Vec3D{0, -ShooterConsts::GRAVITY, 0});
setCollision(true);
setVisible(false);
@ -109,15 +109,17 @@ void Player::previousWeapon() {
}
}
void Player::fire() {
bool Player::fire() {
auto camera = attached(ObjectNameTag("Camera"));
if(camera != nullptr) {
auto damagedPlayers = _weapons[_selectedWeapon]->fire(_rayCastFunction, camera->position(), camera->lookAt());
for(auto& [damagedPlayerName, damage] : damagedPlayers) {
auto fireInfo = _weapons[_selectedWeapon]->fire(_rayCastFunction, camera->position(), camera->lookAt());
for(auto& [damagedPlayerName, damage] : fireInfo.damagedPlayers) {
sf::Uint16 targetId = std::stoi(damagedPlayerName.str().substr(6));
_damagePlayerCallBack(targetId, damage);
}
return fireInfo.shot;
}
return false;
}
void Player::reload() {

View File

@ -37,7 +37,7 @@ private:
std::function<void(std::shared_ptr<Weapon>)> _addWeaponCallBack;
std::function<void(std::shared_ptr<Weapon>)> _removeWeaponCallBack;
std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> _rayCastFunction;
std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> _rayCastFunction;
public:
Player();
@ -57,8 +57,10 @@ public:
void nextWeapon();
void previousWeapon();
void fire();
bool fire();
void reload();
[[nodiscard]] ObjectNameTag weaponName() const { return _weapons[_selectedWeapon]->name(); }
std::shared_ptr<Weapon> weapon() { return _weapons[_selectedWeapon]; }
void rotateWeaponsRelativePoint(const Vec3D& point, const Vec3D& v, double val);
@ -83,7 +85,7 @@ public:
void setRemoveWeaponCallBack(std::function<void(std::shared_ptr<Weapon>)> removeWeapon) {
_removeWeaponCallBack = std::move(removeWeapon);
}
void setRayCastFunction(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction) {
void setRayCastFunction(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction) {
_rayCastFunction = std::move(rayCastFunction);
}

View File

@ -9,6 +9,7 @@
#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,
@ -107,15 +108,24 @@ void PlayerController::update() {
SoundController::playSound(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND);
}
if (Mouse::isButtonPressed(sf::Mouse::Button::Left)) {
bool shot = _player->fire();
if(shot) {
if(!_player->inCollision() && (_player->weaponName() == ObjectNameTag("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 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 * 60.0 / Time::fps(), 0 });
_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 * 60.0 / Time::fps(), 0 });
_player->translate(Vec3D{ 0, Time::deltaTime() * ShooterConsts::WALK_SPEED * 2 * coeff, 0 });
_isSliding = true;
} else {
_isSliding = false;
@ -149,10 +159,6 @@ void PlayerController::update() {
_player->previousWeapon();
}
if (Mouse::isButtonPressed(sf::Mouse::Button::Left)) {
_player->fire();
}
if(Keyboard::isKeyPressed(sf::Keyboard::R)) {
_player->reload();
}

View File

@ -59,3 +59,4 @@ GamePlay:
![Project demonstration](img/gamePlay5.png)
![Project demonstration](img/gamePlay6.png)
![Project demonstration](img/gamePlay7.png)
![Project demonstration](img/opengl.png)

View File

@ -81,7 +81,7 @@ void Shooter::start() {
// TODO: encapsulate call backs inside Player
player->setAddTraceCallBack([this](const Vec3D& from, const Vec3D& to){ client->addTrace(from, to); addFireTrace(from, to); });
player->setDamagePlayerCallBack([this] (sf::Uint16 targetId, double damage) { client->damagePlayer(targetId, damage); });
player->setRayCastFunction([this](const Vec3D& from, const Vec3D& to) { return world->rayCast(from, to, "Enemy"); });
player->setRayCastFunction([this](const Vec3D& from, const Vec3D& to) { return world->rayCast(from, to, "weapon Player"); });
player->setTakeBonusCallBack([this] (const string& bonusName) { client->takeBonus(bonusName); });
player->setAddWeaponCallBack([this](std::shared_ptr<Weapon> weapon){ addWeapon(std::move(weapon)); });
player->setRemoveWeaponCallBack([this](std::shared_ptr<Weapon> weapon){ removeWeapon(std::move(weapon)); });
@ -246,7 +246,7 @@ void Shooter::addFireTrace(const Vec3D &from, const Vec3D &to) {
world->addBody(std::make_shared<RigidBody>(Mesh::LineTo(from, to, 0.05)), ObjectNameTag(traceName));
world->body(ObjectNameTag(traceName))->setCollider(false);
Timeline::animate(AnimationListTag(traceName + "_fadeOut"), new AColor(world->body(ObjectNameTag(traceName)), {255, 255, 255, 0}));
Timeline::animate(AnimationListTag(traceName + "_fadeOut"), new AColor(world->body(ObjectNameTag(traceName)), {150, 150, 150, 0}));
Timeline::animate(AnimationListTag(traceName + "_delete"), new AFunction([this, traceName](){ removeFireTrace(ObjectNameTag(traceName)); }, 1, 2));
}
@ -266,7 +266,7 @@ void Shooter::removeBonus(const ObjectNameTag &bonusName) {
}
void Shooter::addWeapon(std::shared_ptr<Weapon> weapon) {
world->addBody(weapon, weapon->name());
world->addBody(weapon, ObjectNameTag("weapon_" + weapon->name().str()));
if(client != nullptr)
client->changeWeapon(weapon->name().str());
@ -294,5 +294,5 @@ void Shooter::changeEnemyWeapon(const std::string& weaponName, sf::Uint16 enemyI
}
void Shooter::removeWeapon(std::shared_ptr<Weapon> weapon) {
world->removeBody(ObjectNameTag(weapon->name()));
world->removeBody(ObjectNameTag("weapon_" + weapon->name().str()));
}

View File

@ -6,7 +6,6 @@
#include "utils/Log.h"
#include <cmath>
#include "Consts.h"
std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mesh) {
@ -64,9 +63,9 @@ std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mes
Triangle clippedProjected = clipped * _SP;
Triangle clippedProjectedNormalized = Triangle(clippedProjected[0] / clippedProjected[0].w(),
clippedProjected[1] / clippedProjected[1].w(),
clippedProjected[2] / clippedProjected[2].w(),
ambientColor);
clippedProjected[1] / clippedProjected[1].w(),
clippedProjected[2] / clippedProjected[2].w(),
ambientColor);
_triangles.emplace_back(std::make_shared<Triangle>(clippedProjectedNormalized));
}
@ -128,3 +127,30 @@ void Camera::clear() {
_triangles.clear();
_V = Matrix4x4::View(left(), up(), lookAt(), position());
}
// OpenGL function
GLfloat *Camera::view() const {
auto* v = (GLfloat*)malloc(4*4*sizeof(GLfloat));
v[0] = -(GLfloat)left().x();
v[4] = -(GLfloat)left().y();
v[8] = -(GLfloat)left().z();
v[12] = (GLfloat)position().dot(left());
v[1] = (GLfloat)up().x();
v[5] = (GLfloat)up().y();
v[9] = (GLfloat)up().z();
v[13] = -(GLfloat)position().dot(up());
v[2] = -(GLfloat)lookAt().x();
v[6] = -(GLfloat)lookAt().y();
v[10] = -(GLfloat)lookAt().z();
v[14] = (GLfloat)position().dot(lookAt());
v[3] = (GLfloat)0.0f;
v[7] = (GLfloat)0.0f;
v[11] = (GLfloat)0.0f;
v[15] = (GLfloat)1.0f;
return v;
}

View File

@ -6,9 +6,9 @@
#define ENGINE_CAMERA_H
#include <vector>
#include "Screen.h"
#include "Plane.h"
#include "Mesh.h"
#include <SFML/OpenGL.hpp>
class Camera final : public Object{
private:
@ -24,6 +24,7 @@ private:
bool _ready = false;
double _aspect = 0;
public:
Camera() = default;
Camera(const Camera& camera) = delete;
@ -36,6 +37,9 @@ public:
[[nodiscard]] int buffSize() const { return _triangles.size(); }
std::vector<std::shared_ptr<Triangle>> sorted();
// OpenGL function
[[nodiscard]] GLfloat* view() const;
};

View File

@ -13,6 +13,7 @@ namespace Consts {
const sf::Color BACKGROUND_COLOR = sf::Color(255, 255, 255);
const std::string PROJECT_NAME = "engine";
const bool USE_LOG_FILE = true;
const bool USE_OPEN_GL = true;
const double PI = 3.14159265358979323846264338327950288;
const double EPS = 0.000001;

View File

@ -42,11 +42,6 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name,
Time::update();
update();
/* Project all mesh
* Here we project all _tris for each body from world._objects.
* When we call camera.project(m.second),
*/
// sometimes we dont need to update physics world
// (for example in menu or while pause)
// hence we can set '_updateWorld' equal to false in setUpdateWorld(bool):
@ -54,15 +49,30 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name,
Timeline::update();
camera->clear();
world->update();
world->projectObjectsInCamera(camera);
// draw projected body
for (auto &t : camera->sorted())
screen->drawTriangle(*t);
if(_useOpenGL) {
GLfloat* view = camera->view();
for(auto & it : *world) {
if (it.second->isVisible()) {
GLfloat* geometry = Screen::glMeshToGLfloatArray(it.second, camera->position());
screen->glDrawMesh(geometry, view, 3 * it.second->triangles().size());
free(geometry);
}
}
free(view);
} else {
// clear triangles from previous frame
camera->clear();
// project triangles to the camera plane
for(auto & it : *world)
camera->project(it.second);
// draw triangles on the screen
for (auto &t : camera->sorted())
screen->drawTriangle(*t);
_triPerSec = camera->buffSize() * Time::fps();
_triPerSec = camera->buffSize() * Time::fps();
}
printDebugText();
gui();
@ -87,13 +97,18 @@ void Engine::exit() {
void Engine::printDebugText() const {
if (_debugText) {
screen->debugText(_name + "\n\n X: " +
std::string str = _name + "\n\n X: " +
std::to_string((camera->position().x())) + "\n Y: " +
std::to_string((camera->position().y())) + "\n Z: " +
std::to_string((camera->position().z())) + "\n\n" +
std::to_string(screen->width()) + "x" +
std::to_string(screen->height()) + "\n" +
std::to_string(Time::fps()) +
" fps \n" + std::to_string((int) _triPerSec) + " tris/s");
std::to_string(screen->height()) + "\t" +
std::to_string(Time::fps()) + " fps";
if(_useOpenGL) {
str += "\n Using OpenGL acceleration";
} else {
str += "\n" + std::to_string((int) _triPerSec) + " tris/s";
}
screen->debugText(str);
}
}

View File

@ -20,6 +20,7 @@ private:
double _triPerSec = 0;
bool _debugText = true;
bool _updateWorld = true;
bool _useOpenGL = Consts::USE_OPEN_GL;
void printDebugText() const;
protected:
@ -35,6 +36,7 @@ protected:
void setDebugText(bool value) { _debugText = value; }
void setUpdateWorld(bool value) { _updateWorld = value; }
void setGlEnable(bool value) { _useOpenGL = value; }
virtual void gui(){}
public:

View File

@ -52,7 +52,7 @@ 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, 255});
Mesh static LineTo(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

@ -7,6 +7,9 @@
#include <utility>
#include "utils/Log.h"
#include "ResourceManager.h"
#include <SFML/OpenGL.hpp>
#include <cmath>
void Screen::open(int screenWidth, int screenHeight, const std::string &name, bool verticalSync, sf::Color background, sf::Uint32 style) {
_title = name;
@ -15,6 +18,7 @@ void Screen::open(int screenWidth, int screenHeight, const std::string &name, bo
_background = background;
sf::ContextSettings settings;
settings.depthBits = 24;
settings.antialiasingLevel = 8;
_window = std::make_shared<sf::RenderWindow>();
@ -37,6 +41,9 @@ void Screen::display() {
}
void Screen::clear() {
// Clear the depth buffer
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
_window->clear(_background);
}
@ -48,7 +55,10 @@ void Screen::drawTriangle(const Triangle& triangle)
sf::Vertex(sf::Vector2f((float)triangle[1].x(), (float)triangle[1].y()), triangle.color()),
sf::Vertex(sf::Vector2f((float)triangle[2].x(), (float)triangle[2].y()), triangle.color())
};
_window->pushGLStates();
_window->draw(tris, 3, sf::Triangles);
_window->popGLStates();
}
void Screen::setTitle(const std::string& title) {
@ -71,9 +81,11 @@ void Screen::debugText(const std::string& text) {
t.setString(text);
t.setCharacterSize(30);
t.setFillColor(sf::Color::Black);
t.setPosition(10, 10);
t.setPosition(10, 50);
_window->pushGLStates();
_window->draw(t);
_window->popGLStates();
}
void Screen::drawTetragon(const Vec2D &p1, const Vec2D &p2, const Vec2D &p3, const Vec2D &p4, sf::Color color) {
@ -84,7 +96,10 @@ void Screen::drawTetragon(const Vec2D &p1, const Vec2D &p2, const Vec2D &p3, con
polygon.setPoint(2, sf::Vector2f((float)p3.x(), (float)p3.y()));
polygon.setPoint(3, sf::Vector2f((float)p4.x(), (float)p4.y()));
polygon.setFillColor(color);
_window->pushGLStates();
_window->draw(polygon);
_window->popGLStates();
}
void Screen::drawText(const std::string& string, const Vec2D &position, int size, sf::Color color) {
@ -98,17 +113,125 @@ void Screen::drawText(const std::string& string, const Vec2D &position, int size
text.setPosition((float)position.x(), (float)position.y());
text.setString(string);
_window->pushGLStates();
_window->draw(text);
_window->popGLStates();
}
void Screen::drawSprite(const sf::Sprite &sprite) {
_window->pushGLStates();
_window->draw(sprite);
_window->popGLStates();
}
void Screen::drawText(const sf::Text &text) {
_window->pushGLStates();
_window->draw(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:
// Make the window the active window for OpenGL calls
_window->setActive(true);
glEnable(GL_CULL_FACE); // enable culling face
glCullFace(GL_BACK); // cull faces from back
glFrontFace(GL_CCW); // vertex order (counter clock wise)
// Enable Z-buffer read and write
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glClearDepth(1.f);
// Disable lighting
glDisable(GL_LIGHTING);
// enable alpha channel:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Configure the viewport (the same size as the window)
glViewport(0, 0, _window->getSize().x, _window->getSize().y);
// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat ratio = static_cast<float>(_window->getSize().x) / _window->getSize().y;
glFrustum(-ratio, ratio, -1.f, 1.f, 1.0f, 500.f);
// Enable position and texture coordinates vertex components
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 7 * sizeof(GLfloat), geometry);
glColorPointer(4, GL_FLOAT, 7 * sizeof(GLfloat), geometry + 3);
// Disable normal and color vertex components
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Apply some transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf(view);
// Draw the mesh
glDrawArrays(GL_TRIANGLES, 0, count);
// Make the window no longer the active window for OpenGL calls
_window->setActive(false);
}
GLfloat* Screen::glMeshToGLfloatArray(std::shared_ptr<Mesh> mesh, const Vec3D& cameraPosition) {
Vec3D pos = mesh->position();
std::vector<Triangle>& triangles = mesh->triangles();
auto* geometry = (GLfloat*)malloc(7*3*triangles.size()*sizeof(GLfloat));
for(int i = 0; i < triangles.size(); i++) {
int stride = 21*i;
double dot = triangles[i].norm().dot((pos + Vec3D(triangles[i][0]) - cameraPosition).normalized());
sf::Color color = triangles[i].color();
sf::Color ambientColor = sf::Color((sf::Uint8)(color.r * (0.3 * std::abs(dot) + 0.7)),
(sf::Uint8)(color.g * (0.3 * std::abs(dot) + 0.7)),
(sf::Uint8)(color.b * (0.3 * std::abs(dot) + 0.7)),
(sf::Uint8)color.a);
geometry[stride + 0] = (GLfloat)triangles[i][0].x() + pos.x();
geometry[stride + 1] = (GLfloat)triangles[i][0].y() + pos.y();
geometry[stride + 2] = (GLfloat)triangles[i][0].z() + pos.z();
geometry[stride + 3] = (GLfloat)ambientColor.r/255.0f;
geometry[stride + 4] = (GLfloat)ambientColor.g/255.0f;
geometry[stride + 5] = (GLfloat)ambientColor.b/255.0f;
geometry[stride + 6] = (GLfloat)ambientColor.a/255.0f;
geometry[stride + 7] = (GLfloat)triangles[i][1].x() + pos.x();
geometry[stride + 8] = (GLfloat)triangles[i][1].y() + pos.y();
geometry[stride + 9] = (GLfloat)triangles[i][1].z() + pos.z();
geometry[stride + 10] = (GLfloat)ambientColor.r/255.0f;
geometry[stride + 11] = (GLfloat)ambientColor.g/255.0f;
geometry[stride + 12] = (GLfloat)ambientColor.b/255.0f;
geometry[stride + 13] = (GLfloat)ambientColor.a/255.0f;
geometry[stride + 14] = (GLfloat)triangles[i][2].x() + pos.x();
geometry[stride + 15] = (GLfloat)triangles[i][2].y() + pos.y();
geometry[stride + 16] = (GLfloat)triangles[i][2].z() + pos.z();
geometry[stride + 17] = (GLfloat)ambientColor.r/255.0f;
geometry[stride + 18] = (GLfloat)ambientColor.g/255.0f;
geometry[stride + 19] = (GLfloat)ambientColor.b/255.0f;
geometry[stride + 20] = (GLfloat)ambientColor.a/255.0f;
}
return geometry;
}

View File

@ -13,6 +13,8 @@
#include "utils/Time.h"
#include "Mouse.h"
#include "Consts.h"
#include "Mesh.h"
#include "Camera.h"
class Screen final {
private:
@ -29,7 +31,7 @@ public:
void display();
void clear();
bool hasFocus() const { return _window->hasFocus(); }
[[nodiscard]] bool hasFocus() const { return _window->hasFocus(); }
void drawTriangle(const Triangle& triangle);
void drawTetragon(const Vec2D& p1, const Vec2D& p2, const Vec2D& p3, const Vec2D& p4, sf::Color color);
@ -50,6 +52,10 @@ public:
void debugText(const std::string& text);
void attachMouse(std::shared_ptr<Mouse> mouse);
// OpenGL functions
void glDrawMesh(GLfloat* geometry, GLfloat* view, size_t count);
static GLfloat* glMeshToGLfloatArray(std::shared_ptr<Mesh> mesh, const Vec3D& cameraPosition);
};

View File

@ -6,6 +6,8 @@
#include "utils/Log.h"
#include "Plane.h"
#include "ResourceManager.h"
#include <sstream>
#include <cmath>
using namespace std;
@ -19,15 +21,28 @@ void World::loadBody(const ObjectNameTag& tag, const string &filename, const Vec
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + tag.str() + "' with " + std::to_string(_objects[tag]->triangles().size()) + " tris.");
}
std::pair<Vec3D, ObjectNameTag> World::rayCast(const Vec3D& from, const Vec3D& to, const std::string& tag) {
IntersectionInformation World::rayCast(const Vec3D& from, const Vec3D& to, const std::string& skipTags) {
std::pair<Vec3D, string> result;
// make vector of tags, that we are going to escape
vector <string> tagsToSkip;
stringstream s(skipTags);
std::string t;
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>();
std::string bodyName;
double minDistance = Consts::RAY_CAST_MAX_DISTANCE;
std::shared_ptr<RigidBody> intersectedBody = nullptr;
for(auto& [name, body] : _objects) {
if(!tag.empty() && name.str().find(tag) == std::string::npos)
//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)
continue;
for(auto& tri : body->triangles()) {
@ -39,11 +54,14 @@ std::pair<Vec3D, ObjectNameTag> World::rayCast(const Vec3D& from, const Vec3D& t
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);
bodyName = name.str();
intersected = true;
intersectedBody = body;
}
}
}
return {*point, ObjectNameTag(bodyName)};
return IntersectionInformation{*point, sqrt(minDistance), *triangle, ObjectNameTag(bodyName), intersectedBody, intersected};
}
void World::loadMap(const std::string& filename, const Vec3D& scale) {
@ -53,6 +71,8 @@ void World::loadMap(const std::string& filename, const Vec3D& scale) {
addBody(std::make_shared<RigidBody>(*objs[i]), meshName);
body(meshName)->scale(scale);
}
auto it = _objects.begin();
}
void World::removeBody(const ObjectNameTag& tag) {
@ -95,11 +115,6 @@ void World::update() {
}
}
void World::projectObjectsInCamera(std::shared_ptr<Camera> camera) {
for (auto &[name, body] : _objects)
camera->project(body);
}
std::shared_ptr<RigidBody> World::body(const ObjectNameTag& tag) {
if(_objects.count(tag) == 0)
return nullptr;

View File

@ -7,8 +7,18 @@
#include <map>
#include "Camera.h"
#include "Screen.h"
#include "physics/RigidBody.h"
struct IntersectionInformation final {
const Vec3D pointOfIntersection;
const double distanceToObject;
const Triangle intersectedTriangle;
const ObjectNameTag objectName;
const std::shared_ptr<RigidBody> obj;
const bool intersected;
};
class World final {
private:
std::map<ObjectNameTag, std::shared_ptr<RigidBody>> _objects;
@ -17,19 +27,19 @@ public:
void checkCollision(const ObjectNameTag& tag);
void update();
void projectObjectsInCamera(std::shared_ptr<Camera> camera);
void addBody(std::shared_ptr<RigidBody> mesh, const ObjectNameTag& tag);
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});
// rayCast returns pair of Point4D and std::string:
// 1) Point4D is point of collision
// 2) std::string - title of the object
std::pair<Vec3D, ObjectNameTag> rayCast(const Vec3D& from, const Vec3D& to, const std::string& tag = "");
// std::string skipTags is a string that consist of all objects we want to skip in ray casting
IntersectionInformation rayCast(const Vec3D& from, const Vec3D& to, const std::string& skipTags = "");
void loadMap(const std::string& filename, const Vec3D & scale = Vec3D{1, 1, 1});
std::map<ObjectNameTag, std::shared_ptr<RigidBody>>::iterator begin() { return _objects.begin(); }
std::map<ObjectNameTag, std::shared_ptr<RigidBody>>::iterator end() { return _objects.end(); }
};

View File

@ -8,7 +8,7 @@
using namespace std;
Ak47::Ak47(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::AK47_OBJ, Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) {
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;

View File

@ -10,7 +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{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) {
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;

View File

@ -8,7 +8,7 @@
using namespace std;
Gun::Gun(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::GUN_OBJ, Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) {
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;

View File

@ -6,7 +6,7 @@
#include "Rifle.h"
#include "../ShooterConsts.h"
Rifle::Rifle(int ammo, const std::string &weaponName) : Weapon(weaponName, ShooterConsts::RIFLE_OBJ, Vec3D{3, 3, 3}, Vec3D{-1.2, 1, 0.3}, Vec3D{0, Consts::PI, 0}) {
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;

View File

@ -9,7 +9,7 @@
using namespace std;
Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::SHOTGUN_OBJ, Vec3D{3, 3, 3}, Vec3D{-0.95, 1.3, -0.6}, Vec3D{0, Consts::PI, 0}) {
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;
@ -25,7 +25,7 @@ Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, S
}
std::map<ObjectNameTag, double>
Shotgun::processFire(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
Shotgun::processFire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
std::map<ObjectNameTag, double> damagedPlayers;
for(int i = 0; i < 15; i++) {

View File

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

View File

@ -21,7 +21,7 @@ Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, co
translate(t);
}
std::map<ObjectNameTag, double> Weapon::fire(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
FireInformation Weapon::fire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
if(_clipAmmo == 0) {
reload();
if(_clipAmmo == 0)
@ -29,7 +29,7 @@ std::map<ObjectNameTag, double> Weapon::fire(std::function<std::pair<Vec3D, Obje
}
if(_clipAmmo <= 0 || std::abs(Time::time() - _lastFireTime) < _fireDelay || std::abs(Time::time() - _lastReloadTime) < _reloadTime)
return std::map<ObjectNameTag, double>();
return FireInformation{std::map<ObjectNameTag, double>(), false};
_lastFireTime = Time::time();
_clipAmmo--;
@ -37,7 +37,7 @@ std::map<ObjectNameTag, double> Weapon::fire(std::function<std::pair<Vec3D, Obje
SoundController::playSound(SoundTag("fire"), fireSound);
Log::log("Weapon::fire (" + std::to_string(_stockAmmo) + " : " + std::to_string(_clipAmmo) + ")");
return processFire(std::move(rayCastFunction), position, direction);
return FireInformation{processFire(std::move(rayCastFunction), position, direction), true};
}
void Weapon::reload() {
@ -56,11 +56,11 @@ void Weapon::reload() {
_lastReloadTime = Time::time();
}
std::map<ObjectNameTag, double> Weapon::processFire(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
std::map<ObjectNameTag, double> Weapon::processFire(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
return addTrace(std::move(rayCastFunction), position, direction);
}
std::map<ObjectNameTag, double> Weapon::addTrace(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& from, const Vec3D& directionTo) {
std::map<ObjectNameTag, double> Weapon::addTrace(std::function<IntersectionInformation(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& from, const Vec3D& directionTo) {
std::map<ObjectNameTag, double> damagedPlayers;
double spreading = _spreading*ShooterConsts::FIRE_DISTANCE/100;
@ -70,13 +70,12 @@ std::map<ObjectNameTag, double> Weapon::addTrace(std::function<std::pair<Vec3D,
// damage player
auto rayCast = rayCastFunction(from, from + directionTo * ShooterConsts::FIRE_DISTANCE + randV);
if(rayCast.second.str().find("Enemy") != std::string::npos) {
damagedPlayers[rayCast.second] += _damage/(1.0 + (from - rayCast.first).abs());
}
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]);
Vec3D lineTo = rayCast.first == Vec3D(0) ? position() + -lookAt() * ShooterConsts::FIRE_DISTANCE + randV: rayCast.first;
Vec3D lineTo = rayCast.intersected ? rayCast.pointOfIntersection : position() + -lookAt() * ShooterConsts::FIRE_DISTANCE + randV;
_addTraceCallBack(lineFrom, lineTo);
return damagedPlayers;

View File

@ -15,6 +15,11 @@
#include "../engine/SoundController.h"
#include "../engine/Consts.h"
struct FireInformation {
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
@ -39,14 +44,14 @@ protected:
std::function<void(const Vec3D&, const Vec3D&)> _addTraceCallBack;
std::map<ObjectNameTag, double> addTrace(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
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<std::pair<Vec3D, ObjectNameTag>(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);
std::map<ObjectNameTag, double> fire(std::function<std::pair<Vec3D, ObjectNameTag>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
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); }