你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

用C语言来写个贪吃蛇游戏!

[复制链接]
gaosmile 发布时间:2020-5-1 21:52

贪吃蛇是个非常经典的游戏,用C语言来实现也是一个好玩的事情。这个游戏我写完后放在知乎,竟然点赞的人数超级多。我觉得大家喜欢,一个方面是因为写得简单,大家都能看得懂,一个可扩展性还是非常强的。

我试了说一下这个代码 核心的三个函数

    menu();; g$ c5 }; O( y0 r7 @! m
    setup();
' S8 g8 Y0 T2 z. R" f$ H: ~    draw();
" Y) t& l* \: w6 \) I

menu用来设置菜单,也就是我们一运行看到的那个。setup用来设置参数,我们需要设置高度和宽度,还有分数,食物的位置。draw也就是画,也就是画整个画面。

还有一个枚举类型 这个结构体用来设置蛇的几个状态,我觉得这个也是面向对象编程的一个思想,把蛇的状态都封装成一个枚举类型。

typedef enum
9 M) D- e. D) J5 h( a/ v/ r{" s" ?# Y7 W7 a9 ~
        STOP = 0,
% K% v: [$ `& G# b        LEFT,+ u$ m4 b1 g) R% u
        RIGHT,8 r" }- g; E4 k, A
        UP,
, b1 h' K7 {# t$ x) t        DOWN
4 v8 ]3 b/ K# n5 V* {# l/ ?6 r}Direction;

- o  R; J2 d* N  N0 M& O

还有

/*判断贪吃蛇的长度*/' }! z2 F* p& D) |# t1 {& m5 b  e
void logic()
) q$ K' y6 A7 q6 ~6 U9 o% L

这个函数,这个函数应该是整个贪吃蛇的精髓了,要理解代码怎么把蛇给连接起来。用了点巧妙的东西。

来看这里面的关键代码

/*把上一个位置记下*/1 X- Z& p( P% k1 |2 h1 Z
    int lastX = tailX[0];$ J$ }! `, f* Q% C5 a2 e; }! E
    int lastY = tailY[0];
8 q7 L; P$ J' N' G$ H" O    int last2X, last2Y;
0 z9 [1 ^+ `" Q* Z$ ^7 P    /*重新获取当前的位置*/
/ e) U2 k7 Z" R2 b, a% u4 O# ^    tailX[0]=x;
. `; Z2 m/ M/ T+ p/ ~+ p( |    tailY[0]=y;7 X1 l- J, j! r3 ~- X7 l
    int i=0;
( q3 w3 t6 J. G8 V$ G! n$ z/ ^4 w. j; b: {    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
3 D+ k) v: A3 F2 \0 u    for(i=1; i<ntail;i++)) \4 F% H6 z7 O* N, K6 L1 P
    {
5 w$ l# R7 Z! E2 T        last2X = tailX;9 @- D1 G+ P; Z3 a) W
        last2Y = tailY;
- d" d! s# m4 f3 P+ r7 H, e+ z+ D+ {        tailX=lastX;8 W/ q0 Z3 h, q! S
        tailY=lastY;; @- A8 r  u& J, ^
        lastX = last2X;' ?$ o% z- u" p$ n- B2 R
        lastY = last2Y;
. y5 v# ^% w2 L6 d# s( n    }
0 I+ @5 k" ~: d3 x8 B% V

lastX lastY 用来存上一次的蛇头的位置。后面的 for 循环,通过tail 蛇的长度,把蛇上个状态给保存到数组tailX tailY里面。

完整代码

" d' Y7 I, n$ |; O9 X$ h) v! W
#include <stdio.h>! e# D/ Y6 t" _  _% K
#include <stdlib.h>
7 Z* L( l8 d4 H9 c#include <stdbool.h>
$ Y" ^. [7 D. X3 B#include <Windows.h>1 q! a2 |- {7 X$ L
#include <time.h>$ N$ B2 |# l% v) n
#include <conio.h> /*键盘输入获取*/: W6 k. O- y. a
) y2 |0 v2 C+ D0 X0 Z* X$ }1 s
bool gameOver;
+ {2 F7 w3 Y1 l4 ?6 L4 O0 hbool stop = false;$ \% S. w# G) W7 k' G3 y% x* B
bool hit = false;
3 V. L. r( u0 \$ ]9 b& H/*游戏的边框大小*/$ k) [* X) a4 r
const int width = 50;% ]' k+ _  t/ y
const int height = 20;
5 x, f6 m4 K1 V. S+ ~/*蛇的坐标,食物的坐标还有分数*/0 G0 N9 H  {$ D9 F5 G. z
int x,y,fruitX,fruitY,score;
$ E" V, r* n' f2 Q6 X/ `' T  ]6 S" |; j/*蛇每个点的坐标*/; t2 ]* @- G9 `2 m/ i# P. A5 W3 P3 L$ `
int tailX[200],tailY[200];  |% q6 P- i, `. n! z7 b7 X6 w3 y7 H
/*蛇的默认长度*/: a* U4 K$ {( j3 {9 G: q
int ntail=3;& |* q" V( T2 a3 F7 j

! Q8 h: e0 r: T- Vtypedef enum
" l2 [) i' g/ j6 J{
5 z. a- e( I6 H: V! E        STOP = 0,
9 l' X: N$ E- }/ H0 i3 W( k& d        LEFT,
. ^+ N3 T! p0 d7 F4 v$ Y; U' s        RIGHT,, O" i* b6 S# b; O; g
        UP,
2 M1 E' i& q' S! L6 I        DOWN
* m- O2 Q0 ~7 t8 m' c% w7 t}Direction;. N/ a" p- r# i1 G9 P+ R$ V& W

$ c) N1 Y0 I  _4 U( Q. k  |9 K) xDirection Dir;) S- L' s5 O: q8 i7 P. g' W
/*开始菜单*/  _$ x. |% p- l: k+ Q/ H& x, r$ ^
void menu()
- P6 f- {2 `8 n! f- E{
5 _8 r  F. _/ W7 o6 N5 j0 r9 G0 O    int a;1 h/ Y: e! _6 A& |
    printf("------------------------------------------------------------------\n");8 x; ^; m. L: P
    printf("|                              贪吃蛇游戏                        |\n");. f8 ?; m+ ?7 N# Z0 e( X9 Y
    printf("|                              1) 新游戏                         |\n");- n5 R+ P6 o& M1 X) |: R4 [: k
    printf("|                              2) 开始边界                       |\n");
. A+ o# N6 y) `4 Y+ @8 y9 x7 c    printf("|                              3) 退出游戏                       |\n");. z0 _3 k4 a6 A7 }
    printf("------------------------------------------------------------------\n");+ J( g7 o. L, T3 Z8 z$ G
    printf("---->请输入你的选择:");
8 Q: U$ I! j) |6 s: l/ _    scanf("%d", &a);
' a# D# z& G! v" ~6 q0 P}
5 y0 {+ p* Z# z+ T6 v/ l
$ Y( I2 I2 K0 f: I+ `. b/*初始化状态*/) W; g& m0 q) o; j8 F% h
void setup(): W: i/ u) M& |- J
{6 Q% K8 |, q0 ^, E& E8 r; q. n  z6 c
    gameOver = false;) `3 Q3 T; h* ^3 X: ~
    /*根据当前时间设置“随机数种子”*/& ]& N1 W- v4 b& M3 T/ y  m
    srand(time(NULL));
) a0 x( L9 q* x6 G: V2 i- p5 x    Dir = STOP;) k/ P1 N& a2 s( E2 n! M7 @( X% _
   
3 j# ?- V% y1 w( H& k6 A    /*贪吃蛇的位置,固定在中间*/- ^6 Q' l( f! ]2 x+ K
    x= width/2;3 {0 |& t9 E( j6 [" B3 ]; k4 s" r
    y= height/2;' u4 _& U8 U$ r+ W; f
    /*食物的位置,位置是随机的*/
$ s* l$ \2 o5 v: f    fruitX = rand()%width;
+ l) z1 U6 i+ v& g6 q    fruitY = rand()%height;
7 F  V/ X7 M9 I' j2 B    score = 0;& C( f* d, r( k- ^3 Q. x9 a
}' t# a* ~* S- ]. k
/*绘制界面*/
' _0 a- o  s  J' ?void draw()
# Z: y! \, y* x/ a{
% t+ _* T1 c" ?& A        if(stop == true)
0 m8 ^% _/ M+ H3 R9 |3 p        {- N9 g& y8 q2 e  D$ u
                return;
, Q. x# i  x# _, x( |) `        }
2 `) k$ ?9 S- J  e' X3 p4 [    system("cls");/*清除屏幕*/% B, J1 R3 {9 f- j3 ?( Q4 ?  a' s
    printf("分数:%d",score);& `( {+ }- Y7 y$ w8 r
    printf("\n");2 T, c9 S8 ~  J
   
4 C  g! t( O! T) |- |- {        /*第一行*/. J& W! r+ B9 U8 W; R8 l
    int i;
% E6 z# L3 ~7 y6 V% w    for(i= 0 ;i<width+1;i++), q; ]; ~. {; Q! N8 w3 w* U
        {
  b5 y$ h. |: w  v4 n" D# e        printf("-");3 c5 ?- z( S' x& t/ |" F
    }
8 Z8 M4 I0 X3 \# Z8 y* Q, ?    printf("\n");1 m/ A# X& L8 l: x- s9 {: I
    & I8 |, i3 y* J
    /*画中间的画面*/
2 N' s! @, H! `0 ^    int p;
+ s! l9 r: _: b, R% V    for(p= 0 ;p<height;p++)/*高度*/6 \, \4 i" G, A* d' V( q
        {
0 G, w9 h) a  g, ]0 Y        int q;
: [7 r7 j6 z: I6 V3 T8 ^        for(q= 0 ;q<width;q++)/*宽度*/- }' H" k( H6 f9 p0 p) J/ V
                {
0 k; e7 E9 i6 V4 q( t7 [5 {                        /*第一行最后已给字符*// r+ C; |7 H. W/ L2 c
            if(q==0 || q==width-1)
4 G( v# k2 R+ C, x* o                        {$ i* o. r6 \" k: ?! r
                printf("|");
4 M. }+ d1 F# C. q! q3 s            }
5 p6 c5 t6 C: R5 m6 d2 w* ~            % r. U: s3 Q; n  O- g" e& c
                        if(p == fruitY && q == fruitX)/*食物的随机坐标*/
8 r% u$ `' O/ s2 q5 ?                        {9 y% [- X* C. w8 A2 I$ m
                printf("O");) v" o. @8 ]- [/ o
            }
, u! R: ]0 `0 ?$ U# a3 D& K9 N( ~                        else; p) U" L% C/ h0 X
                        {
& x- c5 a; j3 }+ Y- o                    int k=0;
. E# N* I3 t& ?2 y, q: H3 Y7 H' c; p                    bool print = false;
9 |& w; S  h, N+ B                    /*贪吃蛇的长度 默认长度是 3*/7 K4 A; q% \$ I' c
                                        for(k=0;k<ntail;k++)
, `4 g" s( |5 U                                        {6 O. Z: r/ d9 s+ U( f. N' o
                        if(tailX[k]==q && tailY[k]==p)7 M% z4 t8 r/ n. d( Z# D
                                                {
: L& I- _' C3 l4 N3 i                            printf("*");. M6 [  E: p. ^* e( a5 u
                            print = true;
2 j" ]) h2 |# y0 c6 x! R: B& v                        }
. H! w' N" ]& H" v8 f( ?                    }& S4 D0 b2 R+ H4 o8 o
                    /*如果这个位置打印了 * 就不要打印空格了*/( Q) f4 q; q- x+ O
                    if(!print)9 u- d3 M8 l* d
                                        {
8 j9 v5 ~" N" A8 x  z0 {' R, p/ p+ W                                                printf(" ");
4 b) |9 g7 N# y                                        }
4 Y) J9 j; {& D7 [            }
' \6 r  W3 x# u' i( X        }
5 l0 Q* a) i! s9 r        printf("\n");
3 F. A5 c/ O; b6 R, w    }# x& ]' ]* W3 B# _7 j$ B1 t' _% p
: ~  g- ?7 r8 E/ M8 B+ v; |0 D2 z
        /*最后一行*/
: N' ?; C* H! P    int j;
5 Y1 ]& w5 x1 v9 A- ]7 M  h    for(j= 0 ;j<width+1;j++)
) i: D( c& \- l$ ]1 T        {& n( B. q" X6 U
        printf("-");
0 @3 |+ A+ D- d    }: h& i0 j" `0 F3 H# k
( ~0 S4 B% i+ D0 V4 }+ g1 \
}
3 t, g6 {' C& y/*按键输入控制*/& E. b) p9 j1 [5 h& m4 W' l% h
void input()
4 M/ P, t8 U+ H& p; V( {6 Z{6 I& v$ x* ~, r5 ^, V2 w5 P9 U
    if(_kbhit())
# \% b/ @2 h  @/ `- S        {
0 B$ O* @! Q; V                /*获取键盘的输入字符*/; B) I2 s* y% I8 z" {
        switch(_getch())
4 i: O, `& s0 ?& Z' Q/ @" E                {  O$ P: |, \, ?, X( g! Y
            case '4':
% ]; w+ @& s3 Q+ T            case 75:/*左键*/% ]1 q( _  F1 \& V! K: ?7 h
                Dir = LEFT;
' h+ W9 w  [/ r4 s9 g                hit= true;
" P! h) F6 _: T. {                break;; [) |. p/ `+ t% N6 j; U% N
            case '8':/ t- E2 }% s9 L! @- t& ^
            case 72:/*上键*/
# _9 S- r6 d/ p. l                Dir = UP;! I, n( y) W* `9 Q7 R, g
                hit= true;
" A0 s; ]; o& r; W6 a7 J% K: s                break;
' k5 [: l2 B6 l+ K4 r            case '6':7 O1 i! W2 `+ y# j9 ?) L
            case 77:/*右键*/$ M* P+ O3 k1 w
                Dir = RIGHT;6 ~1 E% _' n# [) S
                hit= true;
0 v2 S4 h. c' G0 K                break;3 c7 I1 u7 V- |2 l& u5 y4 \/ V; V2 `
            case '2':' c/ Z4 ?' I5 }. l# U( S* e# {+ D
            case 80:/*向下键盘键 */
% M1 K5 N5 R* H                Dir = DOWN;
6 [/ Q0 X- \6 H0 l$ o  _7 ?                hit= true;$ k& i* Y  b0 Z
                break;/ r; V6 V0 E4 r8 a' g) R: P. t
            case 'x':
' u' l$ J) `) i: f            case 27:/*ESE*/1 t: e, ^- k+ A
                gameOver = true;' w3 z6 ?9 r/ X
                break;0 {, U  x8 Y+ M( }" l- k5 `
            case 32:/*空格 暂停键*/$ _# r' Z: R9 f) t1 V, n
                                stop = !stop;
% o. V. w! ^6 S: [# v( z0 h% J! X                                break;
! ]8 a7 P. [  X6 f' V9 |        }
- h( n4 H4 B! C: E    }( Q! e* A0 b4 L% b  c: o
        else if(!hit && stop == false)/*如果没有改变方向*/
( v' e1 A4 j1 {' X/ Z( V: g5 y7 |1 l& N        {
( r2 V+ C+ ^. D3 j        x++;
7 N4 e  t" a6 Z  l/ c    }
$ w4 m" a! c% B9 a+ v: b}
$ \5 y* q7 B, {9 _! X3 ~6 {/*判断贪吃蛇的长度*/
- f3 J1 b0 X) X4 f- ovoid logic()
7 T" M$ ?# B9 J{5 |  e- p) Q* m/ [6 ^: _
        if(stop == true)4 |3 l" J6 R. Q8 n8 j2 A
        {
* J5 G! l+ K3 L5 d/ D4 E; P                return;, Z- j0 I3 f1 g9 `" ^* V
        }1 Y! G+ W. E7 a1 o# R! N
        
6 c3 J# ]' o& L- t: }0 {) A        /*把上一个位置记下*/4 _8 e, z3 f& o5 ^$ l
    int lastX = tailX[0];7 N" g6 H5 k0 u+ ?; G" R) v
    int lastY = tailY[0];
) z8 m) T) E9 {7 r    int last2X, last2Y;7 F/ h3 \# m5 I/ K" f: ]' N" L1 L
    /*重新获取当前的位置*/
' x* g! N+ ~+ c% J) g3 p& W        tailX[0]=x;- e3 s& [: Q: A) W. B: Z
    tailY[0]=y;& c3 z% R5 j$ s3 s! w6 x
    int i=0;
0 w) t9 _  y( Q" k. p6 w! O( B    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
3 U/ x9 E' [$ [% J7 Y    for(i=1; i<ntail;i++)
5 S/ j+ w: m2 N/ Y1 \4 [- i! {        {! h1 L% d4 V- K/ X: Z: v! Y
        last2X = tailX;
! Q: q# p: T* F- L        last2Y = tailY;' b% A/ X1 ~- f6 I) ^7 l, H
        tailX=lastX;& q. \4 P; e- i& g: d
        tailY=lastY;
* j, [5 b* w; n& l        lastX = last2X;
$ p5 s% Q' ~3 k( R6 ?        lastY = last2Y;
6 M/ P% s4 ]$ t) c# @, t    }
3 z& M, w2 v. `6 q    /*根据方向来改变x y 的值*/2 F* G4 m- Y) C( H7 H
    switch(Dir)
  G" x( @' `, o& X% `        {6 b! v4 Z2 Z, ~+ _4 a2 Q8 W
        case UP:/ D9 m' d; O1 p% F
            y--;6 y- V5 {9 T- t: P1 P) V6 z
            break;
( v2 p) R/ @4 v4 |; t        case DOWN:
5 o+ M5 W$ }, ]3 m            y++;1 R! M; u' b" z% X
            break;
: W1 m, K  h$ B& w! h        case LEFT:
( e/ w$ i, z2 q- I' q            x--;
& Y* Y6 q( R4 j/ a, Q            break;9 g* Z- n: y" c: x1 V
        case RIGHT:  N2 a- V1 g7 U4 t1 q9 L$ ?" o
            x++;, C+ P  f0 R2 g
            break;
$ h0 p) @3 X5 i) N    }
, _' f( L  k7 l( O% w    if(x<0 || width<x || y<0 || height<y)6 B# t2 e& `) Q4 i; S
        {7 k, Y9 r6 \; |. {7 V6 S
        gameOver = true;
, H' k+ X! T! m0 p! c: ~* ?        /*清除屏幕*/2 ?- m% Z3 t! l8 @+ I: X, e
        system("cls");3 Z6 Q7 q" L% X4 N- j
        printf("------------------------------------------------------------------\n");
2 J' @, p6 b9 s, l4 y            printf("|                                                                |\n");/ H3 I# D! ^5 `  W1 G8 G; c6 |
            printf("|                                                                |\n");
. Q) v2 ^" N; T6 J2 f, z( l* U* c            printf("|                             游戏结束                           |\n");
) y) n1 t% D' {. L            printf("|                                                                |\n");
+ J, V' ]! o' T            printf("|                                                                |\n");. g5 P  ?; u- `6 D  j% A" B* o6 O1 |$ A
            printf("------------------------------------------------------------------\n");
# h" C. }" V0 d* _/ }    }
% K- x5 Y" N8 A- T% d! T) }/ h    if(x==fruitX && y==fruitY); u" C0 P& e/ a( l2 i# N0 |
        {2 y0 j: Q' f6 m, }' Z0 W' V/ |$ c
                /*吃了一个食物,蛇的长度增加1*/8 Y% I  \& T: ~
        ntail++;
  G' H$ w+ E4 k5 E, P        score+=10;
. m3 M: E- W- u& U) ^        /*更新下一个食物的位置*// R( t9 ]- ?7 N" n3 d
        fruitX = rand()%width;
/ Y& P" G- o) O, h        fruitY = rand()%height;9 Z$ v3 H) o: w: A) j; T, B
    }
* r+ o7 j/ w8 j, Y; J}( Y% h% Y) Y! Q5 b* H2 m5 c0 l5 b1 }  w
int main()5 w4 [  M2 W) w9 t' V
{
7 S* D% T: w  Z#if 0& e! \9 t& S- v9 v! M0 B
        while(1)8 b) }3 v7 P) _! ~6 T
        {+ k8 p, ^' f/ {! ~
                printf("%d\n",_getch());' K1 N; H5 A; C, F, y
        }
$ N( |3 k: g' T, V) X#endif
4 K0 B6 g/ Z$ a8 A3 n7 b    menu();3 r: ^/ }2 U/ F
    setup();! r: t# H+ f9 V& c
    draw();
: P0 D2 q1 D( }- g+ u: U+ H    /*循环画贪吃蛇的界面*/
3 ?6 D6 ]% {' Y0 N* Y5 ^% C        while(!gameOver)
+ Y1 k- z$ {, O9 ?: g9 e, M( \        {- p8 e2 p" [9 y( }6 v- u
        draw();. i7 e( N8 J0 t# X
        input();
, C4 ]# I6 V1 |$ F* i        logic();- N9 k4 m( g) d- L, u9 S: t" K5 M7 G
        Sleep(70);1 k. l- P4 E* v, W5 S# _
    }
( x: y4 k% W0 k% o' n) J0 A0 z8 z2 K4 H/ l& e, e4 F
    return 0;
; P7 ?, S. Q5 Q- P  f$ e/ s}
: z9 K# g4 \: v9 b5 }

上面这段代码直接在Dev C++上面应该是可以运行的,很多人在知乎上私信问我,为什么我的贪吃蛇执行不了呢,可能就是平台不同,少了这个头文件,少了那个头文件,但是你为什么不能跟我一样,用Dev C++呢,轻量级,简单。代码的精髓是什么?我认为精髓一定是思想,不是你写了多少行代码,用了什么高端的IDE。

微信图片_20200501214937.png

我自认为我的注释已经写得不错了,所以就没有什么好说明的了吧,有不明白的把代码过一下,至于屏幕刷新这个东西,如果只是用时间刷新就会闪屏,所以出现了一个双缓存,把要显示的东西送到一个buff里面去,另一个buff用来显示,这样就可以保证不会出现闪屏。除了写贪吃蛇,可以用这个方法写其他小程序,挺有意思的。

在知乎上,发起了一个C语言 100 行代码之内实现贪吃蛇的问题。我觉得很不错,里面很多同学的回复都非常赞,特别是叶大神的回复。

http://www.zhihu.com/question/360814879/answer/1013986215

( Y- ]4 ]5 x- l' ^# f
赞 收藏 2 评论1 发布时间:2020-5-1 21:52

举报

1个回答
李康1202 回答时间:2020-5-3 09:21:10
谢谢分享!

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版