#pragma once #include "pixelGameEngine.h" #include "Editor.h" #include "geometry2d.h" #include using namespace olc; const float PI = 3.14159f; enum GAMEMODE { GAME, EDITOR, LEVELCOMPLETE }; enum Direction { NORTH = 1, EAST = 2, SOUTH = 4, WEST = 8 }; struct vec2d { float u = 0; float v = 0; float w = 1; }; struct vec3d { float x = 0; float y = 0; float z = 0; float w = 1; friend std::ostream& operator << (std::ostream& os, const vec3d& rhs) { os << rhs.x << "," << rhs.y << "," << rhs.z; return os; } }; struct Player { private: vec3d pos; olc::utils::geom2d::circle playerR; public: Player(vec3d pos,olc::utils::geom2d::circler):pos(pos), playerR(r) {} void UpdatePos(vec3d pos) { this->pos = pos; playerR.pos = { pos.x,pos.z }; } float GetRadius() { return playerR.radius; } vec3d&GetPos() { return pos; } }; struct Triangle { vec3d p[3]; vec2d uv[3]; Pixel col[3]; Decal* tex; }; struct MapSquare { Decal* wallN = NULL; Decal* wallE = NULL; Decal* wallS = NULL; Decal* wallW = NULL; }; struct Mesh { std::vector tris; Decal* texture = NULL; Mesh() {} Mesh(std::string filename, Decal* tex) :texture(tex) { LoadFromObjectFile(filename,tex); } private: void Parse(std::string str, int& v, int& uv) { //std::cout << str << "\n"; std::stringstream s(str.substr(0, str.find("/") + 1)); s >> v; str.erase(0, str.find("/") + 1); std::stringstream s2(str.substr(0, str.find("/") + 1)); s2 >> uv; //std::cout<<" "< verts; std::vector uvs; std::string data; while (f.good()) { f >> data; if (data == "v") { float x, y, z; f >> x >> y >> z; verts.push_back({ x,y,z }); //std::cout << x << " " << y << " " << z << "\n"; } else if (data == "vt") { float u, v; f >> u >> v; uvs.push_back({ u,1 - v }); //std::cout << u << " " << v << "\n"; } else if (data == "f") { //std::cout<<"face\n"; std::string t1, t2, t3; f >> t1 >> t2 >> t3; int v1, v2, v3, uv1, uv2, uv3; Parse(t1, v1, uv1); Parse(t2, v2, uv2); Parse(t3, v3, uv3); tris.push_back({ verts[v1 - 1],verts[v2 - 1],verts[v3 - 1], uvs[uv1 - 1],uvs[uv2 - 1],uvs[uv3 - 1],{WHITE,WHITE,WHITE},tex }); } } return true; } }; struct Object { Mesh mesh; vec3d pos = { 0,0 }; float rot = 0; float radius = 0.2f; }; struct Bullet : Object{ vf2d spd = { 0,0 }; Pixel col = GREEN; bool friendly=true; EnemyID shooterID; int shooterIndex = -1; bool shooterBlinking = false; bool Update(float fElapsedTime); }; struct Powerup : Object { PowerupType type; Powerup(Mesh mesh, vec3d pos, float rot, PowerupType type); Pixel col; float colorCycle=1; float aliveTime=0; bool opened = false; bool Update(float fElapsedTime); }; struct PowerupData { std::string name; Pixel col; }; struct EnemyData { std::string name; Mesh mesh; Pixel col=YELLOW; int health = 1; float movSpd = 1; float rotSpd = PI / 8; int ammo = 2; float fireDelay = 1; float radius = 0.2f; bool explosive = false; //Explodes on contact. PowerupType powerupDrop=PowerupType::NONE; bool blinking = false; }; struct mat4x4 { float m[4][4] = { 0 }; }; enum class Phase { DEFAULT, TURNING, }; struct Enemy : public Object { private: EnemyID id; int health=1; std::vector shots; float fireDelay=0; float deathTimer=0; bool exploded = false; //If contacted and explosive, then explosion flag is set instead. float colorFactor = 0; Phase phase=Phase::DEFAULT; float lastHitTime = 0; bool blinking = false; float aliveTime = 0; public: float turnAmt = 0; bool flippedTriangles = false; bool finishedAnimation = false; float blinkingAmt = 1; //>0.5 the enemy is visible. Enemy(EnemyID id, vec3d pos, float rot, float radius); EnemyID GetID(); //Can set the damage to 0 to cause just a visual hit. void Hurt(int damage=1); bool isDead(); void increaseDeathTimer(float fElapsedTime); bool deathAnimationOver(); void increaseColorFactor(float fElapsedTime); float getColorFactor(); void decreaseColorFactor(); Phase GetPhase(); void SetPhase(Phase phase); bool CanShoot(); void ShootBullet(int myIndex); void ReloadBullet(float fElapsedTime); bool isLastHitTimerActive(); void reduceLastHitTimer(float fElapsedTime); bool isExplosive(); void setExploded(bool exploded); bool isBlinking(); bool isExploded(); bool Update(float fElapsedTime); void OnDeathEvent(); vf2d GetPlayerPosition(); Enemy freshCopy(bool randomizeLoc=false); }; class FaceBall : public PixelGameEngine { bool freeRoam = false; public: FaceBall() { sAppName = "3D Demo"; } EnemyData GetData(EnemyID id); Decal* circle,*arrow,*YAZAWA; std::mapenemyData; std::mappowerupData; std::vectorenemies; std::vectorwave2Enemies; std::vectorwave3Enemies; std::vectorpowerups; private: Mesh mapWalls,mapFloor,enemy_ShootMe,undefined, enemy_Sonar, mapExit,enemy_ShootMe2,powerup,powerup2, enemy_IShoot; Sprite*mapSpr; Decal*mapDecal; Decal* dot, * enemy_ShootMe_tex,*bullet_tex,*wall_tex,*floor_tex, *enemy_Sonar_tex,*hud,*exit_wall_tex,*enemy_ShootMe2_tex,*enemy_IShoot_tex, *life4,*life3,*life2,*life1,*crosshair,*hudmeter,*powerup_tex,*powerup2_tex, *powerups_tex; vi2d exitCoords = { 0,0 }; std::vectorknownGoodPositions; std::vector>map; std::vectorobjects; GAMEMODE mode=GAMEMODE::GAME; Editor editor; int MapWallsObjectIndex = -1; bool exitWallsCleared = false; int level=1; int tagsRemaining = 10; int lives = 3; double gameTimer = 0; int lastPowerupCollidedWith = -1; std::string hudDisplayText = ""; float stopDuration = 0,shieldDuration=0,camoDuration=0; bool hasMapUpgrade = false; std::arraycolorCycle={ RED, BLACK, YELLOW, WHITE, GREEN, WHITE, CYAN, BLACK, MAGENTA, BLACK, GREY, WHITE, BLUE, BLACK }; int topTargetColInd,botTargetColInd; Pixel topTargetCol,botTargetCol; Pixel topCurrentCol,botCurrentCol; Pixel topCol,botCol; float colTransferAmt=0; mat4x4 matProj; vec3d vLookDir; float zOffset = 2; float fTheta = 0; float fYaw = 0; float pitch = -PI / 6; std::array meter_ARMOR = { vf2d{1039,218}, vf2d{1040,260}, vf2d{1166,244}, vf2d{1164,195} }, meter_SPEED = { vf2d{1038,360}, vf2d{1038,405}, vf2d{1167,408}, vf2d{1167,360} }, meter_SHOTS = { vf2d{1035,512}, vf2d{1032,558}, vf2d{1162,575}, vf2d{1163,525} }; Player player = { {3.7,0.3,0.7}, {{0.5,0.5},0.2} }; const int baseHP = 3; int hp = baseHP; int maxHP=hp; int score = 0; int lastAwardedScore = 0; Object walls; Object exit; vec3d freeRoamCamera = { 1,0.5,1 }; float freeRoamCamera_pitch = pitch; float freeRoamCamera_yaw = fYaw; int armorUpgrades = 0, maxArmorUpgrades=20; int speedUpgrades = 0, maxSpeedUpgrades=5; int shotsUpgrades = 0, maxShotsUpgrades=3; const float baseMoveSpd = 2.0f; const float baseTurnSpd = 2.0f; const float baseShotSpd = 4.0f; int baseShotLimit = 2; int shotLimit = baseShotLimit; float moveSpd = baseMoveSpd; float turnSpd = baseTurnSpd; float hudOffset = 0; float hudOffsetAcc = 0; float hudShakeAmt = 0; Pixel screenCol = WHITE; float screenAlpha = 0; float screenAlpha2 = 255.f; float respawnTimer = 0; vec3d spawnLoc = { 0,0.3,0 }; FacingDirection spawnFacingDir = FacingDirection::NORTH; EnemyID lastHitBy=EnemyID::NONE; bool lastHitByBlinking = false; int triRenderCount = 0; vec3d Matrix_MultiplyVector(mat4x4& m, vec3d& i); mat4x4 Matrix_MakeIdentity(); mat4x4 Matrix_MakeRotationX(float fAngleRad); mat4x4 Matrix_MakeRotationY(float fAngleRad); mat4x4 Matrix_MakeRotationZ(float fAngleRad); mat4x4 Matrix_MakeTranslation(float x, float y, float z); mat4x4 Matrix_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); mat4x4 Matrix_MultiplyMatrix(mat4x4& m1, mat4x4& m2); mat4x4 Matrix_PointAt(vec3d& pos, vec3d& target, vec3d& up); mat4x4 Matrix_QuickInverse(mat4x4& m); vec3d Vector_Add(vec3d& v1, vec3d& v2); vec3d Vector_Sub(vec3d& v1, vec3d& v2); vec3d Vector_Mul(vec3d& v1, float k); vec3d Vector_Div(vec3d& v1, float k); float Vector_DotProduct(vec3d& v1, vec3d& v2); float Vector_Length(vec3d& v); vec3d Vector_Normalise(vec3d& v); vec3d Vector_CrossProduct(vec3d& v1, vec3d& v2); vec3d Vector_IntersectPlane(vec3d& plane_p, vec3d& plane_n, vec3d& lineStart, vec3d& lineEnd, float& t); int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& in_tri, Triangle& out_tri1, Triangle& out_tri2); void RenderWorld(); void HandleKeys(float fElapsedTime); void AddWall(int dir, vi2d gridSquare); bool OnUserCreate() override; bool OnUserUpdate(float fElapsedTime) override; void OnTextEntryComplete(const std::string& sText) override; void InitializeEnemyData(); void InitializePowerupColors(); void LoadLevel(int level); void RenderBulletMesh(mat4x4& matView, std::vector& vecTrianglesToRaster, Bullet& b,bool translucent=true); void RenderMesh(mat4x4&matView, std::vector&vecTrianglesToRaster,Object&o,bool translucent=false); void RenderMeshDeathScreen(mat4x4& matView, std::vector& vecTrianglesToRaster, Object& o); void RenderPowerupMesh(mat4x4& matView, std::vector& vecTrianglesToRaster, Powerup&p); void RunEnemyAI(Enemy& e,float fElapsedTime,int myIndex); void RenderHud(float fElapsedTime); void ConvertBulletColor(Mesh& bullet, Pixel col); void Display3DKillerModel(); int CheckPowerupCollision(vec3d movementVector, vf2d pos, float radius); void ResetScore(); int EnemiesAlive(); public: vi2d MAP_SIZE; float restingTriangleYDepth = 0.f; std::vectorbullets; float hudShakeTime = 0; Mesh bullet; float shotSpd = baseShotSpd; static bool CheckCollision(vec3d movementVector,vf2d pos,float radius); static int CheckEnemyCollision(vec3d movementVector, vf2d pos, float radius, int ignoreIndex = -1); static int CheckExplosiveEnemyCollision(vec3d movementVector, vf2d pos, float radius, int ignoreIndex = -1); static bool CheckPlayerCollision(vec3d movementVector, vf2d pos, float radius); void SubtractTag(); void HurtPlayer(EnemyID id, int damage=1,bool blinking = false); void SpawnPowerup(PowerupType type, vec3d pos); bool PlayerHasCamo(); vf2d GetPlayerPos(); void AddScore(int score); vf2d GetRandomizedSpawnPosition(); };