Accessing other classes inside a class Javascript - javascript

I am trying to make a simple breakout game with p5js. I got the balls to work fine, but when I try to make them interact with the brick class, I run into some problems. I can't seem to figure ourI don't have a ton of experience with classes in javascript, so this is a little confusing to me. Here is the code:
`
//Variables
let scene = 0;
let paddlex = 250;
let paddlespeed = 10;
let allBalls = [];
class Brick {
constructor(brickX, brickY, brickW, brickH) {
this.brickX = brickX
this.brickY = brickY
this.brickW = brickW
this.brickH = brickH
this.brickAlive = true
}
display(){
push()
if(this.brickAlive){
fill("red")
rect(this.brickX, this.brickY, this.brickW, this.brickH)
}
pop()
}
}
class Ball {
constructor(x, y, w, xdir, ydir) {
this.x = x;
this.y = y;
this.w = w;
this.xdir = xdir;
this.ydir = ydir;
this.alive = true;
allBalls.push(this);
}
move() {
this.x += this.xdir;
this.y += this.ydir;
//Bounce off walls
if (this.x >= 600 - this.w / 2) {
this.xdir = this.xdir * -1;
}
if (this.x <= 0 + this.w / 2) {
this.xdir = this.xdir * -1;
}
if (this.y <= 0 + this.w / 2) {
this.ydir = this.ydir * -1;
}
if (this.y >= 400 + this.w / 2) {
this.alive = false;
}
if (
this.y >= 360 - this.w / 2 &&
this.y <= 380 &&
this.x >= paddlex &&
this.x <= paddlex + 100
) {
this.ydir = this.ydir * -1;
}
}
show() {
if (this.alive) {
push();
fill(0);
ellipse(this.x, this.y, this.w, this.w);
pop();
}
}
//I believe this part is causing the error
collide(brick){
if(this.x >= brick.brickX && this.x <= brick.brickX + brick.brickW && this.y <= brick.brickY + brick.brickH){
console.log("HI")
brick.brickAlive = false
}
}
}
`
I recieved an error that said "TypeError: Cannot read properties of undefined (reading 'brickX')"

Related

How to move an object back and forth in p5js javascript

After a few hours of work and research (I just started learning p5js and javascript) I have about 50 lines of code that creates a grid of circles and begins to move them across the canvas. Before I get into my issue, I will share the code.
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
if (this.x < 51) {
this.x += 1
this.y += 1
}
if (this.x < 430) {
this.x += 1
this.y += 1
}
if (this.x > 430) {
this.x -= 1
this.y -= 1
}
if (this.x < 51) {
this.x += 1
this.y += 1
}
}
}
What I would like to do is move this grid of circles starting at (50,50) to the bottom right corner. Once it hits (width-50,height-50) I'd like the movement to reverse back to the starting point, and then back the other way. This code moves the circles to the bottom right corner successfully, them something goes wrong. The circles don't reverse their movement, rather, they get messed up. I thought the if statements would handle this but I must be missing something. I trouble shooted for about an hour and now I thought I'd ask SO. Thanks!
Add a moving direction to the object. Change the direction when the object goes out of bounds:
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
this.x += this.dx
this.y += this.dy
if (this.x < 51 || this.y < 51) {
this.dx = 1
this.dy = 1
}
if (this.x > 430 || this.y > 430) {
this.dx = -1
this.dy = -1
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
If you do not want to move the objects individually, you must use 1 direction of movement for all objects:
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
var dx = 1
var dy = 1
function draw() {
background(50);
mx = dx
my = dy
for (var b = 0; b < circles.length; b++) {
circles[b].show(mx, my);
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function(mx, my) {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
this.x += mx
this.y += my
if (this.x < 51) {
dx = 1
dy = 1
}
if (this.x > 430) {
dx = -1
dy = -1
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>

Collision detection in my js platformer game. Can't stop the object, but detection works

I'm creating a platformer game, and I'm adding collision, but I'm not sure how to stop the object after collision is detected. This is my javascript, and I have a basic html document with a tag. Could someone help me out with stopping an object after I detect collision? I feel like my solutions I've come up with are much to complicated.
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const characterImage = document.getElementById('character')
const level = 1
canvas.width = document.body.scrollWidth
canvas.height = document.body.scrollHeight
let time; // Current time
let prevTime = Date.now(); // Store previous time
let isGrounded; // Check if player is on the ground
class Main {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.lives = 3;
this.speedX = 0;
this.speedY = 0;
this.gravity = .01;
// this.gravitySpeed = 0;
this.jumpSpeed = -1.5; // How fast to jump upwards
this.dx = 0;
this.dy = 0;
this.centerX = canvas.width / 2;
this.centerY = canvas.height / 2;
}
draw() {
if (this.x <= -0) {
this.x = -0
}
if (this.x >= canvas.width - 50) {
this.x = canvas.width - 50
}
const player = {
image: characterImage,
x: this.x,
y: this.y,
w: 50,
h: 50
}
const obstacle1 = {
x: this.centerX,
y: canvas.height - 100,
w: 50,
h: 50
}
const lava = {
}
const ground = {
x: 0,
y: canvas.height - 50,
w: canvas.width,
h: 50
}
//collision detection
if (player.x < obstacle1.x + obstacle1.w &&
player.x + obstacle1.w > obstacle1.x &&
player.y < obstacle1.y + obstacle1.h &&
player.y + player.h > obstacle1.y) {
}
ctx.beginPath();
ctx.fillStyle = '#9b7653'
ctx.fillRect(ground.x, ground.y, ground.w, ground.h)
ctx.closePath();
ctx.beginPath();
ctx.drawImage(player.image, player.x, player.y, player.w, player.h);
ctx.closePath();
//obstacles
ctx.beginPath();
ctx.fillStyle = '#df4759'
ctx.fillRect(obstacle1.x, obstacle1.y, obstacle1.w, obstacle1.h);
ctx.closePath();
}
newPos() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
}
update() {
// Calculate how much time has passed since last update
time = Date.now();
const deltaTime = time - prevTime;
// Update y-position based speed in y-direction
// If we jump this.speed will be set to this.jumpSpeed
this.y += this.speedY * deltaTime;
// Gravity should always affect the player!
// The ground check will make sure we don't fall through the floor
this.y += this.gravity * deltaTime;
// Make sure to reduce our player's speed in y by gravity!
this.speedY += this.gravity * deltaTime;
// Only allow the player to jump if he is on the ground
if (controller1.up && isGrounded) {
// Set the player y-speed to jump speed
this.speedY = this.jumpSpeed;
};
if (controller1.right) {
this.dx += 0.7
};
if (controller1.left) {
this.dx -= 0.7
};
this.x += this.dx;
// this.y += this.dy;
this.dx *= 0.9;
this.dy *= 0.9;
// Ground check
if (this.y >= canvas.height - 100) {
this.y = canvas.height - 100;
isGrounded = true;
} else {
isGrounded = false;
}
// Store the current time to use for calculation in next update
prevTime = Date.now();
}
}
class Controller {
constructor() {
this.up = false;
this.right = false;
this.down = false;
this.left = false;
let keyEvent = (e) => {
if (e.code == "KeyW" || e.code == "ArrowUp" || e.code == "Space") {
this.up = e.type == 'keydown'
};
if (e.code == "KeyD" || e.code == "ArrowRight") {
this.right = e.type == 'keydown'
};
if (e.code == "KeyA" || e.code == "ArrowLeft") {
this.left = e.type == 'keydown'
};
}
addEventListener('keydown', keyEvent);
addEventListener('keyup', keyEvent);
addEventListener('mousemove', keyEvent)
}
}
let main1 = new Main(50, canvas.height - 150, 50, 50)
let controller1 = new Controller();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
main1.update();
main1.draw();
requestAnimationFrame(animate)
}
function updatePos() {
main1.newPos();
}
animate()
setInterval(updatePos, 10)
<canvas id="canvas"></canvas>
<img src="http://placekitten.com/50/50" id="character" style="display: none">
It looks like your code has two sets of velocities for the character: this.speedY gives the vertical velocity from jumping, and this.dx gives the horizontal velocity from controller input, while this.dy isn't actually used. So if you want the character to stop from a collision, you could use something like this:
if (player.x < obstacle1.x + obstacle1.w &&
player.x + obstacle1.w > obstacle1.x &&
player.y < obstacle1.y + obstacle1.h &&
player.y + player.h > obstacle1.y) {
this.dx = this.speedY = 0;
}
You probably want to unify the velocities into one pair of values, e.g. this.dx and this.dy, and adjust either when the player's velocity changes (from any action or gravity).
If you want to disable certain actions while the player is colliding, you might want to set a variable that you can use in the update() function. For example:
this.isColliding =
player.x < obstacle1.x + obstacle1.w &&
player.x + obstacle1.w > obstacle1.x &&
player.y < obstacle1.y + obstacle1.h &&
player.y + player.h > obstacle1.y;
if (this.isColliding) {
this.dx = this.speedY = 0;
}
As another note, prevTime and isGrounded should really be properties of the class (this.prevTime, etc.), not global variables. And time could be declared local to update(), as it's not needed otherwise.
Collision detection in this way is not as simple as a single block of code. This is a good start to determine if the objects do collide but you will then need to pass that information to another function to handle the actions that should be taken based on the side of the collision. This is refered to as 'broad phase' and 'narrow phase'.
Note that there's is no, one perfect formula that handles every rectangle CD. You may find yourself needing to alter your main function to handle specific object within the game at some point because they have different properties.
Now I will provide you with a working example here using your code but I must highly recommend you don't continue piling all of your game objects into one class like you are doing. This is already making things difficult and will only make your game more complicated in the long run. You should break out you obstacles, lava, ground etc and give each their own class. I also notice that you are trying to put all of your CD into the class. This is sometimes ok but for what you are currently trying to accomplish I would have separate functions.
You'll notice in this snippet that the player actually enters into the ground a bit and the obstacles before going back to it's spot. The code overall is a bit finicky because of how it's written.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const characterImage = document.getElementById("character");
const level = 1;
canvas.width = document.body.scrollWidth;
canvas.height = 400//document.body.scrollHeight
let time; // Current time
let prevTime = Date.now(); // Store previous time
let player, obstacle1, obstacle2, ground;
class Main {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.lives = 3;
this.speedX = 0;
this.speedY = 0;
this.gravity = 0.01;
this.jumping = false;
//this.gravitySpeed = 0;
this.jumpSpeed = -1.5; // How fast to jump upwards
this.dx = 0;
this.dy = 0;
this.centerX = canvas.width / 2;
this.centerY = canvas.height / 2;
}
draw() {
if (this.x <= -0) {
this.x = -0;
}
if (this.x >= canvas.width - 50) {
this.x = canvas.width - 50;
}
player = {
image: characterImage,
x: this.x,
y: this.y,
w: 50,
h: 50
};
obstacle1 = {
x: this.centerX,
y: canvas.height - 100,
w: 50,
h: 50
};
obstacle2 = {
x: this.centerX + 50,
y: canvas.height - 100,
w: 50,
h: 50
};
const lava = {};
ground = {
x: 0,
y: canvas.height - 50,
w: canvas.width,
h: 50
};
ctx.beginPath();
ctx.fillStyle = "#9b7653";
ctx.fillRect(ground.x, ground.y, ground.w, ground.h);
ctx.closePath();
ctx.beginPath();
ctx.fillStyle = "pink";
ctx.fillRect(player.x, player.y, player.w, player.h);
ctx.closePath();
//obstacles
ctx.beginPath();
ctx.fillStyle = "#df4759";
ctx.fillRect(obstacle1.x, obstacle1.y, obstacle1.w, obstacle1.h);
ctx.closePath();
ctx.beginPath();
ctx.fillStyle = "#df4759";
ctx.fillRect(obstacle2.x, obstacle2.y, obstacle2.w, obstacle2.h);
ctx.closePath();
}
newPos() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
}
update() {
// Calculate how much time has passed since last update
time = Date.now();
const deltaTime = time - prevTime;
if (controller1.up && !this.jumping) {
// Set the player y-speed to jump speed
this.speedY = this.jumpSpeed;
this.jumping = true; //prevents jumping while already in air
}
if (controller1.right) {
this.dx += 0.7;
}
if (controller1.left) {
this.dx -= 0.7;
}
this.y += this.speedY * deltaTime;
this.y += this.gravity * deltaTime;
this.speedY += this.gravity * deltaTime;
this.x += this.dx;
// this.y += this.dy;
this.dx *= 0.9;
this.dy *= 0.9;
// Store the current time to use for calculation in next update
prevTime = Date.now();
}
}
class Controller {
constructor() {
this.up = false;
this.right = false;
this.down = false;
this.left = false;
let keyEvent = (e) => {
if (e.code == "KeyW" || e.code == "ArrowUp" || e.code == "Space") {
this.up = e.type == "keydown";
}
if (e.code == "KeyD" || e.code == "ArrowRight") {
this.right = e.type == "keydown";
}
if (e.code == "KeyA" || e.code == "ArrowLeft") {
this.left = e.type == "keydown";
}
};
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
addEventListener("mousemove", keyEvent);
}
}
function collision(player, obj) {
if (
player.x + player.w < obj.x ||
player.x > obj.x + obj.w ||
player.y + player.h < obj.y ||
player.y > obj.y + obj.h
) {
return;
}
this.narrowPhase(player, obj);
}
function narrowPhase(player, obj) {
let playerTop_ObjBottom = Math.abs(player.y - (obj.y + obj.h));
let playerRight_ObjLeft = Math.abs(player.x + player.w - obj.x);
let playerLeft_ObjRight = Math.abs(player.x - (obj.x + obj.w));
let playerBottom_ObjTop = Math.abs(player.y + player.h - obj.y);
if (
player.y <= obj.y + obj.h &&
player.y + player.h > obj.y + obj.h &&
playerTop_ObjBottom < playerRight_ObjLeft &&
playerTop_ObjBottom < playerLeft_ObjRight
) {
main1.y = obj.y + obj.h;
main1.speedY = 0;
}
if (
player.y + player.h >= obj.y &&
player.y < obj.y &&
playerBottom_ObjTop < playerRight_ObjLeft &&
playerBottom_ObjTop < playerLeft_ObjRight
) {
main1.y = obj.y - player.h - 0.05;
main1.speedY = 0;
main1.jumping = false;
}
if (
player.x + player.w >= obj.x &&
player.x < obj.x &&
playerRight_ObjLeft < playerTop_ObjBottom &&
playerRight_ObjLeft < playerBottom_ObjTop
) {
main1.x = obj.x - obj.w - 0.05;
main1.dx = 0;
}
if (
player.x <= obj.x + obj.w &&
player.x + player.w > obj.x + obj.w &&
playerLeft_ObjRight < playerTop_ObjBottom &&
playerLeft_ObjRight < playerBottom_ObjTop
) {
main1.x = obj.x + obj.w + 0.05;
main1.dx = 0;
}
}
let main1 = new Main(50, canvas.height - 250, 50, 50);
let controller1 = new Controller();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
main1.draw();
main1.update();
collision(player, obstacle2);
collision(player, obstacle1);
collision(player, ground);
requestAnimationFrame(animate);
}
function updatePos() {
main1.newPos();
}
animate();
setInterval(updatePos, 10);
<canvas id="canvas"></canvas>
I'm going to provide a second example where I've removed the objects from the main class and made each there own. I also removed the dx and dy as I think there was confusion about those and mixing them with speedX and speedY. On another note in your newPos() function you have this.x += this.speedX; but you also have that in the update function so in reality your are doubling it. I don't think that;s what you wanted.
You'll see in this example the collision is much smoother
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const characterImage = document.getElementById("character");
const level = 1;
canvas.width = document.body.scrollWidth;
canvas.height = 400//document.body.scrollHeight
let time; // Current time
let prevTime = Date.now(); // Store previous time
class Entity {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.lives = 3;
this.speedX = 0;
this.speedY = 0;
this.gravity = 0.01;
this.jump = false;
this.jumpSpeed = -1.5; // How fast to jump upwards
this.centerX = canvas.width / 2;
this.centerY = canvas.height / 2;
}
draw() {
ctx.beginPath();
ctx.fillStyle = "pink";
ctx.fillRect(player.x, player.y, player.w, player.h);
ctx.closePath();
}
newPos() {
this.gravitySpeed += this.gravity;
//this.x += this.speedX;
}
collision() {
if (this.x <= -0) {
this.x = -0;
}
if (this.x >= canvas.width - 50) {
this.x = canvas.width - 50;
}
}
update() {
// Calculate how much time has passed since last update
time = Date.now();
const deltaTime = time - prevTime;
if (controller1.up && !this.jump) {
this.speedY = this.jumpSpeed;
this.jump = true;
}
if (controller1.right) {
this.speedX += 0.7;
}
if (controller1.left) {
this.speedX -= 0.7;
}
this.y += this.speedY * deltaTime;
this.y += this.gravity * deltaTime;
this.speedY += this.gravity * deltaTime;
this.x += this.speedX;
this.speedX *= 0.9;
this.speedY *= 0.9;
// Store the current time to use for calculation in next update
prevTime = Date.now();
}
}
class Obstacle {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = '#df4759';
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
/*
class Lava {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = 'red';
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
*/
class Ground {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = '#8a6c4e';
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
class Controller {
constructor() {
this.up = false;
this.right = false;
this.down = false;
this.left = false;
let keyEvent = (e) => {
if (e.code == "KeyW" || e.code == "ArrowUp" || e.code == "Space") {
this.up = e.type == "keydown";
}
if (e.code == "KeyD" || e.code == "ArrowRight") {
this.right = e.type == "keydown";
}
if (e.code == "KeyA" || e.code == "ArrowLeft") {
this.left = e.type == "keydown";
}
};
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
addEventListener("mousemove", keyEvent);
}
}
function collision(player, obj) {
if (
player.x + player.w < obj.x ||
player.x > obj.x + obj.w ||
player.y + player.h < obj.y ||
player.y > obj.y + obj.h
) {
return;
}
this.narrowPhase(player, obj);
}
function narrowPhase(player, obj) {
let playerTop_ObjBottom = Math.abs(player.y - (obj.y + obj.h));
let playerRight_ObjLeft = Math.abs(player.x + player.w - obj.x);
let playerLeft_ObjRight = Math.abs(player.x - (obj.x + obj.w));
let playerBottom_ObjTop = Math.abs(player.y + player.h - obj.y);
if (
player.y <= obj.y + obj.h &&
player.y + player.h > obj.y + obj.h &&
playerTop_ObjBottom < playerRight_ObjLeft &&
playerTop_ObjBottom < playerLeft_ObjRight
) {
player.y = obj.y + obj.h;
player.speedY = 0;
}
if (
player.y + player.h >= obj.y &&
player.y < obj.y &&
playerBottom_ObjTop < playerRight_ObjLeft &&
playerBottom_ObjTop < playerLeft_ObjRight
) {
player.y = obj.y - player.h;
// player.dy = 0;
player.speedY = 0;
player.jump = false;
}
if (
player.x + player.w >= obj.x &&
player.x < obj.x &&
playerRight_ObjLeft < playerTop_ObjBottom &&
playerRight_ObjLeft < playerBottom_ObjTop
) {
player.x = obj.x - obj.w;
player.speedX = 0;
}
if (
player.x <= obj.x + obj.w &&
player.x + player.w > obj.x + obj.w &&
playerLeft_ObjRight < playerTop_ObjBottom &&
playerLeft_ObjRight < playerBottom_ObjTop
) {
player.x = obj.x + obj.w;
player.speedX = 0;
}
}
let obstacle1 = new Obstacle(canvas.width/2, canvas.height - 100, 50, 50)
let obstacle2 = new Obstacle(canvas.width/2 + 50, canvas.height - 100, 50, 50)
let ground = new Ground(0, canvas.height - 50, canvas.width, 50)
let player = new Entity(50, canvas.height - 250, 50, 50);
let controller1 = new Controller();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
collision(player, obstacle2);
collision(player, obstacle1);
collision(player, ground);
player.draw();
player.update();
ground.draw();
obstacle1.draw();
obstacle2.draw();
requestAnimationFrame(animate);
}
function updatePos() {
player.newPos();
}
animate();
setInterval(updatePos, 10);
<canvas id="canvas"></canvas>

p5.js rect circle collision, cant seem to get it to detect

Can someone help me, I can't seem to get my collision detection between an array of balls and a rectangle object to work.
var balls = [];
var obstacle;
function setup() {
createCanvas(windowWidth, windowHeight);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
for(var i = 0; i < balls.length; i++) {
balls[i].display();
balls[i].update();
balls[i].edges();
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0 , 100);
stroke(255);
ellipse(this.x, this.y, this.r*2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= windowHeight - this.r*2) {
this.y = windowHeight - this.r*2;
this.velocity = this.velocity* -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = windowWidth - windowWidth;
this.y = windowHeight / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
}
function RectCircleColliding(Ball, Obstacle) {
var distX = Math.abs(Ball.x - Obstacle.x - Obstacle.w / 2);
var distY = Math.abs(Ball.y - Obstacle.y - Obstacle.h / 2);
if (distX > (Obstacle.w / 2 + Ball.r)) {
return false;
console.log("no hit");
}
if (distY > (Obstacle.h / 2 + Ball.r)) {
return false;
console.log("no hit");
}
if (distX <= (Obstacle.w / 2)) {
return true;
console.log("hit");
}
if (distY <= (Obstacle.h / 2)) {
return true;
console.log("hit");
}
var dx = distX - Obstacle.w / 2;
var dy = distY - Obstacle.h / 2;
return (dx * dx + dy * dy <= (Ball.r * Ball.r));
}
I can't seem to get it to detect anything, I would appreciate any help. I'm using the p5.js library. I can't seem to get it to detect anything.
In the code you provided the function that checks the collision is never called and when it is, it doesn't work.
Here's my attempt at it. Changed the RectCircleColliding method and called it inside draw.
var balls = [];
var obstacle;
function setup() {
createCanvas(windowWidth, windowHeight);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
for(var i = 0; i < balls.length; i++) {
balls[i].display();
balls[i].update();
balls[i].edges();
console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0 , 100);
stroke(255);
ellipse(this.x, this.y, this.r*2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= windowHeight - this.r*2) {
this.y = windowHeight - this.r*2;
this.velocity = this.velocity* -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = windowWidth - windowWidth;
this.y = windowHeight / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var bRight = Obstacle.x + Obstacle.w;
var bLeft = Obstacle.x;
var bTop = Obstacle.y;
var bBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if(Ball.x + Ball.r > bLeft)
if(Ball.x - Ball.r < bRight)
if(Ball.y + Ball.r > bTop)
if(Ball.y - Ball.r < bBottom)
return(true);
return false;
}

p5.js collision/object interaction. Ball bounce

Following the collision between a ball from an array and an object (rectangle), the ball doesn't seem to have the same bounce affect as it has when it hits the ground.
When coming into contact with the object, it seems to pick up speed and suddenly glitches through and comes to rest on the ground.
Questions:
Why does it seem to want to rest on the ground and not on the object itself?
How can I make the ball have the same bounce affect when coming into contact with the object as it has when coming into contact with the ground?
Code:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
balls[i].update();
balls[i].edges();
RectCircleColliding(balls[i], obstacle);
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var oRight = Obstacle.x + Obstacle.w;
var oLeft = Obstacle.x;
var oTop = Obstacle.y;
var oBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if (Ball.x + Ball.r > oLeft) {
if (Ball.x - Ball.r < oRight) {
if (Ball.y + Ball.r > oTop) {
if (Ball.y - Ball.r < oBottom) {
Ball.y = Obstacle.y - Ball.r * 2;
Ball.velocity = Ball.velocity * -1;
Ball.gravity = Ball.gravity * 1.1;
Ball.velocity += Ball.gravity;
Ball.y += Ball.velocity;
return (true);
}
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
The main issue with this question's code is that we need to check for collisions and only allow updates when the ball is not colliding. Another issue was that when collisions occur we must cap the gravity to prevent the ball from plunging all the way to the ground.
Here is the corrected code:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
if (!RectCircleColliding(balls[i], obstacle)){
balls[i].update();
balls[i].edges();
}
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var oRight = Obstacle.x + Obstacle.w;
var oLeft = Obstacle.x;
var oTop = Obstacle.y;
var oBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if (Ball.x + Ball.r > oLeft) {
if (Ball.x - Ball.r < oRight) {
if (Ball.y + Ball.r > oTop) {
if (Ball.y - Ball.r < oBottom) {
let oldY = Ball.y;
Ball.y = oTop - Ball.r;
Ball.velocity = Ball.velocity * -1;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return (true);
}
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

unexpected behavior during a rotation animation on canvas

I've been working on some studies with animation and with the help of some jquery I've created an animation where when a square that is moved by the users mouse through a mousemove jquery event collides with another square on the screen (square2) thats been hit will move a certain length and if the hitbox is struck near its edges than the object is expected to rotate. The problem ive been running into is that when the object rotates it creates a pseudo afterimage of the outline of the square. At first I thought that I could remove the afterImage by using a clearRect() method to encompass a larger area around square2, but doing this not only leaves my problem unresolved, but also makes a part of my first square invisible which is undesired. If anybody could hep me figure out where ive gone wrong in this code, would definitely appreciate it fellas.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 1000;
canvas.height = 400;
var width = canvas.width;
var height = canvas.height;
var particles = [];
var mouseSize = 50;
var isColliding = false;
var mouseX;
var mouseY;
var animationForward = false;
function particle() {
var particle = {
originX: width / 2,
originY: height / 2,
x: width / 2,
y: height / 2,
size: 30,
centerPointX: this.x + this.size / 2,
centerPointY: this.y + this.size / 2,
decay: .98,
vx: 0,
vy: 0,
rotate: 0,
vr: 0,
draw: function() {
ctx.fillStyle = "white";
ctx.fillRect(this.x, this.y, this.size, this.size)
// rotation logic
// method found at http://stackoverflow.com/questions/2677671/how-do-i-rotate-a-single-object-on-an-html-5-canvas
function drawImageRot(x, y, width, height, deg) {
ctx.clearRect(x, y, width, height);
//Convert degrees to radian
var rad = deg * Math.PI / 180;
//Set the origin to the center of the image
ctx.translate(x + width / 2, y + height / 2);
//Rotate the canvas around the origin
ctx.rotate(rad);
//draw the image
ctx.fillRect(width / 2 * (-1), height / 2 * (-1), width, height);
//reset the canvas
ctx.rotate(rad * (-1));
ctx.translate((x + width / 2) * (-1), (y + height / 2) * (-1));
}
//check for collision
if (mouseX < particles[0].x + particles[0].size &&
mouseX + mouseSize > particles[0].x &&
mouseY < particles[0].y + particles[0].size &&
mouseSize + mouseY > particles[0].y) {
isColliding = true;
} else {
isColliding = false;
}
//controlling velocity dependending on location of collision.
if (isColliding) {
//x axis
animationForward = true;
// checking below to see if mouseRect is hitting near the center of particleRect.
// if it hits near center the vy or vx will not be as high depending on direction and if it //does not than we will make square rotate
if (mouseX < this.x) {
this.vr = 3 + Math.random() * 10
if (mouseX + mouseSize / 2 > this.x) {
this.vx = 0 + Math.random() * 2;
} else {
this.vx = 3 + Math.random() * 3;
}
} else {
this.vr = -3 - Math.random() * 10
if (mouseX + mouseSize / 2 < this.x + this.size) {
this.vx = 0 - Math.random() * 2;
} else {
this.vx = -3 - Math.random() * 3;
}
}
//y axis checking
if (mouseY < this.y) {
if (mouseY + mouseSize / 2 > this.y) {
this.vy = 0 + Math.random() * 2;
} else {
this.vy = 3 + Math.random() * 3;
}
} else {
if (mouseY + mouseSize / 2 < this.y + this.size) {
this.vy = 0 - Math.random() * 2;
} else {
this.vy = -3 - Math.random() * 3;
}
}
}
//decay all motions each frame while animation is forward
if (animationForward) {
this.vx *= this.decay;
this.vy *= this.decay;
this.vr *= this.decay;
}
//when animation is done, set all velocities to 0
if (this.x != this.originX && Math.abs(this.vx) < .1 && this.y != this.originY && Math.abs(this.vy) < .1) {
animationForward = false;
this.vx = 0;
this.vy = 0;
this.vr = 0
}
//x check to see if animation over. if it is slowly put square back to original location
if (this.x != this.originX && !animationForward) {
if (this.x > this.originX) {
this.vx = -1;
}
if (this.x < this.originX) {
this.vx = 1;
}
if (this.x > this.originX && this.x - this.originX < 1) {
this.vx = 0;
this.x = this.originX;
}
if (this.x < this.originX && this.originX - this.x < 1) {
this.vx = 0;
this.x = this.originX;
}
}
// end x collison
// y check to see if animation over
if (this.y != this.originX && !animationForward) {
if (this.y > this.originY) {
this.vy = -1;
}
if (this.y < this.originY) {
this.vy = 1;
}
if (this.y > this.originY && this.y - this.originY < 1) {
this.vy = 0;
this.y = this.originY;
}
if (this.y < this.originY && this.originY - this.y < 1) {
this.vy = 0;
this.y = this.originY;
}
}
// end y collison
//check rotation
if (this.rotate != 0 && !animationForward) {
this.rotate = Math.round(this.rotate);
if (this.rotate < 0) {
if (this.rotate < -300) {
this.rotate += 10
} else if (this.rotate < -200) {
this.rotate += 7
} else if (this.rotate < -125) {
this.rotate += 5
} else if (this.rotate < -50) {
this.rotate += 3
} else {
this.rotate++;
}
} else {
if (this.rotate > 300) {
this.rotate -= 10;
} else if (this.rotate > 200) {
this.rotate -= 7
} else if (this.rotate > 125) {
this.rotate -= 5
} else if (this.rotate > 50) {
this.rotate -= 3
} else {
this.rotate--;
}
}
}
// move the rect based off of previous set conditions and make square rotate if edges hit
this.x += this.vx;
this.y += this.vy;
this.rotate += this.vr;
drawImageRot(this.x, this.y, this.size, this.size, this.rotate);
// boundary control
if (this.x + this.size > width || this.x < 0) {
this.vx = -this.vx * 2
}
if (this.y + this.size > height || this.y < 0) {
this.vy = -this.vy * 2
}
}
}
return particle;
}
function createParticles() {
particles.push(particle())
//wouldnt be too hard to put more particles. would have to go back and change the isColliding and animationForward global variable and make each object have their own to check. also would have to go back and implement for loops wherever i mention an element in my array
}
createParticles();
function draw() {
console.log(particles[0].rotate);
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = 'white';
ctx.fillRect(mouseX, mouseY, mouseSize, mouseSize);
particles[0].draw();
requestAnimationFrame(draw);
}
$("#canvas").mousemove(function(event) {
mouseX = event.pageX;
mouseY = event.pageY;
})
window.onload = draw();
I think your problem is right here:
draw: function() {
ctx.fillStyle = "white";
ctx.fillRect(this.x, this.y, this.size, this.size)
....
You are drawing 2nd shape here. Comment this lines and pseudo image should be gone.

Categories

Resources