无引擎游戏开发(2):最简游戏框架 | EasyX制作井字棋小游戏I
一、EasyX中的坐标系
不同于数理中的坐标系,EasyX中的y轴是竖直向下的

二、渲染缓冲区
之前的程序添加了这三个函数改善了绘图时闪烁的情况:

小球在"画布“上移动的过程就是我们在调用绘图函数,这个”画布“就是渲染缓冲区,先绘制的内容可能被后面绘制的内容覆盖掉,所以调用cleardevice()函数,相当于用当前背景颜色覆盖画布实现”清屏“。小球”闪烁“的原因在于,绘制过程并不是一瞬间,而是”逐渐“发生的,先前绘制的小球被不断清除,而人眼同时观察到”绘制“与”清除“,所以有种”闪烁“的感觉。
而在调用BeginBatchDraw函数后,EasyX会为我们新建一个画布(渲染缓冲区):

这个缓冲区是默认不可见的,后面进行的所有绘图操作都会绘制在新的画布上:

而在调用FlushBatchDraw或EndBatchDraw函数时EasyX会将前后两个缓冲区进行快速对调:

所以我们将不会再看见在一张画布上由于绘图频繁而导致的”闪烁“。
三、游戏框架
在之前程序中我们运用了死循环来阻塞程序来防止窗口退出,同时在循环中不断执行清屏和绘制操作,这其实已经完成了游戏框架最核心的部分”主循环“,在主循环中不断读取玩家鼠标操作并将这些操作翻译成对数据的处理逻辑,最后再根据现有的逻辑将画面内容绘制出来。也即读取操作——处理数据——绘制画面,在循环中不断执行这些操作便可以完成几乎所有游戏的逻辑设计:

先前代码如下;
#include<graphics.h>int main() {initgraph(1280, 720);int x, y;//BeginBatchDraw();while (1) {ExMessage msg;while (peekmessage(&msg)) {if (msg.message == WM_MOUSEMOVE) {x = msg.x;y = msg.y;}}cleardevice();solidcircle(x, y, 100);//FlushBatchDraw();}//EndBatchDraw();return 0;}
peekmessage这部分就是读取操作:

将读取到的鼠标坐标赋值给先前定义的x、y就是处理数据:

然后solidcircle便是绘制画面。
还有,一开始需要初始化,最后需要释放资源。
四、设计本地环境的井字棋
井字棋共九格,X/O双方先后落子,同一颗棋子斜或竖连成一线则一方获胜,如果棋盘被填满则平局。
依据框架确定设计思路:①读取操作:双方只使用鼠标游玩,所以只需要读取鼠标消息。 ②处理数据:根据数据检测输赢平局情况,以弹窗形式告知,然后退出主循环。③绘制画面:使用line函数绘制直线将画布分割为3 x 3棋盘,绘制X棋子时只需要使用line函数绘制对应网格的对角线即可完成;绘制O棋子时只需要使用circle函数绘制以对应网格中心为圆心的圆即可。除此之外,在棋盘上方给出当前落子类型给予玩家提示。
接下来便是组织游戏的数据结构,可以使用二维数组表示棋盘

数组默认值为‘-’,代表没有棋子。
游戏结束的条件:①某玩家获胜,可能情况有8种—竖行三种、横行三种、斜角两种 ②平局,在没有玩家获胜前提下,数组中没有‘-’默认值。
开始写代码:首先是读取操作创建ExMessage存储消息/peekmessage获取消息
#include<graphics.h>int main() {initgraph(600, 600);ExMessage msg;bool running = true;//加一个控制变量控制循环,想要结束时改成false即可终止循环while (running) {while (peekmessage(&msg)) {}}return 0;}
接下来是数据处理:把数据拿过来进行判断指定棋子玩家是否获胜—创建CheckWin函数,这个函数接受char类型变量并返回布尔值用来检测对应棋子玩家是否满足获胜条件;创建CheckDraw函数,不传入参数返回布尔值来判断是否平局。当检测到玩家获胜,我们调用MessageBox函数弹窗,同时修改主循环控制条件使游戏结束运行。
小插曲:对MessageBox函数的解释
MessageBox函数接收4个参数,分别为父窗口句柄(相当于win系统中用于指向窗口对象的指针,可使用GetHWnd函数获取用来获取当前绘图窗口的句柄)、提示内容、弹窗标题、弹窗样式

接下来就可以编写获胜情况了:
if(CheckWin('X')){MessageBox(GetHwnd(), _T("X玩家获胜"), _T("游戏结束"), MB_OK);running = false;
}
else if(CheckWin('O'){MessageBox(GetHWnd(), _T("O玩家获胜"), _T("游戏结束"), MB_OK);running = false;
}
else if(CheckDraw()){MessageBox(GetHWnd(), _T("平局!"), _T("游戏结束"), MB_OK);running = false;
}
GetHwnd() 获取当前绘图窗口的句柄,_T(" ")决定显示界面输出内容,MB_OK决定显示界面只出现OK按钮。
接下来便是游戏画面的绘制,首先确保开启了批量绘图BeginBatchDraw() + EndBatchDraw(),并且在每次绘图后刷新批量绘图的渲染缓冲区FlushBatchDraw()。随后在每次绘图前清空画面cleardevice()。定义DrawBoard函数绘制棋盘网格。定义DrawPiece函数绘制棋子。定义DrawTipText函数定义当前棋子的文本提示信息。
全局大致框架如下:
#include<graphics.h>bool CheckWin(char c) {}bool CheckDraw() {}void DrawBoard() {}void DrawPiece() {}void DrawTipText() {}
int main() {initgraph(600, 600);ExMessage msg;BeginBatchDraw();bool running = true;while (running) {while (peekmessage(&msg)) {}if (CheckWin('X')) {MessageBox(GetHWnd(), _T("X玩家获胜"), _T("游戏结束"), MB_OK);running = false;}else if (CheckWin('O')) {MessageBox(GetHWnd(), _T("O玩家获胜"), _T("游戏结束"), MB_OK);running = false;}else if (CheckDraw()) {MessageBox(GetHWnd(), _T("平局!"), _T("游戏结束"), MB_OK);running = false;}cleardevice();DrawBoard();DrawPiece();DrawTipText();FlushBatchDraw();}EndBatchDraw();return 0;}
相关文章:
无引擎游戏开发(2):最简游戏框架 | EasyX制作井字棋小游戏I
一、EasyX中的坐标系 不同于数理中的坐标系,EasyX中的y轴是竖直向下的 二、渲染缓冲区 之前的程序添加了这三个函数改善了绘图时闪烁的情况: 小球在"画布“上移动的过程就是我们在调用绘图函数,这个”画布“就是渲染缓冲区,先绘制的内…...
排书 IDA*
原题链接 题目描述 给定 n 本书,编号为 1∼n。 在初始状态下,书是任意排列的。在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。我们的目标状态是把书按照 1∼n 的顺序依次排列。求最少需要多少次操作。 输…...
playwright录制脚本原理
Paywright录制工具UI 在上一篇博客中介绍了如何从0构建一款具备录制UI测试的小工具。此篇博客将从源码层面上梳理playwright录制原理。当打开playwright vscode插件时,点击录制按钮,会开启一个新浏览器,如下图所示,在新开浏览器页…...
awk脚本监控
awk脚本监控 使用脚本监控内存,cpu和硬盘的根目录,超过80%提示用户,写成函数库的行,每天早上 的8.50分,执行一次脚本 现在脚本中写需要的内容 cpuu () {aa$(top -b -n 1 |awk NR3 {printf "%.F",$2$4})if …...
Python高压电容导电体和水文椭圆微分
🎯要点 🎯二维热传导二阶偏微分方程 | 🎯调和函数和几何图曲率 | 🎯解潮汐波动方程 | 🎯解静止基态旋转球体流体运动函数 | 🎯水文空间插值 | 🎯流体流动模拟求解器 | 🎯随机算法解…...
微信小程序 引入MiniProgram Design失败
这tm MiniProgramDesign 是我用过最垃圾的框架没有之一 我按照官网的指示安装居然能安装不成功,牛! 这里说明我是用js开发的 到以上步骤没有报错什么都没有,然后在引入组件的时候报错 Component is not found in path “./miniprogram _npm/vant/weapp/button/index” (using…...
Java 8 Date and Time API
Java 8引入了新的日期和时间API,位于java.time包下,旨在替代旧的java.util.Date和java.util.Calendar类。新API更为简洁,易于使用,并且与Joda-Time库的一些理念相吻合。以下是Java 8 Date and Time API中几个核心类的简要概述&…...
pyppeteer模块经常使用的功能,相关操作案例
官方仓库地址:https://github.com/miyakogi/pyppeteer 官方文档地址:API Reference — Pyppeteer 0.0.25 documentation Selenium环境的相关配置比较繁琐,此外,有的网站会对selenium和webdriver进行识别和反爬,因此在…...
nginx+keepalived+tomcat集群实验
如遇星河 | nginx+keepalived高可用集群实验 木子87 | Keepalived+Nginx+Tomcat 实现高可用Web集群 环境 192.168.40.204 tomcat-1 192.168.40.138 tomcat-2 安装tomcat [root@bogon local]# vim /etc/profile 添加环境变量 JAVA_HOME=/usr/local/java PATH=$J…...
vue脚手架 axios的二次封装
目录 01 路由懒加载(重要) 02 axios在脚手架中的使用 03.axios的二次封装 04 组件缓存 01 路由懒加载(重要) 一次性导入会出现严重的问题 : 首屏卡顿 因为main.js中引入了router/index.js router/index.js又使用了import语句 静态的引入了每一个组件 导致了首屏卡顿 所以我…...
人机恋爱新趋势:与AI男友谈恋爱的甜蜜与挑战
"我曾经把ChatGPT当成工具,从未追过星,也没有嗑过CP。没想到,到了36岁,我竟然嗑上了AI男友。Open AI,你赢了。你不仅是最好的AI公司,还是乙女游戏公司。" 转行大龄互联网人,走遍20国…...
文生视频开源产品的一些调研(一)
笔者尝试AI视频生成的几个特点: 玄学prompt,每个视频的prompt可能也需要微调很多次,需要找到使用模型的最佳prompt词组合,不恰当的比喻,骑自行车,座位高度等都是人与车彼此熟悉玄学生成,因为需…...
一切前端概念,都是纸老虎
4、listener可以通过 store.getState() 得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。 function listerner() { let newState store.getState(); component.setState(newState); } 对比 Flux 和 Flux 比较一下:Flux 中 Store 是…...
使用自签名 TLS 将 Dremio 连接到 MinIO
Dremio 是一个开源的分布式分析引擎,为数据探索、转换和协作提供简单的自助服务界面。Dremio 的架构建立在 Apache Arrow(一种高性能列式内存格式)之上,并利用 Parquet 文件格式实现高效存储。有关 Dremio 的更多信息,…...
嵌入式系统软件开发环境_2.一般架构
1.Eclipse框架 嵌入式系统软件开发环境是可帮助用户开发嵌入式软件的一组工具的集合,其架构的主要特征离不开“集成”问题,采用什么样的架构框架是决定开发环境优劣主要因素。Eclipse框架是当前嵌入式系统软件开发环境被普遍公认的一种基础环境框架。目…...
单门户上集成多种数据库查询入口
(作者:陈玓玏) 开源项目,欢迎star哦,https://github.com/tencentmusic/cube-studio 在一家公司,我们通常会有多种数据库,每种数据库因为其特性承担不同的角色,比如mysql这种轻量…...
华芯微特SWM34-使用定时器捕获快速解码EV1527编码
在无线应用领域,很多433Mhz和315Mhz的遥控器,红外探测器,门磁报警器,无线门铃等都使用EV1527编码格式来发射数据。发射和接收均有对应的RF芯片完成,而且成本极低(目前市场价3毛钱不到)。接收芯片…...
小程序安卓手机点击uni-data-select 下拉框选择器会出现蓝色阴影
解决方法:在导入的包中找到uni-data-select.vue,接着找到.uni-stat__select样式,把cursor: pointer去掉。 如果出现穿透问题,uni-select__selector的z-index加高,默认是2。...
playwright vscode 插件源码解析
Playwright vscode插件主要功能 Playwright是微软开发的一款主要用于UI自动化测试的工具,在vscode中上安装playwright vscode插件,可以运行,录制UI自动化测试。 playwright vscode插件主要包括两块功能,功能一是在Test Explorer中…...
Mysql: SQL-DDL
一.SQL通用语法 1.SQL可以单行或者多行书写,以分号结尾。 2.SQL语句可以使用空格/缩进来增强语句的可读性。 3.MySQL数据库的SQL语句不区分大小写,关键字建议用大写。 4.注释: 单行注释:注释内容或#注释内容(Mysql特有) 多行注释:/*注释内容*/ 二.SQL分类 1.D…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
