Connect Four四子棋c++程序 - 用户交互(1)

article/2025/7/10 21:30:35

文章目录

  • 回顾
  • 用户交互

回顾

上一个博客里我们只是简单地显示了一个窗口,这次我们把主要的游戏逻辑给它加进去。这一部分里我们要做的任务有:

  1. 控制帧率:即每秒渲染多少帧;
  2. 用户交互:处理用户的鼠标点击事件;
  3. 完成相关棋子的渲染。

完整代码已经放上github了,在这里
在这里插入图片描述

用户交互

先把整段代码放出来

// connect_four_1.h
#ifndef CONNECT_FOUR_1_H
#define CONNECT_FOUR_1_H#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>
#include <cstdio>
#include <vector>
#include <string>
using namespace std;SDL_Window *gWindow = nullptr;
SDL_Renderer *gRenderer = nullptr;
constexpr int GRID_SIZE = 50;
constexpr int SPACE = 0;
constexpr int RED_PLAYER = 1;
constexpr int BLACK_PLAYER = 2;class ConnectFour {
public:ConnectFour() = default;ConnectFour(int nbWGrids, int nbHGrids) :_nbWGrids(nbWGrids),_nbHGrids(nbHGrids),_nbGrids(nbWGrids * nbHGrids),_contents(nbWGrids * nbHGrids, SPACE){_winHeight = GRID_SIZE * nbHGrids;_winWidth = GRID_SIZE * nbWGrids;}void start() {pre_run();run();}
private:int _nbHGrids = 0;int _nbWGrids = 0;int _nbGrids = 0;int _winHeight = 0;int _winWidth = 0;bool _running = false;int _player = RED_PLAYER;int _mousePos = -1;int _lastPos = -1;vector<int> _contents;SDL_Texture *_grayCircle = nullptr;SDL_Texture *_redCircle = nullptr;SDL_Texture *_blackCircle = nullptr;SDL_Surface *_icon = nullptr;void pre_run() {gWindow = SDL_CreateWindow("Connect Four", SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED, _winWidth, _winHeight, SDL_WINDOW_SHOWN);gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);_grayCircle = loadFromFile("images\\gray.png");_redCircle = loadFromFile("images\\red.png");_blackCircle = loadFromFile("images\\blue.png");_icon = IMG_Load("images\\icon.png");SDL_SetWindowIcon(gWindow, _icon);}SDL_Texture *loadFromFile(string path) {SDL_Texture *texture = nullptr;SDL_Surface *surface = IMG_Load(path.c_str());if (surface) {texture = SDL_CreateTextureFromSurface(gRenderer, surface);SDL_FreeSurface(surface);}else {printf("Failed to load `%s`! IMG Error: %s\n", path.c_str(), IMG_GetError());}return texture;}void run() {_running = true;Uint32 tic, elapsed;while (_running) {tic = SDL_GetTicks();handleEvent();clearScreen();renderScreen();SDL_RenderPresent(gRenderer);elapsed = SDL_GetTicks() - tic;if (elapsed < 30)SDL_Delay(30 - elapsed);}}void handleEvent() {SDL_Event e;while (SDL_PollEvent(&e) != 0) {if (e.type == SDL_QUIT)_running = false;handleMouseEvent(e);}}void handleMouseEvent(SDL_Event &e) {_mousePos = -1;if (e.type == SDL_MOUSEMOTION || e.type == SDL_MOUSEBUTTONUP) {int x, y;SDL_GetMouseState(&x, &y);if (x < 0 || y < 0 || x >= _winWidth || y >= _winHeight)return;int gx = x / GRID_SIZE, gy = y / GRID_SIZE;_mousePos = gx + gy * _nbWGrids;if (e.type == SDL_MOUSEBUTTONUP) {if (_contents[_mousePos] == SPACE) {_contents[_mousePos] = _player;_lastPos = _mousePos;switchPlayer();}}}}void switchPlayer() {_player = _player == BLACK_PLAYER ? RED_PLAYER : BLACK_PLAYER;}void clearScreen() {SDL_SetRenderDrawColor(gRenderer, 0xff, 0xff, 0xff, 0xff);SDL_RenderClear(gRenderer);}void renderScreen() {renderPieces();renderPiecePreview();}void renderPieces() {for (int i = 0; i < _nbGrids; i++) {int gx = i % _nbWGrids, gy = i / _nbWGrids;SDL_Rect rect = { gx * GRID_SIZE, gy * GRID_SIZE, GRID_SIZE, GRID_SIZE };if (_contents[i] == SPACE) {SDL_RenderCopy(gRenderer, _grayCircle, nullptr, &rect);}else {SDL_Texture *target = _contents[i] == BLACK_PLAYER ? _blackCircle : _redCircle;SDL_RenderCopy(gRenderer, target, nullptr, &rect);}}}void renderPiecePreview() {if (_mousePos != -1 && _contents[_mousePos] == SPACE) {SDL_Texture *target = _player == BLACK_PLAYER ? _blackCircle : _redCircle;int gx = _mousePos % _nbWGrids, gy = _mousePos / _nbWGrids;SDL_Rect rect = { gx * GRID_SIZE, gy * GRID_SIZE, GRID_SIZE, GRID_SIZE };SDL_SetRenderDrawColor(gRenderer, 0xff, 0xff, 0xff, 0xff);SDL_RenderFillRect(gRenderer, &rect);int s = 5;rect = { gx * GRID_SIZE + s, gy * GRID_SIZE + s, GRID_SIZE - 2 * s, GRID_SIZE - 2 * s };SDL_RenderCopy(gRenderer, target, nullptr, &rect);}}
};

我们首先需要一个SDL_Renderer,就是用来把图片画到窗口的东西。同样我们用一个全局变量来保存它。另外,四子棋每个棋子位置都有三种状态:空的(SPACE)、红棋(RED_PLAYER)和黑棋(BLACK_PLAYER),这里分别对应3个常量。

我们还需要一个变量来保存整个棋局的状态。虽然棋局是一个二维的矩阵,但我们也可以把它表示成为一维的数组,到时候再把相应的x和y计算出来就好了,这里我们采用一维数组的方式,用成员_contents来保存。

分别介绍一下新引入的成员变量:

bool _running = false;       // 是否继续执行游戏的主循环
int _player = RED_PLAYER;    // 记录当前下棋的玩家是哪一方,红方或者黑方int _mousePos = -1;          // 记录当前鼠标在哪一个格子里
int _lastPos = -1;           // 记录上一次玩家落子的格子位置
vector<int> _contents;       // 记录整个棋局的状况,哪些是黑的,哪些是红的,哪些是空白的SDL_Texture *_grayCircle = nullptr;      // 存储空白棋子的图片
SDL_Texture *_redCircle = nullptr;       // 存储红旗的图片
SDL_Texture *_blackCircle = nullptr;     // 存储黑骑的图片
SDL_Surface *_icon = nullptr;            // 存储这个游戏程序的图标图片,一般显示在窗口左上角

pre_run()函数里,我们先把需要的renderer以及图片都加载进来(加载图片的辅助函数loadFromFile自己看上面的代码了):

void pre_run() {gWindow = SDL_CreateWindow("Connect Four", SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED, _winWidth, _winHeight, SDL_WINDOW_SHOWN);gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);_grayCircle = loadFromFile("images\\gray.png");_redCircle = loadFromFile("images\\red.png");_blackCircle = loadFromFile("images\\blue.png");_icon = IMG_Load("images\\icon.png");SDL_SetWindowIcon(gWindow, _icon);
}

即如下4张图片
在这里插入图片描述
接着看游戏的主循环:

void run() {_running = true;Uint32 tic, elapsed;while (_running) {tic = SDL_GetTicks();handleEvent();                   // 处理用户交互事件,如鼠标点击clearScreen();                   // 先清屏renderScreen();                  // 然后把棋子之类的画上去SDL_RenderPresent(gRenderer);    // 刷新屏幕elapsed = SDL_GetTicks() - tic;  // 看一下一次循环用时多少if (elapsed < 30)SDL_Delay(30 - elapsed);     // 如果太快了,可以让CPU休息一下}
}

游戏主循环里分别做了如下几件事:

  1. 处理用户交互事件,如鼠标点击;
  2. 清屏,清除上一帧的东西;
  3. 把棋子之类的画上去;
  4. 刷新屏幕;
  5. 决定是否要等待一些时间,一般帧率fps = 30就可以了,这里我们把每次循环都控制在30ms,帧率也就大概在1000 / 30 = 33左右。

处理交互事件

void handleEvent() {SDL_Event e;while (SDL_PollEvent(&e) != 0) {if (e.type == SDL_QUIT)_running = false;handleMouseEvent(e);}
}

主要三种事件:

  1. 用户点击了右上角的退出按钮;
  2. 用户移动了鼠标;
  3. 用户点击了空白棋子的未知。

第一个事件我们独立处理,后面两种统一在鼠标事件中处理handleMouseEvent()。鼠标事件的处理简单说一下:

  1. 获取鼠标事件的位置x和y,只处理棋局范围内的鼠标事件
  2. 计算出鼠标所在的格子;
  3. 如果是点击事件,我们在BUTTONUP的时候还要把棋子放上去,并且切换玩家switchPlayer()

紧接着,我们要把游戏画面渲染出来renderScreen(),也要做两件事情:

  1. renderPieces(): 把棋子画上去,有三种棋子:SPACE、RED_PLAYER和BLACK_PLAYER;
  2. renderPiecePreview: 当鼠标在空白棋子位置时,我们预先显示该玩家的棋子。这个也很简单,因为前面鼠标事件的时候我们记录了当前鼠标所在的格子_mousePos,如果这个格子是空的,我们就把当前玩家的棋子预先显示在这个格子上。为了有一种动画的效果,代码理preview的时候我把棋子缩小了一点。

http://chatgpt.dhexx.cn/article/O0eIRRRW.shtml

相关文章

三子棋游戏(超级详解,附加电脑下棋优化)

目录 前言 一&#xff0c;游戏规则 二&#xff0c;游戏步骤 三&#xff0c;游戏实现 3.1游戏构思和框架 3.2 棋盘的初始化和打印 3.3 玩家和电脑下棋的实现 3.4 判断输赢 3.5 游戏平局 3.6 游戏头文件game.h 四&#xff0c;电脑下棋优化 五&#xff0c;游戏总代码 …

C语言_三子棋游戏

在这篇博客中&#xff0c;我将从头到尾整理三子棋游戏的代码&#xff0c;争取能将这个小游戏里面包含的细节能全整理出来。为什么要整理呢&#xff1f;因为我觉得如果不看任何参考能用C出一个小游戏&#xff0c;是一件蛮厉害的事情&#xff0c;要做到这件事情&#xff0c;需要对…

十年前开发的平板游戏:HyllCube 三维四子棋游戏,获得了全国一等奖

昨天&#xff0c;无意间翻到了本科时候的一个视频。 那是在 2011 年 9 月&#xff0c;那时刚升大三&#xff0c;我&#xff08;打酱油&#xff09;和另外三位童鞋组队参加了第四届 Intel 杯全国大学生软件创新大赛&#xff0c;开发了 HyllCube 三维四子棋游戏。最终&#xff0c…

人机对战初体验:Python基于Pygame实现四子棋游戏

人机对战初体验—四子棋游戏 继去年3月人机大战引发全球瞩目以来&#xff0c;围棋AI&#xff08;人工智能&#xff09;再度引发跨领域的关注&#xff1a;一个叫Master的围棋AI&#xff0c;几天时间&#xff0c;面对中日韩顶尖职业围棋选手&#xff0c;已取得60胜0败的恐怖战绩&…

三子棋小游戏

今天我们来看看三子棋小游戏吧&#xff01; &#xff08;代码量有点多对于我小小白&#xff09; so分为多文件形式 test.c &#xff1a; 测试三子棋游戏&#xff08;调用其他两个&#xff09; main函数 game.h &#xff1a;三子棋游戏的函数声明 game.c &#xff1a;游戏函…

c++三子棋游戏程序

c编写三子棋游戏程序&#xff08;修改宏定义N&#xff0c;可变成四子棋、五子棋、六子棋....)&#xff0c;代码如下&#xff1a; //c小练习——编写三子棋游戏程序 #include<iostream> #include<cstdlib> #include<time.h> using namespace std; #define N …

三子棋游戏思路

今天用C语言来模拟一个三子棋游戏。 总共大概分为五部 1.构建一个菜单出来&#xff0c;让玩家可以选择是否进行游戏。 2.打印棋盘&#xff0c;通过对二维数组的运用&#xff0c;打印一个N*N的棋盘&#xff0c;主要是用空格将棋盘初始化&#xff0c;并将棋盘的框架打出。 3.…

【C语言】三子棋游戏详解

目录 一、三子棋的游戏规则 二、基本流程 三、实现步骤 3.1打印菜单 3.2 创建并初始化棋盘 3.3 打印棋盘 3.4 玩家落子 3.5 电脑落子 3.6 判断输赢 四、游戏演示 五、完整代码 一、三子棋的游戏规则 三子棋也就是经常玩的井字棋&#xff0c;游戏分为双方对战&#xff…

JAVA安卓植物大战僵尸主题四子棋游戏

前言 这里使用安卓最基本的API实现双人四子棋游戏&#xff08;无AI&#xff09;&#xff0c;开发语言为java&#xff0c;开发环境为Android Studio 2.1.2&#xff0c;目标SDK版本为24&#xff0c;最低为15&#xff1b;界面采用植物大战僵尸主题&#xff0c;图片资源来源于网络&…

三子棋游戏

目录 一、三子棋游戏简介 二、三子棋游戏创建文件 三、三子棋游戏设计 1.主菜单的创建 2.棋盘设计 四、三子棋游戏结果 五、代码源 一、三子棋游戏简介 三子棋是黑白棋的一种。三子棋是一种民间传统游戏&#xff0c;又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线…

人机对战初体验—四子棋游戏

一、实验介绍 1.1 实验内容 实验利用Python模拟AI和玩家进行四子棋游戏&#xff0c;利用游戏实验Pygame库&#xff0c;为游戏提供界面和操作支持。AI算法借用蒙特卡洛搜索树思想。通过设置AI的难度系数&#xff0c;即AI所能考虑到的未来棋子的可能走向&#xff0c;从而选择出最…

Pygame——AI重力四子棋

突然奇想&#xff0c;什么时候可以自己实现一个机器对战的小游戏&#xff0c;但一直不敢去尝试&#xff0c;直到偶尔发现了重力四子棋的规则&#xff0c;有限的空间棋盘正好可以拿来练手。 有关下棋AI的算法&#xff0c;说来说去也就那么几种&#xff0c;随机蒙特卡罗方法、UC…

C语言简单游戏编程入门之四子棋

运行截图 源代码 #include<stdio.h> #include<stdlib.h> /*四子棋1.在一个6行7列的棋盘中2.玩家1和玩家2依次交替下子3.每次下子落于棋盘可能达到的最下方4.先四子相连为胜5.棋盘已满且无四子相连为平局 *//*定义常量*/ //行数 #define ROW 7 //列数 #define C…

基于Python实现四子棋游戏

1. 实验介绍 1.1 实验内容 实验利用 Python 模拟 AI 和玩家进行四子棋游戏&#xff0c;利用游戏实验 Pygame 库&#xff0c;为游戏提供界面和操作支持。AI 算法借用蒙特卡洛搜索树思想。通过设置 AI 的难度系数&#xff0c;即 AI 所能考虑到的未来棋子的可能走向&#xff0c;…

运用Python——劳拉下棋_四连环游戏_重力四子棋游戏(代码与游戏判定)

导航 运用Python——爬虫_网易云音乐热评 运用Python——游戏_四子棋_劳拉下棋 文章目录 导航1.游戏规则2.玩法分析3.部分详解第一部分&#xff1a;初始化第二部分&#xff1a;棋盘显示第三部分&#xff1a;玩家输入第四部分&#xff1a;运行第五部分&#xff1a;胜利判断 4.完…

ISME | 热液微生物群落揭示了喷口区的生物地理学和嗜热性的进化历史

Auka热液喷口区的微生物群落揭示了喷口区的生物地理学和嗜热性的进化历史 Microbial community of recently discovered Auka vent field sheds light on vent biogeography and evolutionary history of thermophily Article The ISME Journal, [IF 10.3] DOI&#xff1a;10.…

S32K1xx 固件更新

1 介绍 随着当前技术的进步&#xff0c;车辆变得更加电子化而不是机械化。车辆中的电子创新不断增加。因此&#xff0c;车辆中的软件也在增加&#xff0c;因此存在潜在错误的风险。 每次发现软件错误时&#xff0c;都需要进行召回过程来更新软件。这些召回代表了汽车制造商的…

萤火虫算法综述

1.萤火虫算法概述 萤火虫闪烁的光芒在热带和温带地区的夏季天空中是一道令人惊叹的风景。大约有两千种萤火虫&#xff0c;大多数萤火虫会发出短暂而有节奏的闪光。闪光的模式对于特定物种来说往往是独一无二的。闪光是由生物发光过程产生的&#xff0c;这种信号系统的真正功能仍…

《闪》(霹雳战狗 bolt)电影感悟

when you stuck your head, relax, turn and pull. 有时候做人做事要转换一下方式&#xff0c;否则还是会卡住头。Because all around the planet, there are animals who feel like they cannot, like a little hamster, who once spends his day in the vehicle park dreamin…

大学英语四新视野 课后习题+答案翻译 Unit1~Unit8

Unit 1 Text A: Words in use 2022年6月16日 20:57 1 As the gender barriers crumbled, the number of women working as lawyers, doctors, or bankers began to increase significantly from the mid-20th century. 随着性别障碍的消除&#xff0c;从20世纪中期开始&am…