タイル状に画像を敷き詰める
今回は画像をタイル状に敷き詰めるサンプルです。左上からタイリングを行うだけでは芸が無いので左下や右上、中央などを基準にタイリングできる関数です。
基本的に描画する関数はX、Y座標から画像のサイズ分だけインクリメントしながら描画していくだけで、描画を開始するX、Y座標を色々変えてやる事で実現しています。

type           {高 <----------- 優先順位 -----------> 低}
  TTileState = (tsLeft, tsTop, tsRight, tsBottom, tsCenter);
  TTileStates = set of TTileState;

procedure DrawTile(TileStates: TTileStates; Dest: TCanvas; DstWidth,
   DstHeight: Integer; Graphic: TGraphic);

implementation

function CalcStartPos(SrcH, DefValue: Integer): Integer;
//DefValue <= 0 になるまでSrcHでデクリメント-------------------------------
begin
  while DefValue > 0 do
    Dec(DefValue, SrcH);
  Result := DefValue;
end;

procedure CustomTileDraw(Dest: TCanvas; const X, Y, Width, Height: Integer;
  Graphic: TGraphic);
//実際に描画を行う関数-----------------------------------------------------
var
  px, py: Integer;
begin
  { 描画開始位置を初期化 }
  py := Y;
  px := X;
  { 描画開始位置がWidthとHeightを超えないようにループしながら }
  { 描画していくだけでタイリングが出来ます                    }
  while py < Height do
  begin
    while px < Width do
    begin
      Dest.Draw(px, py, Graphic);
      Inc(px, Graphic.Width);
    end;
    Inc(py, Graphic.Height);
    px := X;//X座標を元に戻す
  end;
end;

procedure DrawTile(TileStates: TTileStates; Dest: TCanvas; DstWidth,
   DstHeight: Integer; Graphic: TGraphic);
//タイリング関数-----------------------------------------------------------
var
  X, Y: Integer;
begin
  { DrawStartExsには共存できないフラグがあるので注意して下さい。}
  { 集合の要素の優先順位は要素の順序型の値が低い程高くなります。}
  { (つまりdteLeftが最も高くdteCenterが最も低い)                }
  { [dteLeft, dteTop, dteRight, dteBottom]は[dteLeft, dteTop]に }
  { 解釈されます。空の集合は[dteLeft, dteTop]と解釈されます。   }
  if (Graphic = nil) or (Dest = nil) then Exit;
  with Graphic do
  begin
    if tsCenter in TileStates then
    begin
    //tsCenterが含まれている場合
      { tsCenterよりも他のフラグの方が優先順位が高いので... }
      if tsLeft in TileStates then
        X := 0//左基準
      else
        if tsRight in TileStates then
          X := CalcStartPos(Width, DstWidth - Width)//右基準
        else//tsLeft, tsRightが含まれない場合中央基準
          X := CalcStartPos(Width , (DstWidth  - Width ) div 2);

      if tsTop in TileStates then
        Y := 0//上基準
      else
        if tsBottom in TileStates then
          Y := CalcStartPos(Height, DstHeight - Height)//下基準
        else//tsTop, tsBottomが含まれない場合は中央基準
          Y := CalcStartPos(Height, (DstHeight - Height) div 2);
    end else begin
    //tsCenterが含まれない場合
      if not (tsRight in TileStates) then
        X := 0//tsRightよりもtsLeft(空も含め)他方が優先順位が高い
      else
        X := CalcStartPos(Width, DstWidth - Width);
      if not (tsBottom in TileStates) then
        Y := 0//tsBottomよりもtsTop(空も含め)他方が優先順位が高い
      else
        Y := CalcStartPos(Height, DstHeight - Height);
    end;
    //座標の計算が終わったらタイリングを行う関数に渡す
    CustomTileDraw(Dest, X, Y, DstWidth, DstHeight, Graphic);
  end;
end;

指定領域にタイリングを行うような関数を作ると面白いかもしれませんね。頑張ってみてください<やらんのか(^^;

Back    Prev    Next