Pixel art fixes
This commit is contained in:
parent
1c7a7db299
commit
8fdb0dbae3
@ -18,6 +18,7 @@
|
||||
:style="{
|
||||
transform: `scale(${store.zoomLevel.value})`,
|
||||
transformOrigin: 'top left',
|
||||
imageRendering: 'pixelated', // Keep pixel art sharp when zooming
|
||||
}"
|
||||
></canvas>
|
||||
</div>
|
||||
|
@ -56,7 +56,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center bg-gray-700 p-6 rounded mb-6">
|
||||
<canvas ref="animCanvas" class="block"></canvas>
|
||||
<canvas ref="animCanvas" class="block" style="image-rendering: pixelated"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,9 +83,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-gray-400 mt-2">
|
||||
<i class="fas fa-info-circle mr-1"></i> Border will only be visible in the preview and won't be included in the downloaded spritesheet.
|
||||
</div>
|
||||
<div class="text-xs text-gray-400 mt-2"><i class="fas fa-info-circle mr-1"></i> Border will only be visible in the preview and won't be included in the downloaded spritesheet.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -45,7 +45,7 @@ const zoomLevel = ref(1); // Default zoom level (1 = 100%)
|
||||
const previewBorder = reactive({
|
||||
enabled: false,
|
||||
color: '#ff0000', // Default red color
|
||||
width: 2 // Default width in pixels
|
||||
width: 2, // Default width in pixels
|
||||
});
|
||||
|
||||
export function useSpritesheetStore() {
|
||||
@ -144,8 +144,6 @@ export function useSpritesheetStore() {
|
||||
const cols = columns.value;
|
||||
const rows = Math.ceil(totalSprites / cols);
|
||||
|
||||
console.log(`Store: Updating canvas size for ${totalSprites} sprites, ${cols} columns, ${rows} rows`);
|
||||
|
||||
if (cellSize.width <= 0 || cellSize.height <= 0) {
|
||||
console.error('Store: Invalid cell size for canvas update', cellSize);
|
||||
return;
|
||||
@ -156,7 +154,6 @@ export function useSpritesheetStore() {
|
||||
|
||||
// Ensure the canvas is large enough to display all sprites
|
||||
if (canvas.value.width !== newWidth || canvas.value.height !== newHeight) {
|
||||
console.log(`Store: Resizing canvas from ${canvas.value.width}x${canvas.value.height} to ${newWidth}x${newHeight}`);
|
||||
canvas.value.width = newWidth;
|
||||
canvas.value.height = newHeight;
|
||||
|
||||
@ -183,8 +180,6 @@ export function useSpritesheetStore() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Store: Auto-arranging ${sprites.value.length} sprites with ${columns.value} columns`);
|
||||
|
||||
// First update the canvas size to ensure it's large enough
|
||||
updateCanvasSize();
|
||||
|
||||
@ -195,9 +190,6 @@ export function useSpritesheetStore() {
|
||||
|
||||
sprite.x = column * cellSize.width;
|
||||
sprite.y = row * cellSize.height;
|
||||
|
||||
// Log the position of each sprite for debugging
|
||||
console.log(`Store: Sprite ${index} (${sprite.name}) positioned at (${sprite.x}, ${sprite.y})`);
|
||||
});
|
||||
|
||||
// Check if the canvas is ready before attempting to render
|
||||
@ -233,8 +225,6 @@ export function useSpritesheetStore() {
|
||||
// Make sure the canvas size is correct before rendering
|
||||
updateCanvasSize();
|
||||
|
||||
console.log(`Store: Rendering ${sprites.value.length} sprites on canvas ${canvas.value.width}x${canvas.value.height}`);
|
||||
|
||||
// Clear the canvas
|
||||
ctx.value.clearRect(0, 0, canvas.value.width, canvas.value.height);
|
||||
|
||||
@ -242,6 +232,14 @@ export function useSpritesheetStore() {
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
// First, collect all occupied cells
|
||||
const occupiedCells = new Set<string>();
|
||||
sprites.value.forEach(sprite => {
|
||||
const cellX = Math.floor(sprite.x / cellSize.width);
|
||||
const cellY = Math.floor(sprite.y / cellSize.height);
|
||||
occupiedCells.add(`${cellX},${cellY}`);
|
||||
});
|
||||
|
||||
// Draw each sprite - remove the zoom scaling from context
|
||||
sprites.value.forEach((sprite, index) => {
|
||||
try {
|
||||
@ -253,33 +251,23 @@ export function useSpritesheetStore() {
|
||||
// Check if sprite is within canvas bounds
|
||||
if (sprite.x >= 0 && sprite.y >= 0 && sprite.x + sprite.width <= canvas.value!.width && sprite.y + sprite.height <= canvas.value!.height) {
|
||||
if (sprite.img.complete && sprite.img.naturalWidth !== 0) {
|
||||
// Draw the image at its original size
|
||||
ctx.value!.drawImage(sprite.img, sprite.x, sprite.y, sprite.width, sprite.height);
|
||||
// For pixel art, ensure we're drawing at exact pixel boundaries
|
||||
const x = Math.round(sprite.x);
|
||||
const y = Math.round(sprite.y);
|
||||
|
||||
// Draw border around the cell if enabled (preview only)
|
||||
if (previewBorder.enabled) {
|
||||
const cellX = Math.floor(sprite.x / cellSize.width) * cellSize.width;
|
||||
const cellY = Math.floor(sprite.y / cellSize.height) * cellSize.height;
|
||||
|
||||
ctx.value!.strokeStyle = previewBorder.color;
|
||||
ctx.value!.lineWidth = previewBorder.width / zoomLevel.value; // Adjust for zoom
|
||||
ctx.value!.strokeRect(cellX, cellY, cellSize.width, cellSize.height);
|
||||
}
|
||||
// Draw the image at its original size with pixel-perfect rendering
|
||||
ctx.value!.imageSmoothingEnabled = false; // Keep pixel art sharp
|
||||
ctx.value!.drawImage(sprite.img, x, y, sprite.width, sprite.height);
|
||||
} else {
|
||||
console.warn(`Store: Sprite image ${index} not fully loaded, setting onload handler`);
|
||||
sprite.img.onload = () => {
|
||||
if (ctx.value && canvas.value) {
|
||||
ctx.value.drawImage(sprite.img, sprite.x, sprite.y, sprite.width, sprite.height);
|
||||
// For pixel art, ensure we're drawing at exact pixel boundaries
|
||||
const x = Math.round(sprite.x);
|
||||
const y = Math.round(sprite.y);
|
||||
|
||||
// Draw border around the cell if enabled (preview only)
|
||||
if (previewBorder.enabled) {
|
||||
const cellX = Math.floor(sprite.x / cellSize.width) * cellSize.width;
|
||||
const cellY = Math.floor(sprite.y / cellSize.height) * cellSize.height;
|
||||
|
||||
ctx.value.strokeStyle = previewBorder.color;
|
||||
ctx.value.lineWidth = previewBorder.width / zoomLevel.value; // Adjust for zoom
|
||||
ctx.value.strokeRect(cellX, cellY, cellSize.width, cellSize.height);
|
||||
}
|
||||
ctx.value.imageSmoothingEnabled = false; // Keep pixel art sharp
|
||||
ctx.value.drawImage(sprite.img, x, y, sprite.width, sprite.height);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -290,6 +278,28 @@ export function useSpritesheetStore() {
|
||||
console.error(`Store: Error rendering sprite at index ${index}:`, spriteError);
|
||||
}
|
||||
});
|
||||
|
||||
// Draw borders around occupied cells if enabled (preview only)
|
||||
if (previewBorder.enabled && occupiedCells.size > 0) {
|
||||
ctx.value!.strokeStyle = previewBorder.color;
|
||||
ctx.value!.lineWidth = previewBorder.width / zoomLevel.value; // Adjust for zoom
|
||||
|
||||
// Draw borders around each occupied cell
|
||||
occupiedCells.forEach(cellKey => {
|
||||
const [cellX, cellY] = cellKey.split(',').map(Number);
|
||||
|
||||
// Calculate pixel-perfect coordinates for the cell
|
||||
// Add 0.5 to align with pixel boundaries for crisp lines
|
||||
const x = Math.floor(cellX * cellSize.width) + 0.5;
|
||||
const y = Math.floor(cellY * cellSize.height) + 0.5;
|
||||
|
||||
// Adjust width and height to ensure the border is inside the cell
|
||||
const width = cellSize.width - 1;
|
||||
const height = cellSize.height - 1;
|
||||
|
||||
ctx.value!.strokeRect(x, y, width, height);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Store: Error in renderSpritesheetPreview:', error);
|
||||
}
|
||||
@ -305,19 +315,21 @@ export function useSpritesheetStore() {
|
||||
const visibleWidth = canvas.value.width / zoomLevel.value;
|
||||
const visibleHeight = canvas.value.height / zoomLevel.value;
|
||||
|
||||
// Draw vertical lines
|
||||
// Draw vertical lines - ensure pixel-perfect grid lines
|
||||
for (let x = 0; x <= visibleWidth; x += cellSize.width) {
|
||||
const pixelX = Math.floor(x) + 0.5; // Align to pixel boundary for crisp lines
|
||||
ctx.value.beginPath();
|
||||
ctx.value.moveTo(x, 0);
|
||||
ctx.value.lineTo(x, visibleHeight);
|
||||
ctx.value.moveTo(pixelX, 0);
|
||||
ctx.value.lineTo(pixelX, visibleHeight);
|
||||
ctx.value.stroke();
|
||||
}
|
||||
|
||||
// Draw horizontal lines
|
||||
// Draw horizontal lines - ensure pixel-perfect grid lines
|
||||
for (let y = 0; y <= visibleHeight; y += cellSize.height) {
|
||||
const pixelY = Math.floor(y) + 0.5; // Align to pixel boundary for crisp lines
|
||||
ctx.value.beginPath();
|
||||
ctx.value.moveTo(0, y);
|
||||
ctx.value.lineTo(visibleWidth, y);
|
||||
ctx.value.moveTo(0, pixelY);
|
||||
ctx.value.lineTo(visibleWidth, pixelY);
|
||||
ctx.value.stroke();
|
||||
}
|
||||
}
|
||||
@ -380,8 +392,14 @@ export function useSpritesheetStore() {
|
||||
|
||||
tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
|
||||
// Ensure pixel art remains sharp in the downloaded file
|
||||
tempCtx.imageSmoothingEnabled = false;
|
||||
|
||||
sprites.value.forEach(sprite => {
|
||||
tempCtx.drawImage(sprite.img, sprite.x, sprite.y);
|
||||
// Use rounded coordinates for pixel-perfect rendering
|
||||
const x = Math.round(sprite.x);
|
||||
const y = Math.round(sprite.y);
|
||||
tempCtx.drawImage(sprite.img, x, y);
|
||||
});
|
||||
|
||||
const link = document.createElement('a');
|
||||
@ -435,16 +453,26 @@ export function useSpritesheetStore() {
|
||||
const cellX = Math.floor(currentSprite.x / cellSize.width);
|
||||
const cellY = Math.floor(currentSprite.y / cellSize.height);
|
||||
|
||||
const offsetX = currentSprite.x - cellX * cellSize.width;
|
||||
const offsetY = currentSprite.y - cellY * cellSize.height;
|
||||
// Calculate precise offset for pixel-perfect rendering
|
||||
const offsetX = Math.round(currentSprite.x - cellX * cellSize.width);
|
||||
const offsetY = Math.round(currentSprite.y - cellY * cellSize.height);
|
||||
|
||||
// Keep pixel art sharp
|
||||
animation.ctx.imageSmoothingEnabled = false;
|
||||
animation.ctx.drawImage(currentSprite.img, offsetX, offsetY);
|
||||
|
||||
// Draw border if enabled (only for preview, not included in download)
|
||||
// Draw border around the cell if enabled (only for preview, not included in download)
|
||||
if (previewBorder.enabled) {
|
||||
animation.ctx.strokeStyle = previewBorder.color;
|
||||
animation.ctx.lineWidth = previewBorder.width;
|
||||
animation.ctx.strokeRect(0, 0, animation.canvas.width, animation.canvas.height);
|
||||
|
||||
// Use pixel-perfect coordinates for the border (0.5 offset for crisp lines)
|
||||
const x = 0.5;
|
||||
const y = 0.5;
|
||||
const width = animation.canvas.width - 1;
|
||||
const height = animation.canvas.height - 1;
|
||||
|
||||
animation.ctx.strokeRect(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user