手撸俄罗斯方块(五)——游戏主题
创始人
2025-01-11 08:35:45
0次

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

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

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

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

相关内容

热门资讯

实测交流透视挂!宝玛大厅ai智... 实测交流透视挂!宝玛大厅ai智能透视挂教程,宝玛大厅破解软件经验(本来有挂辅助)1、每一步都需要思考...
总算了解辅助器!朱雀吴江三缺一... 总算了解辅助器!朱雀吴江三缺一ai智能透视辅助挂技巧,朱雀吴江三缺一好像是有挂(有辅助挂细节)朱雀吴...
今日公布透视!九五至尊大厅ai... 今日公布透视!九五至尊大厅ai智能透视插件,九五至尊大厅有没有透视挂窍门(切实有挂技术)1、在九五至...
玩家必看科普开挂!聚闲麻将ai... 玩家必看科普开挂!聚闲麻将ai智能透视辅助挂软件,聚闲麻将总是真的有挂(有辅助挂方式)聚闲麻将能透视...
据报道开挂!旅游娱乐ai智能开... 据报道开挂!旅游娱乐ai智能开挂工具,旅游娱乐辅助工具演示(一直有挂教学)1、全新机制【旅游娱乐ai...
一分钟揭秘开挂!决胜朋来麻将a... 一分钟揭秘开挂!决胜朋来麻将ai智能透视辅助挂教程,决胜朋来麻将真是真的是有挂(有辅助挂总结)1、首...
如何分辨真伪透视!红牛ai智能... 如何分辨真伪透视!红牛ai智能透视攻略,红牛是不是有挂经验(真是有挂技术)1、操作简单,无需红牛手机...
2分钟细说辅助器!江湖大庆麻将... 2分钟细说辅助器!江湖大庆麻将ai智能透视辅助挂攻略,江湖大庆麻将竟然是真的有挂(有辅助挂头条)1、...
总算清楚透视挂!老夫子厅ai智... 总算清楚透视挂!老夫子厅ai智能透视挂技巧,老夫子厅怎么开挂课程(好像发现有挂)老夫子厅破解侠是真的...
解密关于辅助!菜鸟麻将ai智能... 解密关于辅助!菜鸟麻将ai智能透视辅助挂脚本,菜鸟麻将总是存在有挂(有辅助挂存在)1、用户打开应用后...