Weekend is OK, handwriting games continue ~
Preview
Steps
1 defining data StructuresLogic and interface separation, the game scene is a two-dimensional array area, the greedy snake is a number of consecutive coordinate point set, with dynamic linked list maintenance, the fruit is a random coordinate point.
const int BLOCK_SIZE=25; Side length const int margin=5 for a single block unit; Scene margin const int area_row=15; Scene line number const int area_col=15; Number of scene columns
Qpoint Foodpoint; The fruit appears in coordinates qlist<qpoint> snake;//Snake structure
const int time_interval=500; Timer interval time enum direction{up , down, left, right };
2 Adding interface refresh and keyboard monitoring
First, a timer is needed to control the movement of the snake and the refresh of the interface, the signal slot of the binding timer
Gametimer=new Qtimer (this); Connect (gametimer,signal ()-Timeout ()), This,slot (Snakeupdate ()));
Window Redraw
void Widget::p aintevent (qpaintevent *event) { qpainter painter (this); Draw the game scene Painter.setbrush (qt::yellow); Painter.setpen (qt::blue); Painter.drawrect (margin,margin,area_col*block_size,area_row*block_size); Draw a snake Painter.setbrush (qt::red); Painter.setpen (qt::green); for (int i=0;i<snake.size (); i++) Painter.drawrect (margin+snake[i].x () *block_size,margin+snake[i].y () * block_size,block_size,block_size); Draw Fruit Painter.setbrush (qt::green); Painter.drawellipse (Margin+foodpoint.x () *block_size,margin+foodpoint.y () *block_size,block_size,block_size); Draw Game score Painter.setpen (qt::black); Painter.setfont (Qfont ("Arial",)); Painter.drawtext (Margin*3+area_col*block_size,margin+2*block_size, "Score:" +qstring::number (Score));}
Keyboard monitoring
void Widget::keypressevent (Qkeyevent *event) { //the direction of the snake is a state machine, note that switching between the various directions has a restricted switch (Event->key ()) { Case qt::key_up: if (dir!=down) dir=up; break; Case Qt::key_down: if (dir!=up) Dir=down; break; Case Qt::key_left: if (dir!=right) dir=left; break; Case Qt::key_right: if (dir!=left) dir=right; break; Case qt::key_p: pauseresumegame (); break; Default: Break ; }}
3 snake move, eat fruit, score, game over logicThe snake's movement is a state machine, always moving in the direction of the current, the logic of the move is to constantly eliminate the tail node, and add a new head knot, if the fruit is encountered, then do not eliminate the tail node each time the fruit will be eaten to a random fruit, and ensure that the fruit will not overlap with the snake body.
void Widgets:: Snakeupdate () {//Snake move strategy is to delete the tail each time, then add a new head, maintain a dynamic link list switch (dir) {case UP:snake.push_front (Qpoint (snake . Front (). x (), Snake.front (). Y ()-1)); Break Case DOWN:snake.push_front (Qpoint (Snake.front (). x (), Snake.front (). Y () +1)); Break Case LEFT:snake.push_front (Qpoint (Snake.front (). x () -1,snake.front (). Y ())); Break Case RIGHT:snake.push_front (Qpoint (Snake.front (). x () +1,snake.front (). Y ())); Break Default:break; }//If the fruit is eaten, the tail is not deleted, otherwise the tail update header if (Snake.contains (Foodpoint)) {score+=1;//score Generatefood ();//Rebuild Fruit} else snake.pop_back (); Whether the game is over if (Isgameover ()) {Gameover (); Return Jump out of the function before redrawing to prevent the snake from actually out of bounds} update (); Redraw, which works better than repaint function}
void Widget::generatefood () { //randomly generates position Foodpoint.setx (rand ()%area_col); Foodpoint.sety (rand ()%area_row); If there is a conflict with the snake location, regenerate if (Snake.contains (foodpoint)) Generatefood ();}
When the snake's head is out of bounds or hit itself, it is decided to end the game
BOOL Widget::isgameover () { int x=snake.front (). x (); int Y=snake.front (). Y (); Out -of-bounds if (x<0| | x>area_col-1| | y<0| | Y>AREA_ROW-1) return true; Hit himself for (int i=3;i<snake.size (); i++) if (Snake[i]==snake.front ()) return true; return false;}
3 game Control logicGame initialization
void Widget::initgame () { //Initialize the snake, initial length 5, note the head in front, tail in the rear for (int j=4;j>=0;j--) snake.push_back (Qpoint ( j,0)); dir=right;//start at the right //Initialize the fruit srand (time (0)); Generatefood (); Initialize game score score=0; Initialize the pause variable ispause=false; Initialize timer gametimer=new Qtimer (this); Connect (gametimer,signal ()-Timeout ()), This,slot (Snakeupdate ())); Gametimer->start (time_interval);}
Game pause and resume
void Widget::P auseresumegame () { //pause and Resume Timer if (!ispause) { ispause=!ispause; Gametimer->stop (); } else { ispause=!ispause; Gametimer->start (Time_interval); }}
Game Over
void Widget::gameover () { gametimer->stop (); Qmessagebox::information (This, "failed", "game over!");}
SOURCE Download: csdn: Greedy snake
Github:snake
QT mini game development: Snake