All files / src/shared/lib/collisions collisionTiles.ts

30.77% Statements 12/39
54.55% Branches 6/11
33.33% Functions 1/3
28.57% Lines 10/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 771x     1x 1x   1x                                                                                                         1x       7x 7x 7x 2x             5x      
import { TILE_SIZE } from "consts";
import { CollisionTileDef } from "shared/lib/resources/types";
 
const collisonTileMaskCache: Record<string, ImageData> = {};
const collisonTileCache: Record<string, HTMLCanvasElement> = {};
 
export const renderCollisionTileIcon = (
  icon: string,
  color: string
): HTMLCanvasElement => {
  const key = `${color}:${icon}`;
 
  // Use cached if available
  const cachedIcon = collisonTileCache[key];
  Iif (cachedIcon) {
    return cachedIcon;
  }
 
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
 
  Iif (!ctx) {
    throw new Error("Unable to create canvas context");
  }
 
  // Convert icon to binary representation
  const iconBits = icon
    .split("")
    .map((c) => parseInt(c, 16).toString(2).padStart(4, "0"))
    .join("");
 
  // Use cached mask if available
  let maskData = collisonTileMaskCache[icon];
  Iif (!maskData) {
    maskData = ctx.getImageData(0, 0, TILE_SIZE, TILE_SIZE);
    // Draw mask
    for (let y = 0; y < TILE_SIZE; y++) {
      for (let x = 0; x < TILE_SIZE; x++) {
        const i = x + y * TILE_SIZE;
        const ii = i * 4;
        maskData.data[ii + 3] = iconBits[i] === "1" ? 255 : 0;
      }
    }
  }
 
  ctx.putImageData(maskData, 0, 0);
 
  // Fill color over mask
  ctx.fillStyle = color;
  ctx.globalCompositeOperation = "source-in";
  ctx.fillRect(0, 0, TILE_SIZE, TILE_SIZE);
 
  // Cache result
  collisonTileMaskCache[icon] = maskData;
  collisonTileCache[key] = canvas;
 
  return canvas;
};
 
export const isCollisionTileActive = (
  value: number,
  tileDef: CollisionTileDef
): boolean => {
  const mask = tileDef.mask || 0xff;
  const maskedValue = value & mask;
  if (tileDef.multi) {
    return (
      // Full mask not selected
      maskedValue !== mask &&
      // But flag bits are
      (maskedValue & tileDef.flag) !== 0
    );
  } else {
    return maskedValue === tileDef.flag;
  }
};