mousePressed inside Constructor Function in JavaScript - p5.js - javascript

I am currently working on a Constructor Function in JavaScript - p5.js. My problem is that the mousePressed() function doesn't execute the code in it when I am clicking in on the right spot on the canvas. Basically what I want is that a faction of the content in the cup disappears when I click the mouse on the cup. and when I hit the button I want to fill the cup as originally filled.
Here is my file:
var bierglas;
var füllung;
var xPos = 200;
var yPos = 100;
function setup() {
createCanvas(650, 450);
bierglas = new Cup();
füllung = new Content();
}
function draw() {
background(51);
füllung.show();
füllung.button();
füllung.move();
bierglas.square();
bierglas.henkel();
}
//
// This draws my cup
//
function Cup() {
this.x = xPos;
this.y = yPos;
this.width = 150;
this.height = 300;
this.square = function() {
fill(255, 150);
rect(this.x, this.y, this.width, this.height);
};
this.henkel = function() {
arc(this.x + this.width, this.y + this.height / 2, 150, 120, 0, HALF_PI);
arc(this.x + this.width, this.y + this.height / 2, 150, 120, 0, 0);
};
}
//
// This is for the mousePressed function, the content of the cup and the button
//
function Content() {
this.x = xPos;
this.y = yPos;
this.width = 150;
this.height = 300;
this.buttonX = width - width / 4;
this.buttonY = height - height / 6;
this.buttonWidth = width / 8;
this.buttonHeight = height / 6;
this.show = function() {
fill(0, 200, 200);
rect(this.x, this.y * 2, this.width, this.height - this.y);
};
this.button = function() {
fill(255, 0, 0);
rect(this.buttonX, this.buttonY, this.buttonWidth, this.buttonHeight);
};
this.move = function() {
mousePressed();
};
}
function mousePressed() {
if (
mouseX < this.x + this.width &&
mouseX > this.x &&
mouseY < this.y + (this.height - this.y) &&
mouseY > this.y
) {
this.y * 2;
console.log("Auf Bierglas getippt");
}
if (
mouseX > this.buttonX &&
mouseX < this.buttonX + this.buttonWidth &&
mouseY > this.buttonY &&
mouseY < this.buttonY + this.buttonHeight
) {
this.y = yPos;
console.log("Auf Button getippt");
}
}

You should get into the habit of checking the developer console for errors. You'll see that your mousePressed() function is indeed firing, but it's hitting an error.
Let's look at the first few lines of your mousePressed() function:
function mousePressed() {
if (
mouseX < this.x + this.width &&
mouseX > this.x &&
mouseY < this.y + (this.height - this.y) &&
mouseY > this.y
) {
this.y * 2;
You have a few problems here. What do you think this is? I'm guessing that you thought it was an instance of Content, but this is not the case. Therefore, this does not contain variables like x, y, width, or height, which is why you're getting your errors. Also, notice that this.y * 2 doesn't actually do anything with the resulting value.
If I were you, I would break your problem down into smaller steps and take those steps on one at a time. Try to get a very simple sketch that uses mousePressed() working:
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
function mousePressed(){
console.log("mouse pressed");
}
Next, try to create a simple sketch that contains one object with a function that you call from the sketch-level mousePressed() function. Here's an example:
var myObject = new MyObject();
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
function mousePressed(){
myObject.mousePressed();
}
function MyObject(){
this.mousePressed = function(){
console.log("object mouse pressed");
};
}
Work your way forward in small steps like this, and remember to always check the developer console for errors. Good luck.

Related

Creating orbiting weapon sprite with JS canvas creates animation errors/glitches

I am trying to make a game in which a player has an equippable weapon. As of now, I have set this weapon to be an image of a bow, and I want to have said weapon to move around the player while facing the mouse. This is similar to buildroyale.io, where the player rotates along with his weapon to face the mouse.
As of now, with the help of #Justin, I've got the bow rotating (somewhat) on the screen. It only shows up when the left click is down, as desired, but does not rotate as expected. Here is a clip showcasing how it moves: clip
Here is the code I use:
class EventHandler {
equip_weapon() {
if (holding) {
player.weapon = player.bag.slot_1;
canv.globalAlpha = 1;
player.weapon.equip();
player.weapon.update();
}
}
}
class Weapon {
image_path;
constructor(image_path) {
this.x = player.x + 30;
this.y = player.y + 30;
this.width = 120;
this.height = 120;
this.angle = 0;
this.distance = 50;
this.image = image_path;
}
equip() {
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
canv.save();
canv.translate(this.x, this.y);
canv.rotate(this.angle);
canv.drawImage(this.image, this.distance, -this.height/2, this.width, this.height);
canv.restore();
}
update() {
this.x = player.x + player.width / 2;
this.y = player.y + player.height / 2;
}
}
bow = new Weapon(bow_image);
player.bag.slot_1 = bow;
aim_bounds = document.documentElement.getBoundingClientRect();
class Player {
constructor() {
this.name = null;
this.speed = 5;
this.skin = player_sheet;
this.can_move = true;
this.is_moving = false;
this.width = 68;
this.height = 68;
this.scale = 1;
this.x = 566;
this.y = 316;
this.direction = facing.down;
this.frame = 0;
this.shadow_offset = 25;
this.frame_rate = 10;
this.health = 100;
this.clip_amount = 10;
this.weapon = null;
// Player inventory
this.bag = {
slot_1 : null,
slot_2 : null,
slot_3 : null,
slot_4 : null,
slot_5 : null,
offhand : null,
armor : null
}
this.is_menu_open = false;
console.log("Player constructed!");
}
update() {
// Animation updates
if (game.tick % this.frame_rate == 0 && this.is_moving && !this.is_menu_open) {
this.frame += 68;
if (this.frame >= 272) { this.frame = 0; }
} else if (!this.is_moving) { this.frame = 0; }
// Movement updates
if (this.can_move) {
if (controller.up) { this.direction = facing.up; this.y -= this.speed; this.is_moving = true; }
else if (controller.down) { this.direction = facing.down; this.y += this.speed; this.is_moving = true; }
else if (controller.left) { this.direction = facing.left; this.x -= this.speed; this.is_moving = true; }
else if (controller.right) { this.direction = facing.right; this.x += this.speed; this.is_moving = true; }
if (!controller.up && !controller.down && !controller.left && !controller.right) { this.is_moving = false; }
}
// Checks
if (this.is_menu_open) { this.can_move = false; } else { this.can_move = true; }
document.getElementById("health_bar").value = this.health;
if (this.is_menu_open) { menu.style.display = "block"; } else { menu.style.display = "none"; }
}
animate() {
// Player shadow
canv.drawImage(player_shadow, this.x, this.y + this.shadow_offset);
// Player
canv.globalAlpha = 1;
canv.drawImage(player_sheet, (sprite.x + this.frame), (sprite.y * this.direction),
sprite.width, sprite.height,
this.x, this.y,
this.width, this.height);
}
}
Here is a download to my current code in case you need more to debug: game.zip
The way I handle this is to make sure my image is first oriented correctly. In my case my bow image would look like this (ignore the quality). Just see that it faces right.
In the draw function I use translate() to position the image and I use the x and y inside the drawImage(img, x, y, w, h) to draw the image centered along the top edge of the canvas. The x (set to 50 in this example) position is essentially the radius of the image rotation and the y is just to center my bow's arrow on the y axis of the canvas.
Using Math.atan2() I can rotate the image
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
In this snippet I have two lines that are commented out. If you uncomment them you will better see what is happening.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
let mouse = {x: 10, y: 10}
let canvasBounds = canvas.getBoundingClientRect();
canvas.addEventListener('mousemove', e => {
mouse.x = e.x - canvasBounds.x
mouse.y = e.y - canvasBounds.y
})
let bow = new Image();
bow.src = "https://lh3.googleusercontent.com/g5Sr3HmGZgWx07sRQMvgvtxZ-ErhWNT0_asFdhLIlw-EQMTuUq3BV3YY8d5rrIrZBiJ-Uo2l836Qlmr8dmaCi-dcCCqN6veS6xnE8jSrmdtRtZKnmF5FQ5aTxuVBgB28n6ICoxSlpA=w2400";
class Weapon {
constructor() {
this.x = 200;
this.y = 200;
this.w = 60;
this.h = 60;
this.angle = 0
}
draw() {
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
//ctx.fillStyle = 'lightgrey';
//ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(bow, 50, -this.h/2, this.w, this.h)
ctx.restore();
}
}
let bowArrow = new Weapon();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
bowArrow.draw();
requestAnimationFrame(animate)
}
animate();
<canvas id="canvas"></canvas>
UPDATE:
Here is what I changed in your files and it works well on my end.
engine.controller.js change mousemove and add listener for resize. I'm also pretty sure there's a way you can get rid of the getMouse function since the listener below gets mouse coordinates for you.
canvas.addEventListener("mousemove", function (event) {
mouse_position = event
mouse.x = event.x - canvas_bounds.x;
mouse.y = event.y - canvas_bounds.y;
})
window.addEventListener('resize', () => {
canvas_bounds = canvas.getBoundingClientRect();
})
engine.eventhandler.js
class Weapon {
image_path;
constructor(image_path) {
this.x = player.x + player.width/2;
this.y = player.y + player.height/2;
this.w = 60;
this.h = 60;
this.angle = 0;
this.image = image_path;
}
equip() {
this.x = player.x + player.width/2;
this.y = player.y + player.height/2;
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
canv.save();
canv.translate(this.x, this.y);
canv.rotate(this.angle);
canv.drawImage(this.image, 50, -this.h/2, this.w, this.h);
canv.restore();
}
}
engine.main.js
function setup() {
game = new Game;
player = new Player;
controller = new Controller;
event_handler = new EventHandler;
canvas.width = 1200;
canvas.height = 700;
canvas_bounds = canvas.getBoundingClientRect();
// REMOVE LATER
bow = new Weapon(bow_image);
player.bag.slot_1 = bow;
document.getElementById("bag").style.display = "block";
}
engine.setup.js
// Weapon stuff
var weapon_equiped = false;
var canvas = document.getElementById("canvas");
let mouse = {
x : 10,
y : 10
}
let canvas_bound;
var mouse_position, holding;
var rect, mouse_x, mouse_y;
...and
//you have a space between canvas. height in both fillRect
canv.fillRect(0, 0, canvas.width, canvas. height);
I think that's all I changed. Pretty sure you can use your mouse_x or the mouse.x but you probably don't need both in your code.

When I run this code on p5 editor, I get an error on line 0

class Bubble {
constructor() {
var allInstances = [];
createCanvas(600,600);
var radius = random(10,100);
this.x = random(0, 600);
this.y = random(0, 600);
this.width = radius;
this.height = radius;
var x = random(0,300);
var y = random(0,300);
var z = random(0,300);
this.velocityX = random(-5, +5);
this.velocityY= random(-5, +5);
this.display = function() {
stroke(10);
fill(x,y,z);
ellipse(this.x, this.y, this.width, this.height);
}
// the below block of code is the one I am having trouble with. the bubbles do not bounce off of the vertical edges of the screen.
if(this.x > 600 || this.x < 0) {
this.velocityX = this.velocityX * -1;
// the above block of code is the one I am having trouble with
}
this.move = function() {
this.x = this.x + this.velocityX;
this.y = this.y + this.velocityY;
}
}
}
Edit:
The program runs and multiple bubbles appear in the way the program is shown above, but I cannot get them to bounce off of the sides of the canvas. Can you help me?
Answer to:
[...] but I cannot get them to bounce off of the sides of the canvas. [...]
You have to evaluate if the bubbles hit side of the canvas and to change the direction of the bubbles in Bubble.move:
class Bubble {
// [...]
constructor() {
// [...]
this.move = function() {
this.x = this.x + this.velocityX;
this.y = this.y + this.velocityY;
if (this.x > 600-this.radius || this.x < this.radius) {
this.velocityX *= -1;
}
if (this.y > 600-this.radius || this.y < this.radius) {
this.velocityY *= -1;
}
}
}
}

variable is not changing properties inside a class

I'm making a ball class / object that bounces around like the DVD screen thing. But when the balls hit the edge the variable that controles their X and Y speeds dont change.
I've already tried running the same IF statement outside the class whith the exact same names and everything and then it works but as soon as i do it inside the class it breaks.
var dvd1;
var dvd2;
function setup() {
createCanvas(400, 400);
dvd1 = new dvdlogo();
dvd2 = new dvdlogo();
}
function draw() {
background(255);
dvd1.move(2, 3);
dvd1.show(200, 200, 200);
dvd2.move(3, 2);
dvd2.show(255, 0, 0);
}
class dvdlogo {
constructor() {
this.x = 0;
this.y = 0;
}
move(speedX, speedY) {
this.x = this.x + speedX;
this.y = this.y + speedY;
//speedX and Y arn't changing when the statement is true
if (this.y >= height || this.y <= 0) {
speedY = -speedY;
}
if (this.x >= width || this.x <= 0) {
speedX = -speedX;
}
}
show(r, g, b) {
noStroke();
fill(r, g, b);
ellipse(this.x, this.y, 50, 50);
}
}
this is what the balls should do: https://editor.p5js.org/wiski/sketches/06p20NSgZ
this is what they do: https://editor.p5js.org/wiski/sketches/mym6EJenN
(If you know how to fix it tell me on here if u change the code in the web editor it doesn't send the changes to me thx in advance)
speedX and speedY are no global variables, they are parameters of the function move. speedY = -speedY changes the value of the parameter, but that doesn't effect the call of the function with the constant values dvd1.move(2, 3);.
The value of speedX and speedY is always 2 repectively 3, because the function move is called with this constant values.
Add attributes .speedX and .speedY to the class dvdlogo and use the attributes rather than parameters:
function setup() {
createCanvas(400, 400);
dvd1 = new dvdlogo(2, 3);
dvd2 = new dvdlogo(3, 2);
}
function draw() {
background(255);
dvd1.move();
dvd1.show(200, 200, 200);
dvd2.move();
dvd2.show(255, 0, 0);
}
class dvdlogo {
constructor(speedX, speedY) {
this.x = 0;
this.y = 0;
this.speedX = speedX;
this.speedY = speedY;
}
move() {
this.x = this.x + this.speedX;
this.y = this.y + this.speedY;
if (this.y >= height || this.y <= 0) {
this.speedY = -this.speedY;
}
if (this.x >= width || this.x <= 0) {
this.speedX = -this.speedX;
}
}
You are so close!
You are passing the xSpeed and the ySpeed in each frame with the .move() function this is making your if statement redundant!
What I recommend is specifying the xSpeed and ySpeed in the constructor, this way it'll be stored in the object for you, so your if statement can alter the fields directly!
var dvd1;
var dvd2;
function setup() {
createCanvas(400, 400);
dvd1 = new dvdlogo(2, 3);
dvd2 = new dvdlogo(3, 2);
}
function draw() {
background(255);
dvd1.move();
dvd1.show(200, 200, 200);
dvd2.move();
dvd2.show(255, 0, 0);
}
class dvdlogo {
constructor(xSpeed, ySpeed) {
this.x = 0;
this.y = 0;
this.speedX = xSpeed;
this.speedY = ySpeed;
}
move() {
this.x = this.x + this.speedX;
this.y = this.y + this.speedY;
if (this.y >= height || this.y <= 0) {
this.speedY = -this.speedY;
}
if (this.x >= width || this.x <= 0) {
this.speedX = -this.speedX;
}
}
show(r, g, b) {
noStroke();
fill(r, g, b);
ellipse(this.x, this.y, 50, 50);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>

clearTimeout not stopping canvas animation

So I have a simple canvas animation I want to start and stop using a toggle switch. The animation works fine and starts up, but the clearTimeout does not seem to work.
I made sure the variable "timeOut" is defined globally so it should have access to it, that seemed to be the usual advice in past questions similar to this one. Am I make a mistake somewhere else? Tried it on Firefox, Chrome and Chromium.
let timeOut;
function circles() {
let canvas = document.querySelector('canvas');
canvas.width = document.querySelector('canvas').offsetWidth;
canvas.height = document.querySelector('canvas').offsetHeight;
let c = canvas.getContext('2d');
let topRadius = 30;
let colorArray = [
'#ff0000',
'#00ff00',
'#0000ff',
]
let mouse = {
x: undefined,
y: undefined
}
window.addEventListener('mousemove', function(e) {
mouse.x = e.x;
mouse.y = e.y;
})
window.addEventListener('resize', function() {
canvas.width = document.querySelector('canvas').offsetWidth;
canvas.height = document.querySelector('canvas').offsetHeight;
init();
});
function Circle(x, y, dx, dy, radius) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dx;
this.radius = radius;
this.minRadius = radius;
this.color = colorArray[Math.floor(Math.random() * colorArray.length)];
this.draw = function() {
if (this.radius < 0) {
this.radius = this.minRadius;
}
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
c.fillStyle = this.color;
c.fill();
}
this.update = function() {
if (this.y + this.radius > innerHeight || this.y - this.radius <= 0) {
this.dy = -this.dy;
}
if (this.x + this.radius > canvas.width|| this.x - this.radius <= 0) {
this.dx = -this.dx;
}
this.x+=this.dx;
this.y+=this.dy;
if (mouse.x - this.x < 50 && mouse.x - this.x > -50 && mouse.y - this.y < 50 && mouse.y - this.y > -50) {
if (this.radius < topRadius) {
this.radius += 1;
}
} else if (this.radius > this.minRadius){
this.radius -= 1;
}
this.draw();
}
}
let circleArray = [];
function init() {
circleArray = [];
for (let i =0; i<50; i++) {
let radius = Math.random() * 10;
let x = Math.random() * (canvas.width - radius*2) + radius;
let y = Math.random() * (canvas.height - radius * 2) + radius;
let dx = (Math.random() - 0.5) * 4;
let dy = (Math.random() - 0.5 )* 4;
circleArray.push(new Circle(x, y, dx, dy, radius));
}
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0,0, canvas.width, innerHeight);
for(let i=0; i < circleArray.length; i++) {
circleArray[i].update();
}
}
init();
animate();
}
$('#startstop').click(function() {
if(!timeOut) {
timeOut = setTimeout(circles, 1000);
} else {
clearTimeout(timeOut);
timeOut = null;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="display: flex; justify-content: space-around;">
<canvas style="width: 100px; height: 800px; background: red;"></canvas>
<div id="startstop">toggle</div>
</div>
You were super close to the solution ;)
in the function animate add line #3 (before for loop), that is having this value:
if (!timeOut) return;
Good luck!
This animation is not stopping because you call clearTimeout on your setTimeout but that only runs once. Your issue is further into the animate function. This relatively loops the requestAnimationFrame. You can store this as a request and then cancelAnimationFrame

Hit detection algorithm not working, unsure why not. (Javascript/Processing.js)

I'm new to programming games (and programming in general). I have previously made a "Flappy Bird" clone and a few others and I used the hit detection algorithm as provided by the Mozilla Developer Network here.
I am now trying to recreate "Pong" but, for whatever reason, its not working in my current code and I'm completely clueless as to why not. I want the ball to hit the "paddle" and then go back the way it came, but right now it ghosts through the paddle.
I'm using the Processing.js library but it should be apparent to anyone (familiar with it or not) what my code is trying to achieve. The draw() function gets called frequently by processing.js.
The code in action (but not working as expected) can be found here
var PADDLE_WIDTH = 10;
var PADDLE_HEIGHT = 75;
var PADDLE_X = 10;
var Player = function(y) {
this.x = PADDLE_X;
this.y = mouseY;
this.score = 0;
this.width = PADDLE_WIDTH;
this.height = PADDLE_HEIGHT;
};
Player.prototype.drawPlayer = function() {
rect(10,mouseY, this.width, this.height);
};
var Ball = function(x,y) {
this.x = x;
this.y = y;
this.speed = 4;
this.width = 10;
this.height = 10;
};
Ball.prototype.drawBall = function() {
rect(this.x, this.y, this.width, this.height);
};
Ball.prototype.onHit = function() {
if(this.y <= 0 || this.y >= height) {
this.speed *= -1;
} else if(this.x <= 0 || this.x >= width){
this.speed *= -1;
// HIT DETECTION UNDERNEATH
} else if (player.x < this.x + this.width &&
player.x + player.width > this.x &&
player.y < this.y + this.height &&
player.height + player.y > this.y){
this.speed *= -1;
}
};
var player = new Player();
var ball = new Ball(width/2, height/2);
draw = function() {
background(0);
fill(250, 250, 250);
ball.x -= ball.speed;
player.drawPlayer();
ball.drawBall();
ball.onHit();
};
In the drawPlayer method you draw player in the (10, mouseY) point, but never update y property of player. It always remains equal to 0. I would recommend you to add update method, which will change player's state and change draw method to render player purely on its state. Something like
Player.prototype.updatePlayer = function() {
this.y = mouseY;
};
Player.prototype.drawPlayer = function() {
rect(this.x , this.y, this.width, this.height);
};
draw = function() {
// ...
player.updatePlayer();
player.drawPlayer();
ball.drawBall();
// ...
};
In drawPlayer you can add the line this.y = mouseY
Player.prototype.drawPlayer = function() {
rect(10,mouseY, this.width, this.height);
this.y = mouseY;
};
Fiddle: http://jsfiddle.net/z0acb8gy/

Categories