Moving a sprite to click location and stop there PIXIJS - javascript
This simple game makes a sprite move around to the position a user clicks. I got it working that the sprite moves to the location, but I need to make it stop at the click location. This code makes the sprite only stop at the click location when the sprite moves towards the bottom right corner. How do I fix this to make it always stop at the click location?
var Container = PIXI.Container,
autoDetectRenderer = PIXI.autoDetectRenderer,
loader = PIXI.loader,
resources = PIXI.loader.resources,
Sprite = PIXI.Sprite;
var stage = new PIXI.Container(),
renderer = PIXI.autoDetectRenderer(1000, 1000);
document.body.appendChild(renderer.view);
PIXI.loader
.add("animal.png")
.load(setup);
var rocket, state;
function setup() {
//Create the `tileset` sprite from the texture
var texture = PIXI.utils.TextureCache["animal.png"];
//Create a rectangle object that defines the position and
//size of the sub-image you want to extract from the texture
var rectangle = new PIXI.Rectangle(192, 128, 32, 32);
//Tell the texture to use that rectangular section
texture.frame = rectangle;
//Create the sprite from the texture
rocket = new Sprite(texture);
rocket.anchor.x = 0.5;
rocket.anchor.y = 0.5;
rocket.x = 50;
rocket.y = 50;
rocket.vx = 0;
rocket.vy = 0;
//Add the rocket to the stage
stage.addChild(rocket);
document.addEventListener("click", function(){
rocket.clickx = event.clientX;
rocket.clicky = event.clientY;
var x = event.clientX - rocket.x;
var y = event.clientY - rocket.y;
rocket.vmax = 5;
var total = Math.sqrt(x * x + y * y);
var tx = x/total;
var ty = y/total;
rocket.vx = tx*rocket.vmax;
rocket.vy = ty*rocket.vmax;
});
state = play;
gameLoop();
}
function gameLoop() {
//Loop this function at 60 frames per second
requestAnimationFrame(gameLoop);
state();
//Render the stage to see the animation
renderer.render(stage);
}
function play(){
rocket.x += rocket.vx;
rocket.y += rocket.vy;
if(rocket.x >= rocket.clickx){
if(rocket.y >= rocket.clicky){
rocket.x = rocket.clickx;
rocket.y = rocket.clicky;
}
}
}
So your sprite has the velocity 5. Then let's just check out the distance between the sprite and the stop position. Whenever it's less than 5, make it stop at the position.
function play(){
var dx = rocket.x - rocket.clickx;
var dy = rocket.y - rocket.clicky;
if (Math.sqrt(dx * dx + dy * dy) <= 5) {
rocket.x = rocket.clickx;
rocket.y = rocket.clicky;
}
else {
rocket.x += rocket.vx;
rocket.y += rocket.vy;
}
}
You can modify the if statement like below to avoid Math.srqt call.
if ((dx * dx + dy * dy) <= (5 * 5)) {
Related
How would I make a randomly generated collider for a game?
Catbus Game code I want to add colliders into my game, so that my main character, the catbus, will jump over them. When he hits them, it will show a game over. I want to be able to randomly generate them, as they come from the right side, and move to the left side. Like the Dinosaur game that shows up when the wifi goes out. I'd like to implement a picture to serve as the collider. The collider that I plan to use goes by: var tinyToto I have no idea how to make a collider such as that, nor how to create a random generator. Any help is much appreciated, even if it is only a small portion of it. Code is as follows: let img; //background var bgImg; //also the background var x1 = 0; var x2; var scrollSpeed = 4; //how fast background is let bing; //for music let cat; var mode; //determines whether the game has started let gravity = 0.2; //jumping forces let velocity = 0.1; let upForce = 7; let startY = 730; //where cat bus jumps from let startX = 70; var font1; //custom fonts var font2; p5.disableFriendlyErrors = true; //avoids errors function preload() { bgImg = loadImage("backgwound.png"); //importing background bing = loadSound("catbus theme song.mp3"); //importing music font1 = loadFont("Big Font.TTF"); font2 = loadFont("Smaller Font.ttf"); } function setup() { createCanvas(1000, 1000); //canvas size img = loadImage("backgwound.png"); //background in x2 = width; bing.loop(); //loops the music cat = { //coordinates for catbus x: startX, y: startY, }; catGif = createImg("catgif.gif"); //creates catbus catGif.position(cat.x, cat.y); //creates position catGif.size(270, 100); //creates how big mode = 0; //game start textSize(50); //text size } function draw() { let time = frameCount; //start background loop image(img, 0 - time, 0); image(bgImg, x1, 2, width, height); image(bgImg, x2, 2, width, height); x1 -= scrollSpeed; x2 -= scrollSpeed; if (x1 <= -width) { x1 = width; } if (x2 <= -width) { x2 = width; } //end background loop fill(128 + sin(frameCount * 0.05) * 128); //text colour if (mode == 0) { textSize(20); textFont(font1); text("press SPACE to start the game!", 240, 500); //what text to type } fill("white"); if (mode == 0) { textSize(35); textFont(font2); text("CATBUS BIZZARE ADVENTURE", 90, 450); //what text to type } cat.y = cat.y + velocity; //code for jumping velocity = velocity + gravity; if (cat.y > startY) { velocity = 0; cat.y = startY; } catGif.position(cat.x, cat.y); } function keyPressed() { if (keyCode === 32 && velocity == 0) { //spacebar code mode = 1; velocity += -upForce; } }
Draw tilemap only on visible canvas area - optimization
I just came up with idea on how to draw only the images that are within the canvas are (javascript tilemap game). however not sure if that is optimized enough as I though it would be. Any ideas on how to make it more optimized? Currently I loop for Y and X using map array and then for every X in Y I use drawImage with position coordinates. I have put an if statement, right before it draws, to check if the current X and Y are within the canvas or not. If it is, it draws the image. Here is a bit of code that can show that and in a moment will give a link to test it. var mapArray=[ [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3], [3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3], [3,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3], [3,0,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,0,0,0,1,3], [3,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,1,1,0,0,0,3], [3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3], [3,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3], [3,0,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,0,0,0,1,3], [3,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,1,1,0,0,0,3], [3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3], [3,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3], [3,0,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,0,0,0,1,3], [3,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,1,1,0,0,0,3], [3,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,3], [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] ]; // x= 22 // y= 15 //----------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------ //----------------------------------------------------------------------- // DRAW PLAYER var player = new Object(); player.y = canvas.height/2-40; //player position - middle of canvas - 40 player.x = canvas.width/2-40; //player position - middle of canvas - 40 player.Width = 80; player.Height = 80; player_image = new Image(); player_image.src = 'http://sarahkerrigan.biz/wpmtest/1/images/horseright1.png'; function drawPlayer() { // drawing the player context.beginPath(); context.drawImage(player_image, player.x, player.y, player.Width, player.Height); context.closePath(); } //----------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------ //----------------------------------------------------------------------- var updateX=(player.x-210); // Starting point of canvas X var updateY=(player.y-160); // Starting point of canvas Y var posX=updateX; var posY=updateY; //------------------------------------------------------------------------------------------------------ //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //DRAW THE MAP AND THE PLAYER function drawMap() { var posY = updateY; // new Y coordinates for the map after movement var grass = new Image(); var stone = new Image(); var black = new Image(); grass.src= 'http://sarahkerrigan.biz/wpmtest/1/images/tile/grass.jpeg'; stone.src = 'http://sarahkerrigan.biz/wpmtest/1/images/tile/sand.jpeg'; black.src = 'http://sarahkerrigan.biz/wpmtest/1/images/tile/black.png'; //--------------------------------------------------------- // Draw the map loop grass.onload = function (){ stone.onload = function (){ black.onload = function (){ for(var i=0; i < mapArray.length; i++){ for(var j=0; j < mapArray[i].length; j++){ //======================================================================= //CHECK IF X AND Y POSITIONS OF THE TILE ARE WITHIN THE CANVAS //======================================================================= if(mapArray[i][j]==0){ if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){ context.drawImage(grass,posX, posY, 64, 64); // Load image for grass "0" } } if(mapArray[i][j]==1){ if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){ context.drawImage(stone,posX,posY,64,64); // Load image for stone "1" } } if(mapArray[i][j]==3){ if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){ context.drawImage(black,posX,posY,64,64); // Load image for black "3" } } //======================================================================= posX+=64; } posY+=64; posX=updateX; // new X coordinates for the map after movement //--------------------------------------------------------- drawPlayer(); // Draw the player } } } } } //----------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------ It looks like it's simple enough and that is why I would like to check if there is anything you can think off that can optimize it more. Here is a link to the whole thing to test it out: https://jsfiddle.net/todorpet/cast5aq2/ Also, though about adding clearRect to the non-visible part around the canvas as the images. Should I add this as well ?
600,000fps not going to happen. There is a major flaw in the code Line 288 setInterval(gameLoop, 30); // 30 milisec to draw next frame This creates an interval event that is called every 30 ms. Because this is inside the function gameLoop, you are just creating more and more interval timers. On the first call game loop is called ~30 times a second, on the next loop you add another interval, so now you have ~60 calls to game loop per second, the next call and you have 90, and now the extra calls start firing and the number of calls to gameLoop start to grow exponentially. If the gameLoop function ran perfectly then within 1000ms (1 second) you would have ~20000 intervals each creating ~30 calls a second, that's ~600000 frames per second. Obviously that cant happen, The interval between any two timer events is throttled by the browser, and the time that the game loop function takes to run limits the rate as well. To fix You had it correct in the code 'requestAnimationFrame` function gameLoop(){ playerMovement(); //Check for movements drawMap(); //Draw the map and the player /* NEVER use setInterval or setTimeout for animating anything!!! */ //setInterval(gameLoop, 30); // 30 milisec to draw next frame // use this. It will automatically slow down the frame rate to 30frames // 20, 15, 10 and so on, per second if your render code is slow. requestAnimationFrame(gameLoop); } To the tile map Your function as I found it. function drawMap() { var posY = updateY; // new Y coordinates for the map after movement var grass = new Image(); var stone = new Image(); var black = new Image(); grass.src = 'http://sarahkerrigan.biz/wpmtest/1/images/tile/grass.jpeg'; stone.src = 'http://sarahkerrigan.biz/wpmtest/1/images/tile/sand.jpeg'; black.src = 'http://sarahkerrigan.biz/wpmtest/1/images/tile/black.png'; grass.onload = function () { stone.onload = function () { black.onload = function () { for (var i = 0; i < mapArray.length; i++) { for (var j = 0; j < mapArray[i].length; j++) { if (mapArray[i][j] == 0) { if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX) { context.drawImage(grass, posX, posY, 64, 64); // Load image for grass "0" } } if (mapArray[i][j] == 1) { if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX) { context.drawImage(stone, posX, posY, 64, 64); // Load image for stone "1" } } if (mapArray[i][j] == 3) { if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX) { context.drawImage(black, posX, posY, 64, 64); // Load image for black "3" } } posX += 64; } posY += 64; posX = updateX; // new X coordinates for the map after movement drawPlayer(); // Draw the player } } } } } This is very bad, each frame you create a new set of images, then you add the onload only to the first image, when that image loads you add the onload event to the next image, and then the same for the third. Not only is this very very slow and resource hungry, it also may not work randomly. Images will not load and fire the onload event in the same order as you create them, If the second image loads before the first its onload event is not set and thus will never fire, same for the third image. Load once. To use resources for a game you load them all at the start of the game before any game plays (the loading screen) As you are using a tile map to reference to images the best is to load the images into an array indexed to match the map. const imageSrcDir = "http://sarahkerrigan.biz/wpmtest/1/images/tile/" const tileImages = []; function loadImages(images) { images.forEach(image => { const img = tileImages[image.mapIndex] = new Image(); img.src = imageSrcDir + image.name; }); } // load the images and add to the tileImage array loadImages([ { name : "grass.jpeg", mapIndex : 0 }, { name : "stone.jpeg", mapIndex : 1 }, { name : "black.png", mapIndex : 3 }, ]); Player You were rendering the player inside the second loop of the map rendering loops. That means you were rendering the player 15 times. No good. You should separate the different parts of the game. Draw the map, then the player as separate functions. See example of how I deal with the player. Setup the map. First flatten the map so you can access it quickly, and I have converted it to a string so it is easier to edit const testMap = [ "3333333333333333333333", "3000000000000000000003", "3000111000000011100003", "3011110000101111000013", "3010011100001001110003", "3000000000000000000003", "3000111000000011100003", "3011110000101111000013", "3010011100001001110003", "3000000000000000000003", "3000111000000011100003", "3011110000101111000013", "3010011100001001110003", "3000011000000001100003", "3333333333333333333333", ]; Function to create a map from the above type map. It get the width and height as well, and converts from string to number. You could use any character to represent different map bits. function createMap(map){ const newMap = {}; newMap.width = map[0].length; newMap.height = map.length; newMap.array = new Uint8Array(newMap.width * newMap.height); var index = 0; for(const row of map){ var i = 0; while(i < row.length){ newMap.array[index++] = Number(row[i++]); } } return newMap; } const currentMap = createMap(testMap); The tiles You need some info about the tiles const tileWidth = 64; const tileHeight = 64; Position the map With the flattened map data you can draw the map, You will need to have a map position (the top right corner) that represents the view. You can get that from the player position, which should be in map coordinates. var playerX = 6; // in tile coordinates 6.5 would be halfway to till 7 var playerY = 2; var mapX = 0; // the map position so that the player can be seen var mapY = 0; // get the map position function getMapPosition(){ // convert player to pixel pos var x = playerX * tileWidth; var y = playerY * tileHeight; x -= canvas.width / 2; // center on the canvas y -= canvas.heigth / 2; mapX = x; mapY = y; } Draw the map There are some important parts. When you see |0 that is the same as floor. eg x = Math.floor(x) is the same as x = x | 0 or x |= 0 This is much faster than floor. The canvas 2D renderer has some flaws that you must avoid. When you draw tiles you need to make sure that they are aligned to the canvas pixels, if not you end up will flickering seams between tiles as the map moves. This is fixed in the line that sets the transform. ctx.setTransform(1, 0, 0, 1, -mapX | 0, -mapY | 0); the mapX and mapY are negated and floored. The floor aligns the map to the pixels ensuring there are no seams. Once this function is called the canvas transform is set to map coordinates. You then draw all other game object at their map coordinates not the canvas coordinates, making drawing objects in the game a lot easier. function drawMap(map) { const w = map.width; // get the width of the tile array const mArray = map.array; const tx = mapX / tileWidth | 0; // get the top left tile const ty = mapY / tileHeight | 0; const tW = (canvas.width / tileWidth | 0) + 2; // get the number of tiles to fit canvas const tH = (canvas.height / tileHeight | 0) + 2; // set the location via the transform // From here on you draw all the game items relative to the map not the canvas ctx.setTransform(1, 0, 0, 1, -mapX | 0, -mapY | 0); // Draw the tiles if tile pos is off map draw black tile for (var y = 0; y < tH; y += 1) { for (var x = 0; x < tW; x += 1) { const i = tx + x + (ty + y) * w; const tileIndex = mArray[i] === undefined ? 3 : mArray[i]; // if outside map draw black tile ctx.drawImage(tileImages[tileIndex], (tx + x) * tileWidth, (ty + y) * tileHeight); } } } So that is how to draw a tile map, well one way to draw a tile map. Example The snippet below shows it all put together with your character, use arrow keys to move. There are a few minor changes from the above. const ctx = canvas.getContext("2d"); const imageSrcDir = "http://sarahkerrigan.biz/wpmtest/1/images/tile/" const tileImages = []; requestAnimationFrame(mainLoop); // start it after all code below has run function mainLoop(){ ctx.setTransform(1,0,0,1,0,0); //control the player if(keys.ArrowUp){ player.y -= 0.1; } if(keys.ArrowDown){ player.y += 0.1; } if(keys.ArrowLeft){ player.x -= 0.1; } if(keys.ArrowRight){ player.x += 0.1; } // Make sure the player stays on the mapo if(player.x < 2){ player.x = 2 } if(player.y < 2){ player.y = 2 } if(player.x >= currentMap.width-2){ player.x = currentMap.width-2} if(player.y >= currentMap.height-2){ player.y = currentMap.height-2} getMapPosition(); drawMap(currentMap); player.draw(); requestAnimationFrame(mainLoop); } function loadImages(images) { images.forEach(image => { const img = tileImages[image.mapIndex] = new Image(); img.src = imageSrcDir + image.name; }); } // load the images and add to the tileImage array loadImages([{ name: "grass.jpeg", mapIndex: 0 }, { name: "sand.jpeg", mapIndex: 1 }, { name: "black.png", mapIndex: 3 }, ]); const player = { x: 6, y: 2, width: 80, height: 80, image: (() => { const img = new Image(); img.src = "https://sarahkerrigan.biz/wpmtest/1/images/horseright1.png"; return img; })(), draw(){ ctx.drawImage(player.image,player.x * tileWidth - player.width / 2, player.y * tileHeight - player.height / 2); }, }; const testMap = [ "3333333333333333333333", "3000000000000000000003", "3000111000000011100003", "3011110000101111000013", "3010011100001001110003", "3000000000000000000003", "3000111000000011100003", "3011110000101111000013", "3010011100001001110003", "3000000000000000000003", "3000111000000011100003", "3011110000101111000013", "3010011100001001110003", "3000011000000001100003", "3333333333333333333333", ]; // function to create a map from the above type map function createMap(map) { const newMap = {}; newMap.width = map[0].length; newMap.height = map.length; newMap.array = new Uint8Array(newMap.width * newMap.height); var index = 0; for (const row of map) { var i = 0; while (i < row.length) { newMap.array[index++] = Number(row[i++]); } } return newMap; } const currentMap = createMap(testMap); const tileWidth = 64; const tileHeight = 64; var mapX = 0; // the map position so that the player can be seen var mapY = 0; // get the map position function getMapPosition() { // convert player to pixel pos var x = player.x * tileWidth + player.width / 2; var y = player.y * tileHeight + player.height / 2; x -= canvas.width / 2; // center on the canvas y -= canvas.height / 2; mapX = x; mapY = y; } function drawMap(map) { const w = map.width; // get the width of the tile array const mArray = map.array; const tx = mapX / tileWidth | 0; // get the top left tile const ty = mapY / tileHeight | 0; const tW = (canvas.width / tileWidth | 0) + 2; // get the number of tiles to fit canvas const tH = (canvas.height / tileHeight | 0) + 2; // set the location via the transform // From here on you draw all the game items relative to the map not the canvas ctx.setTransform(1, 0, 0, 1, -mapX | 0, -mapY | 0); // Draw the tiles if tile pos is off map draw black tile for (var y = 0; y < tH; y += 1) { for (var x = 0; x < tW; x += 1) { const rx = tx + x; // get tile real pos const ry = ty + y; var tileIndex; if(rx < 0 || rx >= w){ tileIndex = 3; // black if off map }else{ const i = rx + ry * w; tileIndex = mArray[i] === undefined ? 3 : mArray[i]; // if outside map draw black tile } ctx.drawImage(tileImages[tileIndex], rx * tileWidth, ry * tileHeight, tileWidth, tileHeight); } } } const keys = { ArrowUp : false, ArrowDown : false, ArrowLeft : false, ArrowRight : false, }; function keyEvents(e){ if(keys[e.code] !== undefined){ keys[e.code] = e.type === "keydown"; e.preventDefault(); } } addEventListener("keyup", keyEvents); addEventListener("keydown", keyEvents); window.focus(); Arrow keys to move. <canvas id="canvas" width="500" height="300"></canvas>
Canvas - Draw only when hovering over new tile instead of whole canvas
Let's say I have a canvas that is split into a 15x10 32-pixel checkboard. Thus, I have this: var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); var tileSize = 32; var xCoord var yCoord var tilesX = 15; // tiles across var tilesY = 10; // tiles up and down var counted = 1; // for drawing purpose for checkerboard for visual guidance var mouseSel = new Image() mouseSel.src = 'http://i.imgur.com/vAA03NB.png' // mouse selection mouseSel.width = 32 mouseSel.height = 32 function isOdd(num) { return num % 2; } function getMousePos(canvas, evt) { // super simple stuff here var rect = canvas.getBoundingClientRect(); return { x: evt.clientX - rect.left, y: evt.clientY - rect.top }; } drawCanvas(); // upon intilization... draw function drawCanvas() { for (var y = 0; y <= 10; y++) { for (var x = 0; x <= 15; x++) { if (isOdd(counted)) { context.fillStyle = '#dedede' context.fillRect(x * 32, y * 32, 32, 32); // checkboard drawn complete. } counted++; } // end first foor loop counted++; } // end last for loop if (counted >= 176) counted = 1 // once all tiles (16x11) are drawn... reset counter for next instance } canvas.addEventListener('mousemove', function (evt) { context.clearRect(0, 0, canvas.width, canvas.height); // clear canvas so mouse isn't stuck drawCanvas(); // draw checkboard // get the actual x,y position of 15x10 32-pixel checkboard var mousePos = getMousePos(canvas, evt); mousePos.xCoord = Math.floor(mousePos.x / tileSize) mousePos.yCoord = Math.floor(mousePos.y / tileSize) // draw the mouse selection context.drawImage(mouseSel, (mousePos.xCoord * 32), (mousePos.yCoord * 32), 32, 32) // draw mouse selection // debug var message = ' (' + mousePos.xCoord + ',' + mousePos.yCoord + ') | (' + mousePos.x + ',' + mousePos.y + ')'; var textarea = document.getElementById('debug'); textarea.scrollTop = textarea.scrollHeight; $('#debug').append(message + '\n'); }, false); canvas#canvas { background: #ABABAB; position: relative; z-index: 1; float: left; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <canvas id="canvas" height="352" width="512" tabindex="0"></canvas> <textarea name="" id="debug" cols="30" rows="35"></textarea> **NOTE: ** Make sure to scroll down in that preview pane so you can see the debug textarea. As you can see, the event of "drawing" fires EVERY single time it moves. That means every pixel. I am trying to figure out how to make the drawing fire ONLY when a new x,y coord has changed. Because it'd be useless to redraw the mouse selection when it's only moved 5 pixels across and it's still going to be drawn at the same place. My suggestion Upon entering, have a temporary value and when that is passed, to redraw again?
Make a temporary value and update that if it was different from before. Then put the code in an if statement where either have changed. var tempX, tempY; var newX = 100; var newY = 100; tempX = mousePos.xCoord; tempY = mousePos.yCoord; if (newX !== tempX || newY !== tempY) { // code here } if (tempX !== newX) newX = mousePos.xCoord; if (tempY !== newY) newY = mousePos.yCoord; JSFiddle: http://jsfiddle.net/weka/bvnma354/8/
how to move an image on canvas using keyboard arrow key in html5
I m Drawing the image on canvas with this code and it successfully draw the image on canvas now i want to move the image on canvas for that i write the code i check that if the right key of my keyboard is pressed i will increment the x coordinate of an image if left key is pressed i will decrement the x coordinate but image is not moving on the canvas player = new Image(); player.src = "game_character.png"; context.drawImage(player,player.x * wallDim + wallDim ,player.y * wallDim + wallDim ,50,50); how to move an image on canvas var handleInput = function(event, keyState) { switch(event.which) { case 37: { // Left Arrow keyDown.arrowLeft = keyState; break; } case 38: { // Up Arrow keyDown.arrowUp = keyState; break; } case 39: { // Right Arrow keyDown.arrowRight = keyState; break; } case 40: { // Down Arrow keyDown.arrowDown = keyState; break; } } } /** * physics * * This function contains the basic logic for the maze. */ var physics = function() { console.log("physics "); console.log("first condition "+keyDown.arrowRight +player.x+1); if(keyDown.arrowLeft && player.x-1 >= 0 && map[player.y][player.x-1] != 1) { player.x--; redraw = true; } if(keyDown.arrowUp && player.y-1 >= 0 && map[player.y-1][player.x] != 1) { player.y--; redraw = true; } if(keyDown.arrowRight && player.x+1 < map[0].length && map[player.y][player.x+1] != 1) { console.log("arrow right"); player.x++; redraw = true; } if(keyDown.arrowDown && player.y+1 < map.length && map[player.y+1][player.x] != 1) { player.y++; redraw = true; } if(keyDown.arrowRight && player.x+1 >= map[0].length) { player.x++; document.getElementById("canvas_div").style.display="none"; document.getElementById("end_screen_div").style.display="block"; //alert("completed"); } } /** * draw * * This function simply draws the current state of the game. */ var draw = function() { // Don't redraw if nothing has changed if(!redraw) return; context.clearRect(0, 0, cols, rows); context.beginPath(); // Draw the maze for(var a = 0; a < rows; a++) { for(var b = 0; b < cols; b++) { switch(map[a][b]) { case C.EMPTY: context.fillStyle = colors.empty; break; case C.WALL: context.fillStyle = colors.wall; break; } context.fillRect(b * wallDim, a * wallDim, wallDim, wallDim); // x, y, width, height } } // Draw the player /* context.fillStyle = colors.player; context.arc( player.x * wallDim + wallDim / 2, // x position player.y * wallDim + wallDim / 2, // y position wallDim / 2, // Radius 0, // Starting angle Math.PI * 2, // Ending angle true // antiClockwise );*/ player = new Image(); player.src = "game_character.png"; context.drawImage(player,player.x * wallDim + wallDim ,player.y * wallDim + wallDim ,50,50); var firstplayer=new Image(); firstplayer.src="top_character01.png"; context.drawImage(firstplayer,680,0,60,60); var secondplayer= new Image(); secondplayer.src="top_character02.png"; context.drawImage(secondplayer,750,0,60,60); context.fill(); context.closePath(); redraw = false; }
In your draw method, you reinitialize the player each time : player = new Image(); player.src = "game_character.png"; So you erase the player.x modified by your event handler. You should initialize the player only once, outside the draw function. You can move the initialization like this : var player = new Image(); player.src = "game_character.png"; var draw = function() { There is absolutely no need to call player.src = "game_character.png"; inside the draw function. As a general rule, when dealing with animation, try to remove all what you can from the draw function, which should be as fast as possible.
You will need to redraw the canvas each time. Something like this: function init() { canvas = document.getElementById("canvas"); context = canvas.getContext("2d"); x = canvas.width / 2; //align to centre of the screen y = canvas.height / 2; //same as above speed = 5; //speed for the player to move at width = 50; //width of the player height = 50; //height of the player playerimage = new Image(); playerimage.src = "path/to/image/for/player"; //path to the image to use for the player canvas.addEventListener("keypress", update); } function update(event) { if (event.keyCode == 38) { y -= speed; //going up } if (event.keyCode == 40) { y += speed; //going down } if (event.keyCode == 37) { x -= speed; //going left } if (event.keyCode == 39) { x += speed; //going right } render(); } function render() { context.clearRect(0, 0, canvas.width, canvas.height); context.drawImage(playerimage, x, y, width, height); } I haven't tested it, so I don't know whether it works and there may be some mistakes here and there. It should work though! If nothing else, it will (hopefully) give you an idea of one way in which you can go about doing it...
Moving Canvas Arcs Towards Mouse
So right now I have a simple canvas element with functions that create random colors, sizes, and positions of arcs (circles). The 'for' loop that generates the random positions of these random circles executes 1 circle every 100 milliseconds (This is done onclick). I want to know how I can make each circle slowly come near the cursor, and then follow the cursor around wherever it moves. http://jsfiddle.net/JXXgx/
You may try something like this: var MAXIMUM_AMOUNT = 1000, FPS = 30, targetToGo, // shapes = []; //storage of circles //Helper class function CircleModel(x,y,r,color){ this.x = x; this.y = y; this.r = r; this.color = color; } function initScene(){ //Listening for mouse position changes $('canvas').mousemove(function(e){ targetToGo.x = e.pageX; targetToGo.y = e.pageY; }); //Circle generation timer var intervalID = setInterval(function(){ if( shapes.length < MAXIMUM_AMOUNT ){ for(var i = 0; i < 1; i++){ //Generating random parameters for circle var randX = targetToGo.x - 500 + Math.floor(Math.random() * 1000); //position x var randY = targetToGo.y - 300 + Math.floor(Math.random() * 600); //position y var randRadius = Math.floor(Math.random() * 12); //radius var randColor = "#"+("000000"+(0xFFFFFF*Math.random()).toString(16)).substr(-6); //color //Adding circle to scene shapes.push( new CircleModel(randX,randY,randRadius,randColor) ); } }else{ clearInterval(intervalID); } }, 100); //Starts rendering timer - // '1000' represents 1 second,as FPS represents seconds,not miliseconds setInterval(render,1000/FPS); } function render(){ var ctx = $('canvas')[0].getContext("2d"); var circle; //Clearing the scene ctx.clearRect(0,0,$('canvas').width(),$('canvas').height()); //Drawing circles for(var i=0; i < shapes.length;++i){ circle = shapes[i]; //(animation part) //repositioning circle -- // (1/circle.r) is a degree of inertion,and the bigger radius,the slower it moves circle.x += (targetToGo.x - circle.x)*1/circle.r; circle.y += (targetToGo.y - circle.y)*1/circle.r; //////////////////////////////////////////// ctx.fillStyle = circle.color; ctx.beginPath(); ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); } } $("canvas").click(function(e){ targetToGo = {x: e.pageX, y:e.pageY}; initScene(); }); Put this code inside of $(document).ready handler. Demo