Why are the two waves (or functions) interfering? - javascript

I was coding a function to plot graphs in JS. Here it goes:
var x = 0;
var y = 0;
var prevx = 0;
var prevy = 0;
var zoom = 25;
function plot(func) {
this.func = func;
this.x = x;
this.y = y;
this.prevx = prevx;
this.prevy = prevy;
function draw() {
c.beginPath();
c.moveTo(this.prevx * zoom, this.prevy * zoom);
c.lineTo(this.x * zoom, this.y * zoom);
c.strokeStyle = '#fff';
c.stroke();
this.prevx = this.x;
this.prevy = this.y;
this.x += 0.1;
this.y = func(this.x);
}
function animate() {
requestAnimationFrame(animate);
draw();
}
animate();
}
plot(Math.sin);
plot(Math.cos);
// plot(Math.tan);
Why are the two functions interfering even if i am using this keyword?
There are already many similar questions on this website itself still i can't get my answer, hence i have asked here.
Thanks in advance!

When you use "this" keyword within a function, it refers to the function itself. Here you want it to refer to the "plot" function while you are inside the "draw" function. You can do that by creating a new variable within the "plot" function and use that. i.e. "that".
var x = 0;
var y = 0;
var prevx = 0;
var prevy = 0;
var zoom = 25;
function plot(func) {
var that = this;
this.func = func;
this.x = x;
this.y = y;
this.prevx = prevx;
this.prevy = prevy;
function draw() {
c.beginPath();
c.moveTo(that.prevx * zoom, that.prevy * zoom);
c.lineTo(that.x * zoom, that.y * zoom);
c.strokeStyle = '#fff';
c.stroke();
that.prevx = that.x;
that.prevy = that.y;
that.x += 0.1;
that.y = func(that.x);
}
function animate() {
requestAnimationFrame(animate);
draw();
}
animate();
}
plot(Math.sin);
plot(Math.cos);
You can do the same by using the "bind" method when you call a function. This would change the "this" keyword in that function to refer to the object passed.
var x = 0;
var y = 0;
var prevx = 0;
var prevy = 0;
var zoom = 25;
function plot(func) {
this.func = func;
this.x = x;
this.y = y;
this.prevx = prevx;
this.prevy = prevy;
this.draw = () => {
c.beginPath();
c.moveTo(this.prevx * zoom, this.prevy * zoom);
c.lineTo(this.x * zoom, this.y * zoom);
c.strokeStyle = '#fff';
c.stroke();
this.prevx = this.x;
this.prevy = this.y;
this.x += 0.1;
this.y = func(this.x);
}.bind(this)
this.animate = () => {
requestAnimationFrame(this.animate);
this.draw();
}.bind(this)
this.animate();
}
plot(Math.sin);
plot(Math.cos);

Related

Game with moving circle through obstacle in Javascript doesn't work

I created a game using Javascript. It is a game where a circle which can be controlled by the mouse, has to navigate through moving obstacles similar to a maze. When the circle hits an obstacle, the game should stop.
When i tried the same game but with one obstacle, it worked. But after adding more lines of code to create more obstacles, the circle and the obstacle doesn't appear in the output. Also, the crashWith function isn't being called when the circle hits the obstacle.
Here is the code:
<!DOCTYPE html>
<html>
<style>
canvas {
border:1px solid #000000;
background-image: url("https://data.whicdn.com/images/223851992/large.jpg");
}
</style>
<body onload="begin()">
<script>
var gamePiece;
var gameObstacle = [];
function begin(){
gameArea.start();
gamePiece = new piece(10, "white", 20, 135);
}
var gameArea = {
canvas : document.createElement("canvas"),
start : function(){
this.canvas.width = 480;
this.canvas.height = 270;
this.canvas.style.cursor= 'none';
this.context = this.canvas.getContext("2d");
document.body.insertBefore( this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGame , 10); //for each frame
window.addEventListener('mousemove', function(n){
gameArea.x = n.pageX;
gameArea.y = n.pageY;
});
},
clear : function(){
this.context.clearRect(0,0, this.canvas.width, this.canvas.height);
},
stop : function(){
clearInterval(this.interval);
}
}
function eachInterval(e){
if((gameArea.frameNo / e) % 1 == 0)
return true;
else
return false;
}
//for circle
function piece (radius, color, x, y){
this.radius = radius;
this.speedx = 0;
this.speedy =0;
this.x = x;
this.y = y;
this.update = function(){
pieceContext = gameArea.context;
pieceContext.beginPath();
pieceContext.arc( this.x, this.y, this.radius, 0, 2 * Math.PI);
pieceContext.fillStyle = color;
pieceContext.fill();
}
this.newPlace = function(){
this.x += this.speedx;
this.y += this.speedy;
}
}
//for obstacle
function obstacle (width, height, color, x, y){
this.width = width;
this.height = height;
this.speedx = 0;
this.speedy =0;
this.x = x;
this.y = y;
this.update = function(){
obstacleContext = gameArea.context;
obstacleContext.fillStyle = color;
obstacleContext.fillRect(this.x, this.y, this.width, this.height);
}
this.newPlace = function(){
this.x += this.speedx;
this.y += this.speedy;
}
//check crash
this.crashWith = function(gamePiece){
var collide = true;
var otherleft = this.x;
var otherright = this.x + (this.width);
var othertop = this.y;
var otherbottom = this.y + (this.height);
var circleBottom = gamePiece.y + (gamePiece.radius);
var circleTop = gamePiece.y;
var circleLeft = gamePiece.x;
var circleRight = gamePiece.x + (gamePiece.radius);
if ((circleBottom < othertop) || (circleTop > otherbottom) || (circleRight < otherleft) || (circleLeft > otherright)) {
collide = false;
}
return collide;
}
}
function updateGame(){
var x,y;
for(i=0 ; i<gameObstacle.length ; i++){
if (gameObstacle[i].crashWith(gamePiece)){
gameArea.stop();
return;
}
}
gameArea.clear();
gameArea.frameNo +=1 ;
if(gameArea.frameNo == 1 || eachInterval(150)){
x = gameArea.canvas.width;
y = gameArea.canvas.height - 200;
gameObstacle.push(new obstacle(10, 200, "grey", x, y));
}
for(i=0 ; i<gameObstacle.length ; i++){
gameObstacle[i].x -= 1;
gameObstacle[i].update();
}
gameObstacle.x -= 1;
//giving co ordinates of cursor to game piece
gamePiece.x = gameArea.x;
gamePiece.y = gameArea.y;
gamePiece.update();
gamePiece.newPlace();
}
</script>
</body>
</html>

How to make a prototype function use the values in a constructor

I am using the JavaScript canvas to make a pong-style game. I am attempting to use the values of the pong board's x and y grid values to create a prototype function for the ball to cause it to bounce off of the pong board whenever it touches. I have tried this a few different ways and I can't seem to get the ball to bounce off the pong board. I did not think that this aspect of the game's functionality would be the difficult part. I will provide snippets of the code below that I think are the problem:
var Pongboard = function() {
this.x = 15;
this.y = 15;
}
Ball.prototype.draw = function() {
makeBall(this.x, this.y, 5);
}
var pongboardValues = Object.values(Pongboard);
var pongX = pongboardValues[0];
var pongY = pongboardValues[1];
Ball.prototype.checkPongCollision = function() {
if (this.x < pongX && this.y < pongY) {
this.xSpeed = -this.xSpeed;
this.ySpeed = -this.ySpeed;
};
}
Any suggestions on how to get this working? Any hints would be greatly appreciated. If it helps, I will provide the full code below.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
//Create ball function
function makeBall (x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI*2, false);
ctx.fill();
}
//Create pong board function
function makePong (x, y) {
ctx.fillRect(x, y, 10, 60);
}
//Ball construcor function
var Ball = function() {
this.x = width;
this.y = height/2;
this.xSpeed = 6;
this.ySpeed = Math.random()*8 - 2;
}
//Pong board constructor function
var Pongboard = function() {
this.x = 15;
this.y = 15;
}
//These are the values for the Pongboard object's location
var pongboardValues = Object.values(Pongboard);
var pongX = pongboardValues[0];
var pongY = pongboardValues[1];
Ball.prototype.draw = function() {
makeBall(this.x, this.y, 5);
}
Ball.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0 || this.x > width) {
this.xSpeed = -this.xSpeed;
};
if (this.y < 0 || this.y > height) {
this.ySpeed = -this.ySpeed;
};
}
Ball.prototype.checkPongCollision = function() {
if (this.x < pongX && this.y < pongY) {
this.xSpeed = -this.xSpeed;
this.ySpeed = -this.ySpeed;
};
}
Pongboard.prototype.draw = function() {
makePong(this.x, this.y);
}
var keyNames = {
38: "up",
40: "down"
};
Pongboard.prototype.moveUpAndDown = function(direction) {
if (direction==="up") {
this.y = this.y += -1*10;
};
if (direction==="down") {
this.y = this.y += 10;
};
};
var ball = new Ball();
var pong = new Pongboard();
$("#start-button").click(function() {
setInterval(function() {
ctx.clearRect(0, 0, width, height);
pong.draw();
ball.draw();
ball.move();
ctx.strokeRect(0, 0, width, height);
}, 30);
})
$("body").keydown(function(event) {
var direction = keyNames[event.keyCode];
pong.moveUpAndDown(direction);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="start-button">Start</button><br>
<canvas width=300 height=200 id="canvas"></canvas>
Here I've got things working the way I think you want it.
You could extend this to make the ball bounce randomly on the Y axis too,..
I've commented out code that really wasn't doing anything too..
Also worth noting, you wasn't even calling checkPongCollision, so I've placed that in the timer.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
//Create ball function
function makeBall (x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI*2, false);
ctx.fill();
}
//Create pong board function
function makePong (x, y) {
ctx.fillRect(x, y, 10, 60);
}
//Ball construcor function
var Ball = function() {
this.x = width;
this.y = height/2;
this.xSpeed = 6;
this.ySpeed = Math.random()*8 - 2;
}
//Pong board constructor function
var Pongboard = function() {
this.x = 15;
this.y = 15;
}
//These are the values for the Pongboard object's location
//not needed..
//var pongboardValues = Object.values(Pongboard);
//var pongX = pongboardValues[0];
//var pongY = pongboardValues[1];
Ball.prototype.draw = function() {
makeBall(this.x, this.y, 5);
}
Ball.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0 || this.x > width) {
this.xSpeed = -this.xSpeed;
};
if (this.y < 0 || this.y > height) {
this.ySpeed = -this.ySpeed;
};
}
Ball.prototype.checkPongCollision = function() {
//if (this.x < pong.x && this.y < pong.y) {
if (
this.x >= pong.x && this.x < pong.x + 10 &&
this.y >= pong.y && this.y < pong.y + 60)
{
this.xSpeed = -this.xSpeed;
//this.ySpeed = -this.ySpeed;
};
}
Pongboard.prototype.draw = function() {
makePong(this.x, this.y);
}
var keyNames = {
38: "up",
40: "down"
};
Pongboard.prototype.moveUpAndDown = function(direction) {
if (direction==="up") {
this.y = this.y += -1*10;
};
if (direction==="down") {
this.y = this.y += 10;
};
};
var ball = new Ball();
var pong = new Pongboard();
$("#start-button").click(function() {
this.style.display = "none";
setInterval(function() {
ctx.clearRect(0, 0, width, height);
pong.draw();
ball.draw();
ball.move();
ctx.strokeRect(0, 0, width, height);
ball.checkPongCollision();
}, 30);
})
$("body").keydown(function(event) {
var direction = keyNames[event.keyCode];
pong.moveUpAndDown(direction);
});
body {
padding: 0;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button style="float:left" id="start-button">Start</button>
<canvas width=300 height=180 id="canvas"></canvas>

Html Canvas Particle system

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!

Html5 canvas image on click

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>

How to create mouseover highlight box in html 5?

If I have a 600 by 400 grid, with 10 by 10 pixel squares like this:
/**
* draws grid to screen
*/
function drawgrid(context)
{
for(var x = 0.5; x < 600; x += 10)
{
context.moveTo(x, 0);
context.lineTo(x, 400);
}
for(var y = 0.5; y < 400; y += 10)
{
context.moveTo(0, y);
context.lineTo(600, y);
}
context.strokeStyle = "#eee";
context.stroke();
}
/**
* Creates a canvas element, loads images, adds events, and draws the canvas for the first time.
*/
function prepareCanvas()
{
var context = document.getElementById('canvas').getContext("2d");
drawgrid(context);
}
How would I mouseover the individual squares and highlight the square that the mouse is hovering over. Like make a red box highlighting the grid square the mouse is over.
See code below. Adjust coordinates for event
<body>
<canvas id=canvas height=400 width=600
onmousemove="over()" style="cursor:crosshair">
</canvas>
</body>
<script type="text/javascript">
<!--
var grid;
function prepareCanvasGrid()
{
var cnv = document.getElementById('canvas');
grid = new CanvasGrid(cnv.getContext("2d"),cnv.offsetLeft, cnv.offsetTop);
}
function CanvasGrid(context,x,y) {
this.sq = [];
this.dirty = [];
this.ctx = context;
this.x = x;
this.y = y;
this.init = function(){
for(var x = 0.5; x < 600; x += 50) {
for(var y = 0.5; y < 400; y += 50) {
var s = new square(x,y, context);
this.sq.push(s);
}
}
}
this.draw = function(){
this.ctx.clearRect(0,0,600,400);
for(var i=0; i < this.sq.length; i++)
this.sq[i].draw();
}
this.clean = function(){
for(var i=0; i < this.dirty.length; i++)
this.dirty[i].draw();
this.dirty = [];
}
this.over = function(ex,ey){
ex = ex - this.x;
ey = ey - this.y;
for(var i=0; i < this.sq.length; i++) {
if(this.sq[i].eleAtPoint(ex,ey)){
this.clean(); // clean up
this.dirty.push(this.sq[i]);
this.sq[i].over();
break;
}
}
}
this.init();
this.draw();
}
function square(x,y, ctx){
this.ctx = ctx;
this.x = x;
this.y = y;
this.h = 50;
this.w = 50;
this.draw = function(){
this.ctx.strokeStyle = "#eee";
this.ctx.strokeRect(this.x, this.y, this.w, this.w);
this.ctx.fillStyle = "#fff";
this.ctx.fillRect(this.x, this.y, this.w, this.w);
}
this.over = function() {
this.ctx.fillStyle = "red";
this.ctx.fillRect(this.x, this.y, this.w, this.w);
}
this.eleAtPoint = function(ex,ey){
if(ex < this.x + this.w && ex > this.x
&& ey > this.y && ey < this.y + this.h)
return true;
return false;
}
}
function over(){
var e = window.event;
grid.over(e.clientX ,e.clientY);
}
prepareCanvasGrid();
//-->
</script>
Updated code for better performance
Just to add to hungryMind's answer, if you don't want any boxes to remain highlighted when the mouse is no longer over the canvas, add these two things:
1) An else if
this.over = function(ex,ey){
ex = ex - this.x;
ey = ey - this.y;
for(var i=0; i < this.sq.length; i++) {
if(this.sq[i].eleAtPoint(ex,ey)){
this.clean(); // clean up
this.dirty.push(this.sq[i]);
this.sq[i].over();
break;
} else if (!this.sq[i].eleAtPoint(ex,ey)) {
this.sq[i].off();
}
}
}
2) A square off() method:
this.off = function() {
this.draw();
}

Categories

Resources