zoukankan      html  css  js  c++  java
  • 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:DownloadsBaiduNetdiskDownload俄罗斯方块Graphicsgame方块.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.
    
    

    最后

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

  • 相关阅读:
    JavaScript And Ajax(JavaScript 基本示例)
    JavaScript And Ajax(JavaScript 本质)
    LINQ(LINQ to Entities)
    XML (转换)
    XML 搜索和验证(XmlDocument、XPath to XmlDocument、LINQ to XDocument)
    图形、GDI + 和图表(Chart 控件)
    XML(简介)
    图形、GDI + 和图表(在网页上嵌入动态图形)
    网站导航(URL 映射和路由)
    JavaScript And Ajax(在客户端回调中使用 Ajax)
  • 原文地址:https://www.cnblogs.com/coder163/p/11438321.html
Copyright © 2011-2022 走看看