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

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

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

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

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

    menu();
3 k: |5 C) @" `  x* F5 P. `    setup();7 N9 @3 ]  ?# W; w* G( P
    draw();

( F, f' T% H* k

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

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

typedef enum
9 D  l) ~) v+ M' v+ a/ u{
( d" j+ y" X4 ?, k: a0 s% p6 ]' @        STOP = 0,3 X2 Y& T' ?$ l2 p  [' N( c3 B
        LEFT,
8 t8 [7 Z  h3 _9 h        RIGHT," Y2 M3 q& u, O% o$ f
        UP,( y# n7 S+ D2 ^  E9 ?& A' G
        DOWN
: |8 {8 d* {* U4 S/ M9 L}Direction;

+ I7 L8 G0 r2 Q5 J/ @, U% R

还有

/*判断贪吃蛇的长度*/
" f6 B/ P& B* w( g; R  hvoid logic()
( o4 v3 L) }7 Q* K

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

来看这里面的关键代码

/*把上一个位置记下*/- E$ L* c0 ~* \+ Y" J) Y! J
    int lastX = tailX[0];
% V- a$ b# @& O! |, h$ w8 H    int lastY = tailY[0];
2 ?, Y) a* M0 ], g) M' Z% M) h    int last2X, last2Y;
8 e+ s( h8 m! F1 q# O: `5 w    /*重新获取当前的位置*/3 N7 i. Y7 m. q5 F8 |. R4 b9 o
    tailX[0]=x;' {9 U" ~) a! b* l
    tailY[0]=y;' A+ ?) w5 j, D- |6 o, N# w
    int i=0;
9 |0 B8 F8 k: L5 v1 K/ t6 S: i6 m1 L  |    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/9 R5 B6 p+ M! @/ r/ P4 e  V
    for(i=1; i<ntail;i++)8 p; G, v5 |/ a: N4 H
    {! q' @) w4 W6 e, H( d6 j; \
        last2X = tailX;
. Y+ G1 `' _- {' u) O" e  f        last2Y = tailY;4 g/ }- r7 Z) O
        tailX=lastX;
/ r. {$ D' Y' ^" D: x( N: Q8 P        tailY=lastY;
; x/ g6 K$ F8 S: m4 a        lastX = last2X;" T7 \. e7 V7 M9 P  J
        lastY = last2Y;
$ u' Y/ F+ s& J4 x    }

0 K6 c+ U3 ?' V& _/ J

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

完整代码

- Y: _6 o$ b+ e9 y
#include <stdio.h>
) m% U( i. y  {9 O7 i4 X- e: s#include <stdlib.h>! I( \; {# f& M! K# `5 I
#include <stdbool.h>
# d! S+ I8 D+ K- e6 g+ W#include <Windows.h>
! p) |& p6 r5 r" |; R  H5 w( g#include <time.h>
; O  Y3 S1 R0 D% ]#include <conio.h> /*键盘输入获取*/
# r3 A! U" w( M3 l4 E, B+ m
! t% y7 B, G3 ?$ K+ Z" d! u+ Abool gameOver;! V9 }% T" |% C4 `) Q7 z
bool stop = false;
0 c# v# j& _4 ^7 nbool hit = false;
0 M1 l; p. h7 o0 v% B/*游戏的边框大小*/
- v5 t1 ?7 H( d% J4 C( T7 i5 x7 o) econst int width = 50;
' c4 z  j- p: B  K4 Nconst int height = 20;" D0 y6 P1 ~5 \$ E
/*蛇的坐标,食物的坐标还有分数*/
( J: Y9 [' H" @. P: ^1 l( [int x,y,fruitX,fruitY,score;
9 J! g+ R! {& \8 ~4 x) y8 S/*蛇每个点的坐标*/" _6 u8 G6 F2 ^7 k5 J8 `3 ?
int tailX[200],tailY[200];
7 q3 f  `( {0 L. I) I8 Q$ I. b/*蛇的默认长度*/6 t) x7 e- p5 T/ b9 U
int ntail=3;
. \, Z( X6 N0 _( y/ B
. T0 R/ C# v: v. i2 v' m+ u! ?typedef enum
& J+ v& {' f3 ?) S) d1 G{
* T: J6 N" B6 N        STOP = 0,  m# ~* h& h0 F! K& q" w
        LEFT,
# C( C1 u& r) e7 _! _+ k        RIGHT,
; f0 s. R7 ~/ G: g- }        UP,7 X8 o. G5 A$ n5 `3 _
        DOWN$ Y6 L6 w$ b7 b, @) r3 X. L
}Direction;
; @0 N8 \+ L2 g6 k, ~3 j
7 N# k9 R$ s: V7 f* l7 Z0 G9 W. uDirection Dir;& C+ y  W7 ^! {) h, a! C
/*开始菜单*/
* U) k5 T& X: J6 v4 i; dvoid menu()
; M& h- d0 c* F2 ~- D{2 c( B2 z: g" k0 Y* Y
    int a;
4 D% d* u' B! h    printf("------------------------------------------------------------------\n");
& c7 X( g: d% D$ P8 `" A    printf("|                              贪吃蛇游戏                        |\n");
3 Q, Y$ @+ Y; s3 v+ V2 J: ]    printf("|                              1) 新游戏                         |\n");
0 h9 p( c  D; {4 ]2 V. C( ?2 _9 m    printf("|                              2) 开始边界                       |\n");- x! W$ Z) F% J# C9 y( ?. a" P
    printf("|                              3) 退出游戏                       |\n");3 a- \& S" X4 W  {8 |1 b
    printf("------------------------------------------------------------------\n");
: x0 T" O- ]5 Y# y2 `2 g9 p, J    printf("---->请输入你的选择:");; e/ a  p; `9 R5 k* h( f
    scanf("%d", &a);+ g8 F& c" ]' x, U* V, e: U) d+ S& |
}
  _/ e" f0 y# U6 V* `  @2 O" g5 r) E, `+ I7 T" j$ H* v3 V
/*初始化状态*/
5 H' ^/ p& D! p. hvoid setup()
- V1 z4 z8 r3 }6 Q{
+ c8 m  _  P3 v6 ?$ N    gameOver = false;: A. \# u9 ^% s( ]! l
    /*根据当前时间设置“随机数种子”*/- H+ h1 H4 C2 ~& ^- W( ]( U
    srand(time(NULL));- [( `  b0 |/ x
    Dir = STOP;
5 G) L9 S8 g+ M4 z* q, s) @% Y   
, ^) |) C6 C6 A9 ?8 T7 P2 P    /*贪吃蛇的位置,固定在中间*/$ \  ]8 n- o8 D1 |+ B# X
    x= width/2;1 _7 o# [! ^3 D, {* B* }, _6 K
    y= height/2;
0 a  `; L. [+ l; F/ o7 ~# M1 O    /*食物的位置,位置是随机的*/
4 {. V6 l4 H3 ?    fruitX = rand()%width;1 c) F( R8 s8 g, o
    fruitY = rand()%height;8 C4 e: @0 j% p+ ?8 ]* {( x1 T
    score = 0;' C! F. G: t& r' U8 H- c1 g  G- f
}
* k  g9 ]% l4 J! p6 C  @) u/*绘制界面*/4 g' n. f& B8 X
void draw()5 S% ~6 `/ |' j7 V
{9 u) k& S4 e$ Q* Y$ a8 D
        if(stop == true)
: f& {! q. @* |8 r' }        {
* _  z9 f; ^- ^$ A# x* d                return;- n( _6 L6 `! ]/ m
        }
! r& j9 S" v* g    system("cls");/*清除屏幕*/" E* F* F+ p" D; w$ v
    printf("分数:%d",score);
* y% Q" b4 s) k  I7 `; g. w    printf("\n");- u0 M4 G4 S# |
   
# I2 C1 I+ b4 |& s        /*第一行*/
6 ^! e- M) n3 }8 |& V    int i;
* Z2 z  l  u2 M) h    for(i= 0 ;i<width+1;i++)
% m0 B, b! G0 b, _        {5 w- o1 _7 }; h
        printf("-");
; B9 U! [8 n5 [; E  J    }3 ?" D& k7 S. o1 h4 U0 h* V
    printf("\n");
+ a- V7 e- a, g   
3 G& l. y* }$ T+ T, h3 H  q2 E0 a. `    /*画中间的画面*/
- A) d. W9 m* W+ p. f6 G    int p;& \# B, K' [" U8 ~; k, e" E8 G
    for(p= 0 ;p<height;p++)/*高度*/7 O/ i* |7 D1 ^
        {
4 Z) A# n/ E4 G) E/ x0 ~        int q;
" E* H. t' }0 ~( u8 K$ }        for(q= 0 ;q<width;q++)/*宽度*/
. a: A7 g1 m8 o/ M! f; R                {4 S: N7 e6 a; t; t& @* G. ]
                        /*第一行最后已给字符*/
; t0 l* k9 H- |; F1 ?            if(q==0 || q==width-1), i, G7 d  A: [3 K, m! |
                        {
2 Y" C$ a/ {) p  \6 a                printf("|");
+ Y; Z. v& R0 |& K            }  [) G2 ^4 P) V2 v  I# i. w) U& D
            
7 V3 Q. Y' D: t                        if(p == fruitY && q == fruitX)/*食物的随机坐标*/8 e) z  I# N3 l  j: J1 @# X
                        {
! X: w8 A+ ?0 {5 B, r( L% j                printf("O");. r; ^% @) A& T
            }; F$ `2 h( ~3 d! q
                        else
  j/ V( u( i% g                        {
. {; W1 L9 A$ i( x1 I+ _3 p& D                    int k=0;- s# x) q- }' a7 Q' u, M
                    bool print = false;
" t5 n0 \: a" `6 s0 |" |                    /*贪吃蛇的长度 默认长度是 3*/9 Y& w+ R% r' l; K& Y9 M7 X
                                        for(k=0;k<ntail;k++)
) I: Q; A8 n# R* O, @                                        {( F% R9 r$ u/ J5 z" `
                        if(tailX[k]==q && tailY[k]==p)
1 Y2 }. z6 I0 p- d6 C+ B+ `                                                {; @; O: w: K3 G; h& z5 n4 @
                            printf("*");
+ Z. W. @/ H$ t6 x% \7 V                            print = true;
3 r% b$ ?2 _+ l7 a                        }
# [8 a5 Y/ L; A/ y                    }
& K7 k% X' Y& S& R5 K' G  j. F                    /*如果这个位置打印了 * 就不要打印空格了*/
  D7 m( r0 K2 }; F  i                    if(!print)
( U3 q# c. s& q, E  V4 X) M5 p6 C                                        {
; T( e7 O9 t6 h. x; ]0 s+ F& O                                                printf(" ");: A0 v! ^+ k/ Z- i
                                        }
( J" \8 l5 y- [5 N2 I            }
, s" w# A1 ?. R( f) H- `, N$ W4 b: G        }$ h# v) K& J% D3 ]8 K/ E$ a
        printf("\n");' F/ z9 L* I8 B  I* G
    }
9 H% {8 l* d( b( A% w( D, C6 p2 J5 A+ e, A6 ~9 K+ X9 x
        /*最后一行*/# ?* b4 R$ d2 z* y! H% L2 V
    int j;: [, \" n, N2 g% f, F8 ^
    for(j= 0 ;j<width+1;j++)
  f! s( l. s3 O) m' Y+ ]        {7 k( ?7 y2 |8 j
        printf("-");9 E( f4 N  m4 q! G+ g4 V
    }
- |3 E* O2 U" o$ K! T: t+ u5 w9 w: x6 P8 M* B$ j% n; }
}5 R, L/ Q) q- U7 M. H6 }/ h
/*按键输入控制*/
/ b4 N) ^8 G. ?6 u, D1 y  p0 qvoid input()
  E* Y% {8 [0 }4 F# G* C{( O4 x1 ^" l/ U
    if(_kbhit())5 ]" N" }; l" F, [6 v+ {0 b
        {
1 j8 p$ x* P- F+ e8 e/ Y2 T6 V4 O                /*获取键盘的输入字符*/  z" |' L, i! u
        switch(_getch())1 M! B4 w3 `5 p! }+ x% g
                {* _- N: w3 V1 C7 n# Z% D* R  X
            case '4':
1 f! D9 b6 U4 I4 _) o1 T/ L! n            case 75:/*左键*/2 _9 u/ P$ Y! n* D& i
                Dir = LEFT;+ d0 `9 i8 M' ^. c" ]/ y
                hit= true;
0 ]; a" i8 i6 ~( K' w                break;
; ]- i4 b0 h* i0 v            case '8':
9 e) c7 c! t) m8 X2 u3 D* O' W6 S1 x$ Q            case 72:/*上键*/
9 _" [: n+ O+ A& D2 t                Dir = UP;
% a" n1 V4 n2 X                hit= true;1 L" H( }8 o* l# g* Q( z
                break;
) ]8 H" r9 H: N8 S            case '6':
/ _8 Y; S$ ~$ t/ `" n3 d            case 77:/*右键*/+ ?8 B( |+ q# g/ @
                Dir = RIGHT;5 y* f/ `) ?2 h. t
                hit= true;
# |9 A  p" Z% e. n                break;
7 @# l/ y2 @6 n) `- g! ]            case '2':
3 P# u2 p/ Q' l& i            case 80:/*向下键盘键 */
5 Z4 g: `- i$ q; A9 N# S9 H                Dir = DOWN;( p7 |* u4 B/ @: L. m$ G
                hit= true;
: X# M+ H5 C2 E/ Y0 L                break;
0 \9 p2 ~! M: _" d1 Z$ ]            case 'x':
0 ]+ r, }5 L: C. I( C            case 27:/*ESE*/7 q7 z0 |" w# D; a& d
                gameOver = true;4 `1 r0 T9 o3 N, H- ?
                break;9 C6 i% _+ Y, D7 N
            case 32:/*空格 暂停键*/
& ?3 q; ^) i3 S, S5 _" A6 I3 y2 j                                stop = !stop;
0 @/ b9 @, L* a3 t. V, }                                break;
: G6 s/ v/ I' b  T        }
" H8 x( M- L8 K  x0 f8 `" R# E' R, C+ e    }% Y# }# Q4 c) t) j- n; o$ N
        else if(!hit && stop == false)/*如果没有改变方向*/8 p( d, q$ A* A) C8 S
        {; G0 G. X' }  z, [& b
        x++;+ \& h3 h" G: n2 Y0 C
    }3 E) |% G6 I2 Y
}* W  B" N6 H3 g
/*判断贪吃蛇的长度*/( i1 u: a8 J# b  `/ D* @  Z( M
void logic()) A, r( G+ C- N7 r" u
{7 N- D# e0 D% V" h4 I& n2 S3 {
        if(stop == true)
: @/ a" @: J0 I  [7 }        {
6 U$ p9 v6 p1 n. ?                return;
" t6 P) V' d( v9 V: r9 [        }: y  l6 j0 `$ p% p
        0 Y- o+ P& M1 p6 f
        /*把上一个位置记下*/  }4 j# ?4 t: U, v- T- ]) {+ n
    int lastX = tailX[0];
* N# V* R% L5 [& v$ I: X    int lastY = tailY[0];
2 c% E. _8 V1 `    int last2X, last2Y;
7 H' \! k2 D& Z5 S" U    /*重新获取当前的位置*/
- k* d( E  ]* ^: U, t        tailX[0]=x;
! g" n' a4 g+ W2 u& b5 R    tailY[0]=y;
* g1 \  t  h( u  O    int i=0;
8 L1 C+ t; b, `7 u; P$ ^    /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/* M' [) c/ |. m
    for(i=1; i<ntail;i++)
5 L7 x  ^" N! O* p1 L        {& F2 N& h( j/ d! p  y4 `4 e! v
        last2X = tailX;
- ]0 a1 x6 I5 R" H7 Z4 [        last2Y = tailY;4 }* F2 S( c- ^$ S6 u" D; N
        tailX=lastX;
" f* @9 |8 L7 E# U' D/ |        tailY=lastY;
; M9 p$ P" e  a# [3 q- j        lastX = last2X;
, o, u8 }  t( R" r        lastY = last2Y;
+ _7 f% w6 I' S" c  K    }
* E+ O- e+ X& a& D    /*根据方向来改变x y 的值*/
) K3 i& F7 Q- r3 L4 K( @    switch(Dir)
1 f4 f* x) ?' h' Y: C& F        {
8 {& P- [4 Z. x/ p7 I. p& k# o        case UP:# J) M6 N) `/ w3 f( @4 F7 D+ {6 ^
            y--;
7 n8 w  }3 B1 Y8 I2 ^/ U            break;
- n: k, ?! ?0 k! V: h6 S/ ^        case DOWN:/ B! ^# e8 i) I9 Q3 M
            y++;3 Q2 E% x9 B* W1 v" K! G# O8 j, M
            break;
7 L6 q# D+ i4 z7 K6 ~        case LEFT:
$ {9 a3 v; V  c3 V' k, S! I            x--;
) \! a0 |  c7 U1 Z7 g            break;; U3 @& M+ j0 z- v- K
        case RIGHT:+ A$ O7 M3 d2 ]- l
            x++;
- U9 [  h7 n( z- [            break;
8 H! C6 b3 H1 v9 v) X    }
& V; i7 h2 }7 D  W! F. D    if(x<0 || width<x || y<0 || height<y)
3 ~4 r! @: U8 a/ Z( T/ ~        {4 }  m  \$ t; [2 n7 z: e
        gameOver = true;: M% F  D* j' _6 e+ E
        /*清除屏幕*/& Z0 _  c# m5 d4 b* p
        system("cls");
, Y; p" M. r% p8 L& k        printf("------------------------------------------------------------------\n");6 f. t( R% A0 p5 x8 j0 }
            printf("|                                                                |\n");  m; A" q0 S% c9 \2 I9 U1 N0 F
            printf("|                                                                |\n");
" Q* h8 G1 ^. I6 z            printf("|                             游戏结束                           |\n");
& U* E( p# o% [/ _" p0 B; L; l3 b            printf("|                                                                |\n");
* j9 X: F$ {( A# x7 X            printf("|                                                                |\n");
* p: j( C8 O. n  j            printf("------------------------------------------------------------------\n");
. v( x5 X% {* w" g% y, i    }
  r# I; d) W* ]- g: l    if(x==fruitX && y==fruitY)
; e- f2 ~: e0 b2 ^; W3 z        {: q6 l& A6 t; X5 h9 R. W
                /*吃了一个食物,蛇的长度增加1*/
+ R  L! L. M* f4 I        ntail++;9 b+ p& R2 g  {) u
        score+=10;
" T' J8 c* B4 ?" K5 i* T0 l        /*更新下一个食物的位置*/# j# Y$ s4 ?6 r* T) Q& d
        fruitX = rand()%width;
8 Z; E2 N7 p$ i        fruitY = rand()%height;. r) x' e, H1 B" {8 ^$ }
    }' d1 D( C/ o" g  n6 p5 U
}
. a* l, E, ~# T6 B! v  y# ~7 P3 ^7 Z4 Vint main()
) p) D9 V, ]; y" I# f$ G$ C{& G% e, K9 R; G1 [8 t; f
#if 0; w+ O8 P2 Z' m
        while(1). [1 p- I1 F5 b
        {; V  A0 L" T7 N) Q% B
                printf("%d\n",_getch());! ~4 M6 e# `. i6 y
        }, c" ~" \7 t# }& B
#endif
/ y* S3 C4 M  ~4 Q* L" d: D    menu();
3 a3 |; B- O- y4 z( l! Y3 w: Y2 r    setup();3 O0 n/ Q! R3 |1 W0 _
    draw();
; L; j0 s9 y$ U    /*循环画贪吃蛇的界面*/
! }4 I- U& i2 z$ I7 C5 N9 {2 P% m        while(!gameOver)
0 Z6 S9 v4 U& q8 P; Z) T3 d, Q        {
: Y2 b) y, c3 i9 V" Z* |# S        draw();
. x0 r/ |3 s3 o        input();
& V. ^/ y; s! c3 ?/ x        logic();
1 R* _. \. J: S+ V% l# r' Q* M        Sleep(70);
$ T' n0 j9 w) t    }, f+ @7 C% C0 y6 @
' [* |; h5 l$ r! f) h8 e5 \' [! ]
    return 0;
6 ?- f/ W6 u3 e9 V; E+ ~( L# _}

# M+ A( z# f' {- d  [: M

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

微信图片_20200501214937.png

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

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

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


! a& h' w/ O. z. ?# j
收藏 2 评论1 发布时间:2020-5-1 21:52

举报

1个回答
李康1202 回答时间:2020-5-3 09:21:10
谢谢分享!
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版