前言

基础知识讲了很多,但是并没有串联起来,所以我最近一直在准备个小项目,但是这个项目的要求不含有数据库部分,也就是数据持久存储的功能,此外不能含有网络功能,它只是对基础知识的一个总结,最后一点是这个项目可以后期进行扩展,加上网络和数据库部分,所以最终选择俄罗斯方块这个小游戏作为基础知识总结的结课项目,因为这个小游戏可以扩展成为双人或者多人对战,同时保存每个人的对战信息

素材准备

我们的课程一直使用的是VCL,VCL原生的窗口太丑,所以需要做一点美化,准备一些图片,不至于让做出来的东西自己都不想看

这张图片是用来画窗口的,它将来的功能就是将整个游戏窗口划分为不同的功能区块,需要注意的是它的背景是透明的,至于大小到时候使用代码对图片进行切割,最终可以让我们绘制任意大小的窗口,本来就没什么时间,加上自己数学又不好,这个切边的问题让我鼓捣好几天.....,具体的计算方式如下:

这张图片是用于拼装图形的,同样的是代码进行切割,每一个方块的大小为32*32像素

这张图片有意思了,用于经验条显示的,也就是随着玩家消除的行数增加,经验条也增加,当经验条满了之后则进行升级,我们这里的升级需要做两个事情,一个是增加方块的下落速度,另一个是更换整个游戏的背景,当然今天用不到这张图

代码编写

为了后期方便扩展,我们需要整理出一个比较规范的代码编写,因为我并不清楚Delphi实际开发的情况是什么样子的,所以我沿用了Java代码设计的思路,我想在这方面每个语言都应该是相同的,我将整个项目划分为了视图、业务和数据,存放的方式以单元为单位

数据单元

这个单元目前来讲只需要存放一个类,用于存储方块图形数据

  • 我之所以将初始化图形的数据放在initialization块内,主要是我想通过类方法直接调用,而在类内部貌似没有办法定义类似于类方法的类变量

  • getRandomSquare函数返回值的问题,它的返回值是一个数组,但是Delphi里面貌似没有办法直接返回数组,所以我将其定义为了一个类型,在调用该方法的时候用于接收的变量类型为uEntity.TArrayPoint。

  1. unit uEntity;
  2. interface
  3. uses
  4. Winapi.Windows, System.Generics.Collections;
  5. type
  6. TArrayPoint = array[0..3] of TPoint;
  7. TGameData = class
  8. private
  9. public
  10. class function getRandomSquare(RandowIndex: Integer): TArrayPoint;
  11. published
  12. end;
  13. implementation
  14. //此处定义的变量在其他单元无法引用
  15. var
  16. ArrayPoint: TArrayPoint;
  17. TypeConfig: TList<TArrayPoint>;
  18. { TGameData }
  19. {*------------------------------------------------------------------------------
  20. 根据指定的索引获取一个方块
  21. @param RandowIndex 索引
  22. @return 方块的做信息
  23. -------------------------------------------------------------------------------}
  24. class function TGameData.getRandomSquare(RandowIndex: Integer): TArrayPoint;
  25. begin
  26. Result := TypeConfig.Items[RandowIndex];
  27. Exit;
  28. end;
  29. initialization
  30. //组装俄罗斯方块的7中图形,这里面存储的实际是方块的x,y坐标
  31. TypeConfig := TList<TArrayPoint>.create;
  32. ArrayPoint[0] := TPoint.create(4, 0);
  33. ArrayPoint[1] := TPoint.create(3, 0);
  34. ArrayPoint[2] := TPoint.create(5, 0);
  35. ArrayPoint[3] := TPoint.create(6, 0);
  36. TypeConfig.Add(ArrayPoint);
  37. ArrayPoint[0] := TPoint.create(4, 0);
  38. ArrayPoint[1] := TPoint.create(3, 0);
  39. ArrayPoint[2] := TPoint.create(5, 0);
  40. ArrayPoint[3] := TPoint.create(4, 1);
  41. TypeConfig.Add(ArrayPoint);
  42. ArrayPoint[0] := TPoint.create(4, 0);
  43. ArrayPoint[1] := TPoint.create(3, 0);
  44. ArrayPoint[2] := TPoint.create(5, 0);
  45. ArrayPoint[3] := TPoint.create(3, 1);
  46. TypeConfig.Add(ArrayPoint);
  47. ArrayPoint[0] := TPoint.create(4, 0);
  48. ArrayPoint[1] := TPoint.create(5, 0);
  49. ArrayPoint[2] := TPoint.create(3, 1);
  50. ArrayPoint[3] := TPoint.create(4, 1);
  51. TypeConfig.Add(ArrayPoint);
  52. ArrayPoint[0] := TPoint.create(4, 0);
  53. ArrayPoint[1] := TPoint.create(5, 0);
  54. ArrayPoint[2] := TPoint.create(4, 1);
  55. ArrayPoint[3] := TPoint.create(5, 1);
  56. TypeConfig.Add(ArrayPoint);
  57. ArrayPoint[0] := TPoint.create(4, 0);
  58. ArrayPoint[1] := TPoint.create(3, 0);
  59. ArrayPoint[2] := TPoint.create(5, 0);
  60. ArrayPoint[3] := TPoint.create(5, 1);
  61. TypeConfig.Add(ArrayPoint);
  62. ArrayPoint[0] := TPoint.create(4, 0);
  63. ArrayPoint[1] := TPoint.create(3, 0);
  64. ArrayPoint[2] := TPoint.create(4, 1);
  65. ArrayPoint[3] := TPoint.create(5, 1);
  66. TypeConfig.Add(ArrayPoint);
  67. end.

业务功能单元

这个单元主要存放,方块控制的一些功能,例如绘制方块、方块下落等等

其中最复杂的一个方法就属于CreateWindow了,其实它并不复杂,只是稍微有点麻烦,我们需要切割图片,所以需要计算一下切割的坐标是多少

DrawImage(img, MakeRect(x, y,Width, Height), ix, iy, iw ,ih , UnitPixel);

这个函数稍微复杂一点,不过并不是太难理解,这个也是我们整个游戏界面的核心函数,它的具体含义是将图片的某一部分绘制到目标窗口的指定位置

x, y,Width, Height:为图片在窗口上显示的x,y坐标以及大小

ix, iy, iw ,ih:为获取图片的那一部分

  1. unit UnitGameService;
  2. interface
  3. uses
  4. uEntity, System.Generics.Collections, Vcl.Imaging.pngimage, Winapi.Windows,
  5. Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  6. Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  7. Vcl.ExtCtrls, Winapi.GDIPOBJ, Winapi.GDIPAPI;
  8. type
  9. TGameService = class
  10. public
  11. procedure DrawBackground(dc: HDC; x, y, width, Height: Integer);
  12. //绘制窗口
  13. procedure CreateWindow(dc: HDC; x, y, Width, Height: Integer);
  14. //绘制图形
  15. procedure DrawActWithImg(dc: HDC; speed: Integer; ArrayPoint: uEntity.TArrayPoint);
  16. end;
  17. implementation
  18. { TGameService }
  19. procedure TGameService.CreateWindow(dc: HDC; x, y, Width, Height: Integer);
  20. var
  21. img: TGPImage;
  22. Graphics: TGPGraphics;
  23. const
  24. BorderWidth: Integer = 7;
  25. begin
  26. Graphics := TGPGraphics.Create(dc);
  27. img := TGPImage.Create('D:\\Downloads\\BaiduNetdiskDownload\\俄罗斯方块\\Graphics\\window\\window.png');
  28. //左上角
  29. Graphics.DrawImage(img, MakeRect(x, y, BorderWidth, BorderWidth), 0, 0, BorderWidth, BorderWidth, UnitPixel);
  30. //左侧竖线
  31. Graphics.DrawImage(img, MakeRect(x, y + BorderWidth, BorderWidth, Height - BorderWidth), 0, BorderWidth, img.GetWidth - (img.GetWidth - BorderWidth), img.GetHeight - BorderWidth * 2, UnitPixel);
  32. //左下角
  33. Graphics.DrawImage(img, MakeRect(x, y + Height, BorderWidth, img.GetHeight), 0, img.GetWidth - BorderWidth, BorderWidth, img.GetHeight, UnitPixel);
  34. //底部中线
  35. Graphics.DrawImage(img, MakeRect(x + BorderWidth, y + Height, Width - BorderWidth, img.GetHeight), BorderWidth, img.GetHeight - BorderWidth, img.GetWidth - BorderWidth * 2, img.GetHeight, UnitPixel);
  36. //右下角
  37. Graphics.DrawImage(img, MakeRect(x + Width, y + Height, img.GetWidth, img.GetHeight), img.GetWidth - BorderWidth, img.GetHeight - BorderWidth, img.GetWidth, img.GetHeight, UnitPixel);
  38. //右侧竖线
  39. Graphics.DrawImage(img, MakeRect(x + Width, y + BorderWidth, img.GetWidth, Height - BorderWidth), img.GetWidth - BorderWidth, BorderWidth, img.GetWidth, img.GetHeight - BorderWidth * 2, UnitPixel);
  40. //右上角
  41. Graphics.DrawImage(img, MakeRect(x + Width, y, img.GetHeight, BorderWidth), img.GetWidth - BorderWidth, 0, img.GetHeight, BorderWidth, UnitPixel);
  42. //顶部中线
  43. Graphics.DrawImage(img, MakeRect(x + BorderWidth, y, Width - BorderWidth, BorderWidth), BorderWidth, 0, img.GetWidth - BorderWidth * 2, BorderWidth, UnitPixel);
  44. //中间
  45. Graphics.DrawImage(img, MakeRect(x + BorderWidth, y + BorderWidth, Width - BorderWidth, Height - BorderWidth), BorderWidth, BorderWidth, img.GetWidth - BorderWidth * 2, img.GetHeight - BorderWidth * 2, UnitPixel);
  46. Graphics.Free;
  47. end;
  48. type
  49. TArrayPoint = array[0..3] of TPoint;
  50. procedure TGameService.DrawActWithImg(dc: HDC; speed: integer; ArrayPoint: uEntity.TArrayPoint);
  51. var
  52. img: TGPImage;
  53. Graphics: TGPGraphics;
  54. const
  55. //每个方块的大小
  56. SIZE: integer = 32;
  57. var
  58. //显示方块的索引
  59. ActIndex: Integer;
  60. var
  61. x, y: integer;
  62. var
  63. i: Integer;
  64. begin
  65. ActIndex := 1;
  66. img := TGPImage.Create('D:\Downloads\BaiduNetdiskDownload\俄罗斯方块\Graphics\game\方块.jpg');
  67. Graphics := TGPGraphics.Create(dc);
  68. for i := Low(ArrayPoint) to High(ArrayPoint) do
  69. begin
  70. // left是左上角的x坐标
  71. x := ArrayPoint[i].x * SIZE;
  72. // Top是左上角的y坐标
  73. y := ArrayPoint[i].y * SIZE;
  74. Graphics.DrawImage(img, MakeRect(x, y + speed, SIZE, SIZE), ActIndex * 32, 0, img.GetWidth - 32 * 8, img.GetHeight, UnitPixel);
  75. end;
  76. Graphics.Free;
  77. img.Free;
  78. end;
  79. procedure TGameService.DrawBackground(dc: HDC; x, y, width, Height: Integer);
  80. var
  81. Graphics: TGPGraphics;
  82. Img: TGPImage;
  83. begin
  84. Img := TGPImage.Create('D:\\Downloads\\BaiduNetdiskDownload\\俄罗斯方块\\Graphics\\background\\016-ForestTown02.jpg');
  85. Graphics := TGPGraphics.Create(dc);
  86. Graphics.DrawImage(Img, MakeRect(x, y, width, Height), 0, 0, width, Img.GetHeight, UnitPixel);
  87. Graphics.Free;
  88. end;
  89. end.

视图

其实所谓的视图也就是界面部分的代码,这里主要是调用以及处理一些事件的代码

核心代码

  1. procedure TForm1.Button3Click(Sender: TObject);
  2. var
  3. ArrayPoint: uEntity.TArrayPoint;
  4. GameService: TGameService;
  5. begin
  6. Form1.Repaint;
  7. ArrayPoint := TGameData.getRandomSquare(TPublicUtil.GetRandomNum(0, 6));
  8. GameService := TGameService.create();
  9. //绘制背景
  10. GameService.DrawBackground(Image1.Canvas.Handle, 0, 0, 700, 600);
  11. //绘制窗口
  12. GameService.CreateWindow(Image1.Canvas.Handle, 20, 20, 400, 450);
  13. //绘制图形
  14. GameService.DrawActWithImg(Image1.Canvas.Handle, 100, ArrayPoint);
  15. end;

工具函数单元

该单元我一般用来存放一些不好分类或者调用频率比较高的函数,一般是类方法(换成Java的说法是静态方法,我不知道在Delphi中具体的称呼)

  1. unit uUtil;
  2. interface
  3. type
  4. TPublicUtil = class
  5. public
  6. class function GetRandomNum(Min, Max: Integer): Integer;
  7. end;
  8. implementation
  9. { TPublicUtil }
  10. {*------------------------------------------------------------------------------
  11. 随机产生一个指定范围内的整数
  12. @param Min 最小值
  13. @param Max 最大值
  14. @return
  15. -------------------------------------------------------------------------------}
  16. class function TPublicUtil.GetRandomNum(Min, Max: Integer): Integer;
  17. begin
  18. randomize;
  19. Result := random(Max) mod (Max - Min + 1) + Min;
  20. Exit;
  21. end;
  22. end.

最后

来一张效果图,我个人觉得还不错,虽然功能还没有做完

Delphi版俄罗斯方块-前奏的更多相关文章

  1. H5版俄罗斯方块(2)---游戏的基本框架和实现

    前言: 上文中谈到了H5版俄罗斯方块的需求和目标, 这次要实现一个可玩的版本. 但饭要一口一口吃, 很多东西并非一蹴而就. 本文将简单实现一个可玩的俄罗斯方块版本. 下一步会引入AI, 最终采用coc ...

  2. H5版俄罗斯方块(4)---火拼对战的雏形

    前言: 勿忘初心, 本系列的目标是实现一款类似QQ"火拼系列"的人机对战版俄罗斯方块. 在完成了基本游戏框架和AI的算法探索后, 让我们来尝试一下人机大战雏形编写. 本系列的文章链 ...

  3. 十六进制字符串转化成字符串输出HexToStr(Delphi版、C#版)

    //注意:Delphi2010以下版本默认的字符编码是ANSI,VS2010的默认编码是UTF-8,delphi版得到的字符串须经过Utf8ToAnsi()转码才能跟C#版得到的字符串显示结果一致. ...

  4. 通过崩溃地址找错误行数之Delphi版

    通过崩溃地址找错误行数之Delphi版2009-5-11 17:42:35 来源: 转载 作者:网络 访问:360 次 被顶:2 次 字号:[大 中 小]核心提示:什么是 MAP 文件?简单地讲, M ...

  5. Delphi版IP地址与整型互转

    Delphi版IP地址与整型互转 unit Unit11; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphic ...

  6. 从内存中加载DLL Delphi版(转)

    源:从内存中加载DLL DELPHI版 原文 : http://www.2ccc.com/article.asp?articleid=5784 MemLibrary.pas //从内存中加载DLL D ...

  7. 雪花算法(snowflake)delphi版

    雪花算法简单描述: + 最高位是符号位,始终为0,不可用. + 41位的时间序列,精确到毫秒级,41位的长度可以使用69年.时间位还有一个很重要的作用是可以根据时间进行排序. + 10位的机器标识,1 ...

  8. 二维码生成delphi版

    二维码生成delphi版 生成二维码的软件,代码从C语言转换过来(源地址:http://fukuchi.org/works/qrencode/),断断续续的差不多花了一周时间来转换和调试.在转换过程中 ...

  9. 从内存中加载DLL DELPHI版

    //从内存中加载DLL DELPHI版 unit MemLibrary; interface uses Windows; function memLoadLibrary(pLib: Pointer): ...

随机推荐

  1. 纯css制作小三角

    在网站制作的过程中常涉及一些小图标,以前大部分会采用小图片.但有了css3后很多变得方便了,比如要在li列表的每行文字的前面加个小三角,可以这么写: <!DOCTYPE html> < ...

  2. Linux 实用指令(10)-RPM和YUM

    目录 RPM 和 YUM 1 rpm 包的管理 1.1 介绍 1.2 rpm包的简单查询指令 1.3 rpm包名基本格式 1.4 rpm包的其他查询指令: 1.5 卸载rpm 包 1.6 安装rpm包 ...

  3. Windows服务调试状态下用Console启动

    最近一直在用服务,发现服务也没有那么难调试. Windows服务调试状态下用Console启动:步骤分两步 第一步改Program,启动代码 static class Program { /// &l ...

  4. mantis 添加新状态配置方法

    在mantis的状态栏中一般只有:新建.反馈.认可.已确认.已分派.已解决.已关闭,七个选项,如果想在其中加入新的状态怎么做? 我要加入的状态为:重新打开 1.添加状态信息 打开config_defa ...

  5. Delphi 最小化窗体到托盘

    ---- 现在很多的应用程序都有这样一种功能,当用户选择最小化窗口时,窗口不是象平常那样最小化到任务栏上,而是“最小化”成一个任务栏图标.象FoxMail 3.0 NetVampire 3.0等都提供 ...

  6. Kibana启动报错 server is not ready yet的解决方案

    前言: ​ 今天在搭建elasticsearch集群的时候,再次使用Kibana操作elasticsearch的时候报告Kibana server is not ready yet的问题, ​ 通过在 ...

  7. BZOJ 2660 (BJOI 2012) 最多的方案

    Description 第二关和很出名的斐波那契数列有关,地球上的OIer都知道:F1=1, F2=2, Fi = Fi-1 + Fi-2,每一项都可以称为斐波那契数.现在给一个正整数N,它可以写成一 ...

  8. hibernate_06_hibernate的延迟加载和抓取策略

    1.延迟加载 1>类级别的延迟加载 指的是通过oad方法查询某个对象的时候,是否采用延迟, session. load(Customer class1L) 类级别延迟加载通过<class& ...

  9. JDK1.8中文CHM下载 -- java开发搬运工

    网上一番查找后,发现csdn有,但是要收费,之后从某地找到热心网友的分享,现贡献给大家! 不啰嗦,直接上货! 链接:https://pan.baidu.com/s/1b6Wg7LiUZsFSYGsvR ...

  10. <Django>第一篇:入门的例子

    1.MVT框架 Model(模型):数据库交互相关.在这部分一般需要进行三个操作: (1)面向数据库:模型对象.列表 (2)定义模型类:指定属性及类型,确定表结构(设计表),需要迁移(生成表) (3) ...