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

Categories

Resources