华容道问题求解第一部分_详细设计(二)之棋子和游戏类_棋盘和棋子渲染

(续上篇)
HrdGame 类中的图像输出部分的函数,包括两部分,布局定义和绘制。

布局定义

广义上讲,布局只是棋子众多排列组合中一个快照,或者说是一个状态,因此引入了一个GameState 类,用来刻画一个布局。

逻辑布局定义

  逻辑布局是UI的内部数据结构,在其定义中主要通过使用HrdPoint 刻画 棋子的位置和大小,数据记录在一个数组中。该类主要属性定义如下:
public class GameState
{public Piece[,] layoutOfObj = new Piece[6, 7];// for the efficiency of searching the blocks beside the blank area public int[,] layoutOfIdx = new int[6, 7];//  use index to represent the piece that can save space for hash and stack. public Piece[] pieces = new Piece[12];public List<OpenPiece> openPieces = new List<OpenPiece>();public Piece selPcs { get; set; }......
}

其中 layoutOfObj , 是一个Piece的二维数组,数组下标就是棋子的位置(左上角),数组元素的值刻画了棋子的属性。理论上,只要记住了元素的位置和类型,它的位置和形状(区域)就可以确定了。为了计算的高效,除了描述位置和类型之外,在棋子的其余位置也进行了描述,记录了棋子的基本属性,包括类型,大小以及位置信息。
为了查询方便,同时引入了一个索引数组,相当于每个棋子的基本属性的实例刻画。这样重复记录的意义在于,查找棋子的位置关系时,比较高效。它和算法本身没有直接联系。这个数组定义如下:

public int[,] layoutOfIdx = new int[6, 7];
棋子定义数组
public Piece[] pieces = new Piece[12];

索引布局数据中的索引即来自上面的棋子定义的索引,为了便于理解,我们不妨把这个索引叫做棋子的ID或者主键,这样一个索引值就表示对应的一个具体的棋子(实例)。

 public List<OpenPiece> openPieces = new List<OpenPiece>();

上面的List 用来记录当前布局下可以移动的棋子,其中 OpenPiece 定义如下:

public class OpenPiece
{public Piece piece { get; set; }public String Dir;public Piece MoveToPcs;// record the blank pieces to move, usually one element, the max is 2 }

其中Dir 用来表示棋子的可以移动的方向,MoveToPcs 用来描述移到到具体哪个空白区域(这个区域也是用Piece来刻画)。

逻辑布局函数

函数用于对上面的属性进行初始化,代码如下

       public void FillLayoutArr(Piece pcs){var pos = pcs.GetHrdPos();var size = pcs.GetHrdSize();var type = pcs.GetHrdType();gameState.layoutOfObj[pos.X, pos.Y] = pcs;gameState.layoutOfObj[pos.X + size.X - 1, pos.Y + size.Y - 1] = pcs;gameState.layoutOfIdx[pos.X, pos.Y] = pcs.idx;gameState.layoutOfIdx[pos.X + size.X - 1, pos.Y + size.Y - 1] = pcs.idx;if (type == 4){gameState.layoutOfObj[pos.X + size.X - 1, pos.Y] = pcs;gameState.layoutOfObj[pos.X, pos.Y + size.Y - 1] = pcs;gameState.layoutOfIdx[pos.X + size.X - 1, pos.Y] = pcs.idx;gameState.layoutOfIdx[pos.X, pos.Y + size.Y - 1] = pcs.idx;}}

上面代码中,对除了左上角的数组元素之外也进行了处理,这样该棋子覆盖区域内的每个数组元素都可踹表征这个棋子的信息。

物理布局函数

物理布局函数将根据逻辑布局以及外部函数传入的控件尺寸,将逻辑布局转化为像素为单位的客户区位置和大小(像素单位),然后调用GDI函数将棋盘和旗子画在输入的控件上。

控件客户区位置和大小映射

函数如下:

       public void SetLocAndSize(Piece pcs){int tW = _ctrl.Width / 4;int tH = _ctrl.Height / 5;int tX = pcs.GetHrdPos().X - 1;int tY = pcs.GetHrdPos().Y - 1;int pcsW = pcs.GetHrdSize().X;int pcsH = pcs.GetHrdSize().Y;var x = tX * tW;var y = tY * tH;var w = pcsW * tW;var h = pcsH * tH;//MessageBox.Show("debug");pcs.PcsLoc = new Point(x, y);pcs.PcsSize = new Size(w, h);}

函数中先获取控件的大小,然后根据获取逻辑布局大小,然后进行适当的比例缩放,设置棋子的实际大小和位置。

棋子绘制

调用上面的函数之后,棋子的实际位置和大小已经确定,在控件将其进行绘制。实际绘制时除了大小位置之外,还有棋子的颜色,名字等属性。函数主要代码如下

      public void DrawRegularBox(Graphics g, Piece pcs, bool bDrawTp = false){var tRec = new Rectangle((int)pcs.PcsLoc.X, (int) pcs.PcsLoc.Y, pcs.PcsSize.Width,pcs.PcsSize.Height);Brush brush = new SolidBrush(PieceClr[pcs.GetHrdType()]);if (pcs.Highlighted)//获取高亮颜色,用于鼠标滑过时显示{// Highlight the block when it's marked as highlightedColor originalColor = pcs.HrdColor; // Replace with your original light colorint darkenFactor = 32; // Adjust this factor to control the darknessint red = Math.Max(0, originalColor.R - darkenFactor);int green = Math.Max(0, originalColor.G - darkenFactor);int blue = Math.Max(0, originalColor.B - darkenFactor);Color darkerColor = Color.FromArgb(originalColor.A, red, green, blue);brush = new SolidBrush(darkerColor);//e.Graphics.DrawRectangle(new Pen(Color.Yellow), blockRect);}if (System.IO.File.Exists(pcs.avatarFile))//如果存在图标文件,则绘制棋子的图标{try{var img = Image.FromFile(pcs.avatarFile);g.DrawImage(img, tRec);img.Dispose();}catch (Exception ex){MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);}//g.DrawRectangle(new Pen( PieceClr[pcs.GetHrdType()]), tRec); ;g.DrawRectangle(new Pen(Color.White), tRec);brush = new SolidBrush(Color.White);}else //如果图标文件不在,则绘制简单的矩形框{g.FillRectangle(brush, tRec); ;g.DrawRectangle(new Pen(Color.White), tRec);}// 创建Font对象,你可以改变字体样式、大小等var emSize = 24;Font font = new Font("Arial", emSize);// 创建Brush对象,你可以改变颜色等  brush = new SolidBrush(Color.Black);if (pcs.Highlighted){brush = new SolidBrush(Color.Yellow);}if (pcs == gameState.selPcs){brush = new SolidBrush(_selFgColor);var fontW = GetStringSize(g, pcs.Name, font.FontFamily, emSize).Width;var fontH = GetStringSize(g, pcs.Name, font.FontFamily, emSize).Height;var x = pcs.PcsLoc.X + (int)(pcs.PcsSize.Width - fontW) / 2;var y = pcs.PcsLoc.Y + (int)(pcs.PcsSize.Height - fontH) / 2 - 3;var w = (int)fontW;var h = (int)fontH;Rectangle blockRect = new Rectangle((int)x, (int)y, w, h);//_layout.DrawRegularBox(e.Graphics, block, true);g.DrawRectangle(new Pen(Color.Yellow), blockRect);}PointF NameLoc = new Point(0, 0);var hrdType = pcs.GetHrdType();// draw the name of the block {NameLoc.X = pcs.PcsLoc.X + (int)(pcs.PcsSize.Width - GetStringSize(g, pcs.Name, font.FontFamily, emSize).Width) / 2;NameLoc.Y = pcs.PcsLoc.Y + (int)(pcs.PcsSize.Height - GetStringSize(g, pcs.Name, font.FontFamily, emSize).Height) / 2;}brush = new SolidBrush(Color.White);g.DrawString(pcs.Name, font, brush, NameLoc);if (bDrawTp){font = new Font("Arial", 10);// 使用DrawString方法写字  g.DrawString(pcs.GetHrdType().ToString() + "->" + pcs.DirFactor.ToString() + "," + pcs.MoveDir, font, brush, pcs.PcsLoc);}}

至此,就可以再UI上输出一个当前的布局了。

下面默认的横刀立马布局的绘制情况

在这里插入图片描述
说明:图片来自百度 文心一言。

下一节,将讲述本软件的第一个查找算法, 即DFS结合Dijkistra的算法。(待续)
MaraSun 2024-03-05 BJFWDQ
PS:《周处除三害》非常好看啊,记录一下。

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

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

相关文章

07 |「存储小工具——SharedPreferences」

前言 实践是最好的学习方式&#xff0c;技术也如此。 文章目录 前言一、简介二、操作1. 存储数据2. 取数据3. 查看存储的位置和文件 一、简介 解决什么问题&#xff1a; Acticivty 中的数据还是临时的&#xff0c;当我们退出之后再进来&#xff0c;这些数据是不会被保存的&…

输出X^N对233333取模的结果。

对任意正整数N&#xff0c;求XN%233333的值。 要求运算的时间复杂度为O(logN)。 例如X30 X15*X15X15X7*X7*XX7X3*X3*XX3X*X*X共7次乘法运算完毕。输入输出格式 输入描述: 输入两个整数X和N&#xff0c;用空格隔开&#xff0c;其中X,N<10^9。 输出描述: 输出X^N对233333取模…

免费!宝藏网站合集,每一个都不容错过

在科技日新月异的时代&#xff0c;PPT已经成为各行各业必不可少的展示工具。为了帮助大家提升PPT制作技巧&#xff0c;本文将为您介绍几款堪称神秘的PPT制作利器。它们分别是PPT宝库、PPT超级市场、魔法幻灯片以及优品PPT。 优品PPT 简介 优品PPT是一个专注于提供高质量PPT模…

机器人工具箱学习(二)

一、机械臂及运动学 1.1 机械臂构成 机械臂多采用关节式机械结构&#xff0c;一般具有6个自由度&#xff0c;其中3个用来确定末端执行器的位置&#xff0c;另外3个则用来确定末端执行装置的方向(姿态)。   如图所示&#xff0c;一个机械臂是由一组可做相对运动的关节连接的连…

新模型Claude 3实测!各项能力超强,确实比GPT-4好用

2024最新教程Claude 3注册账号&#xff0c;小白教程包教包会 过去不到一个月&#xff0c;OpenAI 扔出 Sora 这个重磅炸弹后成为全球焦点&#xff0c;不断推出的视频更是赚足眼球、热度不减。昨晚&#xff0c;Anthropic 突然惊喜上线&#xff0c;时隔八个月携着 Claude 3 走来&…

洛谷 P1083 [NOIP2012 提高组] 借教室(二分+差分)

题目链接&#xff1a; P1083 [NOIP2012 提高组] 借教室 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 在大学期间&#xff0c;经常需要租借教室。大到院系举办活动&#xff0c;小到学习小组自习讨论&#xff0c;都需要向学校申请借教室。教室的大小功能不同&#xff0c;借教…

掌握WhatsApp手机号质量评分:增加信息可达性

WhatsApp手机号质量评分是用于衡量用户手机号与平台互动的健康度&#xff0c;确保用户通讯时的合规性和安全性。在实掌握WhatsApp手机号质量评分实际应用中&#xff0c;这个评分会影响用户的消息发送的可达性。高质量的评分意味着用户的账户被视为可信赖的&#xff0c;其发送的…

批量下载抖音视频|抖音数据挖掘软件

高效批量下载抖音视频&#xff0c;轻松满足您的需求 在日常工作中&#xff0c;需要下载大量视频时&#xff0c;传统的方式往往效率低下&#xff0c;一个个复制粘贴链接进行下载太过繁琐。为了解决这一难题&#xff0c;我们研发了一款基于C#的视频下载软件&#xff0c;让您可以通…

DML相关操作

DML 是数据操作语言&#xff0c;用来对数据库中表的数据记录进行增删改操作 添加数据&#xff08;insert&#xff09;修改数据&#xff08;update&#xff09;删除数据&#xff08;delete&#xff09; DML-添加数据 1.给指定字段添加数据 insert into 表名&#xff08;字段…

【排序】详解冒泡排序

一、思想 冒泡排序的基本思想是利用两两比较相邻记录的方式&#xff0c;通过一系列的比较和交换操作&#xff0c;使得较大或较小的元素逐渐移动到数列的一端。在每一轮的排序过程中&#xff0c;都会从数列的起始位置开始&#xff0c;对相邻的元素进行比较&#xff0c;如果它们…

【c++设计模式14】结构型6:享元模式(Flyweight Pattern)

【c设计模式14】结构型6&#xff1a;享元模式&#xff08;Flyweight Pattern&#xff09; 一、定义二、适用场景三、过程四、享元模式类图五、C示例代码六、使用注意事项 类型序号设计模式描述结构型1适配器模式&#xff08;Adapter Pattern&#xff09;它用于在不修改已有类的…

MS2351M——RF 检测器/控制器

产品简述 MS2351M 是一款对数放大器芯片&#xff0c;主要用于接收信号强度 指示 RSSI 与功率放大器控制&#xff0c;工作频率范围是 50M  3000MHz &#xff0c; 因频率与温度不同&#xff0c;动态范围达 35dB 到 45dB 。 MS2351M 是电压响应器件&#xff0c; 50M…