This commit is contained in:
Dennis Postma 2025-04-04 13:35:09 +02:00
parent 293bed9135
commit 8eec236105
2 changed files with 80 additions and 51 deletions

View File

@ -80,7 +80,7 @@
<div class="flex flex-col justify-center items-center bg-gray-700 p-6 rounded mb-6 relative overflow-auto flex-grow">
<!-- Tooltip for dragging instructions -->
<div class="text-xs text-gray-400 mb-2" v-if="sprites.length > 0">
<span>Position: {{ Math.round(spriteOffset.x) }}px, {{ Math.round(spriteOffset.y) }}px (drag to move within cell)</span>
<span>Position: {{ Math.round(spriteOffset?.x ?? 0) }}px, {{ Math.round(spriteOffset?.y ?? 0) }}px (drag to move within cell)</span>
</div>
<div
@ -129,6 +129,9 @@
const store = useSpritesheetStore();
const animCanvas = ref<HTMLCanvasElement | null>(null);
// Add this constant for pan amount
const panAmount = 10; // pixels to pan per keypress
const isModalOpen = computed({
get: () => store.isModalOpen.value,
set: value => {
@ -150,20 +153,18 @@
get: () => {
// Get the offset for the current frame
const frameOffset = store.getSpriteOffset(currentFrame.value);
// Update the current offset for UI display
store.currentSpriteOffset.x = frameOffset.x;
store.currentSpriteOffset.y = frameOffset.y;
return store.currentSpriteOffset;
// Return the frame-specific offset directly
return frameOffset;
},
set: val => {
// Update both the current offset and the frame-specific offset
store.currentSpriteOffset.x = val.x;
store.currentSpriteOffset.y = val.y;
// Get the frame-specific offset and update it
// Update the frame-specific offset directly
const frameOffset = store.getSpriteOffset(currentFrame.value);
frameOffset.x = val.x;
frameOffset.y = val.y;
// Also update the current offset for UI consistency
store.currentSpriteOffset.x = val.x;
store.currentSpriteOffset.y = val.y;
},
});
const isCanvasDragging = ref(false);
@ -184,7 +185,7 @@
// Computed property to check if sprite has been moved from original position
const hasSpriteOffset = computed(() => {
return spriteOffset.x !== 0 || spriteOffset.y !== 0;
return spriteOffset.value.x !== 0 || spriteOffset.value.y !== 0;
});
// applyOffsetsToMainView function removed
@ -298,10 +299,6 @@
frameOffset.y = centerY;
}
// Update the current offset for UI display
store.currentSpriteOffset.x = frameOffset.x;
store.currentSpriteOffset.y = frameOffset.y;
// Render with the frame-specific offset
store.renderAnimationFrame(0, showAllSprites.value, frameOffset);
}
@ -357,9 +354,8 @@
animation.value.currentFrame = currentFrame.value;
animation.value.manualUpdate = true;
// Get the frame-specific offset
const frameOffset = store.getSpriteOffset(currentFrame.value);
store.renderAnimationFrame(currentFrame.value, showAllSprites.value, frameOffset);
// Use the computed spriteOffset directly
store.renderAnimationFrame(currentFrame.value, showAllSprites.value, spriteOffset.value);
};
const handleFrameRateChange = () => {
@ -438,14 +434,8 @@
const centerX = Math.max(0, Math.floor((store.cellSize.width - currentSprite.width) / 2));
const centerY = Math.max(0, Math.floor((store.cellSize.height - currentSprite.height) / 2));
// Reset the sprite offset for the current frame to the center position
const frameOffset = store.getSpriteOffset(currentFrame.value);
frameOffset.x = centerX;
frameOffset.y = centerY;
// Also update the current offset
store.currentSpriteOffset.x = centerX;
store.currentSpriteOffset.y = centerY;
// Update the sprite offset using the computed property setter
spriteOffset.value = { x: centerX, y: centerY };
// Update the frame to reflect the change
updateFrame();
@ -497,9 +487,6 @@
// Only move when delta exceeds the threshold for one pixel movement at current zoom
const pixelThreshold = previewZoom.value; // One pixel at current zoom level
// Get the frame-specific offset
const frameOffset = store.getSpriteOffset(currentFrame.value);
// Calculate the maximum allowed offset
const maxOffsetX = Math.max(0, store.cellSize.width - currentSprite.width);
const maxOffsetY = Math.max(0, store.cellSize.height - currentSprite.height);
@ -507,8 +494,8 @@
// Move one pixel at a time when threshold is reached
if (Math.abs(deltaX) >= pixelThreshold) {
const pixelsToMove = Math.sign(deltaX);
const newX = frameOffset.x + pixelsToMove;
frameOffset.x = Math.max(0, Math.min(maxOffsetX, newX));
const newX = spriteOffset.value.x + pixelsToMove;
spriteOffset.value.x = Math.max(0, Math.min(maxOffsetX, newX));
// Reset the start X position for next pixel move
canvasDragStart.value.x = e.clientX;
@ -516,17 +503,13 @@
if (Math.abs(deltaY) >= pixelThreshold) {
const pixelsToMove = Math.sign(deltaY);
const newY = frameOffset.y + pixelsToMove;
frameOffset.y = Math.max(0, Math.min(maxOffsetY, newY));
const newY = spriteOffset.value.y + pixelsToMove;
spriteOffset.value.y = Math.max(0, Math.min(maxOffsetY, newY));
// Reset the start Y position for next pixel move
canvasDragStart.value.y = e.clientY;
}
// Update the current offset to match
store.currentSpriteOffset.x = frameOffset.x;
store.currentSpriteOffset.y = frameOffset.y;
// Update the frame
updateFrame();
@ -651,7 +634,7 @@
if (isModalOpen.value && newSprites.length > 0) {
updateCanvasSize();
updateCanvasContainerSize();
store.renderAnimationFrame(currentFrame.value, showAllSprites.value, spriteOffset.value);
updateFrame();
}
},
{ deep: true }
@ -670,7 +653,7 @@
() => previewBorder.value,
() => {
if (isModalOpen.value && sprites.value.length > 0) {
store.renderAnimationFrame(currentFrame.value, showAllSprites.value, spriteOffset.value);
updateFrame();
}
},
{ deep: true }
@ -681,7 +664,7 @@
() => showAllSprites.value,
() => {
if (isModalOpen.value && sprites.value.length > 0) {
store.renderAnimationFrame(currentFrame.value, showAllSprites.value, spriteOffset.value);
updateFrame();
}
}
);

View File

@ -259,9 +259,21 @@ export function useSpritesheetStore() {
// Get the frame-specific offset for this sprite
const frameOffset = getSpriteOffset(index);
// Apply the frame-specific offset to the sprite position
const finalX = x + frameOffset.x;
const finalY = y + frameOffset.y;
// Calculate the maximum allowed offset based on sprite and cell size
const maxOffsetX = Math.max(0, cellSize.width - sprite.width);
const maxOffsetY = Math.max(0, cellSize.height - sprite.height);
// Constrain the offset to prevent out-of-bounds positioning
const constrainedOffsetX = Math.max(0, Math.min(maxOffsetX, frameOffset.x));
const constrainedOffsetY = Math.max(0, Math.min(maxOffsetY, frameOffset.y));
// Update the frame offset with the constrained values
frameOffset.x = constrainedOffsetX;
frameOffset.y = constrainedOffsetY;
// Apply the constrained offset to the sprite position
const finalX = x + constrainedOffsetX;
const finalY = y + constrainedOffsetY;
// Draw the image at its final position with pixel-perfect rendering
ctx.value!.imageSmoothingEnabled = false; // Keep pixel art sharp
@ -277,9 +289,21 @@ export function useSpritesheetStore() {
// Get the frame-specific offset for this sprite
const frameOffset = getSpriteOffset(index);
// Apply the frame-specific offset to the sprite position
const finalX = x + frameOffset.x;
const finalY = y + frameOffset.y;
// Calculate the maximum allowed offset based on sprite and cell size
const maxOffsetX = Math.max(0, cellSize.width - sprite.width);
const maxOffsetY = Math.max(0, cellSize.height - sprite.height);
// Constrain the offset to prevent out-of-bounds positioning
const constrainedOffsetX = Math.max(0, Math.min(maxOffsetX, frameOffset.x));
const constrainedOffsetY = Math.max(0, Math.min(maxOffsetY, frameOffset.y));
// Update the frame offset with the constrained values
frameOffset.x = constrainedOffsetX;
frameOffset.y = constrainedOffsetY;
// Apply the constrained offset to the sprite position
const finalX = x + constrainedOffsetX;
const finalY = y + constrainedOffsetY;
ctx.value.imageSmoothingEnabled = false; // Keep pixel art sharp
ctx.value.drawImage(sprite.img, finalX, finalY, sprite.width, sprite.height);
@ -432,11 +456,33 @@ export function useSpritesheetStore() {
// Ensure pixel art remains sharp in the downloaded file
tempCtx.imageSmoothingEnabled = false;
sprites.value.forEach(sprite => {
// 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);
sprites.value.forEach((sprite, index) => {
// Get the frame-specific offset for this sprite
const frameOffset = getSpriteOffset(index);
// Calculate the cell coordinates for this sprite
const cellX = Math.floor(sprite.x / cellSize.width);
const cellY = Math.floor(sprite.y / cellSize.height);
// Calculate the base position within the cell
const baseX = cellX * cellSize.width;
const baseY = cellY * cellSize.height;
// Calculate the maximum allowed offset based on sprite and cell size
// This prevents sprites from going out of bounds
const maxOffsetX = Math.max(0, cellSize.width - sprite.width);
const maxOffsetY = Math.max(0, cellSize.height - sprite.height);
// Constrain the offset to prevent out-of-bounds positioning
const constrainedOffsetX = Math.max(0, Math.min(maxOffsetX, frameOffset.x));
const constrainedOffsetY = Math.max(0, Math.min(maxOffsetY, frameOffset.y));
// Apply the constrained offset to the base position
const finalX = baseX + constrainedOffsetX;
const finalY = baseY + constrainedOffsetY;
// Draw the sprite at the calculated position
tempCtx.drawImage(sprite.img, finalX, finalY, sprite.width, sprite.height);
});
const link = document.createElement('a');