No dobra, zrobiłem własny mechanizm malowania konturu, który dla każdego mieszczącego się w kamerze hitboksa maluje linie jego ścian. Narzut wynikający z renderowania linii wynosi raptem 1%, ale to i tak nieważne, bo ta funkcja jest dostępna tylko w trybie debugowania. ;)
Aby można było malować linie, najpierw trzeba znać zakres kafli widocznych na ekranie. Klasa kamery przechowuje widoczny obszar liczony w pikselach, więc dodałem sobie nową właściwość, która na jego podstawie oblicza i zwraca obszar liczony w kaflach:
type
TCamera = class(TObject)
{..}
private
function GetHitBoxesZone(): TRect;
public
property HitBoxesZone: TRect read GetHitBoxesZone;
end;
function TCamera.GetHitBoxesZone(): TRect;
begin
Result.Left := FViewZone.Left div TILE_SIZE;
Result.Right := FViewZone.Right div TILE_SIZE;
Result.Top := FViewZone.Top div TILE_SIZE;
Result.Bottom := FViewZone.Bottom div TILE_SIZE;
if FViewZone.Right mod TILE_SIZE <> 0 then Result.Right += 1;
if FViewZone.Bottom mod TILE_SIZE <> 0 then Result.Bottom += 1;
end;
Następnie do klasy renderera poziomu dodałem metodę umożliwiającą namalowanie wszystkich czterech ścian hitboksu:
type
TLevelRenderer = class(TObject)
{..}
private
procedure RenderHitBoxContour(ALayer: TLayer; ACamera: TCamera; AColumn, ARow: Integer);
end;
procedure TLevelRenderer.RenderHitBoxContour(ALayer: TLayer; ACamera: TCamera; AColumn, ARow: Integer);
begin
if not ALayer.HitBox[AColumn - 1, ARow] then
Buffers.Master.Canvas.Line(
ACamera.ToDisplayPoint(AColumn * TILE_SIZE, ARow * TILE_SIZE),
ACamera.ToDisplayPoint(AColumn * TILE_SIZE, ARow * TILE_SIZE + TILE_SIZE)
);
if not ALayer.HitBox[AColumn + 1, ARow] then
Buffers.Master.Canvas.Line(
ACamera.ToDisplayPoint(AColumn * TILE_SIZE + TILE_SIZE - 1, ARow * TILE_SIZE),
ACamera.ToDisplayPoint(AColumn * TILE_SIZE + TILE_SIZE - 1, ARow * TILE_SIZE + TILE_SIZE)
);
if not ALayer.HitBox[AColumn, ARow - 1] then
Buffers.Master.Canvas.Line(
ACamera.ToDisplayPoint(AColumn * TILE_SIZE, ARow * TILE_SIZE),
ACamera.ToDisplayPoint(AColumn * TILE_SIZE + TILE_SIZE, ARow * TILE_SIZE)
);
if not ALayer.HitBox[AColumn, ARow + 1] then
Buffers.Master.Canvas.Line(
ACamera.ToDisplayPoint(AColumn * TILE_SIZE, ARow * TILE_SIZE + TILE_SIZE - 1),
ACamera.ToDisplayPoint(AColumn * TILE_SIZE + TILE_SIZE, ARow * TILE_SIZE + TILE_SIZE - 1)
);
end;
oraz ogólną metodę renderującą kontur wszystkich hitboksów mieszczących się na ekranie:
type
TLevelRenderer = class(TObject)
{..}
public
procedure RenderContour(ALevel: TLevel);
end;
procedure TLevelRenderer.RenderContour(ALevel: TLevel);
var
Column, Row: Integer;
begin
Buffers.Master.Canvas.Pen.Color := COLOR_LAYER_CONTOUR;
Buffers.Master.Canvas.Pen.Style := psDot;
Buffers.Master.Canvas.Brush.Style := bsClear;
for Row := ALevel.Camera.HitBoxesZone.Top to ALevel.Camera.HitBoxesZone.Bottom do
for Column := ALevel.Camera.HitBoxesZone.Left to ALevel.Camera.HitBoxesZone.Right do
if ALevel.CurrentLayer.HitBox[Column, Row] then
RenderHitBoxContour(ALevel.CurrentLayer, ALevel.Camera, Column, Row);
Buffers.Master.Canvas.Pen.Style := psSolid;
Buffers.Master.Canvas.Brush.Style := bsSolid;
end;
Niżej efekt końcowy (dwie najbliższe warstwy są ukryte, aby nie przeszkadzały w testowaniu kolizji):