458 lines
6.8 KiB
C++
458 lines
6.8 KiB
C++
#include "raylib.h"
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <random>
|
|
|
|
struct Wall
|
|
{
|
|
Vector3 position;
|
|
Vector3 size;
|
|
};
|
|
|
|
struct Furniture
|
|
{
|
|
Vector3 position;
|
|
Vector3 size;
|
|
int type;
|
|
};
|
|
|
|
static const int MAZE_W = 41;
|
|
static const int MAZE_H = 41;
|
|
static const float CELL = 4.0f;
|
|
|
|
static bool maze[MAZE_H][MAZE_W];
|
|
static std::vector<Wall> walls;
|
|
static std::vector<Furniture> furniture;
|
|
|
|
extern Vector3 playerPosition;
|
|
extern Camera3D GetPlayerCamera();
|
|
|
|
extern void UpdatePlayer(float deltaTime);
|
|
extern void UpdateEnemy(float deltaTime);
|
|
extern void UpdateWeapons(float deltaTime);
|
|
|
|
extern void DrawEnemy();
|
|
extern void DrawBullets();
|
|
extern void DrawPlayerWeapon();
|
|
|
|
bool IsSolidAt(Vector3 position, float radius)
|
|
{
|
|
for (const Wall& wall : walls)
|
|
{
|
|
if (position.x >= wall.position.x - wall.size.x / 2.0f - radius &&
|
|
position.x <= wall.position.x + wall.size.x / 2.0f + radius &&
|
|
position.z >= wall.position.z - wall.size.z / 2.0f - radius &&
|
|
position.z <= wall.position.z + wall.size.z / 2.0f + radius)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (const Furniture& object : furniture)
|
|
{
|
|
if (position.x >= object.position.x - object.size.x / 2.0f - radius &&
|
|
position.x <= object.position.x + object.size.x / 2.0f + radius &&
|
|
position.z >= object.position.z - object.size.z / 2.0f - radius &&
|
|
position.z <= object.position.z + object.size.z / 2.0f + radius)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static Vector3 CellToWorld(int x, int z)
|
|
{
|
|
return {
|
|
(x - MAZE_W / 2) * CELL,
|
|
0.0f,
|
|
(z - MAZE_H / 2) * CELL
|
|
};
|
|
}
|
|
|
|
static void GenerateMaze()
|
|
{
|
|
for (int z = 0; z < MAZE_H; z++)
|
|
{
|
|
for (int x = 0; x < MAZE_W; x++)
|
|
{
|
|
maze[z][x] = true;
|
|
}
|
|
}
|
|
|
|
std::vector<Vector2> stack;
|
|
stack.push_back({1, 1});
|
|
maze[1][1] = false;
|
|
|
|
std::mt19937 rng(12345);
|
|
|
|
const int dirs[4][2] =
|
|
{
|
|
{ 2, 0 },
|
|
{-2, 0 },
|
|
{ 0, 2 },
|
|
{ 0,-2 }
|
|
};
|
|
|
|
while (!stack.empty())
|
|
{
|
|
Vector2 current = stack.back();
|
|
|
|
std::vector<int> available;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
int nx = (int)current.x + dirs[i][0];
|
|
int nz = (int)current.y + dirs[i][1];
|
|
|
|
if (nx > 0 && nx < MAZE_W - 1 &&
|
|
nz > 0 && nz < MAZE_H - 1 &&
|
|
maze[nz][nx])
|
|
{
|
|
available.push_back(i);
|
|
}
|
|
}
|
|
|
|
if (available.empty())
|
|
{
|
|
stack.pop_back();
|
|
continue;
|
|
}
|
|
|
|
int d = available[rng() % available.size()];
|
|
|
|
int nx = (int)current.x + dirs[d][0];
|
|
int nz = (int)current.y + dirs[d][1];
|
|
|
|
maze[((int)current.y + nz) / 2]
|
|
[((int)current.x + nx) / 2] = false;
|
|
|
|
maze[nz][nx] = false;
|
|
|
|
stack.push_back({(float)nx, (float)nz});
|
|
}
|
|
|
|
for (int z = 3; z < MAZE_H - 3; z += 6)
|
|
{
|
|
for (int x = 3; x < MAZE_W - 3; x += 6)
|
|
{
|
|
maze[z][x] = false;
|
|
|
|
if (x + 1 < MAZE_W - 1)
|
|
maze[z][x + 1] = false;
|
|
|
|
if (x > 1)
|
|
maze[z][x - 1] = false;
|
|
|
|
if (z + 1 < MAZE_H - 1)
|
|
maze[z + 1][x] = false;
|
|
|
|
if (z > 1)
|
|
maze[z - 1][x] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void BuildWalls()
|
|
{
|
|
walls.clear();
|
|
|
|
for (int z = 0; z < MAZE_H; z++)
|
|
{
|
|
for (int x = 0; x < MAZE_W; x++)
|
|
{
|
|
if (!maze[z][x])
|
|
continue;
|
|
|
|
Vector3 p = CellToWorld(x, z);
|
|
|
|
walls.push_back({
|
|
{p.x, 1.5f, p.z},
|
|
{CELL, 3.0f, CELL}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
static void GenerateFurniture()
|
|
{
|
|
furniture.clear();
|
|
|
|
for (int z = 2; z < MAZE_H - 2; z++)
|
|
{
|
|
for (int x = 2; x < MAZE_W - 2; x++)
|
|
{
|
|
if (maze[z][x])
|
|
continue;
|
|
|
|
if ((x * 13 + z * 7) % 17 != 0)
|
|
continue;
|
|
|
|
if (x <= 4 && z <= 4)
|
|
continue;
|
|
|
|
Vector3 p = CellToWorld(x, z);
|
|
|
|
Furniture object;
|
|
object.type = (x * 3 + z * 5) % 5;
|
|
|
|
switch (object.type)
|
|
{
|
|
case 0:
|
|
object.position = {p.x, 0.8f, p.z};
|
|
object.size = {2.4f, 1.6f, 2.4f};
|
|
break;
|
|
|
|
case 1:
|
|
object.position = {p.x, 0.75f, p.z};
|
|
object.size = {1.5f, 1.5f, 1.5f};
|
|
break;
|
|
|
|
case 2:
|
|
object.position = {p.x, 1.35f, p.z};
|
|
object.size = {1.8f, 2.7f, 1.0f};
|
|
break;
|
|
|
|
case 3:
|
|
object.position = {p.x, 0.4f, p.z};
|
|
object.size = {2.5f, 0.8f, 0.8f};
|
|
break;
|
|
|
|
default:
|
|
object.position = {p.x, 0.6f, p.z};
|
|
object.size = {2.0f, 1.2f, 1.2f};
|
|
break;
|
|
}
|
|
|
|
if (!IsSolidAt(object.position, 0.2f))
|
|
furniture.push_back(object);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DrawFloor()
|
|
{
|
|
for (int z = 0; z < MAZE_H; z++)
|
|
{
|
|
for (int x = 0; x < MAZE_W; x++)
|
|
{
|
|
if (maze[z][x])
|
|
continue;
|
|
|
|
Vector3 p = CellToWorld(x, z);
|
|
|
|
int shade = 108 + ((x * 17 + z * 11) % 9);
|
|
|
|
Color color = {
|
|
(unsigned char)shade,
|
|
(unsigned char)shade,
|
|
(unsigned char)(shade + 1),
|
|
255
|
|
};
|
|
|
|
DrawCube(
|
|
{p.x, -0.06f, p.z},
|
|
CELL + 0.16f,
|
|
0.12f,
|
|
CELL + 0.16f,
|
|
color
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DrawWalls()
|
|
{
|
|
for (const Wall& wall : walls)
|
|
{
|
|
DrawCube(
|
|
wall.position,
|
|
wall.size.x,
|
|
wall.size.y,
|
|
wall.size.z,
|
|
{52, 82, 116, 255}
|
|
);
|
|
}
|
|
}
|
|
|
|
static void DrawCeiling()
|
|
{
|
|
for (int z = 0; z < MAZE_H; z++)
|
|
{
|
|
for (int x = 0; x < MAZE_W; x++)
|
|
{
|
|
if (maze[z][x])
|
|
continue;
|
|
|
|
Vector3 p = CellToWorld(x, z);
|
|
|
|
bool lightZone =
|
|
((x * 3 + z * 7) % 11 == 0);
|
|
|
|
Color ceilingColor =
|
|
lightZone
|
|
? Color{155, 155, 155, 255}
|
|
: Color{70, 70, 70, 255};
|
|
|
|
DrawCube(
|
|
{p.x, 3.12f, p.z},
|
|
CELL + 0.16f,
|
|
0.16f,
|
|
CELL + 0.16f,
|
|
ceilingColor
|
|
);
|
|
|
|
if (lightZone)
|
|
{
|
|
DrawCube(
|
|
{p.x, 3.01f, p.z},
|
|
1.3f,
|
|
0.04f,
|
|
0.7f,
|
|
RAYWHITE
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DrawFurniture()
|
|
{
|
|
for (const Furniture& object : furniture)
|
|
{
|
|
Color color;
|
|
|
|
switch (object.type)
|
|
{
|
|
case 0:
|
|
color = {75, 75, 75, 255};
|
|
break;
|
|
|
|
case 1:
|
|
color = {100, 82, 65, 255};
|
|
break;
|
|
|
|
case 2:
|
|
color = {62, 62, 68, 255};
|
|
break;
|
|
|
|
case 3:
|
|
color = {84, 70, 55, 255};
|
|
break;
|
|
|
|
default:
|
|
color = {90, 90, 90, 255};
|
|
break;
|
|
}
|
|
|
|
DrawCube(
|
|
object.position,
|
|
object.size.x,
|
|
object.size.y,
|
|
object.size.z,
|
|
color
|
|
);
|
|
}
|
|
}
|
|
|
|
static void DrawHUD()
|
|
{
|
|
DrawRectangle(
|
|
0,
|
|
0,
|
|
300,
|
|
70,
|
|
{0, 0, 0, 100}
|
|
);
|
|
|
|
DrawText(
|
|
"NIVEL: TALAN-TALAN",
|
|
15,
|
|
12,
|
|
20,
|
|
RAYWHITE
|
|
);
|
|
|
|
DrawText(
|
|
"WASD MOVER",
|
|
15,
|
|
39,
|
|
15,
|
|
LIGHTGRAY
|
|
);
|
|
|
|
int centerX = GetScreenWidth() / 2;
|
|
int centerY = GetScreenHeight() / 2;
|
|
|
|
DrawLine(
|
|
centerX - 8,
|
|
centerY,
|
|
centerX + 8,
|
|
centerY,
|
|
RAYWHITE
|
|
);
|
|
|
|
DrawLine(
|
|
centerX,
|
|
centerY - 8,
|
|
centerX,
|
|
centerY + 8,
|
|
RAYWHITE
|
|
);
|
|
}
|
|
|
|
void RunGame()
|
|
{
|
|
InitWindow(
|
|
1366,
|
|
768,
|
|
"A4B1 - Nivel Talan-Talan"
|
|
);
|
|
|
|
SetTargetFPS(60);
|
|
DisableCursor();
|
|
|
|
GenerateMaze();
|
|
BuildWalls();
|
|
GenerateFurniture();
|
|
|
|
while (!WindowShouldClose())
|
|
{
|
|
float deltaTime = GetFrameTime();
|
|
|
|
if (IsKeyPressed(KEY_F11))
|
|
{
|
|
ToggleFullscreen();
|
|
}
|
|
|
|
UpdatePlayer(deltaTime);
|
|
UpdateEnemy(deltaTime);
|
|
UpdateWeapons(deltaTime);
|
|
|
|
BeginDrawing();
|
|
|
|
ClearBackground({25, 25, 28, 255});
|
|
|
|
BeginMode3D(GetPlayerCamera());
|
|
|
|
DrawFloor();
|
|
DrawWalls();
|
|
DrawCeiling();
|
|
DrawFurniture();
|
|
|
|
DrawEnemy();
|
|
DrawBullets();
|
|
|
|
EndMode3D();
|
|
|
|
DrawPlayerWeapon();
|
|
DrawHUD();
|
|
|
|
EndDrawing();
|
|
}
|
|
|
|
EnableCursor();
|
|
CloseWindow();
|
|
}
|