I have this code which is a bouncing ball that I can move with a mouse and it is supposed to work like a slingshot. The problems are: By dragging the ball I change ball speed to mouse speed but it happens even when I click blank space. Also the speed I get from the mouse is somehow not the one with which i move my mouse. How do I change speed only when I hold the ball and calculate the speed of the whole mouse move?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas id="myCanvas" width="800" height="800"></canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 30;
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 0;
var dy = 0;
var w=myCanvas.width;
var h=myCanvas.height;
var isDrag=false;
var offset={x:0,y:0};
var totalX = 0;
var totalY = 0;
var moveX = 0;
var moveY = 0;
function drawBall() {
ctx.beginPath();
circle(x,y,ballRadius,'#c1153e');;
ctx.fillStyle = "red";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
dy = -dy;
}
x += dx;
y += dy;
}
setInterval(draw, 15);
function circle(x,y,ballRadius,color='black'){
ctx.clearRect(0,0,w,h)
ctx.fillStyle=color;
ctx.beginPath();
ctx.arc(x,y,ballRadius,0,2*Math.PI);
ctx.fill();
}
circle(x,y,ballRadius,'#c1153e');
myCanvas.onmousedown=function(e){
var m=get_mouse_coords(e);
circle(x,y,ballRadius,'green');
if ((x-m.x)*(x-m.x)+(y-m.y)*(y-m.y)<ballRadius*ballRadius){
isDrag=true;
circle(x,y,ballRadius,'red');
offset.x=x-m.x;
offset.y=y-m.y;
x=m.x+offset.x;
y=m.y+offset.y;
}
}
function get_mouse_coords(e){
var m={};
var rect=myCanvas.getBoundingClientRect();
m.x=e.clientX-rect.left;
m.y=e.clientY-rect.top;
//console.log(m);
return m;
}
myCanvas.onmousemove=function(e){
var m=get_mouse_coords(e);
if (isDrag) {
x=m.x;
y=m.y;
x=m.x+offset.x;
y=m.y+offset.y;
circle(x,y,ballRadius,'red');
}
}
myCanvas.onmouseup=function(e){
var m=get_mouse_coords(e);
isDrag=false;
dx=-totalX/300;
dy=-totalY/300;
circle(x,y,ballRadius);
}
var totalX = 0;
var totalY = 0;
var moveX = 0;
var moveY = 0;
document.addEventListener("mousemove", function(ev){
totalX += Math.abs(ev.movementX);
totalY += Math.abs(ev.movementY);
moveX += ev.movementX;
moveY += ev.movementY;
}, false);
setInterval(function(){
console.log(`Speed X: ${totalX}px/s, Y: ${totalY}px/s`);
console.log(`Movement X: ${moveX}px/s, Y: ${moveY}px/s`);
moveX = moveY = totalX = totalY = 0;
}, 10000);
</script>
</body>
</html>
From what I see, the event onmouseup is executed even if you clicked in blank space, you should probably check also that isDrag is true.
Secondly, I am not sure to understand what you want to do exactly, but should you not set the speed of your ball to zero when you click on it? Otherwise the ball is still moving even if your mouse isn't.
Related
I am very new to the HTML canvas and so far the only way I've used it is with the p5.js framework. I have a particle system in which I want the particles to chase my cursor. However, they won't show up, although the inspector isn't throwing any errors:
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
var mouseX, mouseY;
var c=document.getElementById("myCanvas");
c.width = window.innerWidth;
c.height = window.innerHeight;
var ctx=c.getContext("2d");
var img=document.getElementById("stars");
function star(X, Y) {
this.x = X;
this.y = Y;
this.size = getRandomArbitrary(3, 5);
}
star.prototype.draw = function() {
ctx.fillStyle = "red";
ctx.fill();
ctx.beginPath();
ctx.arc(this.x,this.y, this.size, 0, 2*Math.PI);
ctx.stroke();
}
star.prototype.update = function() {
// var mousePos = getMousePos(ctx, e);
var xvel = this.x - mouseX;
var yvel = this.y - mouseY;
Math.max(1, Math.min(xvel, 7));
Math.max(1, Math.min(yvel, 7));
this.x += xvel;
this.y += yvel;
}
function starSystem(Num) {
this.stars = [];
for (var i = 0; i < Num; i++) {
this.stars.push(new star(getRandomArbitrary(0, ctx.width), getRandomArbitrary(0, ctx.height)));
}
}
starSystem.prototype.run = function() {
for (var i = 0; i < this.stars.length; i++) {
this.stars[i].update();
this.stars[i].draw();
}
}
// ctx.drawImage(img,10,10);
var ss = new starSystem(50);
function iterate(e) {
mouseX = e.clientX;
mouseY = e.clientY;
ss.run();
}
Here is my canvas tag:
<canvas id="myCanvas" onmousemove="iterate(event)">
</canvas>
I wouldn't want to call the iterate function this way (I would rather just use a setInterval) but this seems the easiest way I can get hold of the event variable e so I can calculate the mouse position. (See my iterate function)
My main question is: why isn't the draw function for the stars creating any visible results on the canvas? I know my code is probably very messy and unconventional, but I would like to know what is the most efficient way to get the particles to draw on the screen. Thanks so much!
So, I have created an array of 10 blocks(rectangles) that move horizontally towards a "finish" line (end of canvas width) with variable speeds. I'm looking for a way to keep track of the arrival order of each array element and display it on top of each rectangle as it stops moving. I've tried using a counter and the fillText method to do that, but it only works until other elements come to a full stop and then it replaces the order. For a better view of what happens, here is my code. If anyone has any suggestions on what to use in order to fulfill my goal, it is very much appreciated. Keep in mind that I only use plain JavaScript as in no jQuery or other frameworks as I am learning the basics. Thanks in advance.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cars</title>
<style>
canvas {
border:1px solid #3D0404;
}
h2 {
margin-left:23%;
}
</style>
<script>
var c;
var ctx;
var cars = [];
var width = 100;
var height = 100;
var x = 0;
var y = 0;
var i;
var temp;
var cw = 1000;
var ch = 1000;
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
function init() {
c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
pushCar();
}
function CreateCar(x,y,width,height,speed){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
function pushCar(){
for (var i=0; i<10; i++){
var speed = Math.random() * 10;
var car = new CreateCar(x,y,width,height,speed);
cars.push(car);
y += 100;
}
drawAll();
}
function clear (){
ctx.clearRect (0,0,cw,ch);
}
function draw(cars){
ctx.beginPath();
ctx.fillStyle = "#f00";
ctx.fillRect(temp.x, temp.y, width, height);
ctx.strokeStyle = "#000";
ctx.outlineWidth = 2;
ctx.strokeRect(temp.x, temp.y, width, height);
ctx.closePath();
}
function drawAll(){
clear();
var z = 1;
for (var i=0; i<cars.length; i++){
temp = cars[i];
draw(temp);
if (temp.x+100 < c.width){
temp.x += temp.speed;
}else {
ctx.font = "20pt Verdana";
ctx.fillStyle = "#000";
ctx.fillText(z, 950, temp.y+55);
z++;
}
}
requestAnimFrame(drawAll, c);
}
</script>
</head>
<body onLoad = "init()">
<canvas id="myCanvas" width="1000" height="1000"></canvas>
</body>
</html>
You need to put the z variable outside the loop, and save the position of each car in an object. You also need to check if position[i] is already defined to avoid incrementing the current position more times than needed.
var z;
var position;
function drawAll() {
clear();
for (var i = 0; i < cars.length; i++) {
temp = cars[i];
draw(temp);
if (temp.x + 100 < c.width) {
temp.x += temp.speed;
} else {
if (!position[i]) {
position[i] = z;
z++;
}
ctx.font = "20pt Verdana";
ctx.fillStyle = "#000";
ctx.fillText(position[i], 950, temp.y + 55);
}
}
requestAnimFrame(drawAll, c);
}
http://jsfiddle.net/acasaccia/u2vhaqyt/
I'm making Asteroids game in html5 with canvas. I've made moveable ship, which can rotate right and left and can move forward. I've added friction to slow it down when keys aren't pressed. Next thing to do is shooting bullets/lasers. I have yet only one shot and bullet goes forward, but it follow the movement of ship too :/ I don't know how to detach it from the ship and how to make more bullets.
Here's the code:
window.addEventListener('keydown',doKeyDown,true);
window.addEventListener('keyup',doKeyUp,true);
var canvas = document.getElementById('pageCanvas');
var context = canvas.getContext('2d');
var angle = 0;
var H = window.innerHeight; //*0.75,
var W = window.innerWidth; //*0.75;
canvas.width = W;
canvas.height = H;
var xc = W/2; //zeby bylo w centrum :v
var yc = H/2; //jw.
var x = xc;
var y = yc;
var dv = 0.2;
var dt = 1;
var vx = 0;
var vy = 0;
var fps = 30;
var maxVel = 10;
var frict = 0.99;
var brakes = 0.90;
var keys = new Array();
var fire = false;
var laser = false;
///////////////////lasery xD
var lx = 25,
ly = 9,
lw = 4,
lh = 4;
function doKeyUp(evt){
keys[evt.keyCode] = false;
fire = false;
}
function doKeyDown(evt){
keys[evt.keyCode] = true;
}
//OOOOOOOOOOOOOOOOOOLASEROOOOOOOOOOOOOOOOOOOOOOOOOOO
function drawLaser() {
context.fillStyle = "red";
context.fillRect(lx,ly,lw,lh);
}
function moveLaser() {
lx += 2;
}
//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
function ogienZdupy(){
context.fillStyle = "red";
context.beginPath();
context.moveTo(-2,2);
context.lineTo(2,10);
context.lineTo(-2,18);
context.lineTo(-25,10);
context.lineTo(-2,2);
context.strokeStyle = "red";
context.stroke();
}
function convertToRadians(degree) {
return degree*(Math.PI/180);
}
function incrementAngle() {
angle += 5;
if(angle > 360){
angle = 0;
}
}
function decrementAngle(){
angle -= 5;
if(angle > 360){
angle = 0;
}
}
function xyVelocity(){
vx += dv * Math.cos(convertToRadians(angle)); //* friction;
vy += dv * Math.sin(convertToRadians(angle)); //* friction;
if(vx > maxVel){
vx = maxVel;
}
if(vy > maxVel){
vy = maxVel;
}
}
function shipMovement(){
if(38 in keys && keys[38]){
xyVelocity();
fire = true;
}
if(40 in keys && keys[40]){
vx = 0;
vy = 0;
}
if(37 in keys && keys[37]){
decrementAngle();
};
if (39 in keys && keys[39]){
incrementAngle();
};
if (32 in keys && keys[32]){
laser = true;
};
}
function xyAndFriction(){
x += vx * dt;
y += vy * dt;
vx *= frict;
vy *= frict;
}
function outOfBorders(){
if(x > W){
x = x - W;
}
if(x< 0){
x = W;
}
if(y > H){
y = y - H;
}
if(y < 0){
y = H;
}
}
function blazeatron420(){
context.beginPath();
context.moveTo(0,0);
context.lineTo(20,10);
context.lineTo(0,20);
context.lineTo(7,10);
context.lineTo(0,0);
context.strokeStyle = "green";
context.stroke();
}
function space(){
context.fillStyle = "black";
context.fillRect(0,0,W,H);
}
function drawEverything() {
shipMovement();
xyAndFriction();
outOfBorders();
//context.save();
space();
context.save();
context.translate(x,y);
//context.translate(25,25);
context.rotate(convertToRadians(angle));
context.translate(-7,-10);
if(fire){
ogienZdupy();
}
if(laser){
drawLaser();
moveLaser();
}
context.fillStyle = "green";
//context.fillText(vx + " km/h",50,50);
/*context.fillText("dupa",-30,0);
context.beginPath();
context.moveTo(-20,5);
context.lineTo(-5,10);
context.strokeStyle = "green"; //KOLOR LINII ;_;
context.stroke();*/
blazeatron420();
context.restore();
}
setInterval(drawEverything, 20);
And the fiddle http://jsfiddle.net/tomasthall/q40zvd6v/1/
I moved your laser drawing out of the rotated context.
Initiated lx and ly to x y in the moment of firing.
laser = true;
lx = x;
ly = y;
http://jsfiddle.net/q40zvd6v/2/
Now you need to just give the laser a proper vector.
That can be calculated from the angle of your ship and some trigonometry.
if (32 in keys && keys[32]){
laser = true;
lx = x;
ly = y;
var angle_in_radians = convertToRadians(angle);
lvx = Math.cos(angle_in_radians);
lvy = Math.sin(angle_in_radians);
};
And it shoots fine now:
http://jsfiddle.net/q40zvd6v/4/
Looks much nicer if you add the ship vector to projectile vector though.
if (32 in keys && keys[32]){
laser = true;
lx = x;
ly = y;
var angle_in_radians = convertToRadians(angle);
lvx = Math.cos(angle_in_radians);
lvy = Math.sin(angle_in_radians);
lvx += vx;
lvy += vy;
};
http://jsfiddle.net/q40zvd6v/5/
Good luck on your game :>
this be your problem right here:
context.rotate(convertToRadians(angle));
context.translate(-7,-10);
you rotate everything on the canvas..
when in fact you should only be rotating the blazeatron420
Please look at this question:
How do I rotate a single object on an html 5 canvas?
and see the solutions for rotating a single "object"..
I have completed code that has a user click a button (to the right of the canvas), then the image is added to the canvas and is constrained to only move around the circumference of a circle. In order to move the image the user just needs to click the image and then move the mouse. To release the image the user simply needs to click where the image goes on the canvas.
Here is a fiddle showing what the current code does.
http://jsfiddle.net/smacnabb/68awv7sq/9/
Question: I am looking to be able to have the images that move around the circumference of the circle rotate while moving around the circumference of the circle.
This is what I mean:
Here is a fiddle for the code I added to try and make this happen
http://jsfiddle.net/smacnabb/68awv7sq/11/
in the handlemousemove method, it calls state.draw() every time the mouse move i'm passing mouseX, mouseY to state.draw.
state.draw() is in addstate method and this was the code I added to make the image rotate
var dx = mouseX - centerX;
var dy = mouseY - centerY;
var radianAngle = Math.atan2(dy, dx);
context.save();
context.translate(centerX, centerY);
context.rotate(radianAngle);
if (this.dragging) {
context.strokeStyle = 'black';
context.strokeRect(this.x, this.y, this.width + 2, this.height + 2)
}
context.drawImage(this.image, this.x, this.y);
context.restore();
What am I doing wrong?
You are close...Take a look at this example:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var radianAngle = 0;
var cx = 225;
var cy = 125;
var radius = 50;
// image loader
var imageURLs = [];
var imagesOK = 0;
var imgs = [];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/cars.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/plane.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/cars1.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/plane1.png");
loadAllImages(start);
function loadAllImages(callback) {
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function() {
imagesOK++;
if (imagesOK >= imageURLs.length) {
callback();
}
};
img.onerror = function() {
alert("image load failed");
}
img.crossOrigin = "anonymous";
img.src = imageURLs[i];
}
}
var imagesY = 20;
var targets = [];
var selectedTarget = -1;
function start() {
var n = imgs.length / 2;
for (var i = 0; i < n; i++) {
var target = imgs[i + n];
ctx.drawImage(target, 15, imagesY);
targets.push({
x: 15,
y: imagesY,
width: target.width,
height: target.height,
image: imgs[i]
});
imagesY += target.height + 10;
}
}
function handleMouseDown(e) {
e.preventDefault();
x = parseInt(e.clientX - offsetX);
y = parseInt(e.clientY - offsetY);
for (var i = 0; i < targets.length; i++) {
var t = targets[i];
if (x >= t.x && x <= t.x + t.width && y >= t.y && y <= t.y + t.height) {
selectedTarget = i;
draw(x, y);
}
}
}
function handleMouseMove(e) {
if (selectedTarget < 0) {
return;
}
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
draw(mouseX, mouseY);
}
function draw(mouseX, mouseY) {
var dx = mouseX - cx;
var dy = mouseY - cy;
var radianAngle = Math.atan2(dy, dx);
// Drawing code goes here
var img = targets[selectedTarget].image;
ctx.clearRect(100, 0, canvas.width, canvas.height);
// draw the circle
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
// draw the image rotated around the circumference
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(radianAngle);
ctx.drawImage(img, radius - img.width / 2, -img.height / 2);
ctx.restore();
}
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Select an icon on left by clicking<br>
Then move mouse to have icon rotate around circle</h4>
<canvas id="canvas" width=350 height=350></canvas>
I'm having a problem whit my code.
I draw some circles in a circular path and I expect when to click on them to return something other than 0 in firebug console but that's not happening;
I don't know what is wrong with my code and i hope someone will tell me.
Here's my code:
var canvas, ctx;
var circle_data = [];
function circles(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
circle_data.push(this);
}
circles.prototype = {
draw: function (context) {
context.beginPath();
context.arc(this.x, this.y, this.radius / 5, 0, 2 * Math.PI, false);
context.fillStyle = "red";
context.fill();
}
}
function draw() {
ctx.translate(250, 250);
for (var n = 0; n < 10; n++) {
var radi = (Math.PI / 180);
var x = Math.sin(radi * n * 36) * 70;
var y = Math.cos(radi * n * 36) * 70;
var radius = 50;
var thiscircle = new circles(x, y, radius);
thiscircle.draw(ctx);
}
}
function mouseDown(e) {
var img_data = ctx.getImageData(e.pageX, e.pageY, 1, 1);
console.log(img_data.data[3]);
}
function init() {
canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
canvas.addEventListener('mousedown', mouseDown, false);
}
init();
It dosen't matter is i use data[3];
I tried whit console.log(img_data.data[0]+" "+img_data.data[1]+" "+img_data.data[2]);
Still getting 0 0 0
Your detecting the mouse position relative to the page and not the canvas, you need to get the position of the canvas on the page and subtract that from the X and Y of the mouse to find you position relative to the canvas. I use functions similar to the ones below when working with canvas.
getOffsetPosition = function(obj){
/*obj is the Canvas element*/
var offsetX = offsetY = 0;
if (obj.offsetParent) {
do {
offsetX += obj.offsetLeft;
offsetY += obj.offsetTop;
}while(obj = obj.offsetParent);
}
return [offsetX,offsetY];
}
getMouse = function(e,canvasElement){
OFFSET = getOffsetPosition(canvasElement);
mouse_x = (e.pageX || (e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft)) - OFFSET[0];
mouse_y = (e.pageY || (e.clientY + document.body.scrollTop + document.documentElement.scrollTop)) - OFFSET[1];
return [mouse_x,mouse_y];
}
The following code works.
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<body>
<canvas id="canvas" width="500" height="500" style="background-color:#999999;"></canvas>
</body>
<script>
var canvas,ctx;
var circle_data = [];
function circles(x,y,radius)
{
this.x = x;
this.y = y;
this.radius = radius;
circle_data.push(this);
}
circles.prototype = {
draw: function(context){
context.beginPath();
context.arc(this.x, this.y, this.radius / 5, 0, 2* Math.PI, false);
context.fillStyle = "red";
context.fill();
}
}
getOffsetPosition = function(obj){
/*obj is the Canvas element*/
var offsetX = offsetY = 0;
if (obj.offsetParent) {
do {
offsetX += obj.offsetLeft;
offsetY += obj.offsetTop;
}while(obj = obj.offsetParent);
}
return [offsetX,offsetY];
}
getMouse = function(e,canvasElement){
OFFSET = getOffsetPosition(canvasElement);
mouse_x = (e.pageX || (e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft)) - OFFSET[0];
mouse_y = (e.pageY || (e.clientY + document.body.scrollTop + document.documentElement.scrollTop)) - OFFSET[1];
return [mouse_x,mouse_y];
}
function draw(){
ctx.translate(250, 250);
for (var n = 0; n < 10; n++) {
var radi = (Math.PI/180);
var x = Math.sin(radi*n*36)*70;
var y = Math.cos(radi*n*36)*70;
var radius = 50;
var thiscircle = new circles(x,y,radius);
thiscircle.draw(ctx);
}
}
function mouseDown(e)
{
var pos = getMouse(e,ctx.canvas);
var img_data = ctx.getImageData(pos[0],pos[1],1,1);
console.log(img_data.data[3]);
}
function init() {
canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
draw();
canvas.addEventListener('mousedown', mouseDown, false);
}
init();
</script>
</html>