手撸俄罗斯方块(五)——游戏主题

手撸俄罗斯方块(五)——游戏主题

当确定游戏载体(如控制台)后,界面将呈现出来。但是游戏的背景色、方块的颜色、方框颜色都应该支持扩展。

当前游戏也是如此,引入了 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

自此手撸俄罗斯方块的代码部分就讲到这里,后续将依次为开始展开,从俄罗斯方块开始,我们能走多远。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/44540.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust入门实战 编写Minecraft启动器#2建立资源模型

首发于Enaium的个人博客 我们需要声明几个结构体来存储游戏的资源信息&#xff0c;之后我们需要将json文件解析成这几个结构体&#xff0c;所以我们需要添加serde依赖。 serde { version "1.0", features ["derive"] }资源相关asset.rs use serde::De…

雨量监测站的重要性有哪些

在全球气候变化和极端天气事件频发的背景下&#xff0c;雨量监测站成为了我们理解降水模式、预测天气变化以及制定应对措施的重要工具。 雨量监测站是一种专门用于测量和记录降水量的设施。它们通过配备高精度的雨量传感器&#xff0c;能够实时监测降雨情况&#xff0c;并提供关…

【分布式系统】CephFS文件系统之MDS接口详解

目录 一.服务端操作 1.在管理节点创建 mds 服务 2.查看各个节点的 mds 服务&#xff08;可选&#xff09; 3.创建存储池&#xff0c;启用 ceph 文件系统 4.查看mds状态&#xff0c;一个up&#xff0c;其余两个待命&#xff0c;目前的工作的是node01上的mds服务 5.创建用户…

SuperCLUE最新测评发布,360智脑大模型稳居大模型第一梯队

7月9日&#xff0c;国内权威大模型评测机构SuperCLUE发布《中文大模型基准测评2024上半年报告》&#xff0c;360智脑大模型&#xff08;360gpt2-pro&#xff09;在SuperCLUE基准6月测评中&#xff0c;取得总分72分&#xff0c;超过GPT-3.5-Turbo-0125&#xff0c;位列国内大模型…

离线安装压缩工具xz指南

在Linux操作系统上离线安装压缩工具xz可能会遇到一些挑战&#xff0c;尤其是当官方下载地址无法访问时。本文将为你提供详细的指导&#xff0c;确保你能够顺利安装xz。 一、下载xz安装包 首先&#xff0c;你可以尝试从xz官方网站下载xz的安装包。以下是官方下载地址&#xff…

制作一个自动养号插件的必备源代码!

随着网络社交平台的日益繁荣&#xff0c;用户对于账号的维护和运营需求也日益增长&#xff0c;在这样的背景下&#xff0c;自动养号插件应运而生&#xff0c;成为了许多用户提升账号活跃度、增加曝光量的得力助手。 然而&#xff0c;制作一个高效、稳定的自动养号插件并非易事…

免费分享:中国1KM分辨率月平均气温数据集(附下载方法)

数据简介 中国1KM分辨率月平均气温数据集为中国逐月平均温度数据&#xff0c;空间分辨率为0.0083333&#xff08;约1km&#xff09;。 数据集获取&#xff1a;根据全国2472个气象观测点数据进行插值获取&#xff0c;验证结果可信。 数据集包含的地理空间范围&#xff1a;全国…

Kruskal

Prim算法用来处理稠密图&#xff0c;Kruskal算法来处理稀疏图。 大致思路&#xff1a; 先用结构体对该的边以及点进行储存&#xff0c;然后根据每条边的权重来进行升序排序&#xff0c; 取权重最小的边放入所要维护的树中&#xff1a;如果该条边不在区域中才会将其放入区域中…

常见摄像头模块性能对比

摄像头模块在现代电子设备与嵌入式开发中扮演着重要角色&#xff0c;从智能手机到安全监控系统&#xff0c;再到机器人视觉系统&#xff0c;它们无处不在。以下是一些常见的摄像头模块及其特点的对比&#xff1a; OV2640 分辨率&#xff1a;最高可达200万像素&#xff08;1600x…

vue3 antdv Modal通过设置内容里的容器的最小高度,让Modal能够适当的变高一些

1、当收款信息Collapse也折叠的时候&#xff0c;我们会发现Modal的高度也变成了很小。 2、我们希望高度稍微要高一些&#xff0c;这样感觉上面显示的Modal高度太小了&#xff0c;显示下面的效果。 3、初始的时候&#xff0c;想通过class或者style或者wrapClassName来实现&#…

交易员需要克服的十大心理问题

撰文&#xff1a;Koroush AK 编译&#xff1a;Chris&#xff0c;Techub News 本文来源香港Web3媒体&#xff1a;Techub News 一个交易者在交易上所犯下的最大的错误可能更多来自于心态的失衡而并非技术上的失误&#xff0c;类似的情况已经发生在了无数交易者身上。作为交易者…

linux自动化内存监控与告警

文章目录 前言一、脚本实现1. shell脚本实现2. 脚本功能概览 二、设置定时执行1. 编辑cron任务表2. 设置定时任务 三、通知结果示例总结 前言 在当今数字化与网络化日益普及的时代&#xff0c;系统管理与维护成为了确保业务连续性和数据安全的关键环节。其中&#xff0c;监控系…

宪法学学习笔记(个人向) Part.3

宪法学学习笔记(个人向) Part 3 3. 国家基本制度 3.1 国家性质 3.1.1 国家性质概述 国家性质的概念 国家性质也称国体&#xff0c;或国家的阶级本质&#xff0c;是指各个阶级在国家中的地位&#xff08;哪个阶层是统治阶层&#xff0c;哪个阶层是被统治阶层&#xff0c;哪个…

MT3056 交换序列

思路&#xff1a; 与题目 MT3055 交换排列 类似 代码&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e4 10; int n, fa[N], b[N], d[N]; void init(int n) {for (int i 1; i < n; i)fa[i] i; } int find(int x) {return x fa[x] ?…

快手可图模型的要点

Kolors模型 摘要与介绍 Kolors是一个基于扩散的文本生成图像模型&#xff0c;能够生成高逼真度的图像&#xff0c;支持英文和中文。该模型结合了通用语言模型&#xff08;GLM&#xff09;和由多模态大语言模型生成的细粒度标题&#xff0c;从而提升了其理解和渲染能力。 关键…

PostgreSQL 查询字段as别名驼峰大写未生效的坑

as别名驼峰大写的错误示例: select id, game_name as gameName from app_projects;运行效果: as别名驼峰大写的正确示例: select id, game_name as "gameName" from app_projects;运行效果: 代码示例:

1.10编程基础之简单排序--02:奇数单增序列

OpenJudge - 02:奇数单增序列http://noi.openjudge.cn/ch0110/02/ 描述 给定一个长度为N(不大于500)的正整数序列,请将其中的所有奇数取出,并按升序输出。 输入 共2行: 第1行为 N; 第2行为 N 个正整数,其间用空格间隔。 输出 增序输出的奇数序列,数据之间以逗号间隔。数…

Java面试题系列 - 第8天

题目&#xff1a;深入解析Java中的异常处理机制 背景说明&#xff1a;Java的异常处理机制是其强类型安全和健壮性的重要组成部分。了解如何正确地使用异常处理&#xff0c;对于编写可靠和易于维护的代码至关重要。 问题要求&#xff1a; 解释Java异常处理机制的基本概念&…

springboot 旅游导航系统-计算机毕业设计源码69476

目 录 第 1 章 引 言 1.1 选题背景 1.2 研究现状 1.3 论文结构安排 第 2 章 系统的需求分析 2.1 系统可行性分析 2.1.1 技术方面可行性分析 2.1.2 经济方面可行性分析 2.1.3 法律方面可行性分析 2.1.4 操作方面可行性分析 2.2 系统功能需求分析 2.3 系统性需求分析…

「解析」Cosine-Warmup 学习率策略

参考论文&#xff1a;SGDR: Stochastic Gradient Descent with Warm Restarts Bag of Tricks for Image Classification with Convolutional Neural Networks 梯度下降算法需要我们设置一个值&#xff0c;用来控制权重更新幅度&#xff0c;我们将其称之为学习率。它是控制模型学…