[Fix] Pathfinding fixes...

This commit is contained in:
Tamir Atias 2012-02-21 02:00:36 +02:00
parent 61f1f2b2a4
commit 837ace3c2a
9 changed files with 176 additions and 150 deletions

View File

@ -100,9 +100,10 @@ void Player::Update(void) {
// For now The camera will be static.
//SetCamera();
tileX = x / AStarTile::FAKE_SIZE;
tileY = y / AStarTile::FAKE_SIZE;
int tileX = x / TILE_WIDTH;
int tileY = y / TILE_HEIGHT;
if(tileX != _lastTileX || tileY != _lastTileY) {
_lastTileX = tileX;
_lastTileY = tileY;

View File

@ -1,10 +1,7 @@
#include "Character.h"
// Pixels * 60 / sec
const float Character::CHARACTER_SPEED = 3.5f;
static list<Character*>collisionList;
static list<Character*>::iterator collisionIter;
const float Character::CHARACTER_SPEED = 1.0f;
Character::Character(LevelGen* mapArg) {
map = mapArg;
@ -24,8 +21,6 @@ Character::Character(LevelGen* mapArg) {
_texture = NULL;
collisionList.push_front(this);
_healthBar.SetBackgroundRGB(0, 0, 0);
_healthBar.SetForegroundRGB(255, 0, 0);
@ -34,12 +29,6 @@ Character::Character(LevelGen* mapArg) {
Character::~Character(void) {
SDL_FreeSurface(_texture);
for(collisionIter = collisionList.begin(); collisionIter != collisionList.end(); collisionIter++) {
if((*collisionIter) == this) {
collisionList.erase(collisionIter);
break;
}
}
}
void Character::LoadSprites(string filename, int wArg, int hArg) {

View File

@ -46,6 +46,7 @@ public:
void OnAttack(void);
// Overload new and delete operators to utilize MemManager.
/*
inline void* operator new(size_t size) {
return gMemManager.Allocate(size);
}
@ -61,6 +62,7 @@ public:
inline void operator delete [](void* object) {
gMemManager.Free(object);
}
*/
enum {
FACING_UP,

View File

@ -31,58 +31,78 @@ void NPC::Update(void) {
}
void NPC::Move(void) {
Character::HealthBarScroll();
xVel = 0.0f;
yVel = 0.0f;
if(!_walkInPath) {
return;
}
Vec2 realPos(x, y);
Vec2 tilePos(tileX, tileY);
Character* player = map->GetPlayer();
SDL_Rect selfRect;
selfRect.x = x - 5;
selfRect.y = y - 5;
selfRect.w = w + 5;
selfRect.h = h + 5;
SDL_Rect playerRect;
playerRect.x = player->GetX() - 5;
playerRect.y = player->GetY() - 5;
playerRect.w = player->GetWidth() + 5;
playerRect.h = player->GetHeight() + 5;
if(CheckCollisionRect(selfRect, playerRect)) {
_walkInPath = false;
return;
}
float targetX = (float)(tileX * AStarTile::FAKE_SIZE);
float targetY = (float)(tileY * AStarTile::FAKE_SIZE);
if(realPos != tilePos) {
float targetX = (float)(tileX * AStarTile::FAKE_SIZE);
float targetY = (float)(tileY * AStarTile::FAKE_SIZE);
float dx = targetX - realPos.x;
float dy = targetY - realPos.y;
float distance = sqrtf(dx*dx + dy*dy);
if(fabs(distance) > CHARACTER_SPEED) {
dx /= distance;
dy /= distance;
dx *= CHARACTER_SPEED;
dy *= CHARACTER_SPEED;
xVel = dx;
yVel = dy;
map->MoveIfPossible(this, xVel, yVel, false);
Character::HealthBarScroll();
_moving = true;
} else {
xVel = 0.0f;
yVel = 0.0f;
_moving = false;
}
} else {
xVel = 0.0f;
yVel = 0.0f;
_moving = false;
}
if(_walkInPath && !_moving) {
Vec2 targetPos((float)_target->GetX(), (float)_target->GetY());
if(fabs(Vec2::Distance(targetPos, realPos)) <= CHARACTER_SPEED) {
_target = _astar.GetSolutionNext();
if(_target == NULL || _target == _lastTarget) {
_walkInPath = false;
} else {
tileX = _target->GetX() / AStarTile::FAKE_SIZE;
tileY = _target->GetY() / AStarTile::FAKE_SIZE;
}
}
}
float dx = targetX - realPos.x;
float dy = targetY - realPos.y;
if(dx > 0.0f) {
xVel = CHARACTER_SPEED;
}
else if(dx < 0.0f) {
xVel = -CHARACTER_SPEED;
}
if(dy > 0.0f) {
yVel = CHARACTER_SPEED;
}
else if(dy < 0.0f) {
yVel = -CHARACTER_SPEED;
}
if(xVel != 0.0f || yVel != 0.0f) {
map->MoveIfPossible(this, xVel, yVel, false);
}
else {
_target = _astar.GetSolutionNext();
if(_target == NULL || _target == _lastTarget) {
_walkInPath = false;
} else {
tileX = _target->GetX() / AStarTile::FAKE_SIZE;
tileY = _target->GetY() / AStarTile::FAKE_SIZE;
}
}
}
void NPC::OnPlayerMove(Player* player) {
Vec2 selfPos(x, y);
Vec2 playerPos(player->GetX(), player->GetY());
if(Vec2::DistanceSquared(selfPos, playerPos) > 96*96) {
return;
}
AStarTile& start = map->GetAStarTile(x / AStarTile::FAKE_SIZE, y / AStarTile::FAKE_SIZE);
AStarTile& goal = map->GetAStarTile(player->GetX() / AStarTile::FAKE_SIZE, player->GetY() / AStarTile::FAKE_SIZE);
@ -90,7 +110,6 @@ void NPC::OnPlayerMove(Player* player) {
_walkInPath = false;
// Dirty loop to calculate the path
while(true) {
unsigned int state = _astar.SearchStep();
if(state == AStarSearch<AStarTile>::SEARCH_STATE_SUCCEEDED) {
@ -101,13 +120,18 @@ void NPC::OnPlayerMove(Player* player) {
}
}
_lastTarget = _astar.GetSolutionEnd();
_target = _astar.GetSolutionStart();
_target = _astar.GetSolutionNext();
if(!_target) {
_walkInPath = false;
} else {
tileX = _target->GetX() / AStarTile::FAKE_SIZE;
tileY = _target->GetY() / AStarTile::FAKE_SIZE;
}
if(_walkInPath) {
_lastTarget = _astar.GetSolutionEnd();
_target = _astar.GetSolutionStart();
_target = _astar.GetSolutionNext();
if(_target == NULL) {
_walkInPath = false;
_target = NULL;
} else {
tileX = _target->GetX() / AStarTile::FAKE_SIZE;
tileY = _target->GetY() / AStarTile::FAKE_SIZE;
}
}
}

View File

@ -83,12 +83,12 @@ bool WorldManager::CheckCollision(const SDL_Rect& charRect, Character* exclude)
if(npc == exclude) {
continue;
}
SDL_Rect npcRect;
npcRect.x = npc->GetX();
npcRect.y = npc->GetY();
npcRect.w = npc->GetWidth();
npcRect.h = npc->GetHeight();
SDL_Rect npcRect;
npcRect.x = npc->GetX();
npcRect.y = npc->GetY() + (npc->GetHeight() / 4) * 3;
npcRect.w = npc->GetWidth();
npcRect.h = npc->GetHeight() / 4;
if(CheckCollisionRect(npcRect, charRect)) {
return true;

View File

@ -21,33 +21,45 @@ float AStarTile::GetCost(AStarTile& goal) {
}
bool AStarTile::GetSuccessors(AStarSearch<AStarTile>* search) {
if(_level->MetaTilePassable((x - 1) * FAKE_SIZE, y * FAKE_SIZE)) {
if(!_level) {
return false;
}
if(x > 0) {
AStarTile& successor = _level->GetAStarTile(x - 1, y);
if(!search->AddSuccessor(successor)) {
return false;
if(successor._passable) {
if(!search->AddSuccessor(successor)) {
return false;
}
}
}
if(_level->MetaTilePassable((x + 1) * FAKE_SIZE, y * FAKE_SIZE)) {
if(x < (levelWidth / FAKE_SIZE)) {
AStarTile& successor = _level->GetAStarTile(x + 1, y);
if(!search->AddSuccessor(successor)) {
return false;
if(successor._passable) {
if(!search->AddSuccessor(successor)) {
return false;
}
}
}
if(_level->MetaTilePassable(x * FAKE_SIZE, (y - 1) * FAKE_SIZE)) {
if(y > 0) {
AStarTile& successor = _level->GetAStarTile(x, y - 1);
if(!search->AddSuccessor(successor)) {
return false;
if(successor._passable) {
if(!search->AddSuccessor(successor)) {
return false;
}
}
}
if(_level->MetaTilePassable(x * FAKE_SIZE, (y + 1) * FAKE_SIZE)) {
if(y < (levelHeight / FAKE_SIZE)) {
AStarTile& successor = _level->GetAStarTile(x, y + 1);
if(!search->AddSuccessor(successor)) {
return false;
if(successor._passable) {
if(!search->AddSuccessor(successor)) {
return false;
}
}
}
return true;
}
}

View File

@ -18,8 +18,7 @@ public:
int GetX() { return x * FAKE_SIZE; }
int GetY() { return y * FAKE_SIZE; }
static const int FAKE_SIZE = 64
;
static const int FAKE_SIZE = 16;
private:
LevelGen* _level;

View File

@ -17,8 +17,8 @@ void LevelGen::New(void) {
_world = WorldManager(this);
levelWidth = TILE_ARRAY_SIZE;
levelHeight = TILE_ARRAY_SIZE;
levelWidth = TILE_ARRAY_WIDTH;
levelHeight = TILE_ARRAY_HEIGHT;
for(x = 0; x < levelWidth; x++) {
for(y = 0; y < levelHeight; y++) {
@ -258,23 +258,23 @@ void LevelGen::Render(void) {
void LevelGen::Unload(void) {
_tileTextures.Unload();
_entityTextures.Unload();
for(int x = 0; x < TILE_ARRAY_SIZE; x++) {
for(int y = 0; y < TILE_ARRAY_SIZE; y++) {
for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) {
_tile[x][y] = MapTile();
}
}
}
void LevelGen::DoMagic(void) {
GenerateEntities("tree", 25);
GenerateEntities("hedge", 15);
GenerateEntities("barrel", 40);
GenerateEntities("barrel2", 100);
GenerateEntities("stone", 35);
GenerateEntities("stone2", 35);
GenerateEntities("closedChest", 100);
GenerateEntities("closedChestMetal", 150);
GenerateEntities("closedChestMetal2", 250);
GenerateEntities("tree", 45);
GenerateEntities("hedge", 35);
GenerateEntities("barrel", 60);
GenerateEntities("barrel2", 120);
GenerateEntities("stone", 55);
GenerateEntities("stone2", 55);
GenerateEntities("closedChest", 120);
GenerateEntities("closedChestMetal", 170);
GenerateEntities("closedChestMetal2", 270);
MakeWalkingPaths();
GenerateEnemies();
}
@ -283,8 +283,8 @@ void LevelGen::GenerateEntities(const string& name, int frequency) {
int nextEntityGen = 1 + (rand() % frequency);
std::string filename = "../Data/Media/Images/Entities/" + name + ".png";
for(int x = 0; x < BOUNDARIES_X; x++) {
for(int y = 0; y < BOUNDARIES_Y; y++) {
for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) {
nextEntityGen--;
if(!_tile[x][y].GetTileSolidity() && !_tile[x][y].GetEntitySolitity() && nextEntityGen <= 0) {
_tile[x][y].SetEntityTextureName(name);
@ -304,10 +304,10 @@ void LevelGen::GenerateEntities(const string& name, int frequency) {
void LevelGen::MakeWalkingPaths(void) {
int lastOpenY = rand() % 5;
for(int x = 0; x < BOUNDARIES_X; x++) {
for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
bool pathFound = false;
for(int y = 0; y < BOUNDARIES_Y; y++) {
for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) {
if(!_tile[x][y].GetEntitySolitity()) {
pathFound = true;
break;
@ -324,8 +324,8 @@ void LevelGen::MakeWalkingPaths(void) {
}
void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight) {
xArg = rand() % (BOUNDARIES_X * TILE_WIDTH);
yArg = rand() % (BOUNDARIES_Y * TILE_HEIGHT);
xArg = rand() % (TILE_ARRAY_WIDTH * TILE_WIDTH);
yArg = rand() % (TILE_ARRAY_HEIGHT * TILE_HEIGHT);
if((xArg + objWidth + 1) > SCREEN_WIDTH) {
xArg = SCREEN_WIDTH - objWidth - 1;
@ -355,8 +355,8 @@ void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight)
}
}
for(int i = 0; i < BOUNDARIES_X; i++) {
for(int j = 0; j < BOUNDARIES_Y; j++) {
for(int i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(_tile[i][j].GetTileSolidity()) {
FindSpawnPoint(xArg, yArg, objWidth, objHeight);
return;
@ -395,8 +395,8 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
return;
}
int targetX = character->GetX() + xVel;
int targetY = character->GetY() + yVel;
float targetX = character->GetX() + xVel;
float targetY = character->GetY() + yVel;
if(targetX < 0 || targetX > (SCREEN_WIDTH - character->GetWidth()) ||
targetY < 0 || targetY > (SCREEN_HEIGHT - character->GetHeight())) {
@ -416,8 +416,8 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
charRect.w = character->GetWidth();
charRect.h = character->GetHeight() / 4;
for(int i = 0; i < BOUNDARIES_X; i++) {
for(int j = 0; j < BOUNDARIES_Y; j++) {
for(int i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(!_tile[i][j].GetEntitySolitity()) {
continue;
}
@ -434,8 +434,10 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
}
}
if(_world.CheckCollision(charRect, character)) {
return;
if(true) {
if(_world.CheckCollision(charRect, character)) {
return;
}
}
if(!isPlayer) {
@ -453,20 +455,15 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
character->SetXY(targetX, targetY);
}
bool LevelGen::MetaTilePassable(int xArg, int yArg) {
if(xArg < 0 || xArg > SCREEN_WIDTH ||
yArg < 0 || yArg > SCREEN_HEIGHT) {
return false;
}
/*
SDL_Rect moverRect;
moverRect.x = xArg;
moverRect.y = yArg;
moverRect.w = 40;
moverRect.h = 45;
bool LevelGen::AStarTilePassable(int xArg, int yArg) {
SDL_Rect tileRect;
tileRect.x = xArg * AStarTile::FAKE_SIZE;
tileRect.y = yArg * AStarTile::FAKE_SIZE;
tileRect.w = 40;
tileRect.h = 45;
for(int i = 0; i < BOUNDARIES_X; i++) {
for(int j = 0; j < BOUNDARIES_Y; j++) {
for(int i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(!_tile[i][j].GetEntitySolitity()) {
continue;
}
@ -477,7 +474,7 @@ bool LevelGen::MetaTilePassable(int xArg, int yArg) {
entityRect.w = _tile[i][j].GetEntityWidth();
entityRect.h = _tile[i][j].GetEntityHeight();
if(CheckCollisionRect(moverRect, entityRect)) {
if(CheckCollisionRect(tileRect, entityRect)) {
return false;
}
}
@ -485,22 +482,24 @@ bool LevelGen::MetaTilePassable(int xArg, int yArg) {
SDL_Rect playerRect;
playerRect.x = _player->GetX();
playerRect.y = _player->GetY();
playerRect.y = _player->GetY() + (_player->GetHeight() / 4) * 3;
playerRect.w = _player->GetWidth();
playerRect.h = _player->GetHeight();
playerRect.h = _player->GetHeight() / 4;
if(CheckCollisionRect(moverRect, playerRect)) {
if(CheckCollisionRect(tileRect, playerRect)) {
return false;
}
*/
return true;
}
void LevelGen::UpdateAStarTiles(void) {
for(int x = 0; x < ASTAR_ARRAY_SIZE; x++) {
for(int y = 0; y < ASTAR_ARRAY_SIZE; y++) {
bool passable = MetaTilePassable(x * AStarTile::FAKE_SIZE, y * AStarTile::FAKE_SIZE);
_astarTile[x][y] = AStarTile(this, x, y, passable);
int maxX = levelWidth / AStarTile::FAKE_SIZE;
int maxY = levelHeight / AStarTile::FAKE_SIZE;
for(int x = 0; x < maxX; x++) {
for(int y = 0; y < maxY; y++) {
_astarTile[x][y] = AStarTile(this, x, y, AStarTilePassable(x, y));
}
}
}

View File

@ -34,7 +34,6 @@ public:
void FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight);
void MoveIfPossible(Character* character, float xVel, float yVel, bool isPlayer = false);
bool MetaTilePassable(int xArg, int yArg);
bool GetTileSolidity(int xArg, int yArg);
int GetTileX(int xArg, int yArg);
@ -54,7 +53,8 @@ public:
WorldManager& GetWorld(void) { return _world; }
void SetPlayer(Player* player) { _player = player; }
void SetPlayer(Player* player) { _player = player; }
Player* GetPlayer() { return _player; }
private:
void Unload(void);
@ -62,20 +62,20 @@ private:
void GenerateEntities(const std::string& name, int frequency);
void MakeWalkingPaths(void);
void GenerateEnemies(void);
bool AStarTilePassable(int xArg, int yArg);
void UpdateAStarTiles(void);
string _currentMap;
int x;
int y;
static const int TILE_ARRAY_SIZE = 15;
MapTile _tile[TILE_ARRAY_SIZE][TILE_ARRAY_SIZE];
static const int TILE_ARRAY_WIDTH = (SCREEN_WIDTH / TILE_WIDTH) + 1;
static const int TILE_ARRAY_HEIGHT = (SCREEN_HEIGHT / TILE_HEIGHT) + 1;
MapTile _tile[TILE_ARRAY_WIDTH][TILE_ARRAY_HEIGHT];
static const int ASTAR_ARRAY_SIZE = TILE_ARRAY_SIZE * (TILE_WIDTH / AStarTile::FAKE_SIZE);
AStarTile _astarTile[ASTAR_ARRAY_SIZE][ASTAR_ARRAY_SIZE];
static const int BOUNDARIES_X = (SCREEN_WIDTH / TILE_WIDTH);
static const int BOUNDARIES_Y = (SCREEN_HEIGHT / TILE_HEIGHT);
static const int ASTAR_ARRAY_WIDTH = TILE_ARRAY_WIDTH * (TILE_WIDTH / AStarTile::FAKE_SIZE);
static const int ASTAR_ARRAY_HEIGHT = TILE_ARRAY_HEIGHT * (TILE_HEIGHT / AStarTile::FAKE_SIZE);
AStarTile _astarTile[ASTAR_ARRAY_WIDTH][ASTAR_ARRAY_HEIGHT];
TextureManager _tileTextures;
TextureManager _entityTextures;