Delphi版俄罗斯方块-前奏
前言
基础知识讲了很多,但是并没有串联起来,所以我最近一直在准备个小项目,但是这个项目的要求不含有数据库部分,也就是数据持久存储的功能,此外不能含有网络功能,它只是对基础知识的一个总结,最后一点是这个项目可以后期进行扩展,加上网络和数据库部分,所以最终选择俄罗斯方块这个小游戏作为基础知识总结的结课项目,因为这个小游戏可以扩展成为双人或者多人对战,同时保存每个人的对战信息
素材准备
我们的课程一直使用的是VCL,VCL原生的窗口太丑,所以需要做一点美化,准备一些图片,不至于让做出来的东西自己都不想看

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


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

这张图片有意思了,用于经验条显示的,也就是随着玩家消除的行数增加,经验条也增加,当经验条满了之后则进行升级,我们这里的升级需要做两个事情,一个是增加方块的下落速度,另一个是更换整个游戏的背景,当然今天用不到这张图
代码编写
为了后期方便扩展,我们需要整理出一个比较规范的代码编写,因为我并不清楚Delphi实际开发的情况是什么样子的,所以我沿用了Java代码设计的思路,我想在这方面每个语言都应该是相同的,我将整个项目划分为了视图、业务和数据,存放的方式以单元为单位
数据单元
这个单元目前来讲只需要存放一个类,用于存储方块图形数据
我之所以将初始化图形的数据放在initialization块内,主要是我想通过类方法直接调用,而在类内部貌似没有办法定义类似于类方法的类变量
getRandomSquare函数返回值的问题,它的返回值是一个数组,但是Delphi里面貌似没有办法直接返回数组,所以我将其定义为了一个类型,在调用该方法的时候用于接收的变量类型为uEntity.TArrayPoint。
unit uEntity;
interface
uses
Winapi.Windows, System.Generics.Collections;
type
TArrayPoint = array[0..3] of TPoint;
TGameData = class
private
public
class function getRandomSquare(RandowIndex: Integer): TArrayPoint;
published
end;
implementation
//此处定义的变量在其他单元无法引用
var
ArrayPoint: TArrayPoint;
TypeConfig: TList<TArrayPoint>;
{ TGameData }
{*------------------------------------------------------------------------------
根据指定的索引获取一个方块
@param RandowIndex 索引
@return 方块的做信息
-------------------------------------------------------------------------------}
class function TGameData.getRandomSquare(RandowIndex: Integer): TArrayPoint;
begin
Result := TypeConfig.Items[RandowIndex];
Exit;
end;
initialization
//组装俄罗斯方块的7中图形,这里面存储的实际是方块的x,y坐标
TypeConfig := TList<TArrayPoint>.create;
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(3, 0);
ArrayPoint[2] := TPoint.create(5, 0);
ArrayPoint[3] := TPoint.create(6, 0);
TypeConfig.Add(ArrayPoint);
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(3, 0);
ArrayPoint[2] := TPoint.create(5, 0);
ArrayPoint[3] := TPoint.create(4, 1);
TypeConfig.Add(ArrayPoint);
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(3, 0);
ArrayPoint[2] := TPoint.create(5, 0);
ArrayPoint[3] := TPoint.create(3, 1);
TypeConfig.Add(ArrayPoint);
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(5, 0);
ArrayPoint[2] := TPoint.create(3, 1);
ArrayPoint[3] := TPoint.create(4, 1);
TypeConfig.Add(ArrayPoint);
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(5, 0);
ArrayPoint[2] := TPoint.create(4, 1);
ArrayPoint[3] := TPoint.create(5, 1);
TypeConfig.Add(ArrayPoint);
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(3, 0);
ArrayPoint[2] := TPoint.create(5, 0);
ArrayPoint[3] := TPoint.create(5, 1);
TypeConfig.Add(ArrayPoint);
ArrayPoint[0] := TPoint.create(4, 0);
ArrayPoint[1] := TPoint.create(3, 0);
ArrayPoint[2] := TPoint.create(4, 1);
ArrayPoint[3] := TPoint.create(5, 1);
TypeConfig.Add(ArrayPoint);
end.
业务功能单元
这个单元主要存放,方块控制的一些功能,例如绘制方块、方块下落等等
其中最复杂的一个方法就属于CreateWindow了,其实它并不复杂,只是稍微有点麻烦,我们需要切割图片,所以需要计算一下切割的坐标是多少
DrawImage(img, MakeRect(x, y,Width, Height), ix, iy, iw ,ih , UnitPixel);
这个函数稍微复杂一点,不过并不是太难理解,这个也是我们整个游戏界面的核心函数,它的具体含义是将图片的某一部分绘制到目标窗口的指定位置
x, y,Width, Height:为图片在窗口上显示的x,y坐标以及大小
ix, iy, iw ,ih:为获取图片的那一部分
unit UnitGameService;
interface
uses
uEntity, System.Generics.Collections, Vcl.Imaging.pngimage, Winapi.Windows,
Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
Vcl.ExtCtrls, Winapi.GDIPOBJ, Winapi.GDIPAPI;
type
TGameService = class
public
procedure DrawBackground(dc: HDC; x, y, width, Height: Integer);
//绘制窗口
procedure CreateWindow(dc: HDC; x, y, Width, Height: Integer);
//绘制图形
procedure DrawActWithImg(dc: HDC; speed: Integer; ArrayPoint: uEntity.TArrayPoint);
end;
implementation
{ TGameService }
procedure TGameService.CreateWindow(dc: HDC; x, y, Width, Height: Integer);
var
img: TGPImage;
Graphics: TGPGraphics;
const
BorderWidth: Integer = 7;
begin
Graphics := TGPGraphics.Create(dc);
img := TGPImage.Create('D:\\Downloads\\BaiduNetdiskDownload\\俄罗斯方块\\Graphics\\window\\window.png');
//左上角
Graphics.DrawImage(img, MakeRect(x, y, BorderWidth, BorderWidth), 0, 0, BorderWidth, BorderWidth, UnitPixel);
//左侧竖线
Graphics.DrawImage(img, MakeRect(x, y + BorderWidth, BorderWidth, Height - BorderWidth), 0, BorderWidth, img.GetWidth - (img.GetWidth - BorderWidth), img.GetHeight - BorderWidth * 2, UnitPixel);
//左下角
Graphics.DrawImage(img, MakeRect(x, y + Height, BorderWidth, img.GetHeight), 0, img.GetWidth - BorderWidth, BorderWidth, img.GetHeight, UnitPixel);
//底部中线
Graphics.DrawImage(img, MakeRect(x + BorderWidth, y + Height, Width - BorderWidth, img.GetHeight), BorderWidth, img.GetHeight - BorderWidth, img.GetWidth - BorderWidth * 2, img.GetHeight, UnitPixel);
//右下角
Graphics.DrawImage(img, MakeRect(x + Width, y + Height, img.GetWidth, img.GetHeight), img.GetWidth - BorderWidth, img.GetHeight - BorderWidth, img.GetWidth, img.GetHeight, UnitPixel);
//右侧竖线
Graphics.DrawImage(img, MakeRect(x + Width, y + BorderWidth, img.GetWidth, Height - BorderWidth), img.GetWidth - BorderWidth, BorderWidth, img.GetWidth, img.GetHeight - BorderWidth * 2, UnitPixel);
//右上角
Graphics.DrawImage(img, MakeRect(x + Width, y, img.GetHeight, BorderWidth), img.GetWidth - BorderWidth, 0, img.GetHeight, BorderWidth, UnitPixel);
//顶部中线
Graphics.DrawImage(img, MakeRect(x + BorderWidth, y, Width - BorderWidth, BorderWidth), BorderWidth, 0, img.GetWidth - BorderWidth * 2, BorderWidth, UnitPixel);
//中间
Graphics.DrawImage(img, MakeRect(x + BorderWidth, y + BorderWidth, Width - BorderWidth, Height - BorderWidth), BorderWidth, BorderWidth, img.GetWidth - BorderWidth * 2, img.GetHeight - BorderWidth * 2, UnitPixel);
Graphics.Free;
end;
type
TArrayPoint = array[0..3] of TPoint;
procedure TGameService.DrawActWithImg(dc: HDC; speed: integer; ArrayPoint: uEntity.TArrayPoint);
var
img: TGPImage;
Graphics: TGPGraphics;
const
//每个方块的大小
SIZE: integer = 32;
var
//显示方块的索引
ActIndex: Integer;
var
x, y: integer;
var
i: Integer;
begin
ActIndex := 1;
img := TGPImage.Create('D:\Downloads\BaiduNetdiskDownload\俄罗斯方块\Graphics\game\方块.jpg');
Graphics := TGPGraphics.Create(dc);
for i := Low(ArrayPoint) to High(ArrayPoint) do
begin
// left是左上角的x坐标
x := ArrayPoint[i].x * SIZE;
// Top是左上角的y坐标
y := ArrayPoint[i].y * SIZE;
Graphics.DrawImage(img, MakeRect(x, y + speed, SIZE, SIZE), ActIndex * 32, 0, img.GetWidth - 32 * 8, img.GetHeight, UnitPixel);
end;
Graphics.Free;
img.Free;
end;
procedure TGameService.DrawBackground(dc: HDC; x, y, width, Height: Integer);
var
Graphics: TGPGraphics;
Img: TGPImage;
begin
Img := TGPImage.Create('D:\\Downloads\\BaiduNetdiskDownload\\俄罗斯方块\\Graphics\\background\\016-ForestTown02.jpg');
Graphics := TGPGraphics.Create(dc);
Graphics.DrawImage(Img, MakeRect(x, y, width, Height), 0, 0, width, Img.GetHeight, UnitPixel);
Graphics.Free;
end;
end.
视图
其实所谓的视图也就是界面部分的代码,这里主要是调用以及处理一些事件的代码
核心代码
procedure TForm1.Button3Click(Sender: TObject);
var
ArrayPoint: uEntity.TArrayPoint;
GameService: TGameService;
begin
Form1.Repaint;
ArrayPoint := TGameData.getRandomSquare(TPublicUtil.GetRandomNum(0, 6));
GameService := TGameService.create();
//绘制背景
GameService.DrawBackground(Image1.Canvas.Handle, 0, 0, 700, 600);
//绘制窗口
GameService.CreateWindow(Image1.Canvas.Handle, 20, 20, 400, 450);
//绘制图形
GameService.DrawActWithImg(Image1.Canvas.Handle, 100, ArrayPoint);
end;
工具函数单元
该单元我一般用来存放一些不好分类或者调用频率比较高的函数,一般是类方法(换成Java的说法是静态方法,我不知道在Delphi中具体的称呼)
unit uUtil;
interface
type
TPublicUtil = class
public
class function GetRandomNum(Min, Max: Integer): Integer;
end;
implementation
{ TPublicUtil }
{*------------------------------------------------------------------------------
随机产生一个指定范围内的整数
@param Min 最小值
@param Max 最大值
@return
-------------------------------------------------------------------------------}
class function TPublicUtil.GetRandomNum(Min, Max: Integer): Integer;
begin
randomize;
Result := random(Max) mod (Max - Min + 1) + Min;
Exit;
end;
end.
最后
来一张效果图,我个人觉得还不错,虽然功能还没有做完

Delphi版俄罗斯方块-前奏的更多相关文章
- H5版俄罗斯方块(2)---游戏的基本框架和实现
前言: 上文中谈到了H5版俄罗斯方块的需求和目标, 这次要实现一个可玩的版本. 但饭要一口一口吃, 很多东西并非一蹴而就. 本文将简单实现一个可玩的俄罗斯方块版本. 下一步会引入AI, 最终采用coc ...
- H5版俄罗斯方块(4)---火拼对战的雏形
前言: 勿忘初心, 本系列的目标是实现一款类似QQ"火拼系列"的人机对战版俄罗斯方块. 在完成了基本游戏框架和AI的算法探索后, 让我们来尝试一下人机大战雏形编写. 本系列的文章链 ...
- 十六进制字符串转化成字符串输出HexToStr(Delphi版、C#版)
//注意:Delphi2010以下版本默认的字符编码是ANSI,VS2010的默认编码是UTF-8,delphi版得到的字符串须经过Utf8ToAnsi()转码才能跟C#版得到的字符串显示结果一致. ...
- 通过崩溃地址找错误行数之Delphi版
通过崩溃地址找错误行数之Delphi版2009-5-11 17:42:35 来源: 转载 作者:网络 访问:360 次 被顶:2 次 字号:[大 中 小]核心提示:什么是 MAP 文件?简单地讲, M ...
- Delphi版IP地址与整型互转
Delphi版IP地址与整型互转 unit Unit11; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphic ...
- 从内存中加载DLL Delphi版(转)
源:从内存中加载DLL DELPHI版 原文 : http://www.2ccc.com/article.asp?articleid=5784 MemLibrary.pas //从内存中加载DLL D ...
- 雪花算法(snowflake)delphi版
雪花算法简单描述: + 最高位是符号位,始终为0,不可用. + 41位的时间序列,精确到毫秒级,41位的长度可以使用69年.时间位还有一个很重要的作用是可以根据时间进行排序. + 10位的机器标识,1 ...
- 二维码生成delphi版
二维码生成delphi版 生成二维码的软件,代码从C语言转换过来(源地址:http://fukuchi.org/works/qrencode/),断断续续的差不多花了一周时间来转换和调试.在转换过程中 ...
- 从内存中加载DLL DELPHI版
//从内存中加载DLL DELPHI版 unit MemLibrary; interface uses Windows; function memLoadLibrary(pLib: Pointer): ...
随机推荐
- [转载]Spring AOP 深入剖析
转载自 http://www.cnblogs.com/digdeep/p/4528353.html 多谢@digdeep AOP是Spring提供的关键特性之一.AOP即面向切面编程,是OOP编程的有 ...
- GetOpenFilename的基本用法(文件夹实操)
Sub 数据导入()Dim f, arr, i&, j&, k, m%, n%, p%, sh As Workbookf = Application.GetOpenFilename(f ...
- 【JDK】:java.lang.Integer源码解析
本文对JDK8中的java.lang.Integer包装类的部分数值缓存技术.valueOf().stringSize().toString().getChars().parseInt()等进行简要分 ...
- The linux command 之引用
[me@linuxbox ~]$ echo this is a test this is a test shell 会对echo进行单词分割(word splitting)去除多余的空白. [me@l ...
- postman报InvalidArgumentException
解决方案:
- 记一次付工解决Sqlserver问题的过程
问题:Sqlserver连接不上 1 检查自身 Sqlserve服务是否开启 Windows服务是否开启 2 用CMD尝试连接Sqlserver 显示详细错误 由于文件不可访问,或者内存或磁盘空间不 ...
- Java 基础 - 如何重写equals()
ref:https://www.cnblogs.com/TinyWalker/p/4834685.html -------------------- 编写equals方法的建议: 显示参数命名为oth ...
- thinkphp 模版引擎
系统支持原生的PHP模板,而且本身内置了一个基于XML的高效的编译型模板引擎,系统默认使用的模板引擎是内置模板引擎,关于这个模板引擎的标签详细使用可以参考模版引擎部分. 内置的大理石平台检定规程模板引 ...
- Eclipse中servlet简易模版
package ${enclosing_package}; import java.io.IOException; import javax.servlet.ServletException; imp ...
- Xadmin+layUi Net框架
1.引用xadmin layui 2.autofac+dapper+mvc 3.效果展示 4.github https://github.com/sulin888/LsProject 登录密码:Ad ...