手撸俄罗斯方块(五)——游戏主题
手撸俄罗斯方块(五)——游戏主题
当确定游戏载体(如控制台)后,界面将呈现出来。但是游戏的背景色、方块的颜色、方框颜色都应该支持扩展。
当前游戏也是如此,引入了 Theme 的概念,支持主题的扩展。
AbstractTheme
系统抽象了一个AbstractTheme,它将一些渲染过程中的行为进行了抽象,抽象定义如下:
abstract class AbstractTheme {/*** 设置外框的样式,如外框的颜色、整体的背景等。* @param outer 指代外框对象的元素,通过修改其内容改变显示样式。*/abstract outStyle(outer: any): void;/*** 设置内框的样式,如内框的颜色、整体的背景等。* @param inner 指代内框对象的元素,通过修改其内容改变显示样式。*/abstract innerStyle(inner: any): void;/*** 设置分数的样式。* @param score 指代分数对象的元素,通过修改其内容改变显示样式。*/abstract scoreStyle(score: any): void;/*** 设置状态栏的样式* @param status 指代状态对象的元素。*/abstract statusStyle(status: any): void;/*** 分数的格式化字符串,输入一个分数的数字,将其转换为目标的样式;* @param score {number} 当前游戏的分数*/abstract scoreTemplate(score: number): string;abstract nextStyle(blocks: any): void;abstract currentStyle(current: any): void;/*** 设置方块区域的样式* @param block 指代当前方块区域*/abstract blockStyle(block: any): void;/*** 设置current区域和已填充区域的小方块的样式* @param blockItem 当前小方块,如一个IBlock会拆分成4各BlockItem。* @param point 当前小方块的位置信息,包括`x`轴和`y`轴的坐标等信息*/abstract blockPointStyle(blockItem: any, point: Point): void;/*** 设置next区域的小方块的样式* @param blockItem* @param point*/abstract nextPointStyle(blockItem: any, point: Point): void;
}
注释已经描述得比较清晰了,分别对外框、内框等进行了设定。
控制台如何实现主题
为了使主题生效,需要在AbstractCanvas子类中调用Theme提供的方法。这里以ConsoleCanvas为例,它的实现如下:
export class ConsoleCanvas extends AbstractCanvas {render(): void {const { game } = this;if (!game) {return;}const { stage, dimension } = game;const printArray: string[] = [];console.clear();const { score, current, next } = stage;const { xSize, ySize } = dimension;const outLength = 1 + 1 + xSize + 1 + this.rightWidth + 1;if (!this.isHideOuter) {// 1. 渲染外边框的上边框const outLine1 = this.getOutterLine(this.outerLeftTopChar +this.createChar(xSize + 2 + this.rightWidth, this.horizonalChar) +this.outerRightTopChar);printArray.push(outLine1);}// 2. 渲染scoreconst scoreText = this.theme.scoreTemplate(score);const scoreConsoleChar = ConsoleChar.create(scoreText);this.theme.scoreStyle(scoreConsoleChar);// 计算左侧需要补充的空格const leftSpace = this.rightWidth - scoreText.length - 3;// 右侧需要补充的空格const rightSpace = 3;let scoreLine =this.getOutterLine(this.outerLeftVerticalChar) +this.createChar(xSize + 2 + leftSpace) +scoreConsoleChar.ch +this.createChar(rightSpace) +this.getOutterLine(this.outerRightVerticalChar);printArray.push(scoreLine);// 3. 渲染内边框的上边框let line1 =this.getOutterLine(this.outerLeftVerticalChar) +this.getInnerLine(this.innerLeftTopChar);for (let x = 0; x < xSize; x++) {const oneBlockItem = current?.points.find((item) => item.x === x);if (oneBlockItem) {line1 += this.getInnerLine(bold(this.horizonalChar));} else {line1 += this.getInnerLine(this.horizonalChar);}}line1 +=this.getInnerLine(this.innerRightTopChar) +this.createChar(this.rightWidth) +this.getOutterLine(this.outerRightVerticalChar);printArray.push(line1);let line2 =this.getOutterLine(this.outerLeftVerticalChar) +this.getInnerLine(this.innerLeftBottomChar);for (let x = 0; x < xSize; x++) {const oneBlockItem = current?.points.find((item) => item.x === x);if (oneBlockItem) {line2 += this.getInnerLine(bold(this.horizonalChar));} else {line2 += this.getInnerLine(this.horizonalChar);}}line2 +=this.getInnerLine(this.innerRightBottomChar) +this.createChar(this.rightWidth) +this.getOutterLine(this.outerRightVerticalChar);printArray.push(line2);if (!this.isHideOuter) {const outLine2 = this.getOutterLine(this.outerLeftBottomChar +this.createChar(xSize + 2 + this.rightWidth, this.horizonalChar) +this.outerRightBottomChar);printArray.push(outLine2);}if (this.exitMessage) {printArray.push(this.exitMessage);} else {printArray.push("");}process.stdout.write(this.handleOutput(outLength, printArray).join("\n"));}
}
我们看到渲染上边框,调用了getOutterLine方法,这个方法是在AbstractCanvas中定义的,它的实现如下:
export class ConsoleCanvas extends AbstractCanvas {// ...getOutterLine(char: string): string {if (this.isHideOuter) {return "";}const consoleChar = new ConsoleChar(str || "|");this.theme.outStyle(consoleChar);return consoleChar.ch;}// ...
}
它内部调用了 theme.outStyle 方法,对应我们上述 theme 的定义。
类似的,对于内边框的渲染,也是调用了getInnerLine方法,它的实现如下:
export class ConsoleCanvas extends AbstractCanvas {// ...getInnerLine(char: string): string {const consoleChar = new ConsoleChar(str || "|");this.theme.innerStyle(consoleChar);return consoleChar.ch;}// ...
}
这样,我们就实现了主题的扩展。
主题的扩展
我们可以通过继承AbstractTheme,实现自己的主题,比如实现一个RedTheme:
export class RedTheme extends DefaultTheme {outStyle(outer: any): void {outer.ch = color.red(outer.ch);}
}
它实现了outStyle方法,将外边框的颜色设置为红色。
我们使用该主题,效果如下

详细内容可以我的git项目: https://github.com/shushanfx/tetris
也可以关注我的git账号: https://github.com/shushanfx
自此手撸俄罗斯方块的代码部分就讲到这里,后续将依次为开始展开,从俄罗斯方块开始,我们能走多远。
相关文章:
手撸俄罗斯方块(五)——游戏主题
手撸俄罗斯方块(五)——游戏主题 当确定游戏载体(如控制台)后,界面将呈现出来。但是游戏的背景色、方块的颜色、方框颜色都应该支持扩展。 当前游戏也是如此,引入了 Theme 的概念,支持主题的扩…...
【测试开发】--安全渗透测试
1. 安全渗透 1.1 分类 web数据库安全web应用服务器安全(文件上传漏洞、文件包含漏洞)web客户端安全(XSS跨站攻击) 2. sql注入 2.1 sql注入介绍 sql注入在安全问题中排行榜首sql注入攻击是输入参数未经过滤,然后直…...
AMEYA360:类比半导体三款车规级新品介绍
类比半导体三款全新车规级智能驱动芯片——HD70504与HD70804四通道高边驱动、HD7004低导通电阻高边驱动以及DR8112直驱马达驱动芯片介绍,进一步扩展了其汽车智能驱动产品的深度与广度。 新品首发,诠释“芯”动未来 HD70504 & HD70804四通道高边驱动芯…...
内衣洗衣机哪个牌子好用?五大硬核宝藏内衣洗衣机推荐
在日常生活中,内衣洗衣机已成为现代家庭必备的重要家电之一。选择一款耐用、质量优秀的内衣洗衣机,不仅可以减少洗衣负担,还能提供高效的洗涤效果。然而,市场上众多内衣洗衣机品牌琳琅满目,让我们往往难以选择。那么&a…...
红酒与未来科技:传统与创新的碰撞
在岁月的长河中,红酒以其深邃的色泽、丰富的口感和不同的文化魅力,成为人类文明中的一颗璀璨明珠。而未来科技,则以其迅猛的发展速度和无限的可能性,领着人类走向一个崭新的时代。当红酒与未来科技相遇,一场传统与创新…...
php快速入门
前言 php是一门脚本语言,可以访问服务器,对数据库增删查改(后台/后端语言) 后台语言:php,java,c,c,python等等 注意:php是操作服务器,不能直接在…...
【排序 - 归并排序】
归并排序(Merge Sort)是一种高效的排序算法,基于分治(Divide and Conquer)策略。它将待排序数组分成两个较小的子数组,分别对它们进行排序,然后将排好序的子数组合并成一个整体有序的数组。归并…...
Appium元素定位(全网详细讲解)(二)
1.appium inspector(定位元素的工具)使用方法 详细介绍: 详细解释: 图标名称说明1Show Element Handles是否显示元素句柄2Select Elements选择元素定位3Tap/Swipe By Coordinates按坐标点击/滑动4Download Screenshot下载屏幕截…...
滑动窗口,最长子序列最好的选择 -> O(N)
最近在学校上短学期课程,做程序设计题,一下子回忆起了大一学数据结构与算法的日子! 这十天我会记录一些做题的心得,今天带来的是对于最长子序列长度题型的解题框架:滑动窗口 本质就是双指针算法: 通过le…...
【Python】已解决:Python安装过程中的报错问题
文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确解决方法五、注意事项 已解决:Python安装过程中的报错问题 一、分析问题背景 在安装Python 3.9.6(64位)版本时,用户可能会遇到一个报错信息,提…...
C++ STL IO流介绍
目录 一:IO流的继承关系: 二:输入输出功能 1. 基本用法 2. 格式化输入 3.非格式化输入 4. 格式化输出 三:流 1. 字符流 2. 向字符流中写入数据 3. 从字符流中读出数据 4. 清空字符流 5.完整的例子 四:文件…...
华为浏览器,Chrome的平替,插件无缝连接
文章目录 背景插件书签 背景 不知道各位小伙伴有没有这样的痛点,办公电脑、家里的电脑还有手机、平板等,收藏了一个网址或者在手机上浏览了某个网页,保存起来,可是一换平台或者换个电脑,在想要浏览之前收藏的东西&…...
SpringBoot新手快速入门系列教程:前述
我自己是一个SpringBoot新手,花了一天时间学了SpringBoot。大家不要惊讶,前提是我自己已经有了10几年的编程经验精通多门语言,并且在人间最强兵器Chat某T的AI助手帮助下,才能创造一天快速学会一个框架的神话。 当然中间遇到了很多…...
C语言9 指针
目录 指针的声明与初始化 指针运算 指针的加法和减法 指针的比较 指针与数组 通过指针访问数组元素 指针与多维数组 声明指向多维数组的指针 访问多维数组元素 指针数组和数组指针 指针数组 数组指针 字符指针 字符串的定义和字符指针 直接使用字符指针初始化字…...
Floyd判圈算法——寻找重复数(C++)
287. 寻找重复数 - 力扣(LeetCode) 题目描述 给定一个包含 n 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 ,返…...
面试题目分享
学习目标: 从面试了解自己的不足。 学习内容: 1.你会什么语言? 我该如何回答,我会java,c,c等,在工作中我会用到合适的语言。 牛逼吹的大话 尊敬的面试官,我精通Java和Python&…...
Solana开发之Anchor框架
文章目录 Solana开发之Anchor框架一、什么是Anchor二、安装和使用1. 安装rust2. 安装Solana下载预构建的二进制文件 3. 使用 Anchor 版本管理器 (avm) 进行安装(推荐) 四、Anchor 核心原理Anchor 程序由三部分组成程序的 ID 从哪里…...
界面组件Kendo UI for React 2024 Q2亮点 - 生成式AI集成、设计系统增强
随着最新的2024年第二季度发布,Kendo UI for React为应用程序开发设定了标准,包括生成式AI集成、增强的设计系统功能和可访问的数据可视化。新的2024年第二季度版本为应用程序界面提供了人工智能(AI)提示,从设计到代码的生产力增强、可访问性…...
python输出/sys/class/power_supply/BAT0/电池各项内容
读取 /sys/class/power_supply/BAT0/ 目录下的所有相关文件,并输出其内容: import os# 定义电池信息文件的路径 battery_path = "/sys/class/power_supply/BAT0/"# 读取文件内容的函数 def read_battery_info(file_name):try:with open(os.path.join(battery_path…...
HDFS体系架构文件写入/下载流程
HDFS体系架构 HDFS(Hadoop Distributed File System,Hadoop分布式文件系统)是Hadoop项目中的一个核心组件,旨在以高容错、高吞吐量来处理大规模数据集。它的体系架构由以下几个主要部分组成:Client,NameNo…...
跨平台兼容计算引擎:解锁非NVIDIA GPU的CUDA计算潜能
跨平台兼容计算引擎:解锁非NVIDIA GPU的CUDA计算潜能 【免费下载链接】ZLUDA CUDA on non-NVIDIA GPUs 项目地址: https://gitcode.com/GitHub_Trending/zl/ZLUDA 在高性能计算领域,硬件壁垒常常限制着开发者的创新空间——当你手中的Intel GPU无…...
别只训练了!聊聊LSTM翻译模型保存的那些事儿:.h5权重、字符字典与config.json
LSTM翻译模型工程化实战:从权重保存到完整资产包的深度解析 当你花了三天三夜训练出一个效果不错的LSTM翻译模型,看着验证集上的BLEU分数终于突破30,正准备松口气时——突然意识到这个模型可能永远走不出你的Jupyter Notebook。这不是危言耸听…...
从深海冷泉到实验室:原核生物抗病毒系统研究的5个前沿突破与未来方向
深海微生物的病毒防御战:5项颠覆性发现与跨学科研究路径 在南海1200米深的冷泉区,一簇簇贻贝群落正无声上演着微观世界的军备竞赛——这里的硫氧化细菌每20分钟就会遭遇一次噬菌体袭击,而它们携带的抗毒素蛋白和逆转录酶构成了独特的防御工事…...
NPS内网穿透实战:如何为本地站点快速配置HTTPS(含防火墙设置)
NPS内网穿透实战:如何为本地站点快速配置HTTPS(含防火墙设置) 在数字化转型浪潮中,远程访问内网资源的需求日益增长。想象一下这样的场景:你正在开发一个本地Web应用,需要让异地同事实时测试;或…...
Labelme标注完别急着训练!手把手教你批量把JSON转成YOLO能吃的TXT格式
Labelme标注数据转YOLO格式实战指南:从原理到批量处理 当你用Labelme完成数百张图片的标注,满心欢喜准备开始YOLO模型训练时,却发现训练脚本报错——原来YOLO无法直接读取Labelme生成的JSON文件。这不是代码问题,而是格式不匹配的…...
OpenClaw+千问3.5-9B:学术论文摘要生成与关键词提取
OpenClaw千问3.5-9B:学术论文摘要生成与关键词提取 1. 为什么需要自动化文献处理工具 作为一名经常需要阅读大量文献的研究人员,我深刻体会到手动处理论文的痛点。每次面对几十篇PDF文献时,光是阅读摘要和提取关键词就要耗费数小时。更糟糕…...
单电源运放差分放大电路实战:3.3V供电下的精确计算与仿真验证
单电源运放差分放大电路实战:3.3V供电下的精确计算与仿真验证 在嵌入式系统开发中,信号调理电路的设计往往面临低功耗与高精度的双重挑战。单电源运放差分放大电路因其结构简单、成本低廉,成为3.3V供电环境下小信号放大的首选方案。本文将深入…...
LRCGet:三步构建完美离线音乐歌词库的终极指南
LRCGet:三步构建完美离线音乐歌词库的终极指南 【免费下载链接】lrcget Utility for mass-downloading LRC synced lyrics for your offline music library. 项目地址: https://gitcode.com/gh_mirrors/lr/lrcget 你是否曾面对庞大的本地音乐收藏,…...
效能倍增:ZenTimings的场景化内存性能优化指南
效能倍增:ZenTimings的场景化内存性能优化指南 【免费下载链接】ZenTimings 项目地址: https://gitcode.com/gh_mirrors/ze/ZenTimings ZenTimings是一款专为AMD Ryzen平台打造的内存时序监控与优化工具,通过精准的参数调校和实时监控功能&#…...
万象视界灵坛效果展示:同一图像下10组候选神谕的同步率热力图
万象视界灵坛效果展示:同一图像下10组候选神谕的同步率热力图 1. 平台概览 万象视界灵坛(Omni-Vision Sanctuary)是一款基于OpenAI CLIP技术的高级多模态智能感知平台。它将复杂的语义对齐过程转化为直观的视觉体验,采用独特的1…...
