FAZA 17: 2.5D Minecraft-Style Terrain + Y-Layer Stacking + Custom Sprites
COMPLETED FEATURES: Custom Sprite Integration: - Player, Zombie, Merchant sprites (0.2 scale) - 11 custom sprites + 5 asset packs loaded - Auto-transparency processing (white/brown removal) - Gravestone system with atlas extraction 2.5D Minecraft-Style Terrain: - Volumetric blocks with 25px thickness - Strong left/right side shading (30%/50% darker) - Minecraft-style texture patterns (grass, dirt, stone) - Crisp black outlines for definition Y-Layer Stacking System: - GRASS_FULL: All green (elevation > 0.7) - GRASS_TOP: Green top + brown sides (elevation 0.4-0.7) - DIRT: All brown (elevation < 0.4) - Dynamic terrain depth based on height Floating Island World Edge: - Stone cliff walls at map borders - 2-tile transition zone - Elevation flattening for cliff drop-off effect - 100x100 world with defined boundaries Performance & Polish: - Canvas renderer for pixel-perfect sharpness - CSS image-rendering: crisp-edges - willReadFrequently optimization - No Canvas2D warnings Technical: - 3D volumetric trees and rocks - Hybrid rendering (2.5D terrain + 2D characters) - Procedural texture generation - Y-layer aware terrain type selection
This commit is contained in:
@@ -4,6 +4,7 @@ class TextureGenerator {
|
||||
|
||||
// Generiraj player sprite (32x32px pixel art)
|
||||
static createPlayerSprite(scene, key = 'player') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const size = 32;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
@@ -94,6 +95,7 @@ class TextureGenerator {
|
||||
|
||||
// Generiraj walking animacijo (4 frame-i)
|
||||
static createPlayerWalkSprite(scene, key = 'player_walk') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const frameWidth = 32;
|
||||
const frameHeight = 32;
|
||||
const frameCount = 4;
|
||||
@@ -177,9 +179,6 @@ class TextureGenerator {
|
||||
if (frame === 2) legOffset = 1; // Right foot forward
|
||||
|
||||
for (let y = 11; y < 16; y++) {
|
||||
const leftShift = (frame === 1) ? 0 : 0;
|
||||
const rightShift = (frame === 2) ? 0 : 0;
|
||||
|
||||
// Leva noga
|
||||
pixel(ox + 0, oy + y, outlineColor);
|
||||
pixel(ox + 1, oy + y, pantsColor);
|
||||
@@ -200,6 +199,7 @@ class TextureGenerator {
|
||||
|
||||
// Generiraj NPC sprite (32x32px pixel art)
|
||||
static createNPCSprite(scene, key = 'npc', type = 'zombie') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const size = 32;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
@@ -253,6 +253,19 @@ class TextureGenerator {
|
||||
pixel(ox + 2, oy + 4, outlineColor);
|
||||
pixel(ox + 5, oy + 4, outlineColor);
|
||||
|
||||
// Dreads (if Zombie)
|
||||
if (type === 'zombie') {
|
||||
const hairColor = '#3e2723'; // Dark Brown
|
||||
// Top
|
||||
for (let x = 1; x < 7; x++) pixel(ox + x, oy + 1, hairColor);
|
||||
// Side Dreads
|
||||
pixel(ox, oy + 2, hairColor); pixel(ox - 1, oy + 3, hairColor); pixel(ox - 1, oy + 4, hairColor);
|
||||
pixel(ox + 7, oy + 2, hairColor); pixel(ox + 8, oy + 3, hairColor); pixel(ox + 8, oy + 4, hairColor);
|
||||
// Back Dreads
|
||||
pixel(ox, oy + 5, hairColor);
|
||||
pixel(ox + 7, oy + 5, hairColor);
|
||||
}
|
||||
|
||||
// Telo - srajca
|
||||
for (let y = 6; y < 11; y++) {
|
||||
pixel(ox + 0, oy + y, outlineColor);
|
||||
@@ -290,4 +303,466 @@ class TextureGenerator {
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Generiraj Flower sprite (16x16px)
|
||||
static createFlowerSprite(scene, key = 'flower') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const size = 16;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
// Steblo
|
||||
ctx.fillStyle = '#228B22';
|
||||
ctx.fillRect(7, 8, 2, 8);
|
||||
ctx.fillRect(5, 12, 2, 1); // List levo
|
||||
ctx.fillRect(9, 10, 2, 1); // List desno
|
||||
|
||||
// Cvet (random barva vsakič ko kličemo? Ne, tekstura je statična, ampak lahko naredimo več variant)
|
||||
// Za zdaj rdeča roža
|
||||
ctx.fillStyle = '#FF0000';
|
||||
ctx.fillRect(6, 4, 4, 4); // Center
|
||||
ctx.fillStyle = '#FF69B4'; // Petals
|
||||
ctx.fillRect(6, 2, 4, 2); // Top
|
||||
ctx.fillRect(6, 8, 4, 2); // Bottom
|
||||
ctx.fillRect(4, 4, 2, 4); // Left
|
||||
ctx.fillRect(10, 4, 2, 4); // Right
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Generiraj Bush sprite (32x32px)
|
||||
static createBushSprite(scene, key = 'bush') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const size = 32;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
// Grm
|
||||
ctx.fillStyle = '#006400'; // DarkGreen
|
||||
|
||||
// Risemo kroge/elipse pikslov za grm
|
||||
// Base
|
||||
ctx.fillRect(4, 16, 24, 14);
|
||||
ctx.fillRect(2, 20, 28, 6);
|
||||
|
||||
// Highlights
|
||||
ctx.fillStyle = '#228B22'; // ForestGreen
|
||||
ctx.fillRect(6, 18, 10, 6);
|
||||
ctx.fillRect(18, 14, 8, 8);
|
||||
|
||||
// Berries (rdeče pike)
|
||||
ctx.fillStyle = '#FF0000';
|
||||
ctx.fillRect(10, 20, 2, 2);
|
||||
ctx.fillRect(20, 18, 2, 2);
|
||||
ctx.fillRect(15, 24, 2, 2);
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Generiraj Tree sprite (64x64px) - Blue Magical Tree
|
||||
static createTreeSprite(scene, key = 'tree') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const width = 64;
|
||||
const height = 64;
|
||||
const canvas = scene.textures.createCanvas(key, width, height);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
// Trunk
|
||||
ctx.fillStyle = '#8B4513'; // SaddleBrown
|
||||
ctx.fillRect(28, 40, 8, 24); // Main trunk
|
||||
ctx.fillRect(24, 58, 4, 6); // Root L
|
||||
ctx.fillRect(36, 58, 4, 6); // Root R
|
||||
|
||||
// Branches
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 40);
|
||||
ctx.lineTo(20, 30); // L
|
||||
ctx.lineTo(24, 28);
|
||||
ctx.lineTo(32, 35);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 40);
|
||||
ctx.lineTo(44, 30); // R
|
||||
ctx.lineTo(40, 28);
|
||||
ctx.lineTo(32, 35);
|
||||
ctx.fill();
|
||||
|
||||
// Foliage (Blue/Teal/Cyan)
|
||||
const cols = ['#008B8B', '#20B2AA', '#48D1CC', '#00CED1'];
|
||||
|
||||
const drawCluster = (cx, cy, r) => {
|
||||
const col = cols[Math.floor(Math.random() * cols.length)];
|
||||
ctx.fillStyle = col;
|
||||
for (let y = -r; y <= r; y++) {
|
||||
for (let x = -r; x <= r; x++) {
|
||||
if (x * x + y * y <= r * r) {
|
||||
ctx.fillRect(cx + x * 2, cy + y * 2, 2, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Main Canopy
|
||||
drawCluster(32, 20, 10);
|
||||
drawCluster(20, 25, 6);
|
||||
drawCluster(44, 25, 6);
|
||||
drawCluster(32, 10, 5);
|
||||
|
||||
// Magic sparkels
|
||||
ctx.fillStyle = '#E0FFFF'; // LightCyan
|
||||
for (let i = 0; i < 10; i++) {
|
||||
ctx.fillRect(10 + Math.random() * 44, 5 + Math.random() * 30, 2, 2);
|
||||
}
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Generiraj Cloud sprite (64x32px)
|
||||
static createCloudSprite(scene, key = 'cloud') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const width = 64;
|
||||
const height = 32;
|
||||
const canvas = scene.textures.createCanvas(key, width, height);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
|
||||
// Simple pixel art cloud shape
|
||||
// Three circles/blobs
|
||||
ctx.fillRect(10, 10, 20, 15);
|
||||
ctx.fillRect(25, 5, 20, 20);
|
||||
ctx.fillRect(40, 10, 15, 12);
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
// Generiraj Crop sprite (32x32px) - stages 1-4
|
||||
static createCropSprite(scene, key, stage = 4) {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const size = 32;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
const cx = 16;
|
||||
const cy = 24; // Base position
|
||||
|
||||
if (stage === 1) {
|
||||
// Seeds
|
||||
ctx.fillStyle = '#D2B48C';
|
||||
ctx.fillRect(cx - 2, cy, 2, 2);
|
||||
ctx.fillRect(cx + 2, cy - 2, 2, 2);
|
||||
ctx.fillRect(cx, cy + 2, 2, 2);
|
||||
} else if (stage === 2) {
|
||||
// Sprout
|
||||
ctx.fillStyle = '#32CD32'; // LimeGreen
|
||||
ctx.fillRect(cx - 1, cy, 2, 4); // Stem
|
||||
ctx.fillRect(cx - 3, cy - 2, 2, 2); // Leaf left
|
||||
ctx.fillRect(cx + 1, cy - 2, 2, 2); // Leaf right
|
||||
} else if (stage === 3) {
|
||||
// Growing
|
||||
ctx.fillStyle = '#228B22'; // ForestGreen
|
||||
ctx.fillRect(cx - 1, cy - 4, 3, 8); // Stem
|
||||
ctx.fillRect(cx - 5, cy - 4, 4, 3); // Leaf L
|
||||
ctx.fillRect(cx + 2, cy - 6, 4, 3); // Leaf R
|
||||
} else if (stage === 4) {
|
||||
// Ripe
|
||||
ctx.fillStyle = '#006400'; // DarkGreen
|
||||
ctx.fillRect(cx - 2, cy - 8, 4, 12); // Stem
|
||||
|
||||
// Leaves
|
||||
ctx.fillStyle = '#228B22';
|
||||
ctx.fillRect(cx - 6, cy - 2, 4, 4);
|
||||
ctx.fillRect(cx + 2, cy - 4, 4, 4);
|
||||
|
||||
// Fruit (Corn/Wheat/Generic yellow/orange)
|
||||
ctx.fillStyle = '#FFD700'; // Gold
|
||||
ctx.fillRect(cx - 2, cy - 12, 4, 6);
|
||||
}
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
// Generiraj Structure sprite (Fence, Wall, House)
|
||||
static createStructureSprite(scene, key, type) {
|
||||
if (scene.textures.exists(key)) return;
|
||||
const size = 32;
|
||||
const width = (type === 'house' || type === 'ruin') ? 64 : 32;
|
||||
const height = (type === 'house' || type === 'ruin') ? 64 : 32;
|
||||
|
||||
const canvas = scene.textures.createCanvas(key, width, height);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
if (type === 'fence') {
|
||||
// Brown Fence
|
||||
ctx.fillStyle = '#8B4513';
|
||||
ctx.fillRect(8, 8, 4, 24); // Post L
|
||||
ctx.fillRect(20, 8, 4, 24); // Post R
|
||||
ctx.fillRect(8, 12, 16, 4); // Rail Top
|
||||
ctx.fillRect(8, 20, 16, 4); // Rail Bot
|
||||
} else if (type === 'wall') {
|
||||
// Grey Wall
|
||||
ctx.fillStyle = '#808080';
|
||||
ctx.fillRect(0, 8, 32, 24);
|
||||
ctx.fillStyle = '#696969'; // Bricks
|
||||
ctx.fillRect(4, 12, 10, 6);
|
||||
ctx.fillRect(18, 12, 10, 6);
|
||||
ctx.fillRect(2, 22, 10, 6);
|
||||
ctx.fillRect(16, 22, 10, 6);
|
||||
} else if (type === 'house') {
|
||||
// Isometric House
|
||||
// Left Wall (Darker)
|
||||
ctx.fillStyle = '#C2B280'; // Sand/Wheat dark
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 60); // Bottom Center
|
||||
ctx.lineTo(10, 50); // Bottom Left corner
|
||||
ctx.lineTo(10, 30); // Top Left corner
|
||||
ctx.lineTo(32, 40); // Top Center (Roof start)
|
||||
ctx.fill();
|
||||
|
||||
// Right Wall (Lighter)
|
||||
ctx.fillStyle = '#F5DEB3'; // Wheat light
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 60); // Bottom Center
|
||||
ctx.lineTo(54, 50); // Bottom Right corner
|
||||
ctx.lineTo(54, 30); // Top Right corner
|
||||
ctx.lineTo(32, 40); // Top Center
|
||||
ctx.fill();
|
||||
|
||||
// Door (Right Wall)
|
||||
ctx.fillStyle = '#8B4513';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(38, 56);
|
||||
ctx.lineTo(48, 52);
|
||||
ctx.lineTo(48, 38);
|
||||
ctx.lineTo(38, 42);
|
||||
ctx.fill();
|
||||
|
||||
// Roof (Left Slope)
|
||||
ctx.fillStyle = '#8B0000'; // Dark Red
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 40);
|
||||
ctx.lineTo(10, 30);
|
||||
ctx.lineTo(32, 10); // Peak
|
||||
ctx.lineTo(32, 40);
|
||||
ctx.fill();
|
||||
|
||||
// Roof (Right Slope)
|
||||
ctx.fillStyle = '#FF0000'; // Red
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 40);
|
||||
ctx.lineTo(54, 30);
|
||||
ctx.lineTo(32, 10); // Peak
|
||||
ctx.lineTo(32, 40);
|
||||
ctx.fill();
|
||||
|
||||
} else if (type === 'ruin') {
|
||||
// Isometric Ruin
|
||||
|
||||
// Left Wall (Broken)
|
||||
ctx.fillStyle = '#555555'; // Dark Grey
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 60);
|
||||
ctx.lineTo(10, 50);
|
||||
ctx.lineTo(10, 40); // Lower than house
|
||||
ctx.lineTo(20, 45); // Jagged
|
||||
ctx.lineTo(25, 38);
|
||||
ctx.lineTo(32, 45);
|
||||
ctx.fill();
|
||||
|
||||
// Right Wall (Broken)
|
||||
ctx.fillStyle = '#777777'; // Light Grey
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(32, 60);
|
||||
ctx.lineTo(54, 50);
|
||||
ctx.lineTo(54, 35);
|
||||
ctx.lineTo(45, 30);
|
||||
ctx.lineTo(40, 35);
|
||||
ctx.lineTo(32, 25); // Exposed interior?
|
||||
ctx.lineTo(32, 60);
|
||||
ctx.fill();
|
||||
|
||||
// Debris piles
|
||||
ctx.fillStyle = '#333333';
|
||||
ctx.beginPath(); // Pile 1
|
||||
ctx.arc(20, 55, 5, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath(); // Pile 2
|
||||
ctx.arc(45, 55, 4, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Overgrowth
|
||||
ctx.fillStyle = '#228B22';
|
||||
ctx.fillRect(10, 48, 4, 8); // Vines Left
|
||||
ctx.fillRect(50, 45, 5, 10); // Vines Right
|
||||
|
||||
// Random Bricks
|
||||
ctx.fillStyle = '#444444';
|
||||
ctx.fillRect(15, 60, 4, 2);
|
||||
ctx.fillRect(35, 62, 3, 2);
|
||||
}
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// ========== 2.5D VOLUMETRIC GENERATORS ==========
|
||||
|
||||
// Generiraj 3D volumetric tree (Minecraft-style)
|
||||
static createTreeSprite(scene, key = 'tree') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
|
||||
const size = 64;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
// Tree trunk (3D block)
|
||||
const trunkW = 12;
|
||||
const trunkH = 24;
|
||||
const trunkX = size / 2 - trunkW / 2;
|
||||
const trunkY = size - trunkH - 8;
|
||||
|
||||
// Trunk - left side (darker)
|
||||
ctx.fillStyle = '#8B6F47';
|
||||
ctx.fillRect(trunkX, trunkY, trunkW / 2, trunkH);
|
||||
|
||||
// Trunk - right side (darkest)
|
||||
ctx.fillStyle = '#654321';
|
||||
ctx.fillRect(trunkX + trunkW / 2, trunkY, trunkW / 2, trunkH);
|
||||
|
||||
// Trunk - top (brightest)
|
||||
ctx.fillStyle = '#A0826D';
|
||||
ctx.fillRect(trunkX + 2, trunkY - 2, trunkW - 4, 2);
|
||||
|
||||
// Foliage (3D spherical)
|
||||
const foliageX = size / 2;
|
||||
const foliageY = trunkY - 8;
|
||||
const radius = 20;
|
||||
|
||||
// Back shadow
|
||||
ctx.fillStyle = '#228B22';
|
||||
ctx.beginPath();
|
||||
ctx.arc(foliageX - 2, foliageY + 2, radius, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Main foliage
|
||||
ctx.fillStyle = '#32CD32';
|
||||
ctx.beginPath();
|
||||
ctx.arc(foliageX, foliageY, radius, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Highlight
|
||||
ctx.fillStyle = '#90EE90';
|
||||
ctx.beginPath();
|
||||
ctx.arc(foliageX + 5, foliageY - 5, 8, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Generiraj 3D volumetric bush/rock (Minecraft-style)
|
||||
static createBushSprite(scene, key = 'bush') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
|
||||
const size = 48;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
// Rock/Bush as 3D isometric block
|
||||
const w = 24;
|
||||
const h = 16;
|
||||
const x = size / 2 - w / 2;
|
||||
const y = size - h - 4;
|
||||
|
||||
// Left face (darker)
|
||||
ctx.fillStyle = '#7d7d7d';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y + h / 2);
|
||||
ctx.lineTo(x + w / 2, y + h);
|
||||
ctx.lineTo(x + w / 2, y);
|
||||
ctx.lineTo(x, y + h / 2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// Right face (darkest)
|
||||
ctx.fillStyle = '#5a5a5a';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + w / 2, y + h);
|
||||
ctx.lineTo(x + w, y + h / 2);
|
||||
ctx.lineTo(x + w, y - h / 2);
|
||||
ctx.lineTo(x + w / 2, y);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// Top face (brightest)
|
||||
ctx.fillStyle = '#a0a0a0';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y + h / 2);
|
||||
ctx.lineTo(x + w / 2, y);
|
||||
ctx.lineTo(x + w, y - h / 2);
|
||||
ctx.lineTo(x + w / 2, y);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// Black outline
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Generiraj 3D flower (simple volumetric)
|
||||
static createFlowerSprite(scene, key = 'flower') {
|
||||
if (scene.textures.exists(key)) return;
|
||||
|
||||
const size = 32;
|
||||
const canvas = scene.textures.createCanvas(key, size, size);
|
||||
const ctx = canvas.getContext();
|
||||
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
|
||||
// Stem
|
||||
ctx.fillStyle = '#228B22';
|
||||
ctx.fillRect(size / 2 - 1, size / 2, 2, size / 2 - 4);
|
||||
|
||||
// Flower petals (simple 2D for flowers)
|
||||
const colors = ['#FF69B4', '#FFD700', '#FF4500', '#9370DB'];
|
||||
const color = colors[Math.floor(Math.random() * colors.length)];
|
||||
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(size / 2, size / 2 - 4, 6, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#FFFF00';
|
||||
ctx.beginPath();
|
||||
ctx.arc(size / 2, size / 2 - 4, 3, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
canvas.refresh();
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user