I have a basic game moving a sprite around a map using Quintus html5 game. I have the sprite moving from square to square (64px) with a keypress fine. I want the player to move one square also when a button is click on the webpage.
I am unsure how to call the step method in Quintus from a button click.
Outside the canvas I have a <button id="move-player">Move Player One Square</button>
document.getElementById("move-player").addEventListener("click", function( event ) {
//move player one square by possibly calling PlayerControls step
});
Quintus player code
Q.component("PlayerControls", {
// default properties to add onto our entity
defaults: {speed: 32, direction: 'null'},
// called when the component is added to
// an entity
added: function () {
var p = this.entity.p;
// adding default properties
Q._defaults(p, this.defaults);
// every time our entity steps, call its step method
this.entity.on("step", this, "step");
},
step: function (dt) {
// entity's properties
var p = this.entity.p;
var total_points = Q.state.get("points");
if (total_points >= 4) {
Q.state.set("points", 4);
Q.stageScene("GameOverMsg", 2);//display game over message
}//inner if
// direction from the input will help in animation
p.direction = Q.inputs['left'] ? 'left' :
Q.inputs['right'] ? 'right' :
Q.inputs['up'] ? 'up' :
Q.inputs['down'] ? 'down' : null;
window.onkeyup = function (e) {
if (e.keyCode == 37)//left
{
p.x -= p.speed;
move_collision = "left";
}
else if (e.keyCode == 38)//up
{
if (!(p.y <= 36)) {
p.y -= p.speed;
move_collision = "up";
}
}
else if (e.keyCode == 39)//right
{
p.x += p.speed;
move_collision = "right";
}
else if (e.keyCode == 40)//down
{
if (!(p.y >= 480)) {
p.y += p.speed;
move_collision = "down";
}
}
};
// movement
switch (move_collision) {
case "left":
p.x -= p.speed;
move_collision = "";
break;
case "right":
p.x += p.speed;
move_collision = "";
break;
case "up":
p.y -= p.speed;
move_collision = "";
break;
case "down":
if (!(p.y >= 480)) {
p.y += p.speed;
}
move_collision = "";
break;
default:
break;
}
}
});
//Player Sprite
Q.Sprite.extend("Player",
{
init: function (properties) {
properties.sheet = "snailspritesheet";
properties.sprite = "snail";
properties.frame = 4;
this._super(properties);
this.add("2d,PlayerControls,animation,tween");
Consider that step function is a kind of callback function.
That function is called periodically with timer.
So, there are two method to move a player
Make a state machine: change state when button is clicked and interleave the code to step function for moving player
Make a trigger function to move a player with global variable: for example,
var player;
Q.scene("start",function(stage) {
stage.insert(new Q.UI.Button({
asset: 'move.png',
x: Q.width/2,
scale: 0.5,
y: 370
}, function() {
player.x += 10;
player.y -= 10;
})
);
}
I hope it is useful to you.
Related
I'm trying to build Snake from scratch using Javascript. But when I use the arrow keys to get it from 1 part of the canvas to the other part of the canvas it dissapears for 1 frame, how to resolve this? You can try it on: https://annedegraaff.nl/snake/
<canvas id="snake" width="400" height="400">
</html>
<script>
var canvas;
var canvasContext;
var ball1X = 12.5;
var ball1Y = 12.5;
window.onload = function() {
canvas = document.getElementById('snake');
canvasContext = canvas.getContext('2d');
var framesPerSecond = 60;
setInterval(function() {
draw();
move();
}, 1000/framesPerSecond);
}
function move() {
window.onkeydown = function(e) {
var key = e.keyCode ? e.keyCode : e.which;
if (ball1X < 12.5) {
ball1X += 395;
}else if (ball1X > 385) {
ball1X -= 395;
}
if (key == 39) {
ball1X += 10;
}else if (key == 37) {
ball1X -= 10;
}else if (key == 40) {
ball1Y += 10;
}else if (key == 38) {
ball1Y -= 10;
}
}
}
function draw() {
canvasContext.fillStyle = 'green';
canvasContext.fillRect(0,0,canvas.width,canvas.height);
canvasContext.fillStyle = 'black';
canvasContext.fillRect(ball1X,ball1Y,10,10);
}
</script>
Logic error in keyEvent handler
Though not directly evident where the problem is in the given code I am assuming it is the test for edges in the keydown handler. There are also other ting being done incorrectly that will present additional problems and difficulties as you develop the game.
Your bug
In your keyboard function you test if the ball is close to the edge and if so you move it to the other size. Looks like you move it too far and thus can not be seen.
The following is a quick fix. Move the test to after the ball has been moved and make sure the the move to the other side does not put it too far so that it is moved again on the next event.
window.onkeydown = function(e) {
var key = e.keyCode ? e.keyCode : e.which;
if (key == 39) {
ball1X += 10;
}else if (key == 37) {
ball1X -= 10;
}else if (key == 40) {
ball1Y += 10;
}else if (key == 38) {
ball1Y -= 10;
}
if (ball1X < 12.5) {
ball1X += 400;
}else if (ball1X > 400-12.5) {
ball1X -= 400;
}
}
Other problems.
Use requestAnimationFrame for animations not setInterval
Key event listeners should only record the keyboard state as they have nothing to do with the game and dont know what to do with the keys pressed. The game code should use the keyboard state and its own current state to work out what to do with each key
Use addEventListener add events as directly setting event can be overwritten
Encapsulate your game inside a function so that all the variables and functions are isolated from the global names space and you can easily insert the game into any page.
Use objects to group properties and function together. Eg you had ballX, ballY and most like will add other properties each will have a ball prefix. By creating an object named ball and adding properties like x,y you can get access to the balls x, y with via a reference ball.x, ball.y or var b = ball; b.x += 1;`. Once an object has been defined you can make many copies easily.
Change the key handler to hold the key state of only the keys you are interested in. You only want to know if the key is down so listen to key up and down setting a flag to true when a key is down.
And other stuff
Rewrite
A quick rewrite showing a better way to implement what you had. It is a recommendation only. It is a little longer than you had it and is not the only way, but if you write like this it will be easier as the game develops.
See comments for the reasons and what does what.
// create onload event handler as a function and encapsulate all variables and functions to key global name space clean
function start(){
// create canvas and context
const canvas = document.getElementById("snakeCanvas");
const ctx = canvas.getContext("2d"); // formaly canvasContext;
// get the size as we use that a lot
const width = canvas.width;
const height = canvas.height;
requestAnimationFrame(mainLoop); // will call mainloop after this function (start) has run
// create an object to hold all related properties and
// functions for the ball
const ball = { // position ball in center
x : width / 2 | 0, // the or zero ( | 0) rounds down to nearest integer
y : height / 2 | 0,
size : 10,
speed : 10,
draw() { // function to draw the ball
ctx.fillStyle = 'black';
ctx.fillRect(this.x - this.size / 2,this.y - this.size / 2, this.size, this.size);
},
update() { // moves the ball
if (keys.up === true) { this.y -= this.speed }
if (keys.down === true) { this.y += this.speed }
if (keys.left === true) { this.x -= this.speed }
if (keys.right === true) { this.x += this.speed }
// get half size
const hSize = this.size / 2;
// check for edges and move to other side of canvas
if(this.x + hSize < 0) { this.x += width }
if(this.x - hSize > width) { this.x -= width }
if(this.y + hSize < 0) { this.y += height }
if(this.y - hSize > height) { this.y -= height }
},
}
// the background function clears and displays the background
function background(){
ctx.fillStyle = 'green';
ctx.fillRect(0,0,width,height);
}
// Object to hold the current keyboard state
const keys = {
up : false,
down : false,
left : false,
right : false,
map : new Map([ // use a Map to find keys
[39,"right"], // key code and string name of keys.name
[37,"left"],
[40,"down"],
[38,"up"],
])
}
// the key event listener
function keyEvents(event){
// get key code as a string
const keyCode = event.keyCode ? event.keyCode : event.which;
// get if avalible the key name from the map
const key = keys.map.get(keyCode);
// if a key is mapped set its state
if(key){
keys[key] = event.type === "keydown";
event.preventDefault(); // pervent default action
}
}
// listent to the keyboard events and set the keyboard state
["keydown","keyup"].forEach(eventName => addEventListener(eventName, keyEvents));
// for the stackoverflow snippet we need to get focus to
// hear any of the key events
focus();
function mainLoop(time){ // time is automatic and in ms (1/1000th second)
background(); // call the background function that clears and displays the background
// update and draw the ball object
ball.update();
ball.draw();
requestAnimationFrame(mainLoop); // request next frame in 1/60th second
}
}
// when loaded start the game
addEventListener("load", start);
<canvas id="snakeCanvas" width="400" height="400">
I'm trying my hands at some simple game programming in Javascript and have come to realize I need to change the way I handle sprites. The only question is, "how"?
I have a hero that moves around with the arrow keys and fires laser rays with WASD. This is how I define rays:
function Ray (x, y, width, height, direction, index) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.direction = direction;
this.index = index;
this.speed = 512;
this.disabled = false;
}
The index just indicates where in an array of rays (heh) it is being stored. I currently have a hard-coded limit of 5 simultaneous rays, although the other restrictions (screen size, ray size, speed, hero size etc) shouldn't allow for more than 4:
var rays = [];
var numberOfRays = 0;
var rayLimit = 5;
var shotClock = 300;
And so, in the update() function that gets called by the game loop, I have listeners for the WASD keys. They look like this:
// D
if (68 in keysDown && numberOfRays <= rayLimit && Date.now() - lastShootTime > shotClock) {
lastShootTime = Date.now();
var newRayIndex = findFreeRay();
rays[newRayIndex] = new Ray(hero.x + hero.width + 12, hero.y + hero.height / 2, rayImage.width, rayImage.height, 'right', newRayIndex);
numberOfRays++;
}
(findFreeRay() just returns the lowest unused or disabled (off the screen) index in rays[])
Earlier in the update() method (I have also tried putting it later) I have the logic for updating ray movement:
rays.forEach(function(ray) {
if (ray != null && !ray.disabled) {
switch(ray.direction) {
case 'right':
ray.x += ray.speed * modifier;
break;
case 'left':
ray.x -= ray.speed * modifier;
break;
case 'up':
ray.y -= ray.speed * modifier;
break;
case 'down':
ray.y += ray.speed * modifier;
break;
}
}
});
Finally, there is the image for the ray (actually, one for horizontal rays and another one for vertical rays). Currently, I am using one Image object of each globally, that the existing rays share. But I have also tried, without much luck, to create individual image objects for every ray.
// Ray images
var rayReady = false;
var rayImage = new Image();
rayImage.onload = function() {
rayReady = true;
};
rayImage.src = "images/ray.png";
var rayVertReady = false;
var rayVertImage = new Image();
rayVertImage.onload = function() {
rayVertReady = true;
};
rayVertImage.src = "images/ray_vert.png";
And here is how they get drawn:
if (rayReady && rayVertReady && numberOfRays > 0) {
rays.forEach(function(ray) {
if (ray.x > canvas.width
|| ray.x + ray.width < 0
|| ray.y > canvas.height
|| ray.y + ray.height < 0) {
numberOfRays--;
ray.disabled = true;
}
else if (ray.direction == 'right' || ray.direction == 'left'){
ctx.drawImage(rayImage, ray.x, ray.y);
}
else {
ctx.drawImage(rayVertImage, ray.x, ray.y);
}
});
}
The problem
After shooting only a few rays, new ones start to either flicker and disappear, or stay invisible altogether. They actually exist as gameplay objects though, as they can hit targets.
What likely causes this flickering?
(credit to Matt Hackett for the base of this code)
fiddle: http://jsfiddle.net/Vr3MW/
I'm trying to make a top down shooter game to learn about coding in HTML/JS/CSS.
I've got a canvas, my player moves and rotates on the canvas, but I'm having some trouble getting his gun working. I've got this with the aid of tutorials and searching through other stackoverflow posts, but this one I can't seem to fix alone.
I have defined a variable 'gunfire' which is set to 1 if the left mouse button is pressed and is otherwise 0, in my function draw() I have an if statement that should draw a rectangle in front of my sprite (to represent bullets) when the left mouse button is pressed.
The problem I have is that the bullets appear at all times, independent of whether the mouse button is pressed. If anyone can point out what it is that I'm doing wrong then I would be very grateful, here's the code (the canvass is created in separate HTML/CSS files):
var turn = 0;
var frameRate = 24;
var main_x = 0,
main_y = 0,
move_x = 0,
move_y = 0;
var gunfire = 0;
var speed = 4;
function keyPress(e) {
if (e.keyCode == 68) { //d
move_x = speed;
}
if (e.keyCode == 65) { //a
move_x = -speed;
}
if (e.keyCode == 83) { //s
move_y = speed;
}
if (e.keyCode == 87) { //w
move_y = -speed;
}
if (e.keyCode == 1) { //left mouse
gunfire = 1;
}
}
function keyRelease(e) {
if (e.keyCode == 68) { //d
move_x = 0;
}
if (e.keyCode == 65) { //a
move_x = 0;
}
if (e.keyCode == 83) { //s
move_y = 0;
}
if (e.keyCode == 87) { //w
move_y = 0;
}
if (e.keyCode == 1) { //left mouse
gunfire = 0;
}
}
function move() {
main_x += move_x;
main_y += move_y;
if (main_x < -220) {
main_x = -220
}
if (main_y < -220) {
main_y = -220
}
if (main_x > 220) {
main_x = 220
}
if (main_y > 220) {
main_y = 220
}
}
function mouseMove(e) {
var mouseX, mouseY;
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
} else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
mouseX = mouseX - (top_canvas.width / 2) - main_x;
mouseY = mouseY - (top_canvas.height / 2) - main_y;
window.radians = Math.atan2(mouseY, mouseX);
//document.getElementById("info").innerHTML = radians
}
var background = new Image();
background.src = "assets/background3.jpg";
var player1 = new Image();
player1.src = "assets/player1.png";
function draw() { //draws all content on the canvas
ctx_1.save();
ctx_1.clearRect(0, 0, top_canvas.width, top_canvas.height);
ctx_1.drawImage(background, 0, 0);
ctx_1.translate(top_canvas.width / 2 + main_x, top_canvas.height / 2 + main_y);
ctx_1.rotate(turn);
ctx_1.drawImage(player1, -25, -25, 50, 70);
if (gunfire = 1) {
ctx_1.fillStyle = "#000";
ctx_1.fillRect(0, -10, 200, 20);
}
ctx_1.restore();
}
function gameLoop() {
// all functions to update go here
draw();
turn = window.radians
move();
}
function init() {
window.top_canvas = document.getElementById("top_canvas");
window.ctx_1 = top_canvas.getContext("2d");
setInterval(gameLoop, 1000 / frameRate);
//event fires every time the mouse moves
top_canvas.addEventListener("mousemove", mouseMove, false);
window.addEventListener("keydown", keyPress, false);
window.addEventListener("keyup", keyRelease, false);
}
window.addEventListener("load", init, false);
First of all, as Kippie points out, you're setting gunfire to 1 each time which results in a true statement. It must be changed to == or === (latter preferable) or simply drop the comparison as the non-zero value would be true:
if (gunfire) {
...
}
Second, you are checking for mouse clicks inside a key handler and assuming keyCode would indicate a mouse button click. keyCode 1 is not related to mouse clicks at all and no mouse clicks will end up here.
Third, you are not having any event handler for mouse clicks...
To solve these issues (in addition to the first) add an event handler for mouse clicks:
top_canvas.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mouseup", mouseUp, false);
Then inside the handlers (only showing for mouse down):
function mouseDown(e) {
if (e.button === 0) { // check left mouse-button
gunfire = 1;
}
}
The reason for using window for mouse up is that in case your mouse pointer is outside the canvas element the up event won't register and the gun will continue to fire. Using the window object will allow you to register up event even in this situation.
if (gunfire = 1)
You're using the assignment operator, rather than doing a comparison.
Use === instead.
How do I run a sprite animation when pressing the left or right arrow keys in JavaScript? Here's my code:
var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;
window.addEventListener('keydown', KeyDown);
function setUpGame() { //This is the function that is called from the html document.
gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
context=gameCanvas.getContext("2d");
context.font = "18px Iceland";
context.textBaseline = "top";
avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
avatarImage.onload=function(){
// avatarImage is now fully loaded and ready to drawImage
context.drawImage(avatarImage, Math.random() * 100, avatarY);
// start the timer
tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
avatarImage.addEventListener('load', startLoop, false);
avatarImage.src = "img/ships.png"; //Ditto from above.
}
function startLoop() {
console.log("Detecting whether moving to the right is: " + moving);
if(moving == 0) {
gameLoop();
}
}
function gameLoop() {
setTimeout(gameLoop, 100);
handleTick();
}
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 0;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 1;
}
break;
}
}
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
}
}
function handleTick() {
context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
context.drawImage(avatarImage, 32*animationCounter, 0, 32,32, avatarX, avatarY, 64, 64);
context.fillText("Seconds: " + counter, 5, 5);
context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);
animationCounter++
if(animationCounter >1) {
animationCounter = 0;
}
}
There are many ways to implement animation. The one i use is pretty easy and looks something like this:
var player = {
x: 0,
y: 0,
width: 50,
height: 100,
sprite: {
column: 0,
row: 0,
height: 50,
width: 100
},
image: PlayerImage,
animation: {
active: true, //Determines if the animation is running or not.
counter: 0,
progress: 0,
sequence: []
}
}
//This functions fires when the left arrow is pressed.
var onLeft = function(){
player.animation.sequence = [{column: 0, row: 0, t: 12}, {column: 1, row: 0, t: 12}, {column: 2, row: 0, t: 12}];
player.animation.active = true;
}
//This functions fires when the right arrow is pressed.
var onRight = function(){
player.animation.sequence = [{column: 0, row: 1, t: 12}, {column: 1, row: 1, t: 12}, {column: 2, row: 1, t: 12}];
player.animation.active = true;
}
//This function fires when no arrow are pressed.
var standingStill = function(){
player.animation.active = false;
}
var handleTick = function(){
//Clear the canvas.
context.canvas.width = context.canvas.width;
//If the animation is active.
if(player.animation.active){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(player.animation.counter >= player.animation.sequence[player.animation.progress]){
player.animation.counter = 1;
if(player.animation.progress >= player.animation.sequence.length - 1){
player.animation.progress = 0;
}else{
player.animation.progress++;
}
var currentFrame = player.animation.sequence[player.animation.progress];
//Change player.sprite column and row.(new frame)
player.sprite.column = currentFrame.column;
player.sprite.row = currentFrame.row;
}else{
player.animation.counter++;
}
}
context.drawImage(player.image, player.sprite.column * player.sprite.width, player.sprite.row * player.sprite.height, player.sprite.width, player.sprite.height, player.x, player.y, player.width, player.height)
}
The sequence is an array that contains objects that look like that: {column: 0, row: 0, t: 12} Every object is a frame. The column value is the current x of the sprite, the row is the y of the sprite. The script automatically creates the x and the y value, so all you need to add is value like 0, 1, 3, 5, and so on.(Just which frame it is on either x or y axis.) So for example, if the column is 0 and the row is 0, this is the frame that is in the top-left corner(the first frame). The t value stands for tick, this determines how many ticks there has to happend before the animation goes to the next frame.
Player.sprite also has properties width and height, that's the width and the height of the frame, it is often the same value as the width and height of the player object.
You have to make your own player.animation.sequence in onLeft and onRight function so it animates how you want it to animate.
I hope you understood what i meant. This might seem complicated, but it really isn't and if you don't get it now, don't worry, you'll get it eventually. If you really have difficulties with understanding, just ask.
Edit: First of all i highly recommend using objects to store information about entities. It makes game making much easier and cleaner. Just look at the player object, it's much easier to get the x simply by writing player.x than PlayerX. It looks more professional too. :) And when you have to give a lot of information about your entity you don't have to pass many arguments, you pass the whole object. Example:
//Entity properties stored in separate variable.
function animate(EntityX, EntityY, EntitySpriteX, EntitySpriteY, ...){
var x = EntityX;
//And so on...
}
//Entity stored in an object.
function animate(Entity){
var x = Entity.x;
//And so on...
}
Anyway, back to your question. First, we have to add variables that store information about our sprite.
var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.
We also have to add variables that store the information about the animation.
var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.
Then, in your handleTick function you have to add a code that will animate the sprite. You have to add this code before you draw your entity.
//If the animation is active.
if(animationActive){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(animationCounter >= animationSequence[animationProgress]){
animationCounter = 1;
//Reset the progress, so that next time another animation frame shows up.
if(animationProgress >= animationSequence.length - 1){
animationProgress = 0;
}else{
animationProgress++;
}
//Select information about the current animation frame and store it in a variable so it is easier to access.
var currentFrame = animationSequence[animationProgress];
//Change player.sprite column and row.(new frame);
avatarSpriteColumn = currentFrame.column;
avatarSpriteRow = currentFrame.row;
}else{
animationCounter.counter++;
}
}
Ok, now you have a code that animates the sprite, but how do we run it? Well, i see you have a variable called moving. It tells us in what direction the player is moving and if it is moving at all. It looks like you implemented it a little bit wrong. Right now your function that operates the keys looks like this:
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 0;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 1;
}
break;
}
}
The variable is supposed to return 1 if the entity is going to the right, 2 if it is going to the left and 0 if the entity is standing still, right? Right now it shows 0 when the entity is moving to the right and 1 when it is moving to the left. It also doesn't show us if the entity is idle. We have to fix it. Change it to something like this:
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 1;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 2;
}
break;
default:
moving = 0;
}
}
Ok, now we have to add this code to the handleTick function. This code starts the animation and changes the sequence.:
if(moving == 1){ //Moving in the right direction.
animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
animationActive = true; //Run the animation.
}else{
animationActive = false; //Stops the animation, but the last frame stays.
/*
Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.
animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
animationActive = true;
*/
}
Now, the last thing we have to do is to draw the entity. In your case, this will look something like this:
context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);
In the end your whole code will look something like this:
var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;
var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.
var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.
window.addEventListener('keydown', KeyDown);
function setUpGame() { //This is the function that is called from the html document.
gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
context=gameCanvas.getContext("2d");
context.font = "18px Iceland";
context.textBaseline = "top";
avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
avatarImage.onload=function(){
// avatarImage is now fully loaded and ready to drawImage
context.drawImage(avatarImage, Math.random() * 100, avatarY);
// start the timer
tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
avatarImage.addEventListener('load', startLoop, false);
avatarImage.src = "img/ships.png"; //Ditto from above.
}
function startLoop() {
console.log("Detecting whether moving to the right is: " + moving);
if(moving == 0) {
gameLoop();
}
}
function gameLoop() {
setTimeout(gameLoop, 100);
handleTick();
}
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 1;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 2;
}
break;
default:
moving = 0;
}
}
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
}
}
function handleTick() {
context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
if(moving == 1){ //Moving in the right direction.
animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
animationActive = true; //Run the animation.
}else{
animationActive = false; //Stops the animation, but the last frame stays.
/*
Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.
animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
animationActive = true;
*/
}
//If the animation is active.
if(animationActive){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(animationCounter >= animationSequence[animationProgress]){
animationCounter = 1;
//Reset the progress, so that next time another animation frame shows up.
if(animationProgress >= animationSequence.length - 1){
animationProgress = 0;
}else{
animationProgress++;
}
//Select information about the current animation frame and store it in a variable so it is easier to access.
var currentFrame = animationSequence[animationProgress];
//Change player.sprite column and row.(new frame);
avatarSpriteColumn = currentFrame.column;
avatarSpriteRow = currentFrame.row;
}else{
animationCounter.counter++;
}
}
context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);
context.fillText("Seconds: " + counter, 5, 5);
context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);
}
The only thing you have to do right now is to make your own animationSequences and check if it works, let me know if you have any problems with that.
Of course, the code i am using is more complicated and has more "abilities" and is easier to use(the code behind is more complicated), but hopefully this will help you.
I must also apoligize for making this thing seem so complicated, when it's not. I am bad at explaining.
I am working on a school assignment to make a small game using HTML5 canvas and Javascript. The idea is based on space invaders but with kites (I know really badass). So I got the kite moving with key press and now I want it to show a different image when pressing left and right (kites bend to the left and right).
I got the left kite image on the screen but it also shows the normal kite. Also there is still no difference when pressing keys left and right.
Do I need to add another function to draw the left kite separately? Or add an if statement when key is true draw image ? This could all be wrong but I am kind of stuck here.
Here is my code
const FPS = 30;
var canvas = null;
var context = null;
window.onload = init ;
function init() {
canvas = document.getElementById('gameCanvas');
context = canvas.getContext('2d');
setInterval(loop, 1000 / FPS);
// register keyboard events
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
// Initialize the player object
player.vx = 0;
player.vy = 0;
player.image = new Image();
player.image.src = "./kite.png";
player.imgLeft = new Image();
player.imgLeft.src = "./kite-links.png";
player.x = canvas.width/2 - player.image.width/2;
player.y = canvas.height/1.3 - player.image.height/2;
player.speed = 10;
}
var player = Object(); // Initialize a player object
// Things to do when keys are down
function onKeyDown(event)
{
if (event.keyCode >= 37 && event.keyCode<=39)
event.preventDefault(); // prevent arrow keys from scrolling the page
switch (event.keyCode) {
case 37: player.vx = -1; break; // left key pressed
case 38: player.vy = -1; break; // up key pressed
case 39: player.vx = 1; break; // right key pressed
}
}
// Things to do when keys are up
function onKeyUp(event)
{
switch (event.keyCode) {
case 37: case 39: player.vx = 0; break; // left or right key released
case 38: player.vy = 0; break; // up or down key released
}
}
function update(){
// update all your objects here
player.x += player.vx * player.speed; // update player position
player.y += player.vy * player.speed;
}
function draw(){
// clear the screen
context.clearRect(0, 0, canvas.width, canvas.height);
// draw all your objects here
context.drawImage(player.image, player.x, player.y, player.image.width, player.image.height);
context.drawImage(player.imgLeft, player.x, player.y, player.image.width, player.image.height);
}
function loop() {
update();
draw();
}
You can have each of the images you want (up, right, and left) saved as properties on the player object, and change the main image (the one that is being drawn) whenever the player changes direction.
init:
//default to straight in init()
player.image = new Image();
player.image.src = "./kite.png";
player.imgUp = new Image();
player.imgUp.src = "./kite.png";
player.imgLeft = new Image();
player.imgLeft.src = "./kite-links.png";
player.imgRight = new Image();
player.imgRight.src = "./kite-right.png";
onKeyDown:
switch (event.keyCode) {
case 37: player.vx = -1; player.image = player.imgLeft; break; // left key
case 38: player.vy = -1; player.image = player.imgUp; break; // up key
case 39: player.vx = 1; player.image = player.imgRight; break; // right key
}
You also don't need to draw all of the images inside draw() like you have now. You only need to draw player.image