I have a canvas element and i'm drawing on this little duck sprite sheet to fly across from the right hand side of the screen to the left. The code i have right now achieves that. But i can't for the life of me figure out how to make the frame the duck is in, bigger, without messing with the animations of it.
Right now it appears that the duck is confined into a little sliver of a box like this | | so you only see bits and pieces of the animation, not nearly enough to see it consistently flying across the screen. Every time i try to adjust the width or frame, its just making the duck much larger.
I know the snippet doesn't work cuz it wont load in the assets but you can see the JS side of it so hopefully that helps!
Thank you guys
$(document).ready(function () {
// Variables for IDs - getContext to draw and clear canvas
const canvas = $("#game-canvas")[0];
const context = canvas.getContext("2d");
const startButton = $("#start-button");
const backgroundImage = new Image();
backgroundImage.src = "https://opengameart.org/sites/default/files/duck_spritesheet.png";
// Onload function to pull the background image of the game
$(backgroundImage).on("load", function () {
context.drawImage(backgroundImage, 0, 0);
});
// On click function to change the crosshair and pull in the duck image
startButton.on("click", function () {
const spriteSheet = new Image();
spriteSheet.src = "https://opengameart.org/sites/default/files/duck_spritesheet.png";
$("#game-canvas").on("mouseenter", function () {
$(this).addClass("canvas-cursor");
});
$("#game-canvas").on("mouseleave", function () {
$(this).removeClass("canvas-cursor");
});
$(spriteSheet).on("load", function () {
const totalFrames = 4; // Total number of frames in the sprite sheet
const scale = 3; // Scale to TRY and scale it, didn't work...
const duckSpeed = 10; // ducks movement speed across the canvas
//multiplying any of these didn't work for me
const duckWidth = spriteSheet.width / totalFrames;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight;
const animationSpeed = 200; // Milliseconds per frame
let currentFrame = 0; // Current frame of the animation
let duckX = canvas.width; // Starting position of the duck on the right side of the canvas
let duckY = canvas.height / 2 - (frameHeight * scale) / 2; // Center the duck vertically
function animateDuck() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(backgroundImage, 0, 0);
const frameX = (currentFrame % totalFrames) * frameWidth;
const frameY = Math.floor(currentFrame / totalFrames) * frameHeight;
// Draw the current frame of the duck image
context.drawImage(
spriteSheet,
frameX,
frameY,
frameWidth,
frameHeight,
duckX,
duckY,
frameWidth * scale,
frameHeight * scale
);
// current frame
currentFrame = (currentFrame + 1) % (totalFrames * totalFrames);
// duck's position
duckX -= duckSpeed;
// if the duck has reached the left side of the canvas
if (duckX + frameWidth * scale * 2 < 0) {
duckX = canvas.width;
}
setTimeout(animateDuck, animationSpeed);
}
animateDuck();
});
});
});
body {
background-color: #eee;
text-align: center;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
h1 {
color: #333;
}
#game-container {
position: relative;
}
#game-canvas {
display: block;
margin: 0 auto;
border: 1px solid black;
background-color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<body>
<div id="game-container">
<canvas id="game-canvas" width="400" height="100"></canvas>
</div>
<button id="start-button">Start Game</button>
</body>
Look at your sprite again:
and then your code:
const duckWidth = spriteSheet.width / totalFrames;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight;
...
const frameX = (currentFrame % totalFrames) * frameWidth;
That should be enough clue to get you moving...
Do the math by hand, that helps, Do you get the expected values for the frames?
Below is my correction to your code, challenge yourself try to fix yours without looking at my snippet
const canvas = $("#game-canvas")[0];
const context = canvas.getContext("2d");
const spriteSheet = new Image();
spriteSheet.src = "https://opengameart.org/sites/default/files/duck_spritesheet.png";
$(spriteSheet).on("load", function() {
const totalFrames = 4; // Total number of frames in the sprite sheet
const scale = 3; // Scale to TRY and scale it, didn't work...
const duckSpeed = 2; // ducks movement speed across the canvas
const duckWidth = spriteSheet.width;
const duckHeight = spriteSheet.height / totalFrames;
const frameWidth = duckWidth;
const frameHeight = duckHeight;
let currentFrame = 0; // Current frame of the animation
let duckX = canvas.width;
let duckY = canvas.height / 2 - (frameHeight * scale) / 2;
function animateDuck() {
context.clearRect(0, 0, canvas.width, canvas.height);
const frameX = 0
const frameY = Math.floor(currentFrame / totalFrames) * frameHeight;
context.drawImage(spriteSheet, frameX, frameY, frameWidth, frameHeight, duckX, duckY, frameWidth * scale, frameHeight * scale );
currentFrame = (currentFrame + 1) % (totalFrames * totalFrames);
duckX -= duckSpeed;
if (duckX + frameWidth * scale * 2 < 0) {
duckX = canvas.width;
}
setTimeout(animateDuck, 40);
}
animateDuck();
});
body {
background-color: #eee;
text-align: center;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
h1 {
color: #333;
}
#game-container {
position: relative;
}
#game-canvas {
display: block;
margin: 0 auto;
border: 1px solid black;
background-color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<body>
<div id="game-container">
<canvas id="game-canvas" width="400" height="100"></canvas>
</div>
</body>
In a nutshell the image of your sprite is not a square but a rectangle, the duck width does not need to be divided by the total frames and the framex is also not a value that changes for your sprite this is always 0.
If you want to challenge yourself try other sprites like this one:
https://opengameart.org/content/explosion-sheet