FireMonkey3D之中国象棋程序(一)界面设计
声明:本程序设计参考象棋巫师源码(开发工具dephi 11,建议用delphi 10.3以上版本)。
第一步我们设计图形界面,显示初始化棋局。效果如下图:
我们先做个3D象棋子控件(请看我的博客关于FireMonkey3D的文章:万能控件Mesh详解),源码如下:
unit ChessPiece; interface uses System.SysUtils,System.Types,System.UITypes,System.Classes, FMX.Types, FMX.Controls3D, FMX.Objects3D,FMX.Types3D, FMX.Materials,System.Math.Vectors,FMX.Graphics,System.Math,System.RTLConsts; type TChessPiece = class(TControl3D) private FMat:TLightMaterial; FBitmap:TTextureBitmap; FChessName:string; FSide,FID:Byte;//ID为棋子序号 FColor:TAlphaColor; procedure SetChessName(const Value:string); procedure SetSide(const Value:Byte); procedure SetID(const Value:Byte); procedure DrawPiece; protected procedure Render; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property ChessName:string read FChessName write SetChessName; property Side:Byte read FSide write SetSide default 0; property id:Byte read FID write SetID; property Cursor default crDefault; property DragMode default TDragMode.dmManual; property Position; property Scale; property RotationAngle; property Locked default False; property Width; property Height; property Depth nodefault; property Opacity nodefault; property Projection; property HitTest default True; property VisibleContextMenu default True; property Visible default True; property ZWrite default True; property OnDragEnter; property OnDragLeave; property OnDragOver; property OnDragDrop; property OnDragEnd; property OnClick; property OnDblClick; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnMouseWheel; property OnMouseEnter; property OnMouseLeave; property OnKeyDown; property OnKeyUp; property OnRender; end; procedure Register; implementation procedure TChessPiece.DrawPiece; var Rect:TRectF; begin with FBitmap do begin Canvas.BeginScene; Clear($FFFFFFFF); Rect:=TRectF.Create(2,2,98,98); Canvas.Stroke.Thickness:=2; Canvas.Stroke.Color:=FColor; Canvas.DrawEllipse(Rect,1); Canvas.Fill.Color:=FColor; Canvas.FillText(Rect,FChessName,false,1,[TFillTextFlag.RightToLeft],TTextAlign.Center,TTextAlign.Center); Canvas.EndScene; end; Repaint; end; constructor TChessPiece.Create(AOwner: TComponent); begin inherited; FColor:=$FFFF0000; FChessName:="车"; FMat:=TLightMaterial.Create; FMat.Emissive:=TAlphaColorRec.Burlywood; FBitmap:=TTextureBitmap.Create; with FBitmap do begin SetSize(100,200); Canvas.Font.Family:="方正隶书繁体"; Canvas.Font.Size:=85; end; DrawPiece; end; destructor TChessPiece.Destroy; begin FMat.Free; FBitmap.Free; inherited; end; procedure TChessPiece.SetChessName(const Value:string); begin if FChessName <> Value then begin FChessName := Value; DrawPiece; end; end; procedure TChessPiece.SetSide(const Value:Byte); begin if FSide <> Value then begin FSide := Value; case FSide of 0: FColor:=$FFFF0000; 1: FColor:=$FF24747D; end; DrawPiece; end; end; procedure TChessPiece.SetID(const Value:Byte); begin if FID<>value then FID:=Value; end; procedure TChessPiece.Render; var i,j,k,VH,VW,AA,BB,M:Integer; indice:array of Integer; P,P1:TPoint3D; Ver:TVertexBuffer; Idx:TIndexBuffer; Pt:TPointF; Angle,H,D,R:Single;//H:前后圆的半径Height/2,R:棋子周边圆弧的半径,D棋子的厚度Height/5 begin VH:=32;VW:=12; indice:=[0,1,3,0,3,2]; H:=0.5*Height; D:=0.2*Height; R:=D/sin(DegToRad(48)); FMat.Texture:=nil; FMat.Texture:=FBitmap.Texture; Ver:=TVertexBuffer.Create([TVertexFormat.Vertex,TVertexFormat.Normal,TVertexFormat.TexCoord0],VH*VW*4+VH*2); Idx:=TIndexBuffer.Create(VH*6*VW+VH*6-12,TIndexFormat.UInt32); AA:=0;BB:=0; //Around棋子周边 for I := 0 to VH-1 do for J := 0 to VW-1 do begin for k := 0 to 1 do begin Angle:=DegToRad((318-(j+k)*8)); P:=Point3D(0,R*sin(Angle),R*Cos(Angle)); P1:=P/R; P.Offset(0,-R*Sin(DegToRad(318))-H,0); Ver.Vertices[AA+k*2]:=P*TMatrix3D.CreateRotationZ(2*Pi/VH*i); Ver.Normals[AA+k*2]:=P1*TMatrix3D.CreateRotationZ(2*Pi/VH*i); Ver.Vertices[AA+k*2+1]:=P*TMatrix3D.CreateRotationZ(2*Pi/VH*(i+1)); Ver.Normals[AA+k*2+1]:=P1*TMatrix3D.CreateRotationZ(2*Pi/VH*(i+1)); //按横向、纵向细分一个贴图 Ver.TexCoord0[AA+k*2]:=PointF(1/12*(J+k),I/128+0.5); Ver.TexCoord0[AA+k*2+1]:=PointF(1/12*(J+k),(I+1)/128+0.5); end; inc(AA,4); for k :=0 to 5 do begin Idx.Indices[BB]:=indice[k]+4*(BB div 6); inc(BB); end; end; //Front Back 前后圆 M:=AA; for I := 0 to VH-1 do begin P:=Point3D(0,-H,-D); Ver.Vertices[AA]:=P*TMatrix3D.CreateRotationZ(2*Pi/VH*i); Ver.Normals[AA]:=Point3D(0,0,-1); Pt:=PointF(0,-0.5).Rotate(2*Pi/VH*i); Pt.Offset(0.5,0.5); Ver.TexCoord0[AA]:=PointF(Pt.x,Pt.y/2);; P:=Point3D(0,-H,D); Ver.Vertices[AA+1]:=P*TMatrix3D.CreateRotationZ(2*Pi/VH*i); Ver.Normals[AA+1]:=Point3D(0,0,1); Ver.TexCoord0[AA+1]:=PointF(Pt.x,Pt.y/2+0.5); Inc(AA,2); end; for I := 0 to VH-3 do begin Idx.Indices[BB]:=M+2+I*2; Idx.Indices[BB+1]:=M+4+I*2; Idx.Indices[BB+2]:=M; Idx.Indices[BB+3]:=M+5+I*2; Idx.Indices[BB+4]:=M+3+i*2; Idx.Indices[BB+5]:=M+1; Inc(BB,6); end; Context.DrawTriangles(ver,idx,FMat,Opacity); Ver.Free; Idx.Free; end; procedure Register; begin RegisterComponents("3D Others", [TChessPiece]); end; end.