Sign in to follow this  

Snake in Borland C++ Builder 6

This topic is 4814 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having trouble making a snake game in c++ builder. I have shapes as the body and an image as the head i can get the head to move fine and look as if it was a real snake game, but, i can't get the body parts to follow the head correctally. i have a length of the body, how many shapes there are i have directions 1 = up 2 = right 3 = down 4 = left
//---------------------------------------------------------------------------

#include <vcl.h>
#include <COLL.h> //my own collision header file
#pragma hdrstop

#include "snake.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TShape* Body[50];
int length = 3, direction = 0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
  DoubleBuffered = true;
  KeyPreview = 1;
  Body[0] = Shape1;
  Body[1] = Shape2;
  Body[2] = Shape3;
  Body[3] = Shape4;
  Body[4] = Shape5;
  Body[5] = Shape6;
  Body[6] = Shape7;
  Body[7] = Shape8;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 //blah, just to keep this here
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
  //calling the directions
  if(Key == VK_UP){
    direction = 1;
   }
  if(Key == VK_RIGHT){
    direction = 2;
   }
  if(Key == VK_DOWN){
    direction = 3;
   }
  if(Key == VK_LEFT){
    direction = 4;
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::movement_timerTimer(TObject *Sender)
{
  //getting the snake to move in the direction that is called to above
  if(direction == 1){
    snake_head -> Picture -> LoadFromFile("head_up.bmp");
    snake_head -> Top -= 3;
   }
  else if(direction == 2){
    snake_head -> Picture -> LoadFromFile("head_right.bmp");
    snake_head -> Left += 3;
   }
  else if(direction == 3){
    snake_head -> Picture -> LoadFromFile("head_down.bmp");
    snake_head -> Top += 3;
   }
  else if(direction == 4){
    snake_head -> Picture -> LoadFromFile("head_left.bmp");
    snake_head -> Left -= 3;
   }

//i want to add something here in the timer to make the
//snakes body follow the snake.
////////////////////////////////////

does anyone know how to help me? thanks.

Share this post


Link to post
Share on other sites
Sorry if I'm misunderstanding you, but you want to keep the snakes position as it moves? I would suggest a linked list from head to tail, so when the snake-head moves forward, the next body piece can take it's place, and so on. Thus you can change the body bitmap based on the direction each body piece is moving.

EDIT: I was also thinking a linked list would be good for splitting up the snake as well, into seperate snakes. Don't know why you would do this, or even how you would suddenly control an additional snake, but I think wierd stuff sometimes.

Share this post


Link to post
Share on other sites
i tried that using a for loop to record the positions of the body and then placing the other ones in the position of the last one when it moves, but it doesnt seem to work as well as i thought it would....its kinda...idk, it seems like there would be a better way.

Share this post


Link to post
Share on other sites
i did a text snake on ZX-Spectrum 48 , in basic. That was one of my first games....

I just had an array of positions big enough to hold maximally long snake(if you have board NxM, it may be N*M big), and 2 counters, snakehead, and snaketail. IIRC my snake worked like:
At every move, if snake haven't grown i cleaned up cell storen in array[snaketail], and snaketail=(snaketail+1)%max_length. It plotted a char at next head position(depends to snake move direction) and then did snakehead=(snakehead+1)%max_length, and
array[snakehead]=snakehead_position

Very simple.
I was very proud that my program haven't looped over every body cell(if it had, it would be very slow). Also i reinvented a cyclic buffer myself :).Also it worked ideally well.


Sorry, linked list it's certanly _not_ a good idea. AT all. It's certanly a wrongest possible tool for the job one can think of.(edit: that is, it beats someone's winning idea in "most inapporiate use of software" thread, idea about tik-tak-toe game that opens a file and in loop puts "c" into it, while running)

BTW, What a point in studying advanced things such as linked list before double-ended queves/cyclic buffers???

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I noticed you are re-loading the graphic in every frame - not really a good idea.

Share this post


Link to post
Share on other sites
I used a linked stack for my snake game's player object

The method was simple.First the head would be given a location (x,y) and a direction (UP,DOWN,LEFT,RIGHT).These directions are use to deterime how to change the coordinate.

When block was added it woluld be given the last block's direction and the location of the last block altered in the opposite direction.

When the snake moved forward the key press would be checked and the new direction (if any) would be assigned to the head.Then the head is moved and then the block after it is moved according to it's direction,this dir would be stored then it would be assigned the direction of the block before it (in this case the head)

Move snake

nt render_snake(unit &sk,int render)
{
int color,num=0,ret=0;
direction dr,dr1;
box *b;

b=sk.top;
dr = b->d;

color = sk.color;
do
{
num++;

if(num==1)
{
//checking for oppossite movement
/*if(b->d == d_lf && b->next->d == d_rt) ret = -1;
else if(b->d == d_rt && b->next->d == d_lf) ret = -1;
else if(b->d == d_up && b->next->d == d_dn) ret = -1;
else if(b->d == d_dn && b->next->d== d_up) ret = -1;*/


if(b->x > HX_LIMIT)ret=-1;
else if(b->x <= LX_LIMIT) ret=-1;
else if(b->y > HY_LIMIT)ret =-1;
else if(b->y <= LY_LIMIT) ret=-1;
}

if(render == 1)
{
if(b->d == d_lf) b->x -= BL_SZ;
else if(b->d == d_rt) b->x += BL_SZ;
else if(b->d == d_up) b->y -= BL_SZ;
else if(b->d == d_dn) b->y += BL_SZ;
}

dr1 = b->d; //remenber current block direction
b->d = dr; //assign previous block direction

draw_box(b,color);

//cout<<"\nBox "<<num<<" X="<<b->x<<"\tY="<<b->y<<" D ="<<b->d;

//if(b->next==NULL)break;

b = b->next; //next block
dr = dr1; //update block direction

}
while(b!=NULL);

return(ret);
//*/
}







Add new point

box *new_pnt(box *n,unit &s)
{

n->x=s.top->x;
n->y=s.top->y;

if(s.top->d==d_rt) n->x += (BL_SZ);
else if(s.top->d==d_lf) n->x -= (BL_SZ);
else if(s.top->d==d_up) n->y -= (BL_SZ);
else if(s.top->d==d_dn) n->y += (BL_SZ);

return(n);
}






Snake class (almost an standard stck class)

class unit
{
//private:


public:
int len;
int score;
int alive;
int color;
box *top;

unit();
~unit();
void push(box *);
};

unit::unit()
{
score = 0;
len = 0;
top = NULL;
}

unit::~unit()
{
if(len > 0)
{
box *t;
while(len > 0)
{
t = top;
top = top->next;
delete[] t;
len--;
}
}
}

void unit::push(box *p)
{
p->lx = BL_SZ;
p->ly = BL_SZ;

if(len==0)p->d=d_rt;
else p->d=top->d;

p->next = top;
top = p;
len++;
}






Helps?

[Edited by - FireNet on October 10, 2004 9:15:39 AM]

Share this post


Link to post
Share on other sites
thats way too much code for just snake...

int stepx[50];
int stepy[50];
int count;

for(count = 0; count < lentgh; count++){
stepx[count] = Body[count];
stepy[count] = Body[count];
}
for(count = 0; count < length; count++){
Body[count] -> Left = stepx[count -1];
Body[count] -> Top = stepy[count -1];
}

thats all in the timer i did change the movement to the width of the body parts and then slowed the timer so it would work this way....

its that easy...i figured it out, and it works perfectally...

thanks anyways...

ohh and i fixed the loading thing for every frame, thanks for catching that.

Share this post


Link to post
Share on other sites
My first game was snake on the TI-83. I programmed it during Algebra class in TI-Basic... that was fun. Anyway, on to serious stuff.

Quote:
Original post by GT70sgt
thats way too much code for just snake...

int stepx[50];
int stepy[50];
int count;

for(count = 0; count < lentgh; count++){
stepx[count] = Body[count];
stepy[count] = Body[count];
}
for(count = 0; count < length; count++){
Body[count] -> Left = stepx[count -1];
Body[count] -> Top = stepy[count -1];
}

thats all in the timer i did change the movement to the width of the body parts and then slowed the timer so it would work this way....

its that easy...i figured it out, and it works perfectally...

thanks anyways...

ohh and i fixed the loading thing for every frame, thanks for catching that.


It's actually even easier than that... If you have the positions in an array, you don't need to make a copy of the modified array. You can just do:


for(int i = length - 1; i > 0; i--)
position[i] = position[i - 1];

position[0] = (however you get the snake's next position)


That saves the time and memory of making a copy of the snake. You have to do it in reverse order (tail to head) so they don't all have the tail position, though.

Share this post


Link to post
Share on other sites
Oh,can't resist.

it's even simpler than that. There's absolutely no need to move the data, no need to copy the data (it was too slow in basic on zx-spectrum...), no need to reload images at every frame, no need to use linked list, etc. You just need 2 counters and one array! One counter it's head index in array, other it's tail index in array. When snake normally moves, both counters is incremented (with wrap-around). If snake grows, only head is incremented.

If you still don't unserstand, in pseudocode(same as what i explained in my prev. post):

struct pos{
int x,y;
};
int maxlen=screen_x_cells*screen_y_cells
int board[maxlen];
pos snakeposition[maxlen];
int head=1,tail=0,dir=0;// 2 cells-long snake
snakeposition[0].x=startx;snakeposition[0].y=starty;
snakeposition[1].x=startx+1;snakeposition[1].y=starty;
pos hpos=snakeposition[snakehead];
while(playing game){
keyboard input: update dir, check for esc, etc;
draw_snake_body_at(hpos);// replace head image by body image on the screen, because head will be moved
// move the head
switch(dir){
left:
hpos.x-=1; if(hpos.x<0){you loose;}
break;
right:
hpos.x+=1; if(hpos.x>screen_x_cells){you loose;}
break;
up:
hpos.y-=1; if(hpos.y<0){you loose;}
break;
down:
hpos.y+=1; if(hpos.y>screen_y_cells){you loose;}
break;
}
head++;// head is storen one point further in array.
if(head>=maxlen)head-=maxlen;// wrap around if needed
snakeposition[head]=hpos;// store snake head position

//Game logic - if self-intersect, you lose, if hit brick, you lose.
if(board[hpos.x+hpos.y*screen_x_cells]==brick){you loose;}// we hit a brick.
if(board[hpos.x+hpos.y*screen_x_cells]==snake_body){you loose;}// Or we spepped over snake! Oh! There's S SSS SNAKE E!!! :-)

// if cell at board is not eatable
if(board[hpos.x+hpos.y*screen_x_cells]!=eatable){
// then we need to update tail
tmp=snakeposition[tail];
//clean up the board after snake
board[tmp.x+tmp.y*screen_x_cells]=blank;
// and the screen
draw_blank_at(snakeposition[tail]);
// and increment tail pointer
tail++;
if(tail>=maxlen)tail-=maxlen;
// draw tail image on the screen
draw_tail_at(snakeposition[tail]);
}
// update board - there's a snake is in cell hpos.
board[hpos.x+hpos.y*screen_x_cells]=snake_body;
// draw the head
draw_heat_at(hpos);

swap the buffers and wait;
}




2mods: this definitely should be moved to beginers forum.

[Edited by - Dmytry on October 12, 2004 4:35:25 AM]

Share this post


Link to post
Share on other sites

This topic is 4814 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this