diff --git a/Faceball2030/Editor.h b/Faceball2030/Editor.h index d5e988c..dd55ffe 100644 --- a/Faceball2030/Editor.h +++ b/Faceball2030/Editor.h @@ -14,6 +14,7 @@ enum EnemyID { SHOOTME2, ISHOOT, ISHOOT2, + SHOOTME_ARMOR, SONAR, COIN = 56, POWERUP_ARMOR = 57, diff --git a/Faceball2030/MapFormat.txt b/Faceball2030/MapFormat.txt index fc4bb7a..403ce8f 100644 --- a/Faceball2030/MapFormat.txt +++ b/Faceball2030/MapFormat.txt @@ -12,7 +12,7 @@ Width*Height 16-bit values ^ ^ En ID^ ^^^^ | ^^^ NESW | Wave 321 -Blink +Blink (UNUSED! Changed our minds) Armor Speed diff --git a/Faceball2030/assets/Powerup.mtl b/Faceball2030/assets/Powerup.mtl new file mode 100644 index 0000000..e7be6b1 --- /dev/null +++ b/Faceball2030/assets/Powerup.mtl @@ -0,0 +1,11 @@ +# Exported from Wings 3D 2.2.9 +newmtl sphere1_auv +Ns 19.999999999999996 +d 1.0 +illum 2 +Kd 1.0 1.0 1.0 +Ka 0.0 0.0 0.0 +Ks 0.19 0.19 0.19 +Ke 0.0 0.0 0.0 +map_Kd sphere1_auv2.png + diff --git a/Faceball2030/assets/Powerup.wings b/Faceball2030/assets/Powerup.wings new file mode 100644 index 0000000..b0e4b08 Binary files /dev/null and b/Faceball2030/assets/Powerup.wings differ diff --git a/Faceball2030/assets/Powerup2.mtl b/Faceball2030/assets/Powerup2.mtl new file mode 100644 index 0000000..1c5f44d --- /dev/null +++ b/Faceball2030/assets/Powerup2.mtl @@ -0,0 +1,11 @@ +# Exported from Wings 3D 2.2.9 +newmtl octahedron3_auv +Ns 19.999999999999996 +d 1.0 +illum 2 +Kd 1.0 1.0 1.0 +Ka 0.0 0.0 0.0 +Ks 0.19 0.19 0.19 +Ke 0.0 0.0 0.0 +map_Kd octahedron3_auv.png + diff --git a/Faceball2030/assets/Powerup2.wings b/Faceball2030/assets/Powerup2.wings new file mode 100644 index 0000000..0d1ad06 Binary files /dev/null and b/Faceball2030/assets/Powerup2.wings differ diff --git a/Faceball2030/assets/map/map1.map b/Faceball2030/assets/map/map1.map index 4ece5d2..e241d78 100644 --- a/Faceball2030/assets/map/map1.map +++ b/Faceball2030/assets/map/map1.map @@ -20,7 +20,7 @@ 8196 8193 2 -24580 +25492 8201 8204 8197 diff --git a/Faceball2030/assets/octahedron3_auv.png b/Faceball2030/assets/octahedron3_auv.png new file mode 100644 index 0000000..a470e10 Binary files /dev/null and b/Faceball2030/assets/octahedron3_auv.png differ diff --git a/Faceball2030/assets/powerup.png b/Faceball2030/assets/powerup.png new file mode 100644 index 0000000..2e482a3 Binary files /dev/null and b/Faceball2030/assets/powerup.png differ diff --git a/Faceball2030/assets/powerup2.png b/Faceball2030/assets/powerup2.png new file mode 100644 index 0000000..56e6ee3 Binary files /dev/null and b/Faceball2030/assets/powerup2.png differ diff --git a/Faceball2030/assets/sphere1_auv2.png b/Faceball2030/assets/sphere1_auv2.png new file mode 100644 index 0000000..7f93def Binary files /dev/null and b/Faceball2030/assets/sphere1_auv2.png differ diff --git a/Faceball2030/main.cpp b/Faceball2030/main.cpp index 7af8c44..9b906de 100644 --- a/Faceball2030/main.cpp +++ b/Faceball2030/main.cpp @@ -11,7 +11,7 @@ using namespace olc; FaceBall* game; Enemy::Enemy(EnemyID id,vec3d pos,float rot,float radius) - :id(id), health(game->enemyData[id].health), fireDelay(0), + :id(id), health(game->enemyData[id].health), fireDelay(0), blinking(game->enemyData[id].blinking), Object({game->enemyData[id].mesh,pos,rot,radius}) {} EnemyID Enemy::GetID() { @@ -104,12 +104,31 @@ bool Enemy::isExploded() { return exploded; } +bool Enemy::Update(float fElapsedTime) { + if (!isDead()) { + aliveTime += fElapsedTime; + if (isBlinking()) { + blinkingAmt = std::sinf(30 * aliveTime); + } + } + return true; +} + +void Enemy::OnDeathEvent() { + game->SubtractTag(); + if (game->enemyData[id].powerupDrop != PowerupType::NONE) { + game->SpawnPowerup(game->enemyData[id].powerupDrop, pos); + } + blinkingAmt = 1; +} + void FaceBall::InitializeEnemyData() { enemyData[EnemyID::NONE] = { "VOID",undefined,BLACK }; enemyData[EXIT] = { "EXIT",undefined,GREEN }; enemyData[START] = { "SPAWN POSITION",undefined,{128,64,0} }; enemyData[SHOOTME] = { "SHOOTME",enemy_ShootMe,YELLOW,1,1,PI / 8,2,1,0.2f,true }; enemyData[SHOOTME2] = { "SHOOTME2",enemy_IShoot,YELLOW,1,1,PI / 6,2,1,0.3f,true }; + enemyData[SHOOTME_ARMOR] = { "SHOOTME_ARMOR",enemy_ShootMe,YELLOW,6,1,PI / 6,2,1,0.3f,true,PowerupType::ARMOR,true }; enemyData[SONAR] = { "Sonar",enemy_Sonar,RED,5,1,PI / 8,2,1 }; enemyData[COIN] = { "Coin",undefined,BLUE }; enemyData[POWERUP_ARMOR] = { "Armor",undefined,{96,0,96} }; @@ -121,6 +140,32 @@ void FaceBall::InitializeEnemyData() { enemyData[AREA_MAP] = { "Map",undefined,GREEN }; } +void FaceBall::InitializePowerupColors() { + powerupColorData[PowerupType::ARMOR] = DARK_GREEN; + powerupColorData[PowerupType::SPEED] = DARK_BLUE; + powerupColorData[PowerupType::SHOTS] = DARK_RED; + powerupColorData[PowerupType::STOP] = RED; + powerupColorData[PowerupType::SHIELD] = CYAN; + powerupColorData[PowerupType::CAMO] = MAGENTA; + powerupColorData[PowerupType::MAP] = GREEN; + powerupColorData[PowerupType::COIN] = BLUE; +} + +Powerup::Powerup(Mesh mesh, vec3d pos, float rot, PowerupType type) + : type(type), col(game->powerupColorData[type]), Object{ mesh,pos,rot,0.375f } {} + +bool Powerup::Update(float fElapsedTime) { + aliveTime += fElapsedTime; + colorCycle = std::sinf(10 * aliveTime); + col = game->powerupColorData[type] * colorCycle; + return true; +} + +void FaceBall::SpawnPowerup(PowerupType type, vec3d pos) { + Mesh& mesh = (type <= PowerupType::SHOTS) ? powerup : powerup2; + powerups.push_back({ mesh,pos,0,type }); +} + void FaceBall::ConvertBulletColor(Mesh& bullet, Pixel col) { for (Triangle& t : bullet.tris) { t.col[0] = col; @@ -494,6 +539,8 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& vec3d* outside_points[3]; int nOutsidePointCount = 0; vec2d* inside_tex[3]; int nInsideTexCount = 0; vec2d* outside_tex[3]; int nOutsideTexCount = 0; + Pixel* inside_col[3]; int nInsideColCount = 0; + Pixel* outside_col[3]; int nOutsideColCount = 0; // Get signed distance of each point in triangle to plane @@ -501,21 +548,21 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& float d1 = dist(in_tri.p[1]); float d2 = dist(in_tri.p[2]); - if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.uv[0]; } + if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.uv[0]; inside_col[nInsideColCount++] = &in_tri.col[0]; } else { - outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.uv[0]; + outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.uv[0]; outside_col[nOutsideColCount++] = &in_tri.col[0]; } if (d1 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.uv[1]; + inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.uv[1]; inside_col[nInsideColCount++] = &in_tri.col[1]; } else { - outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.uv[1]; + outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.uv[1]; outside_col[nOutsideColCount++] = &in_tri.col[1]; } if (d2 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.uv[2]; + inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.uv[2]; inside_col[nInsideColCount++] = &in_tri.col[2]; } else { - outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.uv[2]; + outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.uv[2]; outside_col[nOutsideColCount++] = &in_tri.col[2]; } // Now classify triangle points, and break the input triangle into @@ -553,6 +600,7 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& // The inside point is valid, so keep that... out_tri1.p[0] = *inside_points[0]; out_tri1.uv[0] = *inside_tex[0]; + out_tri1.col[0] = *inside_col[0]; // but the two new points are at the locations where the // original sides of the triangle (lines) intersect with the plane @@ -560,11 +608,19 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& out_tri1.p[1] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); out_tri1.uv[1].u = t * (outside_tex[0]->u - inside_tex[0]->u) + inside_tex[0]->u; out_tri1.uv[1].v = t * (outside_tex[0]->v - inside_tex[0]->v) + inside_tex[0]->v; + out_tri1.col[1].r = t * (outside_col[0]->r - inside_col[0]->r) + inside_col[0]->r; + out_tri1.col[1].g = t * (outside_col[0]->g - inside_col[0]->g) + inside_col[0]->g; + out_tri1.col[1].b = t * (outside_col[0]->b - inside_col[0]->b) + inside_col[0]->b; + //out_tri1.col[1].a = t * (outside_col[0]->a - inside_col[0]->a) + inside_col[0]->a; out_tri1.uv[1].w = t * (outside_tex[0]->w - inside_tex[0]->w) + inside_tex[0]->w; out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); out_tri1.uv[2].u = t * (outside_tex[1]->u - inside_tex[0]->u) + inside_tex[0]->u; out_tri1.uv[2].v = t * (outside_tex[1]->v - inside_tex[0]->v) + inside_tex[0]->v; + out_tri1.col[2].r = t * (outside_col[1]->r - inside_col[0]->r) + inside_col[0]->r; + out_tri1.col[2].g = t * (outside_col[1]->g - inside_col[0]->g) + inside_col[0]->g; + out_tri1.col[2].b = t * (outside_col[1]->b - inside_col[0]->b) + inside_col[0]->b; + //out_tri1.col[2].a = t * (outside_col[1]->a - inside_col[0]->a) + inside_col[0]->a; out_tri1.uv[2].w = t * (outside_tex[1]->w - inside_tex[0]->w) + inside_tex[0]->w; return 1; // Return the newly formed single triangle @@ -593,11 +649,17 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& out_tri1.p[1] = *inside_points[1]; out_tri1.uv[0] = *inside_tex[0]; out_tri1.uv[1] = *inside_tex[1]; + out_tri1.col[0] = *inside_col[0]; + out_tri1.col[1] = *inside_col[1]; float t; out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); out_tri1.uv[2].u = t * (outside_tex[0]->u - inside_tex[0]->u) + inside_tex[0]->u; out_tri1.uv[2].v = t * (outside_tex[0]->v - inside_tex[0]->v) + inside_tex[0]->v; + out_tri1.col[2].r = t * (outside_col[0]->r - inside_col[0]->r) + inside_col[0]->r; + out_tri1.col[2].g = t * (outside_col[0]->g - inside_col[0]->g) + inside_col[0]->g; + out_tri1.col[2].b = t * (outside_col[0]->b - inside_col[0]->b) + inside_col[0]->b; + //out_tri1.col[2].a = t * (outside_col[0]->a - inside_col[0]->a) + inside_col[0]->a; out_tri1.uv[2].w = t * (outside_tex[0]->w - inside_tex[0]->w) + inside_tex[0]->w; // The second triangle is composed of one of he inside points, a @@ -605,11 +667,17 @@ int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& // triangle and the plane, and the newly created point above out_tri2.p[0] = *inside_points[1]; out_tri2.uv[0] = *inside_tex[1]; + out_tri2.col[0] = *inside_col[1]; out_tri2.p[1] = out_tri1.p[2]; out_tri2.uv[1] = out_tri1.uv[2]; + out_tri2.col[1] = out_tri1.col[2]; out_tri2.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); out_tri2.uv[2].u = t * (outside_tex[0]->u - inside_tex[1]->u) + inside_tex[1]->u; out_tri2.uv[2].v = t * (outside_tex[0]->v - inside_tex[1]->v) + inside_tex[1]->v; + out_tri1.col[2].r = t * (outside_col[0]->r - inside_col[1]->r) + inside_col[1]->r; + out_tri1.col[2].g = t * (outside_col[0]->g - inside_col[1]->g) + inside_col[1]->g; + out_tri1.col[2].b = t * (outside_col[0]->b - inside_col[1]->b) + inside_col[1]->b; + //out_tri1.col[2].a = t * (outside_col[0]->a - inside_col[1]->a) + inside_col[1]->a; out_tri2.uv[2].w = t * (outside_tex[0]->w - inside_tex[1]->w) + inside_tex[1]->w; return 2; // Return two newly formed triangles which form a quad } @@ -914,7 +982,12 @@ void FaceBall::RenderWorld() { t.col[0] = t.col[1] = t.col[2] = {0,(uint8_t)(std::abs(std::sinf(2*PI*gameTimer)) * 255),0}; } for (auto& enemy : enemies) { - RenderMesh(matView, vecTrianglesToRaster, enemy); + if (enemy.blinkingAmt > 0.4f) { + RenderMesh(matView, vecTrianglesToRaster, enemy); + } + } + for (auto& powerup : powerups) { + RenderMesh(matView, vecTrianglesToRaster, powerup); } for (auto& bullet : bullets) { RenderBulletMesh(matView, vecTrianglesToRasterTranslucent, bullet); @@ -1286,11 +1359,15 @@ bool FaceBall::OnUserCreate() life1 = new Decal(new Sprite("assets/life1.png")); crosshair = new Decal(new Sprite("assets/crosshair.png")); hudmeter = new Decal(new Sprite("assets/hudmeter.png")); + powerup_tex = new Decal(new Sprite("assets/powerup.png")); + powerup2_tex = new Decal(new Sprite("assets/powerup2.png")); enemy_ShootMe = { "assets/enemies/ShootMe.obj", enemy_ShootMe_tex }; enemy_IShoot = { "assets/enemies/IShoot.obj", enemy_IShoot_tex }; enemy_Sonar = { "assets/enemies/Sonar.obj", enemy_Sonar_tex }; bullet = { "assets/enemies/bullet.obj",bullet_tex }; + powerup = { "assets/Powerup.obj",powerup_tex}; + powerup2 = { "assets/Powerup2.obj",powerup2_tex }; mapExit = { "assets/Exit.obj",dot }; mapWalls.texture = wall_tex; mapFloor.texture = floor_tex; @@ -1356,7 +1433,7 @@ bool Bullet::Update(float fElapsedTime) { Enemy& enemy = game->enemies[collided_enemy]; enemy.Hurt(); if (enemy.isDead()) { - game->SubtractTag(); + enemy.OnDeathEvent(); } return false; } @@ -1396,6 +1473,99 @@ void FaceBall::HurtPlayer(EnemyID id,int damage,bool blinking) { screenCol = enemyData[lastHitBy].col; } +void FaceBall::Display3DKillerModel() { + // Set up rotation matrices + mat4x4 matRotZ, matRotX, matWorld; + + matRotZ = Matrix_MakeRotationZ(0); + matRotX = Matrix_MakeRotationX(0); + + //matTrans = Matrix_MakeTranslation(0.0f, 0.0f, 0.0f); + matWorld = Matrix_MakeIdentity(); + matWorld = Matrix_MultiplyMatrix(matRotZ, matRotX); + //matWorld = Matrix_MultiplyMatrix(matWorld, matTrans); + + vec3d vUp = { 0,1,0 }; + vec3d vTarget = { 0,sinf(0.0944495052),cosf(0.0944495052) }; + mat4x4 matCameraRot = Matrix_MakeRotationY(3.12987614 - PI / 2); + vLookDir = Matrix_MultiplyVector(matCameraRot, vTarget); + vec3d camera = { 0.758110702,0.222716771,3.00489759 }; + vTarget = Vector_Add(camera, vLookDir); + mat4x4 matCamera = Matrix_PointAt(camera, vTarget, vUp); + mat4x4 matView = Matrix_QuickInverse(matCamera); + std::vectorvecTrianglesToRaster; + Object o = { enemyData[lastHitBy].mesh,{0,0,3} }; + RenderMeshDeathScreen(matView, vecTrianglesToRaster, o); + + //std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;}); + triRenderCount = 0; + for (auto& triToRaster : vecTrianglesToRaster) { + Triangle clipped[2]; + std::listlistTriangles; + listTriangles.push_back(triToRaster); + int nNewTriangles = 1; + + for (int p = 0; p < 4; p++) + { + int nTrisToAdd = 0; + while (nNewTriangles > 0) + { + // Take triangle from front of queue + Triangle test = listTriangles.front(); + listTriangles.pop_front(); + nNewTriangles--; + + // Clip it against a plane. We only need to test each + // subsequent plane, against subsequent new triangles + // as all triangles after a plane clip are guaranteed + // to lie on the inside of the plane. I like how this + // comment is almost completely and utterly justified + switch (p) + { + case 0: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, clipped[0], clipped[1]); break; + case 1: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, (float)ScreenHeight() - 1, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, clipped[0], clipped[1]); break; + case 2: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; + case 3: nTrisToAdd = Triangle_ClipAgainstPlane({ (float)ScreenWidth() - 1, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; + } + + // Clipping may yield a variable number of triangles, so + // add these new ones to the back of the queue for subsequent + // clipping against next planes + for (int w = 0; w < nTrisToAdd; w++) + listTriangles.push_back(clipped[w]); + } + nNewTriangles = listTriangles.size(); + } + + for (auto& t : listTriangles) { + // Rasterize triangle + SetDecalStructure(DecalStructure::LIST); + SetDecalMode(DecalMode::NORMAL); + DrawPolygonDecal(t.tex, { + {t.p[0].x, t.p[0].y}, + {t.p[1].x, t.p[1].y}, + {t.p[2].x, t.p[2].y} + }, { + {t.uv[0].u,t.uv[0].v}, + {t.uv[1].u,t.uv[1].v}, + {t.uv[2].u,t.uv[2].v}, + }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { t.col[0],t.col[1],t.col[2] }); + /*SetDecalMode(DecalMode::WIREFRAME); + DrawPolygonDecal(nullptr,{ + {t.p[0].x, t.p[0].y}, + {t.p[1].x, t.p[1].y}, + {t.p[2].x, t.p[2].y} + },{ + {0,0}, + {0,0}, + {0,0}, + }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { BLACK,BLACK,BLACK });*/ + SetDecalStructure(DecalStructure::FAN); + triRenderCount++; + } + } +} + void FaceBall::RenderHud(float fElapsedTime) { if (hudShakeTime > 0) { hudShakeTime -= fElapsedTime; @@ -1412,96 +1582,7 @@ void FaceBall::RenderHud(float fElapsedTime) { FillRectDecal({ 0,0 }, { float(ScreenWidth()),float(ScreenHeight()) }); std::string topText = enemyData[lastHitBy].name + " SAYS"; std::string bottomText = "HAVE A NICE DAY !"; - // Set up rotation matrices - mat4x4 matRotZ, matRotX, matWorld; - - matRotZ = Matrix_MakeRotationZ(0); - matRotX = Matrix_MakeRotationX(0); - - //matTrans = Matrix_MakeTranslation(0.0f, 0.0f, 0.0f); - matWorld = Matrix_MakeIdentity(); - matWorld = Matrix_MultiplyMatrix(matRotZ, matRotX); - //matWorld = Matrix_MultiplyMatrix(matWorld, matTrans); - - vec3d vUp = { 0,1,0 }; - vec3d vTarget = { 0,sinf(0.0944495052),cosf(0.0944495052) }; - mat4x4 matCameraRot = Matrix_MakeRotationY(3.12987614 - PI / 2); - vLookDir = Matrix_MultiplyVector(matCameraRot, vTarget); - vec3d camera = { 0.758110702,0.222716771,3.00489759 }; - vTarget = Vector_Add(camera, vLookDir); - mat4x4 matCamera = Matrix_PointAt(camera, vTarget, vUp); - mat4x4 matView = Matrix_QuickInverse(matCamera); - std::vectorvecTrianglesToRaster; - Object o = { enemyData[lastHitBy].mesh,{0,0,3} }; - RenderMeshDeathScreen(matView, vecTrianglesToRaster, o); - - //std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;}); - triRenderCount = 0; - for (auto& triToRaster : vecTrianglesToRaster) { - Triangle clipped[2]; - std::listlistTriangles; - listTriangles.push_back(triToRaster); - int nNewTriangles = 1; - - for (int p = 0; p < 4; p++) - { - int nTrisToAdd = 0; - while (nNewTriangles > 0) - { - // Take triangle from front of queue - Triangle test = listTriangles.front(); - listTriangles.pop_front(); - nNewTriangles--; - - // Clip it against a plane. We only need to test each - // subsequent plane, against subsequent new triangles - // as all triangles after a plane clip are guaranteed - // to lie on the inside of the plane. I like how this - // comment is almost completely and utterly justified - switch (p) - { - case 0: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, clipped[0], clipped[1]); break; - case 1: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, (float)ScreenHeight() - 1, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, clipped[0], clipped[1]); break; - case 2: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; - case 3: nTrisToAdd = Triangle_ClipAgainstPlane({ (float)ScreenWidth() - 1, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; - } - - // Clipping may yield a variable number of triangles, so - // add these new ones to the back of the queue for subsequent - // clipping against next planes - for (int w = 0; w < nTrisToAdd; w++) - listTriangles.push_back(clipped[w]); - } - nNewTriangles = listTriangles.size(); - } - - for (auto& t : listTriangles) { - // Rasterize triangle - SetDecalStructure(DecalStructure::LIST); - SetDecalMode(DecalMode::NORMAL); - DrawPolygonDecal(t.tex, { - {t.p[0].x, t.p[0].y}, - {t.p[1].x, t.p[1].y}, - {t.p[2].x, t.p[2].y} - }, { - {t.uv[0].u,t.uv[0].v}, - {t.uv[1].u,t.uv[1].v}, - {t.uv[2].u,t.uv[2].v}, - }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { t.col[0],t.col[1],t.col[2] }); - /*SetDecalMode(DecalMode::WIREFRAME); - DrawPolygonDecal(nullptr,{ - {t.p[0].x, t.p[0].y}, - {t.p[1].x, t.p[1].y}, - {t.p[2].x, t.p[2].y} - },{ - {0,0}, - {0,0}, - {0,0}, - }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { BLACK,BLACK,BLACK });*/ - SetDecalStructure(DecalStructure::FAN); - triRenderCount++; - } - } + Display3DKillerModel(); DrawStringDecal({ (float)(ScreenWidth() / 2 - GetTextSize(topText).x / 2 * 3),140.f }, topText, { 96,96,255 }, { 3,6 }); DrawStringDecal({ float(ScreenWidth() / 2 - GetTextSize(bottomText).x / 2 * 3),float(ScreenHeight() - 140.f) }, bottomText, { 96,96,255 }, { 3,6 }); } @@ -1785,22 +1866,26 @@ void FaceBall::RunEnemyAI(Enemy& e,float fElapsedTime,int myIndex) { bool FaceBall::OnUserUpdate(float fElapsedTime) { gameTimer += fElapsedTime; - for (std::vector::iterator it = bullets.begin(); it != bullets.end(); ++it) { - Bullet& b = *it; + for (std::vector::iterator it = bullets.end(); it != bullets.begin();) { + Bullet& b = *--it; if (!b.Update(fElapsedTime)) { it=bullets.erase(it); - if (it == bullets.end()) { - break; - } } } for (int i = 0; i < enemies.size(); i++) { Enemy& e = enemies[i]; + e.Update(fElapsedTime); if (e.isLastHitTimerActive()) { e.reduceLastHitTimer(fElapsedTime); } RunEnemyAI(e, fElapsedTime,i); } + for (std::vector::iterator it = powerups.end(); it != powerups.begin();) { + Powerup& p = *--it; + if (!p.Update(fElapsedTime)) { + it = powerups.erase(it); + } + } switch (mode) { case GAME: { if (hp > 0) { diff --git a/Faceball2030/main.h b/Faceball2030/main.h index be842f8..40cc480 100644 --- a/Faceball2030/main.h +++ b/Faceball2030/main.h @@ -156,6 +156,27 @@ struct Bullet : Object{ bool Update(float fElapsedTime); }; +enum class PowerupType { + NONE, + ARMOR, + SPEED, + SHOTS, + STOP, + SHIELD, + CAMO, + MAP, + COIN +}; + +struct Powerup : Object { + PowerupType type; + Powerup(Mesh mesh, vec3d pos, float rot, PowerupType type); + Pixel col; + float colorCycle=1; + float aliveTime=0; + bool Update(float fElapsedTime); +}; + struct EnemyData { std::string name; Mesh mesh; @@ -167,6 +188,8 @@ struct EnemyData { float fireDelay = 1; float radius = 0.2f; bool explosive = false; //Explodes on contact. + PowerupType powerupDrop=PowerupType::NONE; + bool blinking = false; }; struct mat4x4 @@ -189,12 +212,14 @@ struct Enemy : public Object { bool exploded = false; //If contacted and explosive, then explosion flag is set instead. float colorFactor = 0; Phase phase=Phase::DEFAULT; - bool blinking = false; //TODO TO BE IMPLEMENTED. 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. @@ -216,6 +241,8 @@ struct Enemy : public Object { void setExploded(bool exploded); bool isBlinking(); bool isExploded(); + bool Update(float fElapsedTime); + void OnDeathEvent(); }; class FaceBall : public PixelGameEngine @@ -230,14 +257,16 @@ class FaceBall : public PixelGameEngine EnemyData GetData(EnemyID id); Decal* circle,*arrow,*YAZAWA; std::mapenemyData; + std::mappowerupColorData; std::vectorenemies; + std::vectorpowerups; private: Mesh mapWalls,mapFloor,enemy_ShootMe,undefined, - enemy_Sonar, mapExit,enemy_IShoot; + enemy_Sonar, mapExit,enemy_IShoot,powerup,powerup2; Decal* dot, * enemy_ShootMe_tex,*bullet_tex,*wall_tex,*floor_tex, *enemy_Sonar_tex,*hud,*exit_wall_tex,*enemy_IShoot_tex, - *life4,*life3,*life2,*life1,*crosshair,*hudmeter; + *life4,*life3,*life2,*life1,*crosshair,*hudmeter,*powerup_tex,*powerup2_tex; vi2d MAP_SIZE; vi2d exitCoords = { 0,0 }; std::vector>map; @@ -336,6 +365,7 @@ class FaceBall : public PixelGameEngine void OnTextEntryComplete(const std::string& sText) override; void InitializeEnemyData(); void InitializeBulletColors(); + 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); @@ -343,6 +373,7 @@ class FaceBall : public PixelGameEngine void RunEnemyAI(Enemy& e,float fElapsedTime,int myIndex); void RenderHud(float fElapsedTime); void ConvertBulletColor(Mesh& bullet, Pixel col); + void Display3DKillerModel(); public: float restingTriangleYDepth = 0.f; std::vectorbullets; @@ -355,4 +386,5 @@ class FaceBall : public PixelGameEngine 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); }; \ No newline at end of file