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

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

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

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

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

    menu();2 c- `/ L# [4 E3 Q; C2 n
    setup();
7 q+ V% H7 r+ H5 y( A1 |; h    draw();
: `* n# z/ W9 K; l

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

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

typedef enum
# B9 n; v# R2 ~{
. y) S/ c0 i3 L9 k& {  k        STOP = 0,
8 B+ x/ b9 f( _% w( h# n        LEFT,
; o2 I4 o. J7 B4 t3 N* y        RIGHT,
. J% M/ O/ N6 C( O        UP,
, G  q* |. M& T! }) n        DOWN
% z  d# l$ n, {& _/ T8 x}Direction;

& Q5 N7 k! q  i# H8 }

还有

/*判断贪吃蛇的长度*/
& G( q. z/ }  p% z* V2 Wvoid logic()
- u  v) l1 C- o) V" d

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

来看这里面的关键代码

/*把上一个位置记下*/
5 v- x( v9 Q- \2 f& U, E    int lastX = tailX[0];$ Q; f( L4 g# R1 V1 i8 }$ @5 v
    int lastY = tailY[0];* A* X4 d& @: a* p! _( }& |. h+ ~. ?, _. M
    int last2X, last2Y;
# @9 b% B5 B  K3 x; c    /*重新获取当前的位置*/
8 T* N' G) w" F. K( R    tailX[0]=x;
3 R. {6 c7 L4 Y' P    tailY[0]=y;5 J$ p( y/ w& m' y( y6 t
    int i=0;
$ Y6 n' P! c9 P& D7 U    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/) W  z, _7 v$ G
    for(i=1; i<ntail;i++)
/ t) I/ K  y- [7 \    {
& {- \7 t" m8 d* r        last2X = tailX;
8 p1 q5 w2 s0 L3 }        last2Y = tailY;  e8 U0 c' Q( s) `, ]/ o! G* b
        tailX=lastX;
0 P$ @1 _& u4 ?9 e        tailY=lastY;& X: Z5 ?8 c" @* n' t8 {7 R
        lastX = last2X;
4 n6 A" @. ?; D5 q' q        lastY = last2Y;
* e9 V0 P: r, h  m3 n    }

1 q, l1 o& K) G. \# Y  H

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

完整代码


# z$ b4 q" N; r* i' d#include <stdio.h>
* k2 y$ ?% G  I( ^. l/ p#include <stdlib.h>
/ Q, r3 t; }5 [0 ]#include <stdbool.h># f- w8 |# O8 t3 v2 R$ R
#include <Windows.h>
* G& o- F; W  R#include <time.h>
* [3 }4 M: C% h#include <conio.h> /*键盘输入获取*/
$ \' f4 A, ^6 x; J  ]& W3 y; @3 `5 h2 u3 w7 e
bool gameOver;' n9 @& E( b+ \2 ~7 v: g
bool stop = false;% P- J1 }4 w9 _: E& q1 B
bool hit = false;
2 i; l  _! k5 i. J! A$ G/*游戏的边框大小*/; N( [$ |. K3 D/ h3 d2 {
const int width = 50;
1 u, \/ l2 Z, A$ c7 w) N5 [const int height = 20;
: T( a* o8 T& B* i% H" H8 J/*蛇的坐标,食物的坐标还有分数*/
6 l: S6 F# v- x$ {4 W! h' x; Cint x,y,fruitX,fruitY,score;3 M2 @6 U' v6 x. y- w
/*蛇每个点的坐标*// |* @7 k* b4 C2 s! Y/ E
int tailX[200],tailY[200];
. ]+ |* |6 i4 }+ e6 N1 L/*蛇的默认长度*/
- O2 T. F5 J; B. Zint ntail=3;
' w  R- a' t9 m, e: L- k$ V) ~4 R0 m; Z+ Z' {
typedef enum! b( d) g, k& f, B2 b# k2 P
{$ J' L! L4 o, X, a
        STOP = 0,  f, h, e8 O# D, F# k
        LEFT,' E5 `: I+ c# D* @3 d( x; W
        RIGHT,$ }. q$ K9 X3 c8 a' u
        UP,2 O4 U' O9 O$ [. R) B1 p, S6 q5 O
        DOWN+ o( }" {. S4 C9 y' c8 u; T
}Direction;
! C) p+ |- J" b& ^3 @0 }9 F, Z! @9 M! F) l) i; P. z$ B" C
Direction Dir;
# h% Z/ U2 O8 v7 i& @/*开始菜单*/
9 u2 v& B, S8 G% |! y7 V" [void menu()
4 V2 P/ G8 K6 y7 ?{
( l2 }0 ~' b! u# u. e% ^    int a;
# x5 A; ]8 M& I: m( k+ M! t. H    printf("------------------------------------------------------------------\n");
& G" U) P4 B, B9 ~    printf("|                              贪吃蛇游戏                        |\n");3 y* B6 `% ]: y; `+ v! s9 t
    printf("|                              1) 新游戏                         |\n");
9 `8 Y- r  W+ D! Y  Q$ [1 A    printf("|                              2) 开始边界                       |\n");; J2 O0 q  T! p5 d; q, [9 O( `  ]
    printf("|                              3) 退出游戏                       |\n");8 F. i( A- d. R( z6 P# i
    printf("------------------------------------------------------------------\n");
$ w# l; k0 Y, o" b4 h    printf("---->请输入你的选择:");
+ T% G7 W& o7 S1 G2 o( o    scanf("%d", &a);4 {5 Z5 I, c' z" h/ ^
}$ y$ S1 G/ t8 ?8 K  T" z# \

6 t+ N+ ~* F2 q: h/*初始化状态*/
2 K; E' C& d! s$ R1 ?void setup()
) R1 z8 I: ^) o, C# `, R+ e* r. A{
; z, c; N- b" l2 F: P' b    gameOver = false;
, A. f" f( I; V0 n; T5 ]* i    /*根据当前时间设置“随机数种子”*/
, v* h. n, y) i! y4 n8 ~    srand(time(NULL));
5 X' t9 ]3 t" Q    Dir = STOP;8 [& e2 J% ^8 h' S% B: W0 G# }
   
- O' N& b! k* j" O: r    /*贪吃蛇的位置,固定在中间*/
, S: H2 q, @: I3 `0 U" m    x= width/2;, K; {: r3 ?) a1 M
    y= height/2;
( b- Y7 Z, j3 D  v( x9 p    /*食物的位置,位置是随机的*/& h8 J4 D0 U+ N7 }/ J( d" Z
    fruitX = rand()%width;: e1 e* k) ?4 k5 c) q1 d
    fruitY = rand()%height;- G3 o6 W+ e* e6 Y+ b" ^
    score = 0;# L4 r' K2 T- a" [* {
}4 Z3 K! h5 d9 n/ Q6 A: R6 F! K
/*绘制界面*/
: B- ^  I/ U0 {: a( X7 ^) F: i. Jvoid draw()
- J) y2 u6 G9 Z" s" k! r{
8 y* H8 K, E6 P0 [6 |8 v1 Y& s        if(stop == true)
% ^  W+ T* {2 V        {. s' T1 l8 w; M( w: [
                return;& P+ Q% t- S1 i- a
        }, m+ e8 p; A* E/ n% x; l
    system("cls");/*清除屏幕*/( P% U! S) `. a0 `9 }5 v& T
    printf("分数:%d",score);/ U0 V6 X; ?/ l; q9 d2 U4 x2 w% P
    printf("\n");
: J6 L* ^0 K  I% B   
. ^1 g' K# |+ a% O$ Z4 y        /*第一行*/
4 }" B/ n8 r7 B% F# B: ]6 a' s    int i;4 b4 l6 ^" Z% m- A1 w1 U8 L
    for(i= 0 ;i<width+1;i++)6 ?% X1 C4 L7 W; t& q
        {
- O: T- _6 b9 Z$ b" V9 @/ h% H        printf("-");
  I5 k1 }8 }& p! E+ ]    }2 e8 u8 l' x; o
    printf("\n");
: w+ T6 O8 v8 m+ ^  O3 D1 w    2 W# E1 A/ b: d) A. v1 L
    /*画中间的画面*/7 O" B0 Y! V  ]: \( z6 \- z0 V/ S
    int p;
2 ]* ]) B- y9 G- Q9 r  @    for(p= 0 ;p<height;p++)/*高度*/! K# C1 G# k+ }) w8 N+ ^
        {
$ f% e3 G( R, U; q: L        int q;
/ A8 w- Z% V. {9 N+ q        for(q= 0 ;q<width;q++)/*宽度*/
" ~2 J% }1 `" t7 v                {, R* k; d! q; C1 U
                        /*第一行最后已给字符*/: g' `9 O; n+ i' O# t
            if(q==0 || q==width-1)
& x! d) p: t8 D3 j                        {
) C( G+ ~6 {( G3 h: b6 w" a( l                printf("|");- N% v3 @/ z# v  s3 q
            }
6 y) L, \4 o9 k. r            ) z  i* }1 c7 L+ c9 N) O# H
                        if(p == fruitY && q == fruitX)/*食物的随机坐标*/& G: v& R- |$ \) W. O2 M
                        {
9 k6 |5 p( G9 m- o* c- p  @& L& y                printf("O");! |5 I$ m& P7 ]! L" U! ?- [* I! F; Y% a
            }
; [# C+ H. L, ?/ ?                        else( S' ?3 V. e6 M# n. a0 X
                        {7 E, a3 ^6 F, v: G8 K
                    int k=0;2 V$ a. g% i( }+ o
                    bool print = false;
( V; ?; v3 t" G' ~) x7 C9 r                    /*贪吃蛇的长度 默认长度是 3*/
  F8 f/ `% J6 h. w0 C+ |2 G' s2 X                                        for(k=0;k<ntail;k++)" T1 H# P2 z5 x8 Y
                                        {; D/ O* ]( {- q5 a5 u* N
                        if(tailX[k]==q && tailY[k]==p)2 B  x" g( H( X+ C: m6 P; P) A
                                                {6 a# u8 s/ i& N* K( n. Y
                            printf("*");9 }  K, n+ |: S1 d+ y
                            print = true;
4 ^2 G4 j9 G/ u2 o7 H                        }5 ^6 ^+ H& d9 S7 M+ a( M4 w# W4 k
                    }
7 B8 O! X3 G1 q$ P" Z% S- y                    /*如果这个位置打印了 * 就不要打印空格了*/
( ?! s- J& M1 ^7 X" Q5 G# R                    if(!print). e( \" @; x  n4 T
                                        {- t; c/ m# ?& F) I* T$ l" S  Z. M
                                                printf(" ");
7 f3 `7 S' J" v7 W  ]' z" a                                        }* T+ G6 |% x4 T6 f5 f
            }
8 z( B5 o/ B9 s, y6 J4 O# z- n        }: ]. A, }  Y9 Y
        printf("\n");
# g7 v9 |5 |" l5 _; ~    }( z& g1 Q* ^) n2 h& p1 k7 ^
8 O* S% V3 a6 B, C/ B" N5 m
        /*最后一行*/
+ i# ~5 R6 I3 [1 t  L: y    int j;/ t2 H  T8 M7 S$ {1 `/ v& @$ E
    for(j= 0 ;j<width+1;j++)
! w; w7 X4 w+ `9 e8 M; y! ~: t& ^5 Z        {' u4 X; l/ G) o* e6 b9 a2 R
        printf("-");
# W" ]& k$ c% T5 H2 d% M3 g& u    }
6 E9 F3 A, ^1 ^* d
- G/ A0 u! {8 g' \0 j}
3 w/ s5 P, u' x5 @/*按键输入控制*/
. a9 }/ k/ R+ s2 K- dvoid input()
$ x6 W. N2 w% _* o0 y1 P8 y{* i4 a4 s* L  d
    if(_kbhit())# i0 A0 a0 w4 g/ x2 _/ e
        {
, {, N  j7 E1 q9 S; Z: A                /*获取键盘的输入字符*/$ R) P, L9 K, A1 I5 v5 O
        switch(_getch())$ c9 s2 W* u# V+ z$ ^% W4 K0 ]
                {  j' X3 D, ~, n- g# f
            case '4':
0 v8 c  a5 t( t2 P- \            case 75:/*左键*/& Q# w* B( q+ |
                Dir = LEFT;- L, C  z! C- J2 B* F* J! u' X
                hit= true;
- Y4 r, B; c) Z) \4 O3 w                break;5 P1 N; w- ^/ V! x1 ?4 J9 k+ E" i* A
            case '8':
$ T2 C' ~2 H& Z+ u$ b- f            case 72:/*上键*/$ T' c4 F- j# x* X; j  S
                Dir = UP;4 w& F( v- L/ `+ d% T- g7 D
                hit= true;
  Q  m1 r2 A, K! ]                break;, s$ p1 K! A/ o# d% o- U
            case '6':5 m: O* i  I+ T3 x' ?0 o6 @9 T
            case 77:/*右键*/
+ Q' H7 ?5 B, \8 }, g0 f. ^                Dir = RIGHT;* u, m! T1 H+ F9 u0 @
                hit= true;
( o( r8 S# h- n6 {* [# z                break;9 p7 i" q2 m+ q: N: p6 Q4 a' L5 M0 r
            case '2':3 I0 ?- T! X2 T# y$ c) @) K
            case 80:/*向下键盘键 */8 z& }* s1 R" ^6 y7 [) \7 Q
                Dir = DOWN;+ J3 x/ S3 N* s8 `1 N
                hit= true;  Z( b. k0 f5 v% y  V3 U  n
                break;
0 Q0 ^' n6 Q* H            case 'x':
& O7 m% k- e2 N! G            case 27:/*ESE*/8 l! F, E; C* V0 q
                gameOver = true;
( {0 W  c8 y$ h                break;
, \: s9 n2 S) w+ R; K            case 32:/*空格 暂停键*/
4 P3 W! ?& k6 l7 n                                stop = !stop;
: q" D, ~" l5 E! L. J                                break;* I9 N+ X: s1 P# E3 f
        }( \' d% k; D( [5 B+ Q2 h
    }
  Z; W( d+ B5 Z5 U        else if(!hit && stop == false)/*如果没有改变方向*/
; S. X2 r- t* m7 x+ o/ t        {. j3 A- @1 w6 V  p, h8 Z
        x++;" q* u3 }& p' X" Y; m! O6 @/ t
    }
' E7 ?) t3 h4 Q7 x8 G; b}
+ f8 e- W4 L3 q1 W+ X7 Q/*判断贪吃蛇的长度*/) j: X$ [, T& ^" F* P: i3 ~1 u
void logic()
3 E& B: s- E( O' D{
6 }0 a5 V/ S. N9 E+ W        if(stop == true)
( L! T6 @' m' D1 F! q8 Q        {* H/ v5 y6 d1 E) ]" Q
                return;
9 |4 }8 [+ n3 H! V% \. S: m" t        }$ G- y3 A9 O  b  [+ U% q
        6 K1 h) x6 ?2 M, M$ L+ ~1 Q' O
        /*把上一个位置记下*/1 ?, s' m# `* r
    int lastX = tailX[0];$ z3 }# ~: K. j4 T! Q, Z
    int lastY = tailY[0];
" ^5 V2 ^* k, o    int last2X, last2Y;
9 m; p6 b( s6 d  i" H. k/ W; i    /*重新获取当前的位置*/
+ ?  m4 l+ w' a3 I        tailX[0]=x;& O( j" Y4 B& q
    tailY[0]=y;- ~; f( Q5 b) N; V
    int i=0;/ z9 G2 s& F) ~8 u; U( C
    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
8 T& J/ F: X* `% {- K    for(i=1; i<ntail;i++)
2 B; w: G6 U( }3 f! R0 ~; O, ~        {
1 X, f6 [4 I& M2 b* y& q: F( p7 w        last2X = tailX;
+ z% R* N* a$ z' A3 g        last2Y = tailY;
1 h, s/ V( n/ T+ l8 |        tailX=lastX;- Q1 ?/ _# z2 [( i4 I
        tailY=lastY;; R+ c# t% N+ q
        lastX = last2X;! p6 J3 I2 H2 L0 z+ K" n; h2 n+ ?
        lastY = last2Y;. |9 V9 }) h  H! @9 l
    }
2 A, i  K  h% Z, O' }! M    /*根据方向来改变x y 的值*/- D! S/ p% M; S# b8 u7 d" V  @
    switch(Dir)
1 B2 Z3 v, L2 c& \5 \* m! T0 w        {
- f, d7 v  r8 U$ X! H        case UP:1 r  e  o+ E  s
            y--;
" [% a# R0 y" D$ l: N, T' S            break;
, ?5 F  l3 Y" K5 y        case DOWN:
5 Z8 R  ~( q# p# R  d3 d8 `            y++;
3 \+ ]) o# e' I" ?3 c            break;; E2 |( s8 ^- V5 i0 U
        case LEFT:& @9 D3 o0 ~/ G8 X/ Z2 q* s% a+ {
            x--;
: S4 F* J, W4 Z            break;
+ N/ N% W+ N6 U$ P        case RIGHT:
4 w0 y3 ]# C  @8 z  x            x++;9 S! g& l* ~1 G$ q8 X) V: Q
            break;1 u9 ?9 G* D3 d- z
    }
* F, ~2 W/ j; @3 m5 j    if(x<0 || width<x || y<0 || height<y)9 j( B! ^% G6 l
        {* J/ M1 i1 f7 C
        gameOver = true;
1 q9 \6 ]( Z0 a# r7 M        /*清除屏幕*/
3 _/ I$ g( _- t+ m- K+ H1 J        system("cls");' G1 G6 n- |; V* k
        printf("------------------------------------------------------------------\n");
+ m% [" X3 J' V' c6 q. @            printf("|                                                                |\n");
- O+ X) O- _# ?: y6 m4 L            printf("|                                                                |\n");
% s( T/ V- ~' k, W; ]            printf("|                             游戏结束                           |\n");
5 p  l5 O: H( Q$ ]            printf("|                                                                |\n");
  \% M! I/ p$ k. l& _# g            printf("|                                                                |\n");# A' R$ Y$ I! l1 L% ^
            printf("------------------------------------------------------------------\n");
1 A; d) j0 z( E4 V3 y    }
  W# l/ ^/ C$ f; e    if(x==fruitX && y==fruitY)5 d2 X+ F+ m. a+ O8 N& B
        {8 ~6 b& d6 s: F% L0 x8 {) T! f5 x& H
                /*吃了一个食物,蛇的长度增加1*/
: c0 m# V+ X; o        ntail++;
) O' o/ Z# [7 _        score+=10;0 Y" R/ n7 K4 q) y- n2 {
        /*更新下一个食物的位置*/
% }+ f9 T) @- z) l7 N! v$ s        fruitX = rand()%width;
! L( a" P! F$ i0 {1 f        fruitY = rand()%height;
1 z" T' s: w- q1 j" s    }$ S( [8 V7 p5 |7 l7 h8 M
}  K+ V4 E  `, p
int main()
( N8 e7 u; X" l# ~{
& z" L( l) }0 V  p  E#if 0
$ I+ y8 d# |2 ?, Q, |        while(1)
; r# {, a+ _) [- ]" k        {5 P  d" w) o: E+ R
                printf("%d\n",_getch());
$ M( R7 E; N$ q6 `+ O        }! U4 ?+ d4 G; a+ J# V
#endif
  @5 {% w% d. W    menu();
8 n6 i: P) n9 a+ [+ K    setup();7 u: h% N, T2 z& r% _" Y* Y
    draw();- C% l4 j; w/ c, g, z
    /*循环画贪吃蛇的界面*/
5 Q8 _  n4 y- S1 F/ g        while(!gameOver)& s' s5 y$ \  U" Z1 V
        {/ J  g4 B5 _$ c% v9 }
        draw();
* a/ h! P* d& ^, G        input();
% [& y& T. Q0 `( Y3 w" ?        logic();
$ R6 J  d- Y- m        Sleep(70);% S6 |) j7 l  H5 F3 A9 o
    }
5 j- n( I0 D+ v
0 _  h3 E0 J, o9 j: p7 C* ]    return 0;% z) w8 Q$ T. |1 S5 Y! R9 A3 a
}
- F! a! K9 _; ?

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

微信图片_20200501214937.png

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

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

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

/ A- S: W5 ^1 n! j& j% v# M
赞 收藏 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 手机版