I have been working on a snake game using sfml and c++ but I am having trouble getting the tail of my snake to follow the snake head which is defined as Snake[0] in my code below. I have implemented code that I think should work but doesn't which is the following
for (int i = 1; i < snakeSize; i++)
{
snakePartX[i] = snakePartX[i-1];
snakePartY[i] = snakePartY[i-1];
}
The way I understand it (and I am probably incredibly wrong and would appreciate if anyone could point out what is actually happening here) is that, that piece of code should set the value of a snake body part to the position of where the previous body part WAS located so that when the program loops they are set to follow the snake as it travels.
What actually does happen though is that when the snake eats an apple the snake will gain 1 block to its tail, but will not grow any farther.
In the classic snake game, the snake is made up of segments. Each segment contains the coordinate of the segment (among other attributes).
Specifically, the snake is a container of segments. The container is your choice, but I recommend a queue.
With the queue, a new head segment is added into the queue and a tail segment removed.
Here's a code fragment to help:
class Snake_Segment
{
public:
int column;
int row;
};
typedef std::deque<Snake_Segment> Segment_Container;
int main(void)
{
Segment_Container snake_body;
Snake_Segment head;
head.row(25);
head.column(30);
snake_body.push_back(head);
Snake_Segment tail = head;
++tail.column;
snake_body.push_back(tail);
return EXIT_SUCCESS;
}
Why do index zero here? Doesn't it get done as part of the for loop too?
Snake[0].setPosition(snakePartX[0], snakePartY[0]);
for(int i = 0; i < snakeSize; i++)
{
Snake[i].setPosition(snakePartX[i], snakePartY[i]);
}
I'm concerned about this section :
snakeSize += 1;
}
Apple.setPosition(applePos.x, applePos.y);
window.draw(Apple);
for(int i = 0; i < snakeSize; i++)
{
window.draw(Snake[i]);
}
Make sure you don't exceed 20 as your parts are a simple array and you will run into problems once you get 20 parts. More importantly, you never set the value for Snake[i] for the new snakeSize. So when you get an apple, you'll use uninitialized memory to draw one snake part.
Another potential problem :
//Clock to set snake speed
ElapsedTime = clock.getElapsedTime();
if(ElapsedTime.asSeconds() >= snakeSpeed)
{
for(int i = 1; i < snakeSize; i++)
{
snakePartX[i] = snakePartX[i - 1];
snakePartY[i] = snakePartY[i - 1];
}
You allow keyboard input to move the snake head along, but you only move the body when the timer expires. So you head can slide way away from the body and the body doesn't move unless the timer goes off.
I printed the field of snake game as a Field[x][y]. So by below code the body of snake following the head. Also, optionMoveNumber==0 in other function checked if Field[x][y]==food or not which means did the snake eat the food of not.
int m=1;
void Snake::Movement(int x, int y){
movey[0]=firstTaily; //first place
movex[0]=firstTailx; //first place
movex[m]=x;
movey[m]=y;
for(int n=m; n>=m-ntail; n--){
Field[movey[n]][movex[n]]=Field[movey[n-1]][movex[n-1]];
}
if(optionMoveNumber==0){
Field[movey[m-1]][movex[m-1]]=tail;
}
else{
Field[movey[m-ntail-1]][movex[m-ntail-1]]=space;
}
m++;
}
Related
I'm learning Artificial Intelligence from a book, the book vaguely explains the code I'm about to post here, I assume because the author assumes everyone has experienced hill climbing algorithm before. The concept is rather straightforward, but I just don't understand some of the code below and I'd like someone to help me understand this algorithm a bit clearer before I move on.
I commented next to the parts that confuses me most, a summary of what these lines are doing would be very helpful to me.
int HillClimb::CalcNodeDist(Node* A, Node* B)
{
int Horizontal = abs(A->_iX - B->_iX);
int Vertical = abs(A->_iY - B->_iY);
return(sqrt(pow(_iHorizontal, 2) + pow(_iVertical, 2)));
}
void HillClimb::StartHillClimb()
{
BestDistance = VisitAllCities();
int CurrentDistance = BestDistance;
while (true)
{
int i = 0;
int temp = VisitAllCities();
while (i < Cities.size())
{
//Swapping the nodes
Node* back = Cities.back();
Cities[Cities.size() - 1] = Cities[i];
Cities[i] = back; // Why swap last city with first?
CurrentDistance = VisitAllCities(); // Why visit all nodes again?
if (CurrentDistance < BestDistance) // What is this doing?
{
BestDistance = CurrentDistance; //???
break;
}
else
{
back = Cities.back();
Cities[Cities.size() - 1] = Cities[i];
Cities[i] = back;
}
i++;
}
if (CurrentDistance == temp)
{
break;
}
}
}
int HillClimb::VisitAllCities()
{
int CurrentDistance = 0;
for (unsigned int i = 0; i < Cities.size(); i++)
{
if (i == Cities.size() - 1)//Check if last city, link back to first city
{
CurrentDistance += CalcNodeDist(Cities[i], Cities[0]);
}
else
{
CurrentDistance += CalcNodeDist(Cities[i], Cities[i + 1]);
}
}
return(CurrentDistance);
}
Also the book doesn't state what type of hill climb this is. I assume it's basic hill climb as it doesn't restart when it gets stuck?
Essentially, it does this in pseudo-code:
initialize an order of nodes (that is, a list) which represents a circle
do{
find an element in the list so that switching it with the last element of the
list results in a shorter length of the circle that is imposed by that list
}(until no such element could be found)
VisitAllCities is a helper that computes the length of that circle, CalcNodeDist is a helper that computes the distance between two nodes
the outer while loop is what I called do-until, the inner while loop iterates over all elements.
The if (CurrentDistance < BestDistance) part simply checks whether changing that list by swapping results in a smaller length, if so, update the distance, if not, undo that change.
Did I cover everything you wanted to know? Question about a particular part?
This is from a homework assignment that was already turned in. The program is a card game that plays correctly but seg faults when the game is over. I can trace the core dump to my delete [] playerArr, but I think the real problem is in how I'm declaring my playerArr.
I have a constructor, copy, overloaded operator and destructor in my .h file that works well with other programs so I think my problem is in main. I've looked at several other questions here and on google and haven't found one quite like this. Here are the code snippets:
struct Player
{
int currentHand; //current number of cards in given player's hand
Queue hand; //queue to store player's hand
};
in main I allocate an array of structs, I think this is my problem. I've trial and errored a variety of approaches but this one allows my program to compile and my game to play as designed:
//allocate array of Player structs
Player *playerArr = new Player[numPlayers];
for (int i = 1; i <= numPlayers; i++)
playerArr[i].currentHand = 0;
//enqueue playerArr.hand
deal(playerArr, deck, numPlayers, currentDeck);
this is the sequence I use to clean up before deleting, the core dumps after cout:
//exit do-while loop and end game
}
while (playerArr[currentPlayer - 1].currentHand != 0);
for (int i = 1; i < numPlayers; i++)
{
while (playerArr[i].currentHand > 0)
{
playerArr[i].hand.dequeue(catchQ);
playerArr[i].currentHand--;
}
}
//empty all deck/discard stacks
while (!deck.isEmpty())
deck.pop(catchPop);
while (!discard.isEmpty())
discard.pop(catchPop);
//reset hand/deck counters to defaults
catchQ = 0;
catchPop = 0;
currentDeck = 52;
currentPlayer = 1;
numPlayers = 2;
cout << "\n\n\n\t Good Game!" << endl << endl;
//free dynamic memory
delete [] playerArr;
It's too late for me to change my grade on this program and with finals week I don't have time to visit my prof during office hours so if someone has a solution for me I can learn from this mistake and move on.
Thank you
One probable cause of the problem is that you forget that array-indexes are zero-based.
An array of numPlayers elements will have indexes from 0 to numPlayers - 1 (inclusive).
The first loop you show doesn't use that, instead if goes from 1 to numPlayers, leading you to index the allocated memory out of bounds which leads to undefined behavior.
My homework is that I have to make a class (register) which contains 3 class arrays (birds, mammals, reptiles) which are in the animal class. Animal is the friend of Register. I will only show the birds part, to keep it simple.
The register class looks like:
class Register
{
Bird* birds;
unsigned int birdSize;
public:
...
}
The constructor of register:
Register::Register()
{
this->birds = new Bird[0];
this->birdSize = NULL;
}
Now I have a function in register that adds one element to the birds array, the input is cin.
void Register::add()
{
...
if (birdSize == 0)
{
birds = new Bird[0];
Bird* temp = new Bird[0];
temp[0].add();
this->birds = temp;
birdSize++;
}
else
{
Bird* temp = new Bird[birdSize+1];
for (unsigned int i=0; i<=birdSize; i++)
{
temp[i] = this->birds[i];
}
temp[birdSize+1].add();
birds = new Bird[birdSize+1];
birds = temp;
birdSize++;
}
temp[0].add() has the cin, it works properly. When I run the program, the user has to add 2 birds to the array. The problem occurs when reaching the part under 'else', so the second element of the array. The program surely reaches "temp[birdSize+1].add();" while running, then the "xyz.exe has stopped working" window pops up and it says in the details " Fault Module Name: StackHash_7e8e" so I'm sure something is wrong with the memory allocation, but the problem is that when I try to find the problematic line in debug mode, everything works fine.
Well, not everything. The program has a print() function, it prints out everything in Register. The second element of the array is the same as the first.
I have no clue what to do. I read many forum posts, read a cpp book, watched online tutorials, but I can't find the solution for this problem. Please help.
Array index starts from 0. So in else part you are writing
Bird* temp = new Bird[birdSize+1]; // size =birdSize +1;
So valid index range will be 0 -> birdSize, not birdSize+1.
The problem is
temp[birdSize+1].add();
you are using birdSize+1th index. It should be
temp[birdSize].add();
There are other bugs in your code:
for (unsigned int i=0; i<=birdSize; i++) // should be i<birdSize
{
temp[i] = this->birds[i];
}
There are other bad coding in your program:
Register::Register()
{
this->birds = new Bird[0]; // should be this->birds=NULL
this->birdSize = NULL; // should be this->birdSize = 0
}
And obviously if your homework does not demand it, you should not use arrays in this way. For variable size container, use vector, list.... Array is only when the size is fixed.
I'm working on a game in C++, and have a player object and a bullet object. I have a std::vector collection for both kinds of object, defined earlier in my code like so:
std::vector<Player*> players;
std::vector<Bullet*> bullets;
My problem happens in my main game loop, where I do all of my update logic. Using a for loop to check each player and update him, I get any bullets he has spawned and add them to the bullets vector.
// update players
for (int i = 0; i < players.size(); ++i){
Player *player = players[i];
player->Update(delta);
// get bullets
for (int b = 0; b < player->Bullets.size(); ++b){
// THIS IS WHERE THINGS GET WEIRD FOR PLAYER 2
Bullet *bull = player->Bullets[i];
bullets.push_back(bull);
}
player->Bullets.clear();
}
While my first player works fine - he can shoot as much as he wants - when you get to the second player, making him shoot causes an EXC_BAD_ACCESS later on when I iterate through the bullets vector. As I was stepping through with a debugger (using Xcode), when I get to the part below my comment ("// THIS IS WHERE THINGS GET WEIRD FOR PLAYER 2"), I notice that the bullet is NULL and the player is NULL as well. Somewhere between calling that player's update method and where I pull the bullets out, things go horribly wrong.
I've been debugging this for several hours now, and I'm wondering what I am missing.
Thanks!
It's a simple typo:
Bullet *bull = player->Bullets[b];
^ not i
You could avoid this kind of mistake using range-based loops (C++11 or later):
for (Player * player : players) {
player->Update(delta);
for (Bullet * bullet : player->Bullets) {
bullets.push_back(bullet);
}
player->Bullets.clear();
}
and/or replacing the inner loop with
bullets.insert(bullets.end(), player->Bullets.begin(), player->Bullets.end());
I have a vector holding 10 items (all of the same class for simplicity call it 'a'). What I want to do is to check that 'A' isn't either a) hiding the walls or b) hiding another 'A'. I have a collisions function that does this.
The idea is simply to have this looping class go though and move 'A' to the next position, if that potion is causing a collision then it needs to give itself a new random position on the screen. Because the screen is small, there is a good chance that the element will be put onto of another one (or on top of the wall etc). The logic of the code works well in my head - but debugging the code the object just gets stuck in the loop, and stay in the same position. 'A' is supposed to move about the screen, but it stays still!
When I comment out the Do while loop, and move the 'MoveObject()' Function up the code works perfectly the 'A's are moving about the screen. It is just when I try and add the extra functionality to it is when it doesn't work.
void Board::Loop(void){
//Display the postion of that Element.
for (unsigned int i = 0; i <= 10; ++i){
do {
if (checkCollisions(i)==true){
moveObject(i);
}
else{
objects[i]->ResetPostion();
}
}
while (checkCollisions(i) == false);
objects[i]->SetPosition(objects[i]->getXDir(),objects[i]->getYDir());
}
}
The class below is the collision detection. This I will expand later.
bool Board::checkCollisions(int index){
char boundry = map[objects[index]->getXDir()][objects[index]->getYDir()];
//There has been no collisions - therefore don't change anything
if(boundry == SYMBOL_EMPTY){
return false;
}
else{
return true;
}
}
Any help would be much appreciated. I will buy you a virtual beer :-)
Thanks
Edit:
ResetPostion -> this will give the element A a random position on the screen
moveObject -> this will look at the direction of the object and adjust the x and Y cord's appropriately.
I guess you need: do { ...
... } while (checkCollisions(i));
Also, if you have 10 elements, then i = 0; i < 10; i++
And btw. don't write if (something == true), simply if (something) or if (!something)
for (unsigned int i = 0; i <= 10; ++i){
is wrong because that's a loop for eleven items, use
for (unsigned int i = 0; i < 10; ++i){
instead.
You don't define what 'doesn't work' means, so that's all the help I can give for now.
There seems to be a lot of confusion here over basic language structure and logic flow. Writing a few very simple test apps that exercise different language features will probably help you a lot. (So will a step-thru debugger, if you have one)
do/while() is a fairly advanced feature that some people spend whole careers never using, see: do...while vs while
I recommend getting a solid foundation with while and if/else before even using for. Your first look at do should be when you've just finished a while or for loop and realize you could save a mountain of duplicate initialization code if you just changed the order of execution a bit. (Personally I don't even use do for that any more, I just use an iterator with while(true)/break since it lets me pre and post code all within a single loop)
I think this simplifies what you're trying to accomplish:
void Board::Loop(void) {
//Display the postion of that Element.
for (unsigned int i = 0; i < 10; ++i) {
while(IsGoingToCollide(i)) //check is first, do while doesn't make sense
objects[i]->ResetPosition();
moveObject(i); //same as ->SetPosition(XDir, YDir)?
//either explain difference or remove one or the other
}
}
This function name seems ambiguous to me:
bool Board::checkCollisions(int index) {
I'd recommend changing it to:
// returns true if moving to next position (based on inertia) will
// cause overlap with any other object's or structure's current location
bool Board::IsGoingToCollide(int index) {
In contrast checkCollisions() could also mean:
// returns true if there is no overlap between this object's
// current location and any other object's or structure's current location
bool Board::DidntCollide(int index) {
Final note: Double check that ->ResetPosition() puts things inside the boundaries.