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

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

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

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

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

    menu();
6 A0 _, f0 I% b7 J1 h    setup();
1 V% {4 Q. h1 @1 O4 U* k4 p    draw();

4 L* ?, o# \( ]8 C4 z) h

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

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

typedef enum' i7 G+ a3 d0 b8 i! n9 d, V$ Z4 e
{
5 V5 a& v- }0 s# b        STOP = 0,
! o( }* n/ |/ v        LEFT,! f# V: y6 D( X; _$ z) d* k9 M7 c
        RIGHT,
0 Q5 Q! a7 h. j  \2 d/ J% m        UP,$ K3 ~# U: x* u- m+ R1 ^
        DOWN. P6 H# ~8 ~. p4 N& s5 h
}Direction;

0 |/ @) s1 m4 k; M1 y6 o, S* a' b

还有

/*判断贪吃蛇的长度*/0 b, c8 }1 q5 A5 Z  d1 U4 k
void logic()

+ E1 C/ V- _; a/ q6 ?

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

来看这里面的关键代码

/*把上一个位置记下*/8 r2 @8 i3 K$ m! J$ `( Z9 ?
    int lastX = tailX[0];% J, o0 E2 T& Z0 D1 |7 D
    int lastY = tailY[0];! C+ i) _7 w4 E0 R8 @" ]4 G
    int last2X, last2Y;
" X! @" ]# q' {* O* Z% `, F    /*重新获取当前的位置*/8 ]9 |: p; f6 n# I- o  b
    tailX[0]=x;6 r6 n5 L3 v0 D- l8 U
    tailY[0]=y;( W0 _5 _: X' U6 ?, A
    int i=0;6 _6 S) ?7 g9 }; Z6 D& e
    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/% P6 I9 b; W% Y7 d
    for(i=1; i<ntail;i++)
" Z" S! h8 ~& x' K7 K    {' R7 g; u$ y% t; _/ y
        last2X = tailX;
7 u" x9 A6 @5 `3 O# k& k! E& ^% T        last2Y = tailY;9 y. E7 `$ {- c( C5 u
        tailX=lastX;( f6 W' V0 K/ U* u
        tailY=lastY;# B& [) L4 h8 p9 V! W
        lastX = last2X;6 v5 h' s7 H3 p: \
        lastY = last2Y;
3 g; n* u0 P: K+ v: |+ A4 Y    }
, X' z# Z% T' W3 p) D( x% c# O

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

完整代码

* g7 n( n1 h8 F+ Z+ y
#include <stdio.h>
% i: X# {7 @/ O' q2 P' M3 _/ L#include <stdlib.h>3 X2 x  [4 U  Z2 O, {. {
#include <stdbool.h>
; e, Y& d& B3 P) \; Q, M9 Q#include <Windows.h>
% V% m; e6 m* N! j0 c" m2 U#include <time.h>/ a: Z% B. I! [; M- C2 T
#include <conio.h> /*键盘输入获取*/2 m$ K, \: v- F
0 a  \; O* i) u$ C) F4 r% n
bool gameOver;( n6 v: C8 f+ t
bool stop = false;3 O7 H9 W4 R& V1 o, g
bool hit = false;
; }+ L* |5 g9 M& d- O/*游戏的边框大小*/8 _1 b9 ?7 W; L! j, U( n- E
const int width = 50;$ m6 @; t* d. W8 n0 y/ }
const int height = 20;
5 p' O# b# Y6 P2 i8 W0 Z: u/*蛇的坐标,食物的坐标还有分数*/
$ n8 e/ V: u: ^# x5 {& Dint x,y,fruitX,fruitY,score;
( M2 @7 d6 M9 a5 i/*蛇每个点的坐标*/
5 w5 H0 p& q9 U$ _% R% G+ V. jint tailX[200],tailY[200];/ f4 w) b6 t6 g+ N! O$ Q8 C
/*蛇的默认长度*/
) I4 C& g  }' a! Q3 A8 E/ Hint ntail=3;
; {7 X4 Z) `  Q9 l0 `- e6 p# D- H: t7 E. z
typedef enum
3 O9 y) o% o1 n; z. x  I{, K0 \7 X; I5 x. ?
        STOP = 0,
- h' k3 Y- ?+ f        LEFT,
# y' I$ p8 `  R2 v$ Q/ S# u; g% n        RIGHT,- w6 u; r& t  |6 D  f
        UP,8 T; Z& B# [" i  o+ H) x  I
        DOWN, c; \+ J$ N$ y. \6 B
}Direction;& J$ Y) c1 C, p; s

/ Y* N: d6 Q% f6 NDirection Dir;
  \$ G2 k" I1 z/*开始菜单*// X0 v7 {* I/ |
void menu()2 O, q; E9 `8 n7 J6 K) j
{
& m' g( W& v. }& m; h8 E) v    int a;" H& U% L6 V' G) e, y' y7 V
    printf("------------------------------------------------------------------\n");
  A3 r3 \8 T7 {! U% K+ R- \% `# ~    printf("|                              贪吃蛇游戏                        |\n");
" j; V. L0 m" p+ Q) M  e0 B    printf("|                              1) 新游戏                         |\n");6 f+ |! r9 ~% S$ m5 Y; x6 h
    printf("|                              2) 开始边界                       |\n");9 a/ u  W1 T" B- q$ ~
    printf("|                              3) 退出游戏                       |\n");" B7 H; `9 z/ I* u$ |
    printf("------------------------------------------------------------------\n");
) U) [( C* u" S( K; ]6 W    printf("---->请输入你的选择:");
  t* N: L0 @6 X! T; C    scanf("%d", &a);
) b! g6 _; G! h% o% u) W}
6 g$ ]: b9 x9 J% V, f3 g: v7 P0 G8 ~
0 K0 ]) A% n8 X; n# ?/*初始化状态*/0 K: a' l0 M2 l2 d
void setup()
8 Y: v6 E* l9 I; g/ F{/ U6 R1 _) j$ b6 ~0 l
    gameOver = false;. A! S) m- f- c3 a$ ^, g0 L
    /*根据当前时间设置“随机数种子”*/, }2 V, Y( E% `, S+ r
    srand(time(NULL));. R1 d6 ]  U( b5 j/ r, R
    Dir = STOP;
1 U1 S( d7 g* j4 U) w% E6 t   
4 M2 m; \/ w4 L    /*贪吃蛇的位置,固定在中间*/' x2 c5 \5 b2 q
    x= width/2;0 t7 |3 S/ @  z- |" a
    y= height/2;: z7 y5 U! |) T# d4 O" g+ p* s# e4 v
    /*食物的位置,位置是随机的*/
6 T) a3 D$ a; i8 Z( f    fruitX = rand()%width;
  c. O5 Z) c* R+ P. Y  f; W( ^6 k    fruitY = rand()%height;
" \# M* D, Q" o5 `# l7 U    score = 0;
; F7 l8 ]0 m1 q% v3 B- h}
6 q% V/ S' P( ^% f/*绘制界面*/
2 |' d- h* S+ N! [5 ?: Gvoid draw()! e* j. w" a2 {. A3 I
{
5 X' k4 ~  o/ J3 e' p; H5 [        if(stop == true)+ l* |3 n: i' A9 s
        {) d) g  ]. b" \% u% y5 u/ P4 P
                return;! W0 A# M% s% A7 L6 o# k. X  z
        }1 Z/ s% x1 y/ ~' F/ I
    system("cls");/*清除屏幕*/
) g. s( N; P5 T. k' i$ m    printf("分数:%d",score);
9 M, ~! I5 P0 O- r" m4 b* Y  ?    printf("\n");
7 y2 a* P2 z: ]" Z% u# n  X5 `2 |2 f! I, ~   
7 o3 [/ H$ H  f- y2 `        /*第一行*/  C/ L& C; n6 ~, ]6 ?* R$ t
    int i;
3 y( j) Y9 Y# y+ t/ {$ ~7 H5 C    for(i= 0 ;i<width+1;i++)
4 ^8 h8 F/ R- i* F# n6 O# l5 k$ r        {
$ B$ n# g6 O) y% ~: a        printf("-");
( N6 w  E1 g$ X    }
! u; |9 l: A! s4 {" z& c+ K- m    printf("\n");$ \4 V! K0 x, S9 g9 d) _
    , G1 H! W: P/ r8 t, a* U8 _* V
    /*画中间的画面*/& }9 H9 W# P* e5 M
    int p;( s: p$ g( J' L3 w% j
    for(p= 0 ;p<height;p++)/*高度*/
8 l+ m1 P( q. P# B, w) }* e4 `        {: C5 c1 C  ]- Z: V, d! S
        int q;
; c# S: Y3 K+ |% B% ]1 Z' i        for(q= 0 ;q<width;q++)/*宽度*/- j) f: ~8 ]+ m
                {
4 _% c6 |% b$ Y" c7 _                        /*第一行最后已给字符*/' O9 p% v6 C3 {4 Y
            if(q==0 || q==width-1)
/ h" ^8 ^* G& C* {2 a5 m                        {
, W% {+ L# T. ^3 @4 y: d" ^) I                printf("|");
* r' F1 g5 |$ f            }
4 V9 D  n; ?1 a8 p8 b, ^            
) w4 Z7 d3 Z& ?  U+ z                        if(p == fruitY && q == fruitX)/*食物的随机坐标*/, E+ I. ?8 ^5 }1 p5 i! F
                        {! c+ Y/ [. m6 n  s% l5 }
                printf("O");
4 k5 N# m. e9 H1 ]8 p            }8 g' \9 s* V& F
                        else) n1 U/ m9 M$ y! `
                        {
. d1 g& U# u5 X; g                    int k=0;+ Z2 C' o; ]4 \& R4 m  Y% ~- y5 K5 u
                    bool print = false;
% v3 N2 ]- h& d1 P& V. ?                    /*贪吃蛇的长度 默认长度是 3*/
9 Q0 q7 K  O2 D( m                                        for(k=0;k<ntail;k++)& `+ G, G1 q$ y" C
                                        {) P! Z" p6 ~7 @; v3 a
                        if(tailX[k]==q && tailY[k]==p)* x) `4 o' ?$ y8 T  t
                                                {
7 \, B" R* c3 }. h9 Z0 ]                            printf("*");% E5 @* o/ h! P; `
                            print = true;
& h; i+ }8 u5 m2 V' y                        }
0 x% S" S# J( i1 T) r2 @                    }
6 w% A& _% S" k& w* h) F. C3 b0 O' Y                    /*如果这个位置打印了 * 就不要打印空格了*/
- b2 }) }4 a- l. e( b. }                    if(!print)( G( {" C$ l9 c+ ^" z. f/ \' j
                                        {
1 G1 w  h) U0 C& c+ _2 w                                                printf(" ");
7 m' \% {9 w7 Y                                        }# U: W6 B0 w) i  X5 }
            }
1 i* {* H( \5 y9 n, o        }
) ^) Z7 G2 `4 [- G7 g2 u& m        printf("\n");
6 m0 p; o2 `* e( E    }
2 k7 t: p* d1 Z! j5 E8 }
4 E* o" M) v/ ]        /*最后一行*/
- Y+ h* f% z0 |0 j# t1 [    int j;; M' ^4 }/ u' R/ n
    for(j= 0 ;j<width+1;j++)# B& {5 f; b$ C* f
        {
7 o  X* _. e8 S        printf("-");
9 Q& C9 [3 v0 p5 x: _. g    }/ ^0 D. n- k8 ^# [

9 _9 v6 h, Q6 ~- @5 j}
  L/ q& I6 Q4 Z7 u! F/*按键输入控制*/
/ h, U. `. q: u3 Yvoid input()
& s6 W" @! ], a# e0 N: n, H{: u" ^0 C4 z$ O/ w4 V
    if(_kbhit())
" W) L+ N1 `: Y( X5 m2 u1 a: m        {3 c) q9 b8 k: y/ Y; C) m9 _. C, _4 e
                /*获取键盘的输入字符*/
$ u/ H* w8 y$ ?- x5 D, W7 W7 B" ]        switch(_getch())
; A: \' J0 X2 O" r$ U                {
1 I3 P" n, D6 a% `5 e- o% E9 L. r8 p            case '4':
/ \' v9 \5 K+ R1 o            case 75:/*左键*/) `# b2 f, ~( |" z) R) e: g" I7 g2 @5 s
                Dir = LEFT;
9 m) k( \, _7 h( F7 D                hit= true;
5 B3 I- G4 D8 b2 w/ f% d* a                break;4 u1 i, x- [# _6 q% a( `4 ~6 w
            case '8':3 D* v7 n/ i8 |3 y  _
            case 72:/*上键*/
( |. T0 t3 i7 r7 R                Dir = UP;
: ], I$ J" v* h7 h9 h                hit= true;( ^# W( U% n9 x1 s1 V3 H
                break;
0 }1 n( M* G/ Q3 l; X            case '6':& O2 i, h8 y* s1 \
            case 77:/*右键*/
$ `+ |$ `8 k/ q5 X+ _; m                Dir = RIGHT;9 g3 B. q) C5 l0 z8 X
                hit= true;! B# @) d( U+ V+ p
                break;
: Q* C% E% \7 B2 b6 v            case '2':: g$ W2 Q; j) F7 X
            case 80:/*向下键盘键 */
+ [9 f- a/ G- d: I2 _4 K+ Y                Dir = DOWN;
$ L5 a) L% |* d7 Q; h0 A                hit= true;' e7 _1 o: J5 @  s, W; u- i2 S
                break;
1 L" Q, B) j; W9 N3 D& z            case 'x':, y/ t6 Q2 {: H
            case 27:/*ESE*/
/ ^5 U' A1 G; C5 Z( f                gameOver = true;
$ u3 N, i# j5 D2 H                break;
, K/ _; q  k5 N) C0 p; M7 y. z# c            case 32:/*空格 暂停键*/3 S, D8 R4 s: D' b$ _8 @* O9 V
                                stop = !stop;: T* W  _" O5 f& z% A9 }
                                break;
' Z9 m, V5 U* m4 r! O/ o* Y- _        }4 P- S( H# D+ D& q! @
    }" q; W; B! d9 m
        else if(!hit && stop == false)/*如果没有改变方向*/6 I; k7 ]3 Z, u6 b" d1 x5 E3 d
        {
, W8 p# @9 d/ m, ^, m" i- b. `3 Q        x++;- v7 G  k& n4 b9 ~9 m  y; w
    }
% _9 e, ?) D  X- p+ F: t+ W}
% ^0 i& Z. V1 o) C( f+ L! o/*判断贪吃蛇的长度*/
+ I% f0 D" X% y4 `- ]0 N) L6 P' kvoid logic()
  A- v: }; g& I{
" _0 c% G) G& {; {+ d        if(stop == true)
  Y- U0 }8 U) D4 p0 v+ E. M- Q' u! ^        {2 [5 V8 n, c9 h( W2 O4 q
                return;
3 \  {1 K: j1 J! z* v; k' U; }9 F        }
" I$ s. o! `2 n1 y+ r- A& _        1 ~- ?0 q) s! @5 T/ I) {
        /*把上一个位置记下*/
0 R' \3 q& i( C6 b& w    int lastX = tailX[0];
4 c! ^7 W, U; D) J% h8 o: [) R$ f    int lastY = tailY[0];6 z* m) l7 L& j9 u% D3 @9 ^
    int last2X, last2Y;
( H8 _' Q1 B, T3 X( {' D# P# j1 }    /*重新获取当前的位置*/4 X  }! x- a) g3 Y5 Y7 y+ d
        tailX[0]=x;
' W* O* X; Q4 P- u: C    tailY[0]=y;# B) X8 O9 H- y3 a% r. j' `) ?
    int i=0;
1 n" @& E, C' d' c) j    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
, y* n8 W* Q8 `7 k: J    for(i=1; i<ntail;i++)" ^/ ~( T: S. D% ~" O# l! p
        {
1 M: c4 N1 D# O0 K        last2X = tailX;' y; J% U3 Q2 i/ e' L; M1 X
        last2Y = tailY;* A4 H' n. k! W) o
        tailX=lastX;
0 w: E0 K! ^3 H6 c' O4 D2 Q" d        tailY=lastY;
% E& Q8 q6 }% K0 L5 C: x* Y        lastX = last2X;
2 p, \6 d/ L. a% K        lastY = last2Y;6 R7 W5 Q1 u6 J* E
    }8 Z: |1 R+ h' t; |# B; n
    /*根据方向来改变x y 的值*/
5 K! J, o+ ]; K5 ?4 p    switch(Dir)3 x! c" C% a, [
        {
% f& R8 I9 }" N3 E        case UP:
2 T* _' j2 u0 Q" A; T3 J            y--;
) C% V$ S, i0 B) I2 Y# n            break;
. r0 ~) R. N- H) |$ N* C        case DOWN:
5 N9 r' {4 k1 ~4 V7 c/ x! O& o# P            y++;  |! e# R6 l; Z$ G: W7 C0 {
            break;
" l9 m; E! Q; }/ [" b. z        case LEFT:" K! u5 _( B" }0 Q
            x--;
# D3 H1 d: s/ s( T. u; c$ w            break;0 }* h" t+ S1 ]* o$ V: k
        case RIGHT:( \, K+ [2 @. C
            x++;
4 r* [6 k8 w& @) H            break;, ?. v4 N) F" m5 H8 ~
    }
0 w8 Y" H  u0 h' H$ C8 [8 W: }$ R    if(x<0 || width<x || y<0 || height<y)& }4 K; r4 ^/ d  U
        {  y! b$ W+ P2 y8 R# c( _+ ]- P
        gameOver = true;" p. {; A0 ^2 b1 ]3 D) j3 M' ^
        /*清除屏幕*/. b& h9 r: }4 y% h' S0 Q
        system("cls");- j! o4 D* X5 X$ g
        printf("------------------------------------------------------------------\n");6 ]# p' E! M1 K8 i; c
            printf("|                                                                |\n");  J7 U& @4 g3 S: _
            printf("|                                                                |\n");% C( O4 }, g9 `: b% x- H+ z
            printf("|                             游戏结束                           |\n");
2 B8 ~1 m" {7 L+ F2 R2 |            printf("|                                                                |\n");; S4 g& ]- b4 h( Q  Q
            printf("|                                                                |\n");
# Q, P5 U+ c" ^            printf("------------------------------------------------------------------\n");6 o8 y: I8 F) X. K3 E% R! k$ s8 u
    }
& \8 A4 c1 s: @& X    if(x==fruitX && y==fruitY)
2 f& P2 P1 d+ H7 ?; ]$ l7 `        {# T$ o) a  p% _7 H" ~6 ?! @
                /*吃了一个食物,蛇的长度增加1*/4 f/ k) z' L" b
        ntail++;. z+ s6 u% g* [% `1 k) h0 h
        score+=10;; Z, o0 R  a- {+ }
        /*更新下一个食物的位置*/* V+ s2 x; x4 I, w4 a$ k) k  ^
        fruitX = rand()%width;& }  R3 `+ h1 C0 ]3 q
        fruitY = rand()%height;7 l5 ^( R: d5 T9 ]3 n
    }
8 }/ a& I( X* z9 \. B}
3 x+ R6 @7 z' ]7 K/ W) E' ]int main()
6 B( J3 t) L% Q( f5 b7 R{
9 w" I; D- C4 x1 {3 U. ]# A#if 0
1 a- {; v# }# [9 G0 q$ X3 u! C        while(1)2 v2 ?, ^" k- r7 }* v8 A9 K
        {
2 N' e5 I7 T$ l% G1 w/ g4 ~5 y  M; ~* j                printf("%d\n",_getch());
7 z! Y$ [& p& o: C2 _        }
9 x7 W& a2 f4 K7 E% M#endif3 V4 v% o& Z7 c' ?2 a3 W
    menu();
" H3 f9 T, [1 u( J; q* \    setup();# O5 I% a' ^2 E
    draw();
" p1 `) F* _+ }% x6 H    /*循环画贪吃蛇的界面*/
* I7 B6 h. |0 p, I        while(!gameOver)
, k9 Q; ?8 M: g. B        {/ S1 Z. ], ]' p. |/ z' l- W5 Q- X4 e
        draw();% h$ o( @0 ]$ k
        input();+ c& D. m! V$ k+ ]: a  V6 u
        logic();, e5 }( r7 d  O0 l1 S( u3 @- ?9 {
        Sleep(70);" i3 h6 J0 a* M5 [6 d# A
    }3 c0 e9 w' K( u8 y2 M
  g) U$ g7 @4 l8 T3 _
    return 0;6 I0 |/ g/ W/ [
}
+ s6 g2 `. w# G; a* b4 d

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

微信图片_20200501214937.png

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

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

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

9 V/ K/ @3 _' Q
赞 收藏 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 手机版