In my code below I'm trying to create a text field on the stage of the pong game. I cant seem to get it to show up on the stage. The code in question is in the main function.
First attempt at jquery and javascript here.
Thanks for your help.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pong</title>
<!-- Basic styling, centering the canvas -->
<style>
canvas {
display: block;
position: absolute;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
<script type="text/javascript" src="http://code.createjs.com/createjs-2013.12.12.min.js"></script>
</head>
<body>
<script>
var
/**
* Constants
*/
score=0,
WIDTH = 700,
HEIGHT = 600,
pi = Math.PI,
UpArrow = 38,
DownArrow = 40,
/**
* Game elements
*/
canvas,
ctx,
keystate,
/**
* The player paddle
*
* #type {Object}
*/
player = {
x: null,
y: null,
width: 20,
height: 100,
/**
* Update the position depending on pressed keys
*/
update: function () {
if (keystate[UpArrow]) this.y -= 7;
if (keystate[DownArrow]) this.y += 7;
// keep the paddle inside of the canvas
this.y = Math.max(Math.min(this.y, HEIGHT - this.height), 0);
},
/**
* Draw the player paddle to the canvas
*/
draw: function () {
ctx.fillRect(this.x, this.y, this.width, this.height);
}
},
/**
* The ai paddle
*
* #type {Object}
*/
ai = {
x: null,
y: null,
width: 20,
height: 100,
/**
* Update the position depending on the ball position
*/
update: function () {
// calculate ideal position
var desty = ball.y - (this.height - ball.side) * 0.5;
// ease the movement towards the ideal position
this.y += (desty - this.y) * 0.1;
// keep the paddle inside of the canvas
this.y = Math.max(Math.min(this.y, HEIGHT - this.height), 0);
},
/**
* Draw the ai paddle to the canvas
*/
draw: function () {
ctx.fillRect(this.x, this.y, this.width, this.height);
}
},
/**
* The ball object
*
* #type {Object}
*/
ball = {
x: null,
y: null,
vel: null,
side: 20,
speed: 12,
/**
* Serves the ball towards the specified side
*
* #param {number} side 1 right
* -1 left
*/
serve: function (side) {
// set the x and y position
var r = Math.random();
this.x = side === 1 ? player.x + player.width : ai.x - this.side;
this.y = (HEIGHT - this.side) * r;
// calculate out-angle, higher/lower on the y-axis =>
// steeper angle
var phi = 0.1 * pi * (1 - 2 * r);
// set velocity direction and magnitude
this.vel = {
x: side * this.speed * Math.cos(phi),
y: this.speed * Math.sin(phi)
}
},
/**
* Update the ball position and keep it within the canvas
*/
update: function () {
// update position with current velocity
this.x += this.vel.x;
this.y += this.vel.y;
// check if out of the canvas in the y direction
if (0 > this.y || this.y + this.side > HEIGHT) {
// calculate and add the right offset, i.e. how far
// inside of the canvas the ball is
var offset = this.vel.y < 0 ? 0 - this.y : HEIGHT - (this.y + this.side);
this.y += 2 * offset;
// mirror the y velocity
this.vel.y *= -1;
}
// helper function to check intesectiont between two
// axis aligned bounding boxex (AABB)
var AABBIntersect = function (ax, ay, aw, ah, bx, by, bw, bh) {
return ax < bx + bw && ay < by + bh && bx < ax + aw && by < ay + ah;
};
// check againts target paddle to check collision in x
// direction
var pdle = this.vel.x < 0 ? player : ai;
if (AABBIntersect(pdle.x, pdle.y, pdle.width, pdle.height,
this.x, this.y, this.side, this.side)
) {
// set the x position and calculate reflection angle
this.x = pdle === player ? player.x + player.width : ai.x - this.side;
var n = (this.y + this.side - pdle.y) / (pdle.height + this.side);
var phi = 0.25 * pi * (2 * n - 1); // pi/4 = 45
// calculate smash value and update velocity
var smash = Math.abs(phi) > 0.2 * pi ? 1.5 : 1;
this.vel.x = smash * (pdle === player ? 1 : -1) * this.speed * Math.cos(phi);
this.vel.y = smash * this.speed * Math.sin(phi);
}
// reset the ball when ball outside of the canvas in the
// x direction
if (0 > this.x + this.side || this.x > WIDTH) {
this.serve(pdle === player ? 1 : -1);
}
},
/**
* Draw the ball to the canvas
*/
draw: function () {
ctx.fillRect(this.x, this.y, this.side, this.side);
}
};
/**
* Starts the game
*/
function main() {
// create, initiate and append game canvas
canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
keystate = {};
// keep track of keyboard presses
document.addEventListener("keydown", function (evt) {
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function (evt) {
delete keystate[evt.keyCode];
});
init(); // initiate game objects
// game loop function
var loop = function () {
update();
draw();
window.requestAnimationFrame(loop, canvas);
};
window.requestAnimationFrame(loop, canvas);
//+++++++++++++++++++++++++++++++++++++++++++++++++++
//Start of code that needs some help
//+++++++++++++++++++++++++++++++++++++++++++
var instructions = new createjs.Container();
instructions.alpha = 0;
instructions.regX = 125;
instructions.regY = 70;
instructions.x = stage.canvas.width / 2;
instructions.y = stage.canvas.height / 2;
var displayBox = new createjs.Shape();
displayBox.graphics.beginFill("white").beginStroke("#000").setStrokeStyle(1).drawRoundRect(0, 0, instructions.regX * 2, instructions.regY * 2, 5).endFill().endStroke();
var text = new createjs.Text("Here are the instructions. Click to continue, or else!!", "15pt Arial", "red");
text.lineWidth = 250;
text.textAlign = "center";
text.x = instructions.regX;
text.y = 10;
//instructions.addEventListener("click", handleInstructionsClick);
instructions.addChild(displayBox, text);
stage.addChild(instructions);
// createjs.Tween.get(instructions).to({ alpha: 1 }, 500);
//+++++++++++++++++++++++++++++++++
//End of bad code block
//+++++++++++++++++++++++++++++++++
}
/**
* Initatite game objects and set start positions
*/
function init() {
player.x = player.width;
player.y = (HEIGHT - player.height) / 2;
ai.x = WIDTH - (player.width + ai.width);
ai.y = (HEIGHT - ai.height) / 2;
ball.serve(1);
}
/**
* Update all game objects
*/
function update() {
ball.update();
player.update();
ai.update();
}
/**
* Clear canvas and draw all game objects and net
*/
function draw() {
ctx.fillRect(0, 0, WIDTH, HEIGHT);
ctx.save();
ctx.fillStyle = "#fff";
ball.draw();
player.draw();
ai.draw();
// draw the net
var w = 4;
var x = (WIDTH - w) * 0.5;
var y = 0;
var step = HEIGHT / 20; // how many net segments
while (y < HEIGHT) {
ctx.fillRect(x, y + step * 0.25, w, step * 0.5);
y += step;
}
ctx.restore();
}
// start and run the game
main();
</script>
</body>
</html>
Definitely you can add any element like text field (<input>) in your page. It's hidden because the <canvas> is above it and covers it.
To add element:
textField = document.createElement("input");
textField.type = "text";
document.body.appendChild(textField);
To make it visible:
input{position: relative;}
Here's the final demo:
var
/**
* Constants
*/
score = 0,
WIDTH = 700,
HEIGHT = 600,
pi = Math.PI,
UpArrow = 38,
DownArrow = 40,
/**
* Game elements
*/
canvas,
ctx,
keystate,
/**
* The player paddle
*
* #type {Object}
*/
player = {
x: null,
y: null,
width: 20,
height: 100,
/**
* Update the position depending on pressed keys
*/
update: function () {
if (keystate[UpArrow]) this.y -= 7;
if (keystate[DownArrow]) this.y += 7;
// keep the paddle inside of the canvas
this.y = Math.max(Math.min(this.y, HEIGHT - this.height), 0);
},
/**
* Draw the player paddle to the canvas
*/
draw: function () {
ctx.fillRect(this.x, this.y, this.width, this.height);
}
},
/**
* The ai paddle
*
* #type {Object}
*/
ai = {
x: null,
y: null,
width: 20,
height: 100,
/**
* Update the position depending on the ball position
*/
update: function () {
// calculate ideal position
var desty = ball.y - (this.height - ball.side) * 0.5;
// ease the movement towards the ideal position
this.y += (desty - this.y) * 0.1;
// keep the paddle inside of the canvas
this.y = Math.max(Math.min(this.y, HEIGHT - this.height), 0);
},
/**
* Draw the ai paddle to the canvas
*/
draw: function () {
ctx.fillRect(this.x, this.y, this.width, this.height);
}
},
/**
* The ball object
*
* #type {Object}
*/
ball = {
x: null,
y: null,
vel: null,
side: 20,
speed: 12,
/**
* Serves the ball towards the specified side
*
* #param {number} side 1 right
* -1 left
*/
serve: function (side) {
// set the x and y position
var r = Math.random();
this.x = side === 1 ? player.x + player.width : ai.x - this.side;
this.y = (HEIGHT - this.side) * r;
// calculate out-angle, higher/lower on the y-axis =>
// steeper angle
var phi = 0.1 * pi * (1 - 2 * r);
// set velocity direction and magnitude
this.vel = {
x: side * this.speed * Math.cos(phi),
y: this.speed * Math.sin(phi)
}
},
/**
* Update the ball position and keep it within the canvas
*/
update: function () {
// update position with current velocity
this.x += this.vel.x;
this.y += this.vel.y;
// check if out of the canvas in the y direction
if (0 > this.y || this.y + this.side > HEIGHT) {
// calculate and add the right offset, i.e. how far
// inside of the canvas the ball is
var offset = this.vel.y < 0 ? 0 - this.y : HEIGHT - (this.y + this.side);
this.y += 2 * offset;
// mirror the y velocity
this.vel.y *= -1;
}
// helper function to check intesectiont between two
// axis aligned bounding boxex (AABB)
var AABBIntersect = function (ax, ay, aw, ah, bx, by, bw, bh) {
return ax < bx + bw && ay < by + bh && bx < ax + aw && by < ay + ah;
};
// check againts target paddle to check collision in x
// direction
var pdle = this.vel.x < 0 ? player : ai;
if (AABBIntersect(pdle.x, pdle.y, pdle.width, pdle.height,
this.x, this.y, this.side, this.side)) {
// set the x position and calculate reflection angle
this.x = pdle === player ? player.x + player.width : ai.x - this.side;
var n = (this.y + this.side - pdle.y) / (pdle.height + this.side);
var phi = 0.25 * pi * (2 * n - 1); // pi/4 = 45
// calculate smash value and update velocity
var smash = Math.abs(phi) > 0.2 * pi ? 1.5 : 1;
this.vel.x = smash * (pdle === player ? 1 : -1) * this.speed * Math.cos(phi);
this.vel.y = smash * this.speed * Math.sin(phi);
}
// reset the ball when ball outside of the canvas in the
// x direction
if (0 > this.x + this.side || this.x > WIDTH) {
this.serve(pdle === player ? 1 : -1);
}
},
/**
* Draw the ball to the canvas
*/
draw: function () {
ctx.fillRect(this.x, this.y, this.side, this.side);
}
};
/**
* Starts the game
*/
function main() {
// create, initiate and append game canvas
canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
textField = document.createElement("input");
textField.type = "text";
document.body.appendChild(textField);
keystate = {};
// keep track of keyboard presses
document.addEventListener("keydown", function (evt) {
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function (evt) {
delete keystate[evt.keyCode];
});
init(); // initiate game objects
// game loop function
var loop = function () {
update();
draw();
window.requestAnimationFrame(loop, canvas);
};
window.requestAnimationFrame(loop, canvas);
//+++++++++++++++++++++++++++++++++++++++++++++++++++
//Start of code that needs some help
//+++++++++++++++++++++++++++++++++++++++++++
var instructions = new createjs.Container();
instructions.alpha = 0;
instructions.regX = 125;
instructions.regY = 70;
instructions.x = stage.canvas.width / 2;
instructions.y = stage.canvas.height / 2;
var displayBox = new createjs.Shape();
displayBox.graphics.beginFill("white").beginStroke("#000").setStrokeStyle(1).drawRoundRect(0, 0, instructions.regX * 2, instructions.regY * 2, 5).endFill().endStroke();
var text = new createjs.Text("Here are the instructions. Click to continue, or else!!", "15pt Arial", "red");
text.lineWidth = 250;
text.textAlign = "center";
text.x = instructions.regX;
text.y = 10;
//instructions.addEventListener("click", handleInstructionsClick);
instructions.addChild(displayBox, text);
stage.addChild(instructions);
// createjs.Tween.get(instructions).to({ alpha: 1 }, 500);
//+++++++++++++++++++++++++++++++++
//End of bad code block
//+++++++++++++++++++++++++++++++++
}
/**
* Initatite game objects and set start positions
*/
function init() {
player.x = player.width;
player.y = (HEIGHT - player.height) / 2;
ai.x = WIDTH - (player.width + ai.width);
ai.y = (HEIGHT - ai.height) / 2;
ball.serve(1);
}
/**
* Update all game objects
*/
function update() {
ball.update();
player.update();
ai.update();
}
/**
* Clear canvas and draw all game objects and net
*/
function draw() {
ctx.fillRect(0, 0, WIDTH, HEIGHT);
ctx.save();
ctx.fillStyle = "#fff";
ball.draw();
player.draw();
ai.draw();
// draw the net
var w = 4;
var x = (WIDTH - w) * 0.5;
var y = 0;
var step = HEIGHT / 20; // how many net segments
while (y < HEIGHT) {
ctx.fillRect(x, y + step * 0.25, w, step * 0.5);
y += step;
}
ctx.restore();
}
// start and run the game
main();
canvas {
display: block;
position: absolute;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
input{position: relative;}
<script src="http://code.createjs.com/createjs-2013.12.12.min.js"></script>
With Jquery, try this
$("body").append('<input type="text" name="myTextName" id="myTextId" class="myTextClass"/>');
Related
I want to move a character along a specific path. How can I achieve this?
Example visualization
It is necessary for the hero to get to a point on the map, but stop at each point and, when you press the button "to the university", continues on his way. That is, when the button was pressed, it made a move.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const hero = new Image();
hero.src = '../img/hero.png';
let x = 430;
let y = 425;
hero.onload = function() {
ctx.drawImage(hero,x,y,31,86)
}
const go = document.querySelector('.go_university');
let tur = 0;
let timer;
let direction = 0;
go.addEventListener('click',()=>{
tur += 1;
turn();
})
function turn(){
ctx.clearRect(0,0,960,630);
direction+=1;
if(direction<=15){
x-=2;
y=(y-2/3);
}else if(direction >= 15 && direction <= 28){
x-=2;
y=(y-2);
}else if(direction >=28 && direction <=48){
x-=2;
y=(y+3/6);
}else if(direction >= 48 && direction <=70){
x-=2;
y=(y+3/6);
}
timer = setTimeout(turn,60);
ctx.drawImage(hero,x,y,31,86)
}
This is the code I wrote. I can't figure it out any further. How can I restore animation on click? And in general, am I doing the calculations correctly?
I wrote a blog post on this a while back while the JS isn't the newest the concepts are all the same. I assume you have a collection of waypoints you want to move your character towards which I define in this code under targets.
The main thing really is the pointing at a target and moving towards it
Ball.prototype.update = function () {
// get the target x and y
this.targetX = targets[this.target].x;
this.targetY = targets[this.target].y;
// We need to get the distance this time around
var tx = this.targetX - this.x,
ty = this.targetY - this.y,
dist = Math.sqrt(tx * tx + ty * ty);
/*
* we calculate a velocity for our object
* divide the target x and y by the distance and multiply it by our speed
* this gives us a constant movement speed.
*/
this.velX = (tx / dist) * this.speed;
this.velY = (ty / dist) * this.speed;
/*
* Get the direction we are facing
* I just use -tx and -ty here because we already calculated tx and ty
* To get the proper x and y you need to subtract the targets x and y from
* our objects x and y
*/
var radians = Math.atan2(-ty,-tx);
this.px = this.x - this.pointLength * Math.cos(radians);
this.py = this.y - this.pointLength * Math.sin(radians);
// Once we hit our target move on to the next.
if (dist > this.radius/2) {
// add our velocities
this.x += this.velX;
this.y += this.velY;
}else{
this.target++;
if(this.target == targets.length){
this.target = 0;
}
}
};
If you want to pause and wait for a click you would do that when the player reaches the target instead of automatically selecting the next target you'd do it onclick.
Full snippet included below.
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 500,
height = 600,
balls = [],
targets = [
{x : 450, y : 20},
{x : 450, y : 150},
{x : 20, y : 150},
{x : 20, y : 250},
{x : 450, y : 250},
{x : 450, y : 350},
{x : 20, y : 350},
{x : 20, y : 450},
{x : 450, y : 450},
{x : 450, y : 550},
{x : 20, y : 550},
{x : 20, y : 20}
],
started = false;
canvas.width = width;
canvas.height = height;
canvas.addEventListener("mouseenter", function (e) {
if(!started){
started = true;
render();
}
});
canvas.addEventListener("mouseleave", function (e) {
started = false;
});
var Ball = function (x, y, radius, color) {
this.x = x || 0;
this.y = y || 0;
this.radius = radius || 10;
this.speed = 3;
this.color = color || "rgb(255,0,0)";
this.pointLength = 20;
this.px = 0;
this.py = 0;
this.target = 0;
this.targetX = 0;
this.targetY = 0;
this.velX = 0;
this.velY = 0;
}
Ball.prototype.update = function () {
// get the target x and y
this.targetX = targets[this.target].x;
this.targetY = targets[this.target].y;
// We need to get the distance this time around
var tx = this.targetX - this.x,
ty = this.targetY - this.y,
dist = Math.sqrt(tx * tx + ty * ty);
/*
* we calculate a velocity for our object this time around
* divide the target x and y by the distance and multiply it by our speed
* this gives us a constant movement speed.
*/
this.velX = (tx / dist) * this.speed;
this.velY = (ty / dist) * this.speed;
/*
* Get the direction we are facing
* I just use -tx and -ty here because we already calculated tx and ty
* To get the proper x and y you need to subtract the targets x and y from
* our objects x and y
*/
var radians = Math.atan2(-ty,-tx);
this.px = this.x - this.pointLength * Math.cos(radians);
this.py = this.y - this.pointLength * Math.sin(radians);
// Once we hit our target move on to the next.
if (dist > this.radius/2) {
// add our velocities
this.x += this.velX;
this.y += this.velY;
}else{
this.target++;
if(this.target == targets.length){
this.target = 0;
}
}
};
Ball.prototype.render = function () {
ctx.fillStyle = this.color;
ctx.beginPath();
// draw our circle with x and y being the center
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.strokeStyle = "rgb(0,0,255)";
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.px, this.py);
ctx.closePath();
ctx.stroke();
};
for(var i = 0; i < 20; i++){
balls.push(new Ball(20 - i * 30, 20, 10));
}
function render() {
ctx.clearRect(0, 0, width, height);
balls.forEach(function(el){
el.update();
el.render();
});
if(started){
requestAnimationFrame(render);
}
}
render();
canvas {
border:1px solid black;
}
<canvas id="canvas"></canvas>
I got this HTML5 canvas project I'm struggling with.
Basically I'm trying to add a new particle on click.
And the particles is pushed to the particles array, but
the particle does not show. I can see that the particle is pushed to the array with the mouse coordinates, but it doesn't seem like the last particle is drawn.
What am I doing wrong?
See example.
// Request animation frame
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Set full-screen
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Options
var num = 100; // Number of particles to draw
var size = 2; // Particle size
var color = '#dd64e6'; // Particle color
var min_speed = .3; // Particle min speed
var max_speed = 2; // Particle max speed
var dist = 100; // Max distance before line gets cut
var dist_sq = dist * dist; // Dist squared
var line_width = 2; // Line width
var background = '#181b23'; // Background color
var line_color = '#1d2631'; // Line color
var fps = 60;
var now, delta;
var then = Date.now();
var interval = 1000 / fps;
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
num = 10;
fps = 29;
}
// Particles array
var particles = [];
for (var i = 0; i < num; i++) {
particles.push(
new create_particle(false, false)
);
}
// Lets animate the particle
function draw() {
// Loop
requestAnimationFrame(draw);
now = Date.now();
delta = now - then;
if (delta > interval) {
then = now - (delta % interval);
// Background
ctx.fillStyle = background;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Lets draw particles from the array now
draw_particles();
}
}
// Draw particles
function draw_particles() {
for (var t = 0; t < num; t++) {
// This particle
var p = particles[t];
for (var q = t + 1; q < num; q++) {
// Check X first, maybe we don't need to
// calculate Y
var x = particles[q].x - p.x;
if ((x *= x) < dist_sq) {
// Check passed, calculate Y
var y = particles[q].y - p.y;
if (x + (y * y) < dist_sq) {
// Check passed, draw line
draw_line(p.x, p.y, particles[q].x, particles[q].y);
}
}
}
// Color
ctx.fillStyle = color;
// Circle path
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
ctx.fill();
// Lets use the velocity now
p.x += p.vx;
p.y += p.vy;
// If there is only 1 particle
// show X, Y, and velocity
if (num === 1) {
ctx.fillText('Y:' + p.y, 20, 20);
ctx.fillText('X:' + p.x, 20, 40);
ctx.fillText('YV:' + p.vy, 20, 60);
ctx.fillText('XV:' + p.vx, 20, 80);
}
// To prevent the balls from moving out of the canvas
if (p.x < size) p.vx *= (p.vx / -p.vx);
if (p.y < size) p.vy *= (p.vy / -p.vy);
if (p.x > canvas.width - size) p.vx *= (-p.vx / p.vx);
if (p.y > canvas.height - size) p.vy *= (-p.vy / p.vy);
}
}
// Return a particle object
function create_particle(xPos, yPos) {
// Position
if (xPos == false && yPos == false) {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
} else {
this.x = xPos;
this.y = yPos;
}
// Velocity
this.vx = random_int_between(min_speed, max_speed);
this.vy = random_int_between(min_speed, max_speed);
// Size
this.radius = size;
console.log('particle created at: ' + this.x + ', ' + this.y);
}
// Returns an random integer, positive or negative
// between the given value
function random_int_between(min, max) {
var num = Math.floor(Math.random() * max) - min;
num *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
return num;
}
// Draw a line between 2 particles
// given the particles x and y position
function draw_line(p_x, p_y, p2_x, p2_y) {
ctx.beginPath();
ctx.lineWidth = line_width;
ctx.strokeStyle = line_color;
ctx.moveTo(p_x, p_y);
ctx.lineTo(p2_x, p2_y);
ctx.stroke();
}
// When the canvas is clicked
// add new particle
function clicked(e) {
var mouseXpos, mouseYpos;
if (e.offsetX) {
mouseXpos = e.offsetX;
mouseYpos = e.offsetY;
} else if (e.layerX) {
mouseXpos = e.layerX;
mouseYpos = e.layerY;
}
particles.push(
new create_particle(mouseXpos, mouseYpos)
);
}
canvas.addEventListener('click', function(e) {
clicked(e);
}, false);
draw();
<!DOCTYPE html>
<html>
<head>
<style>
* {margin:0;padding:0;overflow:hidden;}
</style>
</head>
<body>
<canvas id="canvas">{{-- The background --}}</canvas>
</body>
</html>
Well since no one else answered this other than in a comment, I thought I would answer it so that others might not wonder about the same thing.
The problem is that you use a variable "num" to hold the number of particles. If you instead use "particles.length" you can
// Request animation frame
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Set full-screen
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Options
var num = 100; // Number of particles to draw
var size = 2; // Particle size
var color = '#dd64e6'; // Particle color
var min_speed = .3; // Particle min speed
var max_speed = 2; // Particle max speed
var dist = 100; // Max distance before line gets cut
var dist_sq = dist * dist; // Dist squared
var line_width = 2; // Line width
var background = '#181b23'; // Background color
var line_color = '#1d2631'; // Line color
var fps = 60;
var now, delta;
var then = Date.now();
var interval = 1000 / fps;
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
num = 10;
fps = 29;
}
// Particles array
var particles = [];
for (var i = 0; i < num; i++) {
particles.push(
new create_particle(false, false)
);
}
// Lets animate the particle
function draw() {
// Loop
requestAnimationFrame(draw);
now = Date.now();
delta = now - then;
if (delta > interval) {
then = now - (delta % interval);
// Background
ctx.fillStyle = background;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Lets draw particles from the array now
draw_particles();
}
}
// Draw particles
function draw_particles() {
for (var t = 0; t < particles.length; t++) {
// This particle
var p = particles[t];
for (var q = t + 1; q < particles.length; q++) {
// Check X first, maybe we don't need to
// calculate Y
var x = particles[q].x - p.x;
if ((x *= x) < dist_sq) {
// Check passed, calculate Y
var y = particles[q].y - p.y;
if (x + (y * y) < dist_sq) {
// Check passed, draw line
draw_line(p.x, p.y, particles[q].x, particles[q].y);
}
}
}
// Color
ctx.fillStyle = color;
// Circle path
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
ctx.fill();
// Lets use the velocity now
p.x += p.vx;
p.y += p.vy;
// If there is only 1 particle
// show X, Y, and velocity
if (num === 1) {
ctx.fillText('Y:' + p.y, 20, 20);
ctx.fillText('X:' + p.x, 20, 40);
ctx.fillText('YV:' + p.vy, 20, 60);
ctx.fillText('XV:' + p.vx, 20, 80);
}
// To prevent the balls from moving out of the canvas
if (p.x < size) p.vx *= (p.vx / -p.vx);
if (p.y < size) p.vy *= (p.vy / -p.vy);
if (p.x > canvas.width - size) p.vx *= (-p.vx / p.vx);
if (p.y > canvas.height - size) p.vy *= (-p.vy / p.vy);
}
}
// Return a particle object
function create_particle(xPos, yPos) {
// Position
if (xPos == false && yPos == false) {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
} else {
this.x = xPos;
this.y = yPos;
}
// Velocity
this.vx = random_int_between(min_speed, max_speed);
this.vy = random_int_between(min_speed, max_speed);
// Size
this.radius = size;
console.log('particle created at: ' + this.x + ', ' + this.y);
}
// Returns an random integer, positive or negative
// between the given value
function random_int_between(min, max) {
var num = Math.floor(Math.random() * max) - min;
num *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
return num;
}
// Draw a line between 2 particles
// given the particles x and y position
function draw_line(p_x, p_y, p2_x, p2_y) {
ctx.beginPath();
ctx.lineWidth = line_width;
ctx.strokeStyle = line_color;
ctx.moveTo(p_x, p_y);
ctx.lineTo(p2_x, p2_y);
ctx.stroke();
}
// When the canvas is clicked
// add new particle
function clicked(e) {
var mouseXpos, mouseYpos;
if (e.offsetX) {
mouseXpos = e.offsetX;
mouseYpos = e.offsetY;
} else if (e.layerX) {
mouseXpos = e.layerX;
mouseYpos = e.layerY;
}
particles.push(
new create_particle(mouseXpos, mouseYpos)
);
}
canvas.addEventListener('click', function(e) {
clicked(e);
}, false);
draw();
<!DOCTYPE html>
<html>
<head>
<style>
* {margin:0;padding:0;overflow:hidden;}
</style>
</head>
<body>
<canvas id="canvas">{{-- The background --}}</canvas>
</body>
</html>
I will dare to go outside the scope of our problem because you could prevent such issues in the future by utilizing Array.prototype.forEach, and move the drawing of the dots and constrain them to new functions. With the added benefit of simplifying your code.
// Draw particles
function draw_particles() {
particles.forEach(function(p,pi){
particles.forEach(function(p2,p2i){
if(pi === p2i){
return;
}
// Check X first, maybe we don't need to
// calculate Y
var x = p2.x - p.x;
if ((x *= x) < dist_sq) {
// Check passed, calculate Y
var y = p2.y - p.y;
if (x + (y * y) < dist_sq) {
// Check passed, draw line
draw_line(p.x, p.y, p2.x, p2.y);
draw_dot(p);
constrain(p);
}
}
});
});
}
// Draw particle
function draw_dot(p){
// Color
ctx.fillStyle = color;
// Circle path
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
ctx.fill();
ctx.closePath();
// Lets use the velocity now
p.x += p.vx;
p.y += p.vy;
// If there is only 1 particle
// show X, Y, and velocity
if (particles.length === 1) {
ctx.fillText('Y:' + p.y, 20, 20);
ctx.fillText('X:' + p.x, 20, 40);
ctx.fillText('YV:' + p.vy, 20, 60);
ctx.fillText('XV:' + p.vx, 20, 80);
}
}
// Constrain particle movement
function constrain(p){
// To prevent the balls from moving out of the canvas
if (p.x < size) p.vx *= (p.vx / -p.vx);
if (p.y < size) p.vy *= (p.vy / -p.vy);
if (p.x > canvas.width - size) p.vx *= (-p.vx / p.vx);
if (p.y > canvas.height - size) p.vy *= (-p.vy / p.vy);
}
Using Array.prototype.length and Array.prototype.forEach reduces the risk of heading into issues of array indices.
I want to draw circular balls on an HTML canvas in a pyramid pattern.
Like this:
Fiddle where you can show me the algorithm:
https://jsfiddle.net/ofxmr17c/3/
var canvas = document.getElementById('canvas');
canvas.width = 400;
canvas.height = 400;
var ctx = canvas.getContext('2d');
var balls = [];
var ballsLength = 15;
var Ball = function() {
this.x = 0;
this.y = 0;
this.radius = 10;
};
Ball.prototype.draw = function(x, y) {
this.x = x;
this.y = y;
ctx.fillStyle = '#333';
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.fill();
ctx.closePath();
};
init();
function init() {
for (var i = 0; i < ballsLength; i++) {
balls.push(new Ball());
}
render();
}
function render() {
for (var i = 1; i <= ballsLength; i++) {
if (i >= 1 && i <= 5) {
balls[i].draw(i * 20 + balls[i].radius, 20 + balls[i].radius);
}
if (i >= 6 && i <= 9) {
balls[i].draw(i * 20 + balls[i].radius, 20 + balls[i].radius * 2);
}
if (i >= 10 && i <= 12) {
balls[i].draw(i * 20 + balls[i].radius, 20 + balls[i].radius * 3);
}
if (i >= 13 && i <= 14) {
balls[i].draw(i * 20 + balls[i].radius, 20 + balls[i].radius * 4);
}
if (i == 15) {
balls[i].draw(i * 20 + balls[i].radius, 20 + balls[i].radius * 5);
}
}
window.requestAnimationFrame(render);
}
canvas {
border: 1px solid #333;
}
<canvas id="canvas"></canvas>
I have Ball class with x, y and radius variables:
var Ball = function() {
this.x = 0;
this.y = 0;
this.radius = 10;
};
Then I have method of the Ball class which draws the balls on the canvas:
Ball.prototype.draw = function(x, y) {
this.x = x;
this.y = y;
ctx.fillStyle = '#333';
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.fill();
ctx.closePath();
};
I want to create method which will place any number of balls into a pyramid.
The live demo below shows how to pack an arbitrary number of balls into a pyramid using a bit of trigonometry. To change the amount of layers in the pyramid (and thus the number of balls), edit the NUM_ROWS variable.
This is how it looks when it's done:
Live Demo:
var canvas = document.getElementById('canvas');
canvas.width = 400;
canvas.height = 400;
var ctx = canvas.getContext('2d');
var balls = [];
var ballsLength = 15;
var Ball = function() {
this.x = 0;
this.y = 0;
this.radius = 10;
};
Ball.prototype.draw = function(x, y) {
this.x = x;
this.y = y;
ctx.fillStyle = '#333';
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.fill();
ctx.closePath();
};
init();
function init() {
for (var i = 0; i < ballsLength; i++) {
balls.push(new Ball());
}
render();
}
function render() {
var NUM_ROWS = 5;
for (var i = 1; i <= NUM_ROWS; i++) {
for (var j = 0; j < i; j++) {
balls[i].draw(j * balls[0].radius * 2 + 150 - i * balls[0].radius, -(i * balls[0].radius * 2 * Math.sin(Math.PI / 3)) + 150);
}
}
//window.requestAnimationFrame(render);
}
canvas {
border: 1px solid #333;
}
<canvas id="canvas"></canvas>
JSFiddle Version: https://jsfiddle.net/ofxmr17c/6/
A billiard pyramid like this is always made with some known facts:
Each row always contains one more ball than the previous
It's an equilateral equal angled (sp? in english?) triangle which means next row always starts offset 60°
So we can make a vector (everything else in a billiard game would very much involve vectors so why not! :) ) for the direction of the next row's start point like so:
var deg60 = -60 / 180 * Math.PI; // -60°, up-right direction
var v = {
x: radius * Math.cos(deg60),
y: radius * Math.sin(deg60)
}
Then the algorithm would be (driven by total number of balls):
Start with a max limit of 1 for first row
Plot balls until max limit for row is reached
Then, add one to the max limit
Reset row count
Move position to beginning of last row + vector
Repeat until number of balls is reached
Result:
Example
var ctx = c.getContext("2d"),
radius = 9, // ball radius
deg = -60 / 180 * Math.PI, // direction of row start -60°
balls = 15, // number of balls to draw
drawn = 0, // count balls drawn on current row
rowLen = 1, // max length of current row (first=1)
x = 150, // start point
y = 140,
cx = 150, cy =140, // replicates start point + offsets
v = { // vector
x: radius * 2 * Math.cos(deg),
y: radius * 2 * Math.sin(deg)
},
i;
for(i = 0; i < balls; i++) {
drawBall(cx, cy); // draw ball
cx -= radius * 2; // move diameter of ball to left (in this case)
drawn++; // increase balls on row count
if (drawn === rowLen) { // reached max balls for row?
cx = x + v.x * rowLen; // increase one row
cy = y + v.y * rowLen;
drawn = 0; // reset ball count for row
rowLen++; // increase row limit
}
}
ctx.fillStyle = "#D70000";
ctx.fill();
function drawBall(x, y) {
ctx.moveTo(x + radius, y); ctx.arc(x, y, radius, 0, 6.28);
ctx.closePath();
}
<canvas id=c height=300></canvas>
If you want more flexibility in terms of rotation you can simply swap this line:
cx -= radius * 2;
with a vector perpendicular (calculation not shown) to the first vector so:
cx += pv.x;
cy += pv.y;
So first, I uploaded a car to the canvas and gave it turning and motion properties. I tried to draw a circle to go alongside the car but it is not working properly. The circle is alone and flickering for some reason. I removed the timeout completely, and both the circle and car disappeared. Adjusting the timeout rate doesn't remove the flicker. Help me get them on the screen and keep them there together please?
http://jsbin.com/zogeraduze/1/edit?html,js,output
I don't have your car image, but it seems like you have a setInterval set to 30ms and you call a timeout every 10ms (which is equivalent to a setInterval), each time clearing the canvas, hence creating a flickering. You should have only one repaint function that should clear the canvas, draw the car and then draw the circle.
try
//Setting the canvas and context
var canvas = document.getElementById('gameCanvas');
var context = canvas.getContext('2d');
//Uploading car
var car = new Image();
car.src = "file:///H:/Desktop/Game/img/car.png";
//Setting properties of car
var x = 450;
var y = 730;
var speed = 10;
var angle = 990;
var mod = 0;
//Event listeners for keys
window.addEventListener("keydown", keypress_handler, false);
window.addEventListener("keyup", keyup_handler, false);
//Drawing the car turning and changing speed
function draw() {
x += (speed * mod) * Math.cos(Math.PI / 180 * angle);
y += (speed * mod) * Math.sin(Math.PI / 180 * angle);
context.save();
context.translate(x, y);
context.rotate(Math.PI / 180 * angle);
context.drawImage(car, -(car.width / 2), -(car.height / 2));
context.restore();
}
//Setting the keys
function keyup_handler(event) {
console.log('a');
if (event.keyCode == 38 || event.keyCode == 40) {
mod = 0;
}
}
//Setting all of the keys
function keypress_handler(event) {
console.log(event.keyCode);
if (event.keyCode == 38) {
mod = 1;
}
if (event.keyCode == 40) {
mod = -1;
}
if (event.keyCode == 37) {
angle -= 5;
}
if (event.keyCode == 39) {
angle += 5;
}
}
var context = $('#gameCanvas')[0].getContext('2d');
var width = $('#gameCanvas').width();
var height = $('#gameCanvas').height();
var circleX = width / 2;
var circleY = height / 2;
var circleVX = 1.0;
var circleVY = 0.0;
var circleR = 30;
function update() {
context.clearRect(0, 0, width, height);
/*
circleX = Math.random() * (width - 2 * circleR) + circleR;
circleY = Math.random() * (height - 2 * circleR) + circleR;
*/
draw();
drawCircle(circleX, circleY, circleR);
setTimeout(update, 10);
}
function canvasClick(event) {
var clickX = event.pageX;
var clickY = event.pageY;
var edgeX = clickX - circleX;
var edgeY = clickY - circleY;
var r = Math.sqrt(edgeX * edgeX + edgeY * edgeY);
if (r < circleR) {
context.clearRect(0, 0, width, height);
}
}
function drawCircle(x, y, r) {
context.beginPath();
context.arc(x, y, r, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 3;
context.strokeStyle = 'black';
context.stroke();
}
$('#gameCanvas').click(canvasClick);
update();
Also, look into https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame instead of using timeouts
How to move the square to the destination? Square moves one pixel only when click the mouse? Sorry for my english.
window.onload = function(){
var x = 50;
var y = 50;
var c = document.getElementById("game");
var ctx = c.getContext("2d");
init();
draw();
function init()
{
document.addEventListener("click",paint,false);
}
function paint(e)
{
if(x<e.clientX) x++;
}
function draw()
{
ctx.clearRect(x-1,y,1,15);
ctx.fillStyle = "blue";
ctx.fillRect(x,y,15,15);
window.requestAnimationFrame(draw);
}
}
Here is one way to do it, adapted from this article that I wrote a few months back.
The following is the piece to get it working
var tx = targetX - x,
ty = targetY - y,
dist = Math.sqrt(tx*tx+ty*ty);
velX = (tx/dist)*thrust;
velY = (ty/dist)*thrust;
We need to get the difference between the current position and targeted position (clicked area), we then get the distance, and make the velocity for x and y equal to the difference divided by the total distance multiplied by the speed of the object.
Full working example and code
Live demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 500,
height = 500,
mX = width/2,
mY = height/2;
canvas.width = width;
canvas.height = height;
canvas.addEventListener("click", function (e) {
mX = e.pageX;
mY = e.pageY;
});
var Ball = function (x, y, radius, color) {
this.x = x || 0;
this.y = y || 0;
this.radius = radius || 10;
this.speed = 5;
this.color = color || "rgb(255,0,0)";
this.velX = 0;
this.velY = 0;
}
Ball.prototype.update = function (x, y) {
// get the target x and y
this.targetX = x;
this.targetY = y;
// We need to get the distance this time around
var tx = this.targetX - this.x,
ty = this.targetY - this.y,
dist = Math.sqrt(tx * tx + ty * ty);
/*
* we calculate a velocity for our object this time around
* divide the target x and y by the distance and multiply it by our speed
* this gives us a constant movement speed.
*/
this.velX = (tx / dist) * this.speed;
this.velY = (ty / dist) * this.speed;
// Stop once we hit our target. This stops the jittery bouncing of the object.
if (dist > this.radius / 2) {
// add our velocities
this.x += this.velX;
this.y += this.velY;
}
};
Ball.prototype.render = function () {
ctx.fillStyle = this.color;
ctx.beginPath();
// draw our circle with x and y being the center
ctx.arc(this.x - this.radius / 2, this.y - this.radius / 2, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
};
var ball1 = new Ball(width / 2, height / 2, 10);
function render() {
ctx.clearRect(0, 0, width, height);
ball1.update(mX, mY);
ball1.render();
requestAnimationFrame(render);
}
render();