Navigation Graph(for Game Agent) generation/edition tools - c++

I'm writing a 2d game in which an agent has to go to anywhere of large map, automatically.
Ofcourse, the map's got lots of obstacles, geometries, etc.
I decided to implement it with NavGraph (Navigation Graph), and read a very useful, great article here
After a few minutes, I worried about creating nav graph manually.
I googled hours to look up NavGraph generation tools, but there was nothing. (all result was for NavMesh, not NavGraph)
Is there anybody help me? Any suggestion or reply will be appreciated.
Thanks.

I used libpedsim
It provides a framework to set waypoints and obstacles:
Ped::Tscene* pedscene;
Ped::Twaypoint* w1;
Ped::Tobstacle* o;
Waypoints were simply created by random sampling - we created a texture where red means it is blocked and otherwise the cell is free. The hacky implementation looked like this and worked pretty well:
// setup
pedscene = new Ped::Tscene(-200, -200, 400, 400);
loadMap();
srand(time(NULL));
int x;
int y;
for (int i = 0; i<agnentCount_/10; i++)
{
Ped::Tagent *a = new Ped::Tagent();
while(true)
{
x = rand() % 99;
y = rand() % 99;
if(texData[y * tex_->getWidth() + x][0]==255)
{
break;
}
}
a->setPosition(
x,
-y,
0.2);
while(true)
{
x = std::rand() % 99;
y = std::rand() % 99;
if(texData[y * tex_->getWidth() + x][0]==255)
{
break;
}
}
PathFind seeker(
a->getPosition().x,
-a->getPosition().y,
x,
y,
tex_->getWidth(),
tex_->getHeight(),
texData);
std::vector<buw::vector2i> path;
path = seeker.findPath();
for(std::vector<buw::vector2i>::iterator it = path.begin(); it!=path.end(); it++)
{
w1 = new Ped::Twaypoint( it->x(), -it->y(), 5);
a->addWaypoint(w1);
}
pedscene->addAgent(a);

Related

p5.js - get a rectangle to move left and right repeatedly (bounce)

I'm trying out some sample code for a bigger project, and I'm having trouble getting my rectangle to bounce between two lines.
function draw() {
print(frameCount)
background(255)
var x = 150 + frameCount;
rect(x,200,15,15);
line(150,0,150,400);
line(250,0,250,400);
if (x >= 250) {
background(255)
x = 350-frameCount;
rect(x,200,15,15);
line(250,0,250,400);
line(150,0,150,400);
} if (x <= 145) {
background(255)
x = 145 + (frameCount % 100);
rect(x,200,15,15);
line(250,0,250,400);
line(150,0,150,400);
}
}
I'm getting the feeling that after the first instance, it's disregarding the original if statement, which dictates a bounce to the left. I'm really not sure what's going wrong, and any help would be appreciated.
You probably just want to store the current position and speed in a set of variables, and then move the rectangle based on those. Here's an example:
var x = 0;
var speed = 1;
function draw(){
x += speed;
if(x < 0 || x > width){
speed *= -1;
}
background(64);
line(x, 0, x, height);
}
I've written a tutorial on this available here. That's for regular Processing, but the ideas are the same in P5.js.

Smoothing Land Around Lakes

Sorry if that title isn't very descriptive. Anyway, I am working on something dealing with randomly generating landscapes. I made lakes, but due to how they are make, they often cause straight edges / dropoffs, which aren't desirable. I am trying to smooth it (right after making the lake, if possible), by defining a max variation amount (so land heights cannot vary more than it), and have it fix land if it varies to much, and quit if it is fine.
The problem:
My attempted fix:
As you can see... it didn't work. It also occurs to me, I think it would be broken if it had to move down, although that case shouldn't actually occur, because lakes only ever sink the landscape. Anyway, here is the source of my attempt:
//smoothing land nearby
int maxVariation = 2; //similar to the max height variation when the land is generated
//going right
for (int xPos = rightBound + 1, previousHeight = 0; ; ++xPos)
{
if (previousHeight == 0)
for (; previousHeight < size.y; ++previousHeight)
if (grid[0][rightBound][previousHeight] != BlockColor::DIRT && grid[0][rightBound][previousHeight] != BlockColor::GRASS)
{
--previousHeight;
break;
}
for (int y = 0; y < size.y; ++y)
if (grid[0][xPos][y] == BlockColor::WATER)
goto done_smoothing_right;
int height;
for (height = 0; height < size.y; ++height)
if (grid[0][xPos][height] != BlockColor::DIRT && grid[0][xPos][height] != BlockColor::GRASS)
{
--height;
break;
}
int difference = std::abs(height - previousHeight);
previousHeight = height;
if (difference > maxVariation)
{
for (int j = 0; j < size.y; ++j)
{
int toMove = difference;
while (j + toMove >= size.y)
--toMove;
grid[0][xPos][j] = grid[0][xPos][j + toMove];
}
}
else
goto done_smoothing_right;
}
done_smoothing_right:
int tomakegotowork;
Note that is only the right side, but left should be about the same. How can I do this correctly?
Thanks if you can help.
EDIT:
I never did solve this problem. Instead, I made a recursive function to measure air, (from a certain height), and if a pocket of air (formed by the land) had enough, to fill with water. This has the advantaged of the land looking smooth because it is not altered.
This is written in java so you will need to convert it to c++ but it should give you the basic idea. It will only work for smoothing upwards as well and I only did the right side of the lake but it is very easy to modify it for the left side of the lake. I tried to match what I think the functionality of your code is.
Hope it helps...
void smoothLakeRight(Lake lake){
int x = lake.rightBound+1;
if(getGrassHeight(x)-lake.height>WorldConstants.MAX_LAKESIDE_VARIATION){
//if the right bank is too high start smoothing
int y =lake.height+WorldConstants.MAX_LAKESIDE_VARIATION;
while(grid[0][x][y] == BlockColor.DIRT){
fixGrass(x++, y++);
}
}
}
private int getGrassHeight(int xPos){
int y = WorldConstants.LOWEST_GRASS;
while(grid[0][xPos][y++] != BlockColor.GRASS);
return y-1;
}
private void fixGrass(int xPos, int yPos){
grid[0][xPos][yPos] = BlockColor.GRASS;
aboveAir(xPos,yPos);
belowDirt(xPos, yPos);
}
private void aboveAir(int xPos, int yPos) {
while(grid[0][xPos][++yPos]!=BlockColor.AIR){
if(grid[0][xPos][yPos]==BlockColor.TREE){
upRootTree(xPos, yPos);
}else{
grid[0][xPos][yPos]=BlockColor.AIR;
}
}
}
private void upRootTree(int xPos, int yPos) {
while(grid[0][xPos][yPos]==BlockColor.TREE){//remove stump
grid[0][xPos][yPos++]=BlockColor.AIR;
}
//remove leaves
grid[0][xPos][yPos] = BlockColor.AIR;
grid[0][xPos+1][yPos] = BlockColor.AIR;
grid[0][xPos-1][yPos] = BlockColor.AIR;
grid[0][xPos+1][yPos-1] = BlockColor.AIR;
grid[0][xPos-1][yPos-1] = BlockColor.AIR;
}
private void belowDirt(int xPos, int yPos) {
while(grid[0][xPos][--yPos]!=BlockColor.DIRT){
grid[0][xPos][yPos] = BlockColor.DIRT;
}
}

Stack Overflow with Pathfinding Algorithm

I have been working on a project that will, in short, generate a 2D matrix of numbers, with "empty" spaces are represented by 0's. Each number is connected by a list of nodes. The nodes contain the number value, the number's X and Y position, and a list of all spaces adjacent to it (its "neighbors"), with the exception of spaces diagonally adjacent to the point, due to the algorithm only allowing movements of up, down, left, and right. The issue that I am having is that, as the title would suggest, I am experiencing some stack overflow issues. I will post my code below, if anyone could help, I would be most appreciative.
CoordList* Puzzle::GeneratePath(CoordList* Path, int GoalX, int GoalY)
{
int CurrX;
int CurrY;
CurrX = Path->NeighborX;
CurrY = Path->NeighborY;
if(CurrX == GoalX && CurrY == GoalY)
{
return(Path);
}
else
{
int NewX;
int NewY;
double NewDistance;
int OldX;
int OldY;
double OldDistance;
CoordList* PointNeighbors = NULL;
CoordList* BestChoice = NULL;
for(int i = 0; i < NumDirections; i++)
{
CoordList* NewNeighbor = new CoordList;
NewX = CurrX + DirectsX[i];
NewY = CurrY + DirectsY[i];
if(IsPossible(NewX, NewY))
{
NewNeighbor->NeighborX = NewX;
NewNeighbor->NeighborY = NewY;
if(PointNeighbors == NULL)
{
NewNeighbor->next = NULL;
PointNeighbors = NewNeighbor;
}
else
{
NewNeighbor->next = PointNeighbors;
PointNeighbors = NewNeighbor;
}
}
//delete NewNeighbor;
}
while(PointNeighbors != NULL)
{
if(BestChoice == NULL)
{
CoordList* AChoice = new CoordList;
AChoice->next = NULL;
NewX = PointNeighbors->NeighborX;
NewY = PointNeighbors->NeighborY;
AChoice->NeighborX = NewX;
AChoice->NeighborY = NewY;
BestChoice = AChoice;
PointNeighbors = PointNeighbors->next;
//delete AChoice;
}
else
{
NewX = PointNeighbors->NeighborX;
NewY = PointNeighbors->NeighborY;
NewDistance = DetermineDistance(NewX, NewY, GoalX, GoalY);
OldX = BestChoice->NeighborX;
OldY = BestChoice->NeighborY;
OldDistance = DetermineDistance(OldX, OldY, GoalX, GoalY);
if(NewDistance < OldDistance)
{
BestChoice->NeighborX = NewX;
BestChoice->NeighborY = NewY;
}
PointNeighbors = PointNeighbors->next;
}
}
BestChoice->next = Path;
Path = BestChoice;
return(GeneratePath(Path, GoalX, GoalY));
}
}
I was asked to provide my determine distance function. This is just a simple implementation of the traditional Point Distance formula. Provided below.
double Puzzle::DetermineDistance(int OneX, int OneY, int TwoX, int TwoY)
{
int DifX;
int DifY;
double PointSum;
DifX = (TwoX - OneX);
DifY = (TwoY - OneY);
DifX = (DifX * DifX);
DifY = (DifY * DifY);
PointSum = (DifX + DifY);
return (sqrt(PointSum));
}
The following is the IsPossible function, which determines if an X and Y value lies within the possible grid space.
bool Puzzle::IsPossible(int x, int y)
{
if(x + 1 > Size - 1 || x - 1 < 0
|| y + 1 > Size - 1 || y - 1 < 0)
{
return false;
}
return true;
}
You might have a infinite recursion loop that causes the stackoverflow, as you make new local variables every recursion, especially with your observered oscillation behaviour. I assume you dont have that problem with small matrices. Its just a shot in the dark :-)
The oscillation problem indicates that you dont check whether you have already been on one place already?
Anyways, maybe you want to reconsider using another pathfinding algorithm. I would suggest a agent based solution. I used to use the following solution to solve a maze of similar structure: I started an agent with a "PositionsList" of spots where it have been, so in the beginning only with the starting point. Then it copied itself to every reachable position not being in his own PositionList, adding the new position to that list and destroying itself then. Repeat that pattern with all new agents until the first agent reaches the goal. That way you are guaranteed to find the optimal path. But it might get pretty memory heavy for big matrices, especially when there are a lot different ways to get to the goal and a lot of possible directions per position! But there are plenty of other very good pathfinding algorithms out there. Maybe one of them suits you well :-)
Good Luck!

Crash, on Console Application, trying to draw enemies, out of bounds (following vid tutorial)

{Hopefully improved my post, please still suggest any other code you need, and once again im sorry for being so clueless, im determined to get past this problem though so i truly appreciate your time!!!}
**EDIT: thanks to Frank with his reply below, the program now starts and draws the three enemies, but just a few second later crashes, the program code below therefore is still applicable as its basically the move loop and somewhere in there something is still going wrong.
I realise this is extremely obscure and i have tried my best to explain it, but if noone can advise then the few second its up should be enough to complete the tutorial anyway and ill dissect the whole project after its finished and really try and break it down and learn as much as possible.**
Okay, so I run this loop designed to create new enemies, and then draw them onto the screen, it now works, but after a few second crashes. below is the steps the debugging goes through and the call stack at the end if what it displayed after the crash. hope you can help!
this is a video tutorial im following and im stuck, cant find the answer. checked the code over and over again. (the full code is at the bottom of the post (codeblocks,) but i have tried to include as much info as possible in this post)
the function is:
level->addEnemies(3);
which looks like in the main game.cpp:
bool Game::run(void)
{
level = new Level(&drawArea, 30, 20);
drawArea.createBackgroundTile(TILE_EMPTY, ' ');
drawArea.createBackgroundTile(TILE_WALL, 219);
drawArea.createSprite(SPRITE_PLAYER, 1);
drawArea.createSprite(SPRITE_ENEMY, '$');
player = new Character(level, &drawArea, 0);
level->draw();
level->addPlayer(player);
level->addEnemies(3); <-------- SKIPS TO THIS FUNC
char key = ' ';
startTime = timeGetTime();
frameCount = 0;
lastTime = 0;
posx = 0;
player->move(0,0);
while (key != 'q')
{
while (!getInput(&key))
{
timerUpdate();
}
level->keyPress(key);
}
delete player;
return true;
}
the function in full is below, note that when i remove this addEnemies function from the main game loop everything runs perfectly fine with no crash, so it has something to do with the upcoming functions.
void Level::addEnemies(int num)
{
int i = num;
while (i > 0)
{
int xpos = int(float(rand() % 100) / 100) * (width - 2) + 1;
int ypos = int(float(rand() % 100) / 100) * (height - 2) + 1;
if (level[xpos][ypos] != TILE_WALL)
{
Enemy *temp = new Enemy(this, drawArea, SPRITE_ENEMY,
(float)xpos, float(ypos));
temp->addGoal(player);
addNPC((Sprite *)temp);
i--;
}
}
}
It gets through this function without any problems it seems.
After this function is goes back to the game loops and executes through fine, goes into timer update without any problems. Here is the timerUpdate function:
void Game::timerUpdate(void)
{
double currentTime = timeGetTime() - lastTime;
if (currentTime < GAME_SPEED)
return;
level->update(); <--------SKIPS TO THIS FUNC
frameCount++;
lastTime = timeGetTime();
}
This is the Level->Update() Func:
void Level::update(void)
{
for (Iter = npc.begin(); Iter != npc.end(); Iter++)
{
(*Iter)->idleUpdate(); <-------------SKIPS TO THIS FUNC
if ((*Iter)->isAlive() == false)
{
Sprite *temp = *Iter;
//kill the enemy
Iter--;
delete temp;
npc.remove(temp);
}
}
}
idleUpdate():
void Enemy::idleUpdate(void)
{
if (goal)
simulateAI(); <------ Goes to this func
}
simulateAI():
void Enemy::simulateAI(void)
{
vector goal_pos = goal->getPosition();
vector direction;
direction.x = goal_pos.x - pos.x;
direction.y = goal_pos.y - pos.y;
float mag = sqrt(direction.x * direction.x + direction.y * direction.y);
direction.x = direction.x / (mag);
direction.y = direction.y / (mag);
if (!move(direction.x, direction.y)) <------ SKIPS TO THIS FUNC
{
while (!move(rand() % 3 - 1, rand() % 3 - 1))
{
}
}
move function:
bool Sprite::move(float x, float y)
{
int xpos = (int)(pos.x +x);
int ypos = (int)(pos.y +y);
if (isValidLevelMove(xpos,ypos)) SKIPS TO THIS FUNC
{
//.....rest not needed
isValidMove func:
bool Sprite::isValidLevelMove(int xpos, int ypos)
{
if (level->level[xpos][ypos] != TILE_WALL) <-------------THIS LINE CRASHES!!
return true;
return false;
}
I really cant figure out where this goes wrong, and why at the end the call stakc shows such high out of bounds numbers for xpos adn ypos.
Here is the full call stack:
#0 00402920 Sprite::isValidLevelMove (this=0x791498, xpos=-2147483648, ypos=-2147483648) (sprite.cpp:95)
#1 00000000 0x00401750 in Enemy::move (this=0x791498, x=-nan(0x400000) (enemy.cpp:21)
#2 00401892 Enemy::simulateAI (this=0x791498) (enemy.cpp:67)
#3 004017E5 Enemy::idleUpdate (this=0x791498) (enemy.cpp:46)
#4 0040226E Level::update (this=0x792e90) (level.cpp:86)
#5 00401CB8 Game::timerUpdate (this=0x28fec0) (game.cpp:93)
#6 00401BB5 Game::run (this=0x28fec0) (game.cpp:54)
#7 0040258D main() (main.cpp:11)
which basically tells me xpos and ypos have been mutilated from somehere in thsi proccess and thats causeing the crash im sure because its way out of bounds from the [30][20] int array of the width and height of the drawengine.
ANOTHER EDIT:
Here is the Sprite class, if it helps, will edit in more if needed.
enum
{
SPRITE_CLASSID,
CHARACTER_CLASSID,
ENEMY_CLASSID
};
struct vector
{
float x;
float y;
};
class Sprite
{
public:
Sprite(Level *l, DrawEngine *de, int s_index, float x = 1, float y = 1, int i_lives = 1);
~Sprite();
vector getPosition(void);
float getX(void);
float getY(void);
virtual void addLives(int num = 1);
int getLives(void);
bool isAlive(void);
virtual void idleUpdate(void);
virtual bool move(float x, float y);
protected:
Level *level;
DrawEngine *drawArea;
vector pos;
int spriteIndex;
int numLives;
int classID;
vector facingDirection;
void draw(float x, float y);
void erase(float x, float y);
bool isValidLevelMove(int xpos, int ypos);
};
anyway any help and i would be sooooo grateful, i know i must seem totally useless, but i rteally am determined to learn, and any help you guys can provide would be priceless!!!!
full code file (codeblocks) : http://www.mediafire.com/?5xz2seadmagbetb
This might not be the actual problem, but could be related. Your code to create a random position within your Level::addEnemies(int num) function will always return 1 for xpos and ypos.
This is because of the way you apply the casts. You seem to miss parenthesis for your final cast to int. I think you want something like this:
int xpos = int((float(rand() % 100) / 100) * (width - 2)) + 1;
Update:
The code causing the crash is located in your simulateAI() function. With:
float mag = sqrt(direction.x * direction.x + direction.y * direction.y);
You calculate the distance between two points, but if the points have the same coordinates, the distance is 0.
Later with: direction.x = direction.x / (mag); you devide by this potential 0 and as a result your coordinates will contain NaN. Within your bool Sprite::move(float x, float y) function you cast these NaNs into an int which will give you some undefined number. With this number you are trying to access your array which will lead to the access violation that crashes your program.
So first thing to do is to check for a zero distance and handle that differently.

Simulating movement of a window and have it react to collisions

I was reading this topic and I decided to give it a shot. To my astonishment it really seemed easier than what I am making it I guess. I have some confusion about the "DesiredPos" variable. Well at least in my implementation. I am trying to move a window around constantly and have it react like a ball when it hits the monitors edges. Like the ball in the game Pong. I have made programs like this that move the mouse, But I can't seem to get my head around this one.
This is what I have so far, I have limited experience when it comes to a lot of functions in the Windows API. Keep in mind this is a hardcore rough draft.
EDIT
I haven't implemented any of the collision detection yet I just wanted to get the moving portion working.
#include <windows.h>
#include <math.h>
int newX(int oldx);
int newY(int oldy);
double SmoothMoveELX(double x);
int main()
{
int lengthInMs = 10*1000;
HWND notepad = FindWindow("Notepad",NULL);
RECT window;
SetTimer(
notepad,
NULL,
30,
(TIMERPROC)NULL
);
int startTime = GetTickCount();
int pos = elap / lengthInMs;
while(1)
{
RECT window;
GetWindowRect(notepad,&window);
int elap = (GetTickCount() - startTime);
if(elap >= lengthInMs)
{
int NEWX = NewX(window.x);
int NEWY = NewY(window.y);
MoveWindow(
notepad,
NEWX,
NEWY,
100,
100,
TRUE
);
}
}
}
int NewX(int oldx)
{
int newx = oldx*(1-SmoothMoveELX(pos))
+ 10 *SmoothMoveELX(pos));
return newx;
}
int newY(int oldy)
{
int newy = oldy*(1-SmoothMoveELX(pos))
+ 10 *SmoothMoveELX(pos));
return newy;
}
double SmoothMoveELX(double x)
{
double PI = Atan(1) * 4;
return ((cos(1 - x) * PI + 1) /2 )
}
My advice is to take a look on the "verlet integration". It is a quite easy way to simulate basic mechanics. Google for it and you'll find many examples for it, including collision detection and friction. On the long run this will give you more natrual results then estimating the velocity or the new position with a sine function.