Nuevo funcionamiento TALANES
This commit is contained in:
1 parent
95a1231c63
commit
92daf86379
2 files changed
+602
-50
No files matched your search
+601
-41
@@ -1,10 +1,14 @@
|
|||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <queue>
|
||||||
|
#include <vector>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
extern Vector3 playerPosition;
|
extern Vector3 playerPosition;
|
||||||
extern bool IsSolidAt(Vector3 position, float radius);
|
extern bool IsSolidAt(Vector3 position, float radius);
|
||||||
|
|
||||||
const int NPC_COUNT = 12;
|
const int NPC_COUNT = 20;
|
||||||
|
|
||||||
Vector3 enemyPosition[NPC_COUNT] =
|
Vector3 enemyPosition[NPC_COUNT] =
|
||||||
{
|
{
|
||||||
@@ -21,17 +25,349 @@ Vector3 enemyPosition[NPC_COUNT] =
|
|||||||
{ -28.0f, 1.0f, -68.0f },
|
{ -28.0f, 1.0f, -68.0f },
|
||||||
{ 28.0f, 1.0f, -68.0f },
|
{ 28.0f, 1.0f, -68.0f },
|
||||||
{ -28.0f, 1.0f, 68.0f },
|
{ -28.0f, 1.0f, 68.0f },
|
||||||
{ 28.0f, 1.0f, 68.0f }
|
{ 28.0f, 1.0f, 68.0f },
|
||||||
|
|
||||||
|
{ -60.0f, 1.0f, -52.0f },
|
||||||
|
{ 60.0f, 1.0f, -52.0f },
|
||||||
|
{ -60.0f, 1.0f, 52.0f },
|
||||||
|
{ 60.0f, 1.0f, 52.0f },
|
||||||
|
|
||||||
|
{ -16.0f, 1.0f, -48.0f },
|
||||||
|
{ 16.0f, 1.0f, -48.0f },
|
||||||
|
{ -16.0f, 1.0f, 48.0f },
|
||||||
|
{ 16.0f, 1.0f, 48.0f }
|
||||||
};
|
};
|
||||||
|
|
||||||
float enemyWalkTime[NPC_COUNT] = {};
|
float enemyWalkTime[NPC_COUNT] = {};
|
||||||
float enemyStunTime[NPC_COUNT] = {};
|
float enemyStunTime[NPC_COUNT] = {};
|
||||||
float enemySpin[NPC_COUNT] = {};
|
float enemySpin[NPC_COUNT] = {};
|
||||||
|
bool enemyMoving[NPC_COUNT] = {};
|
||||||
|
|
||||||
const float enemySpeed = 2.4f;
|
const float enemySpeed = 5.5f;
|
||||||
const float enemyStunDuration = 2.5f;
|
const float enemyStunDuration = 2.5f;
|
||||||
|
|
||||||
bool enemyMoving[NPC_COUNT] = {};
|
static bool showEnemyPaths = false;
|
||||||
|
|
||||||
|
static const int GRID_SIZE = 41;
|
||||||
|
static const float CELL_SIZE = 4.0f;
|
||||||
|
static const float GRID_OFFSET = 20.0f;
|
||||||
|
|
||||||
|
struct GridNode
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int z;
|
||||||
|
|
||||||
|
bool operator==(const GridNode& other) const
|
||||||
|
{
|
||||||
|
return x == other.x && z == other.z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<GridNode> enemyPath[NPC_COUNT];
|
||||||
|
|
||||||
|
static int WorldToGridX(float x)
|
||||||
|
{
|
||||||
|
return (int)std::round(x / CELL_SIZE + GRID_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int WorldToGridZ(float z)
|
||||||
|
{
|
||||||
|
return (int)std::round(z / CELL_SIZE + GRID_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vector3 GridToWorld(int x, int z)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
{
|
||||||
|
(x - GRID_OFFSET) * CELL_SIZE,
|
||||||
|
1.0f,
|
||||||
|
(z - GRID_OFFSET) * CELL_SIZE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsInsideGrid(int x, int z)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x >= 0 &&
|
||||||
|
x < GRID_SIZE &&
|
||||||
|
z >= 0 &&
|
||||||
|
z < GRID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsWalkableCell(int x, int z)
|
||||||
|
{
|
||||||
|
if (!IsInsideGrid(x, z))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vector3 position = GridToWorld(x, z);
|
||||||
|
|
||||||
|
return !IsSolidAt(position, 0.42f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float GridDistance(
|
||||||
|
int x1,
|
||||||
|
int z1,
|
||||||
|
int x2,
|
||||||
|
int z2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
float dx = (float)(x1 - x2);
|
||||||
|
float dz = (float)(z1 - z2);
|
||||||
|
|
||||||
|
return std::sqrt(dx * dx + dz * dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<GridNode> FindPath(
|
||||||
|
Vector3 startWorld,
|
||||||
|
Vector3 targetWorld
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GridNode start =
|
||||||
|
{
|
||||||
|
WorldToGridX(startWorld.x),
|
||||||
|
WorldToGridZ(startWorld.z)
|
||||||
|
};
|
||||||
|
|
||||||
|
GridNode target =
|
||||||
|
{
|
||||||
|
WorldToGridX(targetWorld.x),
|
||||||
|
WorldToGridZ(targetWorld.z)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!IsInsideGrid(start.x, start.z))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!IsInsideGrid(target.x, target.z))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Si el destino está ocupado por un mueble,
|
||||||
|
// buscamos la celda caminable más cercana.
|
||||||
|
if (!IsWalkableCell(target.x, target.z))
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (int radius = 1; radius <= 5 && !found; radius++)
|
||||||
|
{
|
||||||
|
for (int z = target.z - radius;
|
||||||
|
z <= target.z + radius && !found;
|
||||||
|
z++)
|
||||||
|
{
|
||||||
|
for (int x = target.x - radius;
|
||||||
|
x <= target.x + radius;
|
||||||
|
x++)
|
||||||
|
{
|
||||||
|
if (IsWalkableCell(x, z))
|
||||||
|
{
|
||||||
|
target = {x, z};
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsWalkableCell(start.x, start.z))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int z;
|
||||||
|
float g;
|
||||||
|
float f;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Node> open;
|
||||||
|
std::vector<bool> closed(
|
||||||
|
GRID_SIZE * GRID_SIZE,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<GridNode> cameFrom(
|
||||||
|
GRID_SIZE * GRID_SIZE,
|
||||||
|
{-1, -1}
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<float> gScore(
|
||||||
|
GRID_SIZE * GRID_SIZE,
|
||||||
|
std::numeric_limits<float>::infinity()
|
||||||
|
);
|
||||||
|
|
||||||
|
auto indexOf =
|
||||||
|
[](int x, int z)
|
||||||
|
{
|
||||||
|
return z * GRID_SIZE + x;
|
||||||
|
};
|
||||||
|
|
||||||
|
gScore[indexOf(start.x, start.z)] = 0.0f;
|
||||||
|
|
||||||
|
open.push_back(
|
||||||
|
{
|
||||||
|
start.x,
|
||||||
|
start.z,
|
||||||
|
0.0f,
|
||||||
|
GridDistance(
|
||||||
|
start.x,
|
||||||
|
start.z,
|
||||||
|
target.x,
|
||||||
|
target.z
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const int directions[4][2] =
|
||||||
|
{
|
||||||
|
{ 1, 0 },
|
||||||
|
{-1, 0 },
|
||||||
|
{ 0, 1 },
|
||||||
|
{ 0,-1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!open.empty())
|
||||||
|
{
|
||||||
|
int best = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i < (int)open.size(); i++)
|
||||||
|
{
|
||||||
|
if (open[i].f < open[best].f)
|
||||||
|
best = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node current = open[best];
|
||||||
|
open.erase(open.begin() + best);
|
||||||
|
|
||||||
|
if (current.x == target.x &&
|
||||||
|
current.z == target.z)
|
||||||
|
{
|
||||||
|
std::vector<GridNode> path;
|
||||||
|
|
||||||
|
GridNode currentNode =
|
||||||
|
{
|
||||||
|
target.x,
|
||||||
|
target.z
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!(currentNode == start))
|
||||||
|
{
|
||||||
|
path.push_back(currentNode);
|
||||||
|
|
||||||
|
GridNode previous =
|
||||||
|
cameFrom[
|
||||||
|
indexOf(
|
||||||
|
currentNode.x,
|
||||||
|
currentNode.z
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
if (previous.x < 0)
|
||||||
|
{
|
||||||
|
path.clear();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode = previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.push_back(start);
|
||||||
|
|
||||||
|
std::reverse(
|
||||||
|
path.begin(),
|
||||||
|
path.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentIndex =
|
||||||
|
indexOf(current.x, current.z);
|
||||||
|
|
||||||
|
if (closed[currentIndex])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
closed[currentIndex] = true;
|
||||||
|
|
||||||
|
for (const auto& direction : directions)
|
||||||
|
{
|
||||||
|
int nx = current.x + direction[0];
|
||||||
|
int nz = current.z + direction[1];
|
||||||
|
|
||||||
|
if (!IsInsideGrid(nx, nz))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!IsWalkableCell(nx, nz))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int nextIndex = indexOf(nx, nz);
|
||||||
|
|
||||||
|
if (closed[nextIndex])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float newG = current.g + 1.0f;
|
||||||
|
|
||||||
|
if (newG < gScore[nextIndex])
|
||||||
|
{
|
||||||
|
gScore[nextIndex] = newG;
|
||||||
|
|
||||||
|
cameFrom[nextIndex] =
|
||||||
|
{
|
||||||
|
current.x,
|
||||||
|
current.z
|
||||||
|
};
|
||||||
|
|
||||||
|
float h =
|
||||||
|
GridDistance(
|
||||||
|
nx,
|
||||||
|
nz,
|
||||||
|
target.x,
|
||||||
|
target.z
|
||||||
|
);
|
||||||
|
|
||||||
|
open.push_back(
|
||||||
|
{
|
||||||
|
nx,
|
||||||
|
nz,
|
||||||
|
newG,
|
||||||
|
newG + h
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool PositionIsFreeForEnemy(
|
||||||
|
Vector3 position,
|
||||||
|
int ignoreIndex
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (IsSolidAt(position, 0.45f))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < NPC_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (i == ignoreIndex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float dx =
|
||||||
|
enemyPosition[i].x -
|
||||||
|
position.x;
|
||||||
|
|
||||||
|
float dz =
|
||||||
|
enemyPosition[i].z -
|
||||||
|
position.z;
|
||||||
|
|
||||||
|
if (dx * dx + dz * dz < 0.75f * 0.75f)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MoveEnemyWithCollision(
|
void MoveEnemyWithCollision(
|
||||||
int index,
|
int index,
|
||||||
@@ -39,23 +375,206 @@ void MoveEnemyWithCollision(
|
|||||||
float moveZ
|
float moveZ
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Vector3 nextX = enemyPosition[index];
|
Vector3 nextX =
|
||||||
|
enemyPosition[index];
|
||||||
|
|
||||||
nextX.x += moveX;
|
nextX.x += moveX;
|
||||||
|
|
||||||
if (!IsSolidAt(nextX, 0.45f))
|
if (PositionIsFreeForEnemy(nextX, index))
|
||||||
enemyPosition[index].x = nextX.x;
|
enemyPosition[index].x = nextX.x;
|
||||||
|
|
||||||
Vector3 nextZ = enemyPosition[index];
|
Vector3 nextZ =
|
||||||
|
enemyPosition[index];
|
||||||
|
|
||||||
nextZ.z += moveZ;
|
nextZ.z += moveZ;
|
||||||
|
|
||||||
if (!IsSolidAt(nextZ, 0.45f))
|
if (PositionIsFreeForEnemy(nextZ, index))
|
||||||
enemyPosition[index].z = nextZ.z;
|
enemyPosition[index].z = nextZ.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RecalculatePath(int index)
|
||||||
|
{
|
||||||
|
enemyPath[index] =
|
||||||
|
FindPath(
|
||||||
|
enemyPosition[index],
|
||||||
|
playerPosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MoveEnemyAlongPath(
|
||||||
|
int index,
|
||||||
|
float deltaTime
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (enemyPath[index].size() < 2)
|
||||||
|
{
|
||||||
|
enemyMoving[index] = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 target =
|
||||||
|
GridToWorld(
|
||||||
|
enemyPath[index][1].x,
|
||||||
|
enemyPath[index][1].z
|
||||||
|
);
|
||||||
|
|
||||||
|
float dx =
|
||||||
|
target.x -
|
||||||
|
enemyPosition[index].x;
|
||||||
|
|
||||||
|
float dz =
|
||||||
|
target.z -
|
||||||
|
enemyPosition[index].z;
|
||||||
|
|
||||||
|
float distance =
|
||||||
|
std::sqrt(dx * dx + dz * dz);
|
||||||
|
|
||||||
|
if (distance < 0.18f)
|
||||||
|
{
|
||||||
|
enemyPath[index].erase(
|
||||||
|
enemyPath[index].begin()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx /= distance;
|
||||||
|
dz /= distance;
|
||||||
|
|
||||||
|
MoveEnemyWithCollision(
|
||||||
|
index,
|
||||||
|
dx * enemySpeed * deltaTime,
|
||||||
|
dz * enemySpeed * deltaTime
|
||||||
|
);
|
||||||
|
|
||||||
|
enemyMoving[index] = true;
|
||||||
|
enemyWalkTime[index] += deltaTime * 9.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int FindClosestEnemy()
|
||||||
|
{
|
||||||
|
int best = 0;
|
||||||
|
float bestDistance =
|
||||||
|
std::numeric_limits<float>::infinity();
|
||||||
|
|
||||||
|
for (int i = 0; i < NPC_COUNT; i++)
|
||||||
|
{
|
||||||
|
float dx =
|
||||||
|
enemyPosition[i].x -
|
||||||
|
playerPosition.x;
|
||||||
|
|
||||||
|
float dz =
|
||||||
|
enemyPosition[i].z -
|
||||||
|
playerPosition.z;
|
||||||
|
|
||||||
|
float distance =
|
||||||
|
dx * dx + dz * dz;
|
||||||
|
|
||||||
|
if (distance < bestDistance)
|
||||||
|
{
|
||||||
|
bestDistance = distance;
|
||||||
|
best = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HasNearbyTalan()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NPC_COUNT; i++)
|
||||||
|
{
|
||||||
|
float dx =
|
||||||
|
enemyPosition[i].x -
|
||||||
|
playerPosition.x;
|
||||||
|
|
||||||
|
float dz =
|
||||||
|
enemyPosition[i].z -
|
||||||
|
playerPosition.z;
|
||||||
|
|
||||||
|
float distance =
|
||||||
|
std::sqrt(dx * dx + dz * dz);
|
||||||
|
|
||||||
|
if (distance < 28.0f)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TeleportOneTalanToPlayerArea()
|
||||||
|
{
|
||||||
|
int index = FindClosestEnemy();
|
||||||
|
|
||||||
|
float bestDistance = 18.0f;
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt < 40; attempt++)
|
||||||
|
{
|
||||||
|
float angle =
|
||||||
|
(float)attempt *
|
||||||
|
(PI * 2.0f / 40.0f);
|
||||||
|
|
||||||
|
float distance =
|
||||||
|
bestDistance +
|
||||||
|
(attempt % 5) * 1.5f;
|
||||||
|
|
||||||
|
Vector3 position =
|
||||||
|
{
|
||||||
|
playerPosition.x +
|
||||||
|
std::cos(angle) * distance,
|
||||||
|
|
||||||
|
1.0f,
|
||||||
|
|
||||||
|
playerPosition.z +
|
||||||
|
std::sin(angle) * distance
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!PositionIsFreeForEnemy(
|
||||||
|
position,
|
||||||
|
index))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<GridNode> testPath =
|
||||||
|
FindPath(
|
||||||
|
position,
|
||||||
|
playerPosition
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!testPath.empty())
|
||||||
|
{
|
||||||
|
enemyPosition[index] =
|
||||||
|
position;
|
||||||
|
|
||||||
|
enemyWalkTime[index] = 0.0f;
|
||||||
|
enemyStunTime[index] = 0.0f;
|
||||||
|
enemySpin[index] = 0.0f;
|
||||||
|
|
||||||
|
enemyPath[index] =
|
||||||
|
testPath;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateEnemy(float deltaTime)
|
void UpdateEnemy(float deltaTime)
|
||||||
{
|
{
|
||||||
|
// P muestra/oculta las rutas.
|
||||||
|
if (IsKeyPressed(KEY_P))
|
||||||
|
{
|
||||||
|
showEnemyPaths =
|
||||||
|
!showEnemyPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Siempre debe haber un talán relativamente
|
||||||
|
// cerca del jugador.
|
||||||
|
if (!HasNearbyTalan())
|
||||||
|
{
|
||||||
|
TeleportOneTalanToPlayerArea();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NPC_COUNT; i++)
|
for (int i = 0; i < NPC_COUNT; i++)
|
||||||
{
|
{
|
||||||
float dx =
|
float dx =
|
||||||
@@ -67,10 +586,7 @@ void UpdateEnemy(float deltaTime)
|
|||||||
enemyPosition[i].z;
|
enemyPosition[i].z;
|
||||||
|
|
||||||
float distance =
|
float distance =
|
||||||
std::sqrt(
|
std::sqrt(dx * dx + dz * dz);
|
||||||
dx * dx +
|
|
||||||
dz * dz
|
|
||||||
);
|
|
||||||
|
|
||||||
// =========================================
|
// =========================================
|
||||||
// MAREADO
|
// MAREADO
|
||||||
@@ -116,24 +632,23 @@ void UpdateEnemy(float deltaTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================
|
// =========================================
|
||||||
// SEGUIR JUGADOR
|
// RUTA INTELIGENTE
|
||||||
// =========================================
|
// =========================================
|
||||||
|
|
||||||
|
// Recalcular frecuentemente para que los talanes
|
||||||
|
// reaccionen si el jugador cambia de dirección.
|
||||||
|
if (enemyPath[i].empty() ||
|
||||||
|
((int)(GetTime() * 4.0) + i) % 5 == 0)
|
||||||
|
{
|
||||||
|
RecalculatePath(i);
|
||||||
|
}
|
||||||
|
|
||||||
if (distance > 1.8f)
|
if (distance > 1.8f)
|
||||||
{
|
{
|
||||||
dx /= distance;
|
MoveEnemyAlongPath(
|
||||||
dz /= distance;
|
|
||||||
|
|
||||||
MoveEnemyWithCollision(
|
|
||||||
i,
|
i,
|
||||||
dx * enemySpeed * deltaTime,
|
deltaTime
|
||||||
dz * enemySpeed * deltaTime
|
|
||||||
);
|
);
|
||||||
|
|
||||||
enemyWalkTime[i] +=
|
|
||||||
deltaTime * 9.0f;
|
|
||||||
|
|
||||||
enemyMoving[i] = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -195,10 +710,6 @@ void TeleportEnemyNearPlayer(
|
|||||||
index >= NPC_COUNT)
|
index >= NPC_COUNT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// =========================================
|
|
||||||
// CONSERVAR LA DISTANCIA ACTUAL
|
|
||||||
// =========================================
|
|
||||||
|
|
||||||
float dx =
|
float dx =
|
||||||
enemyPosition[index].x -
|
enemyPosition[index].x -
|
||||||
playerPosition.x;
|
playerPosition.x;
|
||||||
@@ -216,10 +727,6 @@ void TeleportEnemyNearPlayer(
|
|||||||
if (oldDistance < 3.0f)
|
if (oldDistance < 3.0f)
|
||||||
oldDistance = 3.0f;
|
oldDistance = 3.0f;
|
||||||
|
|
||||||
// =========================================
|
|
||||||
// BUSCAR OTRA DIRECCIÓN
|
|
||||||
// =========================================
|
|
||||||
|
|
||||||
float baseAngle =
|
float baseAngle =
|
||||||
std::atan2(
|
std::atan2(
|
||||||
dz,
|
dz,
|
||||||
@@ -244,17 +751,23 @@ void TeleportEnemyNearPlayer(
|
|||||||
std::sin(angle) * oldDistance
|
std::sin(angle) * oldDistance
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!IsSolidAt(newPosition, 0.45f))
|
if (!PositionIsFreeForEnemy(
|
||||||
|
newPosition,
|
||||||
|
index))
|
||||||
{
|
{
|
||||||
enemyPosition[index] =
|
continue;
|
||||||
newPosition;
|
|
||||||
|
|
||||||
enemyStunTime[index] = 0.0f;
|
|
||||||
enemySpin[index] = 0.0f;
|
|
||||||
enemyWalkTime[index] = 0.0f;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enemyPosition[index] =
|
||||||
|
newPosition;
|
||||||
|
|
||||||
|
enemyStunTime[index] = 0.0f;
|
||||||
|
enemySpin[index] = 0.0f;
|
||||||
|
enemyWalkTime[index] = 0.0f;
|
||||||
|
|
||||||
|
RecalculatePath(index);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,6 +801,53 @@ int CheckEnemyHit(Vector3 bulletPosition)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// RUTAS VISIBLES CON P
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
void DrawEnemyPaths()
|
||||||
|
{
|
||||||
|
if (!showEnemyPaths)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < NPC_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (enemyPath[i].size() < 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vector3 previous =
|
||||||
|
enemyPosition[i];
|
||||||
|
|
||||||
|
previous.y = 0.12f;
|
||||||
|
|
||||||
|
for (size_t p = 1;
|
||||||
|
p < enemyPath[i].size();
|
||||||
|
p++)
|
||||||
|
{
|
||||||
|
Vector3 current =
|
||||||
|
GridToWorld(
|
||||||
|
enemyPath[i][p].x,
|
||||||
|
enemyPath[i][p].z
|
||||||
|
);
|
||||||
|
|
||||||
|
current.y = 0.12f;
|
||||||
|
|
||||||
|
DrawLine3D(
|
||||||
|
previous,
|
||||||
|
current,
|
||||||
|
LIME
|
||||||
|
);
|
||||||
|
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// TALÁN ORIGINAL
|
||||||
|
// NO TOCAR
|
||||||
|
// =============================================
|
||||||
|
|
||||||
void DrawEnemy()
|
void DrawEnemy()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NPC_COUNT; i++)
|
for (int i = 0; i < NPC_COUNT; i++)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ float playerPitch = 0.0f;
|
|||||||
float weaponBobTime = 0.0f;
|
float weaponBobTime = 0.0f;
|
||||||
float weaponShootTime = 0.0f;
|
float weaponShootTime = 0.0f;
|
||||||
|
|
||||||
const float moveSpeed = 7.0f;
|
const float moveSpeed = 11.0f;
|
||||||
const float jumpForce = 9.0f;
|
const float jumpForce = 9.0f;
|
||||||
const float gravity = 20.0f;
|
const float gravity = 20.0f;
|
||||||
|
|
||||||
@@ -50,22 +50,17 @@ Camera3D GetPlayerCamera()
|
|||||||
|
|
||||||
static void MovePlayer(Vector3 movement)
|
static void MovePlayer(Vector3 movement)
|
||||||
{
|
{
|
||||||
// X separado de Z para poder deslizarse por las paredes.
|
|
||||||
Vector3 nextX = playerPosition;
|
Vector3 nextX = playerPosition;
|
||||||
nextX.x += movement.x;
|
nextX.x += movement.x;
|
||||||
|
|
||||||
if (!IsSolidAt(nextX, PLAYER_RADIUS))
|
if (!IsSolidAt(nextX, PLAYER_RADIUS))
|
||||||
{
|
|
||||||
playerPosition.x = nextX.x;
|
playerPosition.x = nextX.x;
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 nextZ = playerPosition;
|
Vector3 nextZ = playerPosition;
|
||||||
nextZ.z += movement.z;
|
nextZ.z += movement.z;
|
||||||
|
|
||||||
if (!IsSolidAt(nextZ, PLAYER_RADIUS))
|
if (!IsSolidAt(nextZ, PLAYER_RADIUS))
|
||||||
{
|
|
||||||
playerPosition.z = nextZ.z;
|
playerPosition.z = nextZ.z;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePlayer(float deltaTime)
|
void UpdatePlayer(float deltaTime)
|
||||||
@@ -150,9 +145,7 @@ void UpdatePlayer(float deltaTime)
|
|||||||
verticalVelocity = 0.0f;
|
verticalVelocity = 0.0f;
|
||||||
|
|
||||||
if (IsKeyPressed(KEY_SPACE))
|
if (IsKeyPressed(KEY_SPACE))
|
||||||
{
|
|
||||||
verticalVelocity = jumpForce;
|
verticalVelocity = jumpForce;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verticalVelocity -= gravity * deltaTime;
|
verticalVelocity -= gravity * deltaTime;
|
||||||
@@ -166,7 +159,6 @@ void UpdatePlayer(float deltaTime)
|
|||||||
verticalVelocity = 0.0f;
|
verticalVelocity = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colisión con el techo.
|
|
||||||
if (playerPosition.y + PLAYER_HEAD_Y > CEILING_Y)
|
if (playerPosition.y + PLAYER_HEAD_Y > CEILING_Y)
|
||||||
{
|
{
|
||||||
playerPosition.y =
|
playerPosition.y =
|
||||||
|
|||||||
Reference in new issue
Block a user