首页 > 其他分享 >基于EasyX和Raylib的贪吃蛇

基于EasyX和Raylib的贪吃蛇

时间:2023-01-25 20:22:24浏览次数:49  
标签:blocks oldHead Raylib int EasyX newHead 贪吃蛇 BLOCK SIZE

基于 EasyX

// 根据《C和C++游戏趣味编程》第七章 贪吃蛇 写出

#include <graphics.h>
#include <conio.h> // _kbhit()
#include <stdio.h>
#include <stdlib.h>

// 全局变量定义
#define HEIGHT 30       // 高度上一共30个小格子
#define WIDTH 40        // 宽度上一共40个小格子
#define BLOCK_SIZE 20    // 每个小格子的长宽大小

int blocks[HEIGHT][WIDTH] = { 0 }; // 记录所有的游戏数据
char moveDirection = 'd'; // move to right
bool fail = false; // 是否游戏失败
bool shouldExit = false;
int food_i;
int food_j;

// 初始化函数
void startup()
{
    blocks[HEIGHT / 2][WIDTH / 2] = 1; // 画面中间画蛇头,数字为1
    // 向左依次4个蛇身,数值依次为2, 3, 4, 5
    for (int i = 1; i <= 4; i++)
    {
        blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
    }

    food_i = rand() % (HEIGHT - 5) + 2;
    food_j = rand() % (WIDTH - 5) + 2;

    initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE, SHOWCONSOLE);
    SetWindowText(GetHWnd(), "Greedy Snake");
    setlinecolor(RGB(200, 200, 200));
    BeginBatchDraw();
}

void moveSnake()
{
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (blocks[i][j] > 0) // 蛇身
            {
                blocks[i][j]++;
            }
        }
    }

    int oldTail_i;
    int oldTail_j;
    int oldHead_i;
    int oldHead_j;
    int max = 0;
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (max < blocks[i][j])
            {
                max = blocks[i][j];
                oldTail_i = i;
                oldTail_j = j;
            }

            if (blocks[i][j] == 2) // 原来的蛇头
            {
                oldHead_i = i;
                oldHead_j = j;
            }
        }
    }

    int newHead_i = oldHead_i;
    int newHead_j = oldHead_j;
    
    if (moveDirection == 'w') // up
    {
        newHead_i = oldHead_i - 1;
    }
    if (moveDirection == 'd') // right
    {
        newHead_j = oldHead_j + 1;
    }
    if (moveDirection == 'a') // left
    {
        newHead_j = oldHead_j - 1;
    }
    if (moveDirection == 's') // down
    {
        newHead_i = oldHead_i + 1;
    }

    // 撞墙、撞到自身, 都算失败
    if ((newHead_j >= WIDTH || newHead_j < 0 || newHead_i >= HEIGHT || newHead_i < 0)
        || (blocks[newHead_i][newHead_j] > 0)
    )
    {
        fail = true;
        return;
    }

    blocks[newHead_i][newHead_j] = 1; // 生成新蛇头
    if (newHead_i == food_i && newHead_j == food_j) // 蛇头吃到食物
    {
        // 重新生成食物
        food_i = rand() % (HEIGHT - 5) + 2;
        food_j = rand() % (WIDTH - 5) + 2;
    }
    else
    {
        blocks[oldTail_i][oldTail_j] = 0; // 没吃到食物时,旧蛇尾变成空白,蛇长度不变
    }
}

// 绘制函数
void show()
{
    cleardevice();

    // 绘制每个方格
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (blocks[i][j] > 0) // 大于0表示是蛇,这里让蛇的身体颜色色调渐变
            {
                setfillcolor(HSVtoRGB(blocks[i][j] * 10, 0.9, 1));
            }
            else // 元素为0表示为空,颜色为灰色
            {
                setfillcolor(RGB(150, 150, 150));
            }

            // 在对应位置处,以对应颜色绘制小方格
            fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j+1) * BLOCK_SIZE, (i+1) * BLOCK_SIZE);
        }
    }

    // 绘制食物
    setfillcolor(RGB(0, 255, 0));
    fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);
    
    if (fail)
    {
        setbkmode(TRANSPARENT); // 文字字体透明
        settextcolor(RGB(255, 0, 0)); // 文字颜色
        settextstyle(80, 0, _T("Consolas")); // 文字颜色、大小、样式

        outtextxy(240, 220, _T("Game Over"));
    }

    FlushBatchDraw();
}

// 与输入无关的更新
void updateWithoutInput()
{
    if (fail)
    {
        return;
    }

    static int waitIndex = 1; // 用于替代原有的用Sleep()来控制帧率的做法。
    waitIndex++;

    // 小蛇每隔10帧移动一次。
    if (waitIndex == 10)
    {
        moveSnake();
        waitIndex = 1;
    }
}

// 和输入有关的更新
void updateWithInput()
{
    if (kbhit())
    {
        char input = getch();

        if (!fail)
        {
            if (input == 'a' || input == 's' || input == 'd' || input == 'w')
            {
                moveDirection = input;
            }
        }
        if (input == 'q')
        {
            shouldExit = true;
        }
    }
}

int main()
{
    startup();
    while (!shouldExit)
    {
        show();
        updateWithInput();
        updateWithoutInput();
    }

    closegraph();

    return 0;
}

基于 Raylib

// 根据《C和C++游戏趣味编程》第七章 贪吃蛇 写出

#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include "raylib_helper.hpp"

// 全局变量定义
#define HEIGHT 30       // 高度上一共30个小格子
#define WIDTH 40        // 宽度上一共40个小格子
#define BLOCK_SIZE 20    // 每个小格子的长宽大小

int blocks[HEIGHT][WIDTH] = { 0 }; // 记录所有的游戏数据
char moveDirection = 'd'; // move to right
bool fail = 0; // 是否游戏失败
int food_i;
int food_j;

// 初始化函数
void startup()
{
    blocks[HEIGHT / 2][WIDTH / 2] = 1; // 画面中间画蛇头,数字为1
    // 向左依次4个蛇身,数值依次为2, 3, 4, 5
    for (int i = 1; i <= 4; i++)
    {
        blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
    }

    food_i = rand() % (HEIGHT - 5) + 2;
    food_j = rand() % (WIDTH - 5) + 2;

    InitWindow(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE, "greedy snake");
    SetTargetFPS(60);
}

void show()
{
    BeginDrawing();
    {
        ClearBackground(BLACK);

        // 绘制每个方格
        for (int i = 0; i < HEIGHT; i++)
        {
            for (int j = 0; j < WIDTH; j++)
            {
                if (blocks[i][j] > 0)  // 大于0表示是蛇,这里让蛇的身体颜色色调渐变
                {
                    Color fill_color = ColorFromHSV(blocks[i][j] * 10, 0.9, 1);
                    DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, fill_color);                    
                }
                else // 元素为0表示为空,颜色为灰色
                {
                    DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, make_color(150, 150, 150, 255));
                }
                // easyx 的 fillrectangle() 会自动绘制边框颜色, raylib 绘制矩形(内部填充)时则并不会绘制边框颜色。
                DrawRectangleLines(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, make_color(200, 200, 200, 255));
            }
        }

        // 绘制食物
        DrawRectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, GREEN);

        if (fail)
        {
            DrawText("Game Over", 240, 200, 80, RED);
        }
    }
    EndDrawing();
}

void moveSnake()
{
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (blocks[i][j] > 0) // 蛇身
            {
                blocks[i][j]++;
            }
        }
    }

    int oldTail_i;
    int oldTail_j;
    int oldHead_i;
    int oldHead_j;
    int max = 0;
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (max < blocks[i][j])
            {
                max = blocks[i][j];
                oldTail_i = i;
                oldTail_j = j;
            }

            if (blocks[i][j] == 2) // 原来的蛇头
            {
                oldHead_i = i;
                oldHead_j = j;
            }
        }
    }

    int newHead_i = oldHead_i;
    int newHead_j = oldHead_j;
    
    if (moveDirection == 'w') // up
    {
        newHead_i = oldHead_i - 1;
    }
    if (moveDirection == 'd') // right
    {
        newHead_j = oldHead_j + 1;
    }
    if (moveDirection == 'a') // left
    {
        newHead_j = oldHead_j - 1;
    }
    if (moveDirection == 's') // down
    {
        newHead_i = oldHead_i + 1;
    }

    // 撞墙、撞到自身, 都算失败
    if ((newHead_j >= WIDTH || newHead_j < 0 || newHead_i >= HEIGHT || newHead_i < 0)
        || (blocks[newHead_i][newHead_j] > 0)
    )
    {
        fail = true;
        return;
    }

    blocks[newHead_i][newHead_j] = 1; // 生成新蛇头
    if (newHead_i == food_i && newHead_j == food_j) // 蛇头吃到食物
    {
        // 重新生成食物
        food_i = rand() % (HEIGHT - 5) + 2;
        food_j = rand() % (WIDTH - 5) + 2;
    }
    else
    {
        blocks[oldTail_i][oldTail_j] = 0; // 没吃到食物时,旧蛇尾变成空白,蛇长度不变
    }
}

void updateWithoutInput()
{
    if (fail)
    {
        return;
    }

    static int waitIndex = 1;
    waitIndex++;

    if (waitIndex == 10)
    {
        moveSnake();
        waitIndex = 1;
    }
}

// 相比于 easyx, 除了asdw键, 还可以使用方向键
void updateWithInput()
{
    if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))
        moveDirection = 'a';
    else if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))
        moveDirection = 's';
    else if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))
        moveDirection = 'd';
    else if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))
        moveDirection = 'w';
}

int main()
{
    startup();

    while (!WindowShouldClose())
    {
        show();
        updateWithInput();
        updateWithoutInput();
    }

    CloseWindow();
}

标签:blocks,oldHead,Raylib,int,EasyX,newHead,贪吃蛇,BLOCK,SIZE
From: https://www.cnblogs.com/zjutzz/p/17067236.html

相关文章

  • ts17贪吃蛇项目_1
    使用ts写一个贪吃蛇的项目第一步:配置webpack和tsconfig,这里可以使用之前配置过的第二步:在之前配置好的webpack中加入css打包时的配置模块运行npmi-Dlessless-load......
  • EasyX——概要
    EasyX之绘图(配置与显示图片)EasyX之鼠标   ......
  • 8KB的C#贪吃蛇游戏热点答疑和.NET7版本
    在之前的一篇文章《看我是如何用C#编写一个小于8KB的贪吃蛇游戏》中,介绍了在.NETCore3.0的环境下如何将贪吃蛇游戏降低到8KB。不过也有很多小伙伴提出了一些疑问和看法,主......
  • 贪吃蛇
    像下图这样的蛇如何拐弯?绿点是新蛇头,红点是旧蛇尾。搜了下,有用JavaScript写的,有用Python写的,好像都是把蛇身用一系列的点来表示。这样比我原先想的用若干根线段表示简单......
  • C++利用easyX实现一个简单图形化窗口
    在实现这个图形化窗口过程中遇到了一些琐碎的问题,不过还是解决了首先easyX下载地址https://easyx.cn/download下载之后安装到VS上或者自己想使用的软件上就行1#incl......
  • 看我是如何用C#编写一个小于8KB的贪吃蛇游戏的
    译者注:这是MichalStrehovský大佬的一篇文章,他目前在微软.NETRuntime团队工作,主要是负责.NETNativeAOT功能的开发。我在前几天看到这篇文章,非常喜欢,虽然它的内容稍微有......
  • 前端使用canvas实现贪吃蛇小游戏
    贪吃蛇是一款益智小游戏,通过点击上下左右四个按键控制蛇头移动。设计思路主要是设计蛇的身体和移动方法。将蛇的身体设置成一个数组,数组里存放蛇身每一节的xy坐标。游......
  • EasyX入门笔记
    基于EasyX的C++图形化界面实现什么是EasyX?EasyX是针对C++的图形库,可以帮助C/C++初学者快速上手图形和游戏编程。比如,可以基于EasyX图形库很快的用几何图形画一......
  • EasyX绘制多边形
    引言:在Easyx中,专门给了一个函数绘制多边形——polygon函数一、打印较简单的多边形像长方形、正方形、三角形、梯形这些多边形较容易打印,因为他们的顶点坐标较容易求出。比如......
  • C语言贪吃蛇大作战
    C语言贪吃蛇大作战贪吃蛇大作战1997年,诺基亚公司发布了贪吃蛇游戏,并将其内置于诺基亚6110手机中,使这款游戏迅速风靡全球,成为一代经典。一般的观点认为,贪吃蛇是手机游......