Why my agent collision doesn't work (javascript) - javascript

I have an agent called cube (cube its just the name, it is a square in reality). Every cube falls and stops on the ground, and I want them to detect the other cubes and stack up.
I am having problems with this method for detecting collision: https://www.youtube.com/watch?v=GY-c2HO2liA&list=PLRqwX-V7Uu6Zy51Q-x9tMWIv9cueOFTFA
I made 2 for loops and all but it doesn't work for some reason.
this is the main script:
var cubes = [];
var nb = 10; //number of cubes
var gravity = .1;
var sz = 10; //cube size
function setup() {
createCanvas(400, 400);
for (i = 0; i < nb; i++) {
cubes.push(new Cube());
}
}
function draw() {
background(51);
for (var i = 0; i < cubes.length; i++) {
cubes[i].show();
for (var j = 0; j < cubes.length; j++) {
if (i != j && !cubes[i].collide(cubes[j]) && !(cubes[i].pos.y + sz > height)) {
cubes[i].pos.y += gravity;
}
}
}
}
this is the cube function linked with p5.js in an HTML file:
function Cube() {
this.rx = (round((random(0, width - sz)) / sz) * sz);
this.ry = (round((random(sz, height - sz)) / sz) * sz);
this.pos = createVector(this.rx, this.ry);
this.show = function() {
fill(220);
noStroke();
rect(this.pos.x, this.pos.y, sz, sz);
}
this.collide = function(other) {
if (this.pos.y + sz == other.pos.y && this.pos.x == other.pos.x) {
return true;
} else {
return false;
}
}
}
I want the cubes to stack up when they hit the ground but they only pass through each other completely ignoring the collision I've set up.

I think your problem is coming from the fact that you are using ==, please try modifying this line :
if (this.pos.y + sz == other.pos.y && this.pos.x == other.pos.x) {
into
if (this.pos.y + sz > other.pos.y && this.pos.y <= other.pos.y+sz &&
this.pos.x < other.pos.x+sz && this.pos.x + sz > other.pos.x)

Related

Changing aspect of single object in an array, indicies not lining up

Objective: When the red candles are clicked, they should turn green.
At the moment, when a candle is clicked, the next candle in the array is changed, instead of the candle that was clicked. When the last candle is clicked, the first candle changes color, so the problem continues to wrap around the array. What would the issue be and how would I fix it?
I've tried all kinds of array manipulation, i.e. (candles[i-1]... etc). And different ways of assigning the color (having a separate 'colors' array. All of which led to the same issue.
let candles = [];
let numCandles = 15;
let bg, r, g;
function setup(){
createCanvas(windowWidth,windowHeight);
r = color(239,83,80);
g = color(38,166,154);
bg = color(19,23,34);
background(bg);
for(let i = 0; i < numCandles; i++){
let c = new candleStick(i);
candles.push(c);
c.show();
}
}
function draw(){
resizeCanvas(windowWidth, windowHeight);
background(bg);
for(let i = 0; i < numCandles; i++){
candles[i].show();
}
}
function mousePressed(){
for(let i = 0; i < numCandles; i++){
if(mouseX <= candles[i].x + candles[i].bodyWidth && mouseX >= candles[i].x &&
mouseY <= candles[i].y + candles[i].bodyHeight && mouseY >= candles[i].y){
if(candles[i].col == r){
candles[i].col = g;
}
else if(candles[i].col == g){
candles[i].col = r;
}
}
}
}
class candleStick{
constructor(index){
this.bodyHeight = 200;
this.bodyWidth = 20;
this.offset = 25;
this.index = index;
this.col = r;
this.x = (windowWidth/2) - (this.index * this.offset) + (numCandles * (this.offset + this.bodyWidth)/4);
this.y = (windowHeight/2) - this.bodyHeight;
}
drawBody(){
rect(this.x, this.y, this.bodyWidth , this.bodyHeight,2);
fill(this.col);
noStroke();
}
drawLine(){
line((height/2 - this.bodyWidth/2) - (this.index * this.offset), (width/2 - this.bodyHeight/2), (height/2 - this.bodyWidth/2) - (this.index * this.offset) , (width/2 - this.bodyHeight/2) - 300);
}
show(){
this.drawBody();
this.drawLine();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>
Expected result: When a candle is clicked, the color of that candle changes (from red to green and from green to red). All other candles should remain the same.
Functions like fill(), noStroke(), ... set states, which are used to draw shapes. fill() sets the color used to fill shapes and noStroke() disables drawing the outline.
rect() draws a rectangle, using the current states.
This means fill() and noStroke() have to be called before rect():
class candleStick{
// [...]
drawBody(){
fill(this.col);
noStroke();
rect(this.x, this.y, this.bodyWidth , this.bodyHeight,2);
}
// [...]
}
Note, the states which you've set didn't affect the currently drawn "candle", the state affected the next candle in the row. This caused the shifting effect.
let candles = [];
let numCandles = 15;
let bg, r, g;
function setup(){
createCanvas(windowWidth,windowHeight);
r = color(239,83,80);
g = color(38,166,154);
bg = color(19,23,34);
background(bg);
for(let i = 0; i < numCandles; i++){
let c = new candleStick(i);
candles.push(c);
c.show();
}
}
function draw(){
resizeCanvas(windowWidth, windowHeight);
background(bg);
for(let i = 0; i < numCandles; i++){
candles[i].show();
}
}
function mousePressed(){
for(let i = 0; i < numCandles; i++){
if(mouseX <= candles[i].x + candles[i].bodyWidth && mouseX >= candles[i].x &&
mouseY <= candles[i].y + candles[i].bodyHeight && mouseY >= candles[i].y){
if(candles[i].col == r){
candles[i].col = g;
}
else if(candles[i].col == g){
candles[i].col = r;
}
}
}
}
class candleStick{
constructor(index){
this.bodyHeight = 200;
this.bodyWidth = 20;
this.offset = 25;
this.index = index;
this.col = r;
this.x = (windowWidth/2) - (this.index * this.offset) + (numCandles * (this.offset + this.bodyWidth)/4);
this.y = (windowHeight/2) - this.bodyHeight;
}
drawBody(){
fill(this.col);
noStroke();
rect(this.x, this.y, this.bodyWidth , this.bodyHeight,2);
}
drawLine(){
line((height/2 - this.bodyWidth/2) - (this.index * this.offset), (width/2 - this.bodyHeight/2), (height/2 - this.bodyWidth/2) - (this.index * this.offset) , (width/2 - this.bodyHeight/2) - 300);
}
show(){
this.drawBody();
this.drawLine();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>

Land a character on a block after he jumps on it in p5.js game

I'm just trying to create a small 2d game where we control a character that can place block on the "map" with the mouse and jump on it to climb etc. It's just a test to practice.
I've achieved to make the character stops when he walk into blocks.
But, i'm facing a problem when I want my character to jump on a block, i'm not able to make him land on it. I can't find the condition to.
Can someone helps me on it ? The code that handle the collision between the character and blocks is in the draw function and in the for.
Controls
Left: Q
Right: D
Jump: Space Bar
Place a block: Mouse Click
Remove a block: Mouse Click
Edit: You might have ask yourself why i'm using some variables that are not declared anywhere. It's because they are given by P5.js. (ex: width)
function Man() {
this.w = 20;
this.h = 40;
this.x = width/2;
this.y = height - this.h;
this.canJump = true;
this.velocity = 0;
this.show = function(){
fill(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function(){
this.velocity += gravity;
this.y += this.velocity;
if(this.y + this.h > height) {
this.y = height - this.h ;
this.velocity = 0;
this.canJump = true;
}
if(this.x <= 0) {
this.x = 0;
}
if(this.x + this.w >= width) {
this.x = width - this.w;
}
}
this.jump = function(){
if(this.canJump) {
man.velocity -= 6;
this.canJump = false;
}
}
}
var man;
var ground;
var gravity = 0.4;
function setup(){
frameRate(60);
createCanvas(640, 480);
man = new Man();
}
var tilesSize = 20;
var tiles = [];
for(var i = 0; i < 640; i+= tilesSize) {
for(var j = 0; j < 480; j+= tilesSize) {
tiles.push({x:i, y:j, empty: true});
}
}
function draw(){
background(0);
noStroke();
push();
for(var i = 0; i < tiles.length; i++) {
if(!tiles[i].empty) {
fill(150);
rect(tiles[i].x, tiles[i].y, tilesSize, tilesSize);
}
if(mouseX >= tiles[i].x && mouseX < tiles[i].x + tilesSize && mouseY >= tiles[i].y && mouseY < tiles[i].y + tilesSize) {
if(tiles[i].empty) {
fill(50);
rect(tiles[i].x, tiles[i].y, tilesSize, tilesSize);
}else {
fill(255,0,0);
rect(tiles[i].x, tiles[i].y, tilesSize, tilesSize);
}
}
// HERE IS CONDITIONS FOR COLLISION WITH BLOCK
if(!tiles[i].empty) {
if(tiles[i].x + tilesSize >= man.x && tiles[i].x < man.x && tiles[i].y < man.y + man.h ) {
man.x = tiles[i].x + tilesSize;
}
if(man.x + man.w >= tiles[i].x && man.x <= tiles[i].x && tiles[i].y < man.y + man.h) {
man.x = tiles[i].x - man.w;
}
}
}
pop();
man.show();
man.update();
moveMan();
}
function moveMan(){
if(keyIsDown(81)) {
man.x -= 2;
}
if(keyIsDown(68)) {
man.x += 2;
}
}
function keyPressed() {
if(keyIsDown(32)) {
man.jump();
}
}
function mouseClicked() {
for(var i = 0; i < tiles.length; i++) {
if(mouseX >= tiles[i].x && mouseX < tiles[i].x + tilesSize && mouseY >= tiles[i].y && mouseY < tiles[i].y + tilesSize) {
if(tiles[i].empty) {
tiles[i].empty = false;
}else {
tiles[i].empty = true;
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>

I am making an Atari Breakout clone & I am wondering how to tell if the ball hits a certain side of a block

I have gotten the part where when the ball collides with the block it deletes the block, but I am also wanting to tell if the ball hits the top or bottom or left or right of the block and bounce accordingly. I have attempted it, but it's not working quite right. It just freaks out jumping around. I have deleted that portion from the code below as it does not work. Can anyone help me out with this problem? Maybe give an example or tell me how it would work?
<canvas id="can" height="500" width="1000"></canvas>
var c = document.getElementById("can");
var ctx = c.getContext("2d");
var blocks= [];
var paddle = {x:450,y:480,h:10,w:100};
var ball = {r:7,x:500,y:469};
var rows=[0,1,2,3,4];
var px = paddle.x, py = paddle.y;
var pxv=0;
var by = ball.y, bx = ball.x;
var bxv = -1.5, byv = -1.5;
function Block(h,w,x,y,c) {
this.h = h;
this.w = w;
this.x = x;
this.y = y;
this.c = c;
}
for(var i =0, len=rows.length;i<len;i++){
for(var j=0; j<20;j++) {
blocks.push(new Block(20,50,j*50,i*20,rows[i]))
}
}
document.addEventListener("keydown",keyPush);
document.addEventListener("keyup",keyRelease);
function keyRelease(evt) {
switch(evt.keyCode) {
case 37:
pxv=0;
break;
case 39:
pxv=0;
break;
}
}
function keyPush(evt) {
switch(evt.keyCode) {
case 37:
pxv=-5;
break;
case 39:
pxv=5
break;
}
}
function AABBIntersect(ax, ay, aw, ah, bx, by, bw, bh) {
return ax < bx+bw && bx < ax+aw && ay < by+bh && by < ay+ah;
};
function draw(){
ctx.clearRect(0,0,1000,500)
bx+=bxv;
by+=byv;
px+=pxv;
if(px > 900) {
px = 900;
}
else if(px < 0) {
px = 0;
}
for(var i = 0, len=blocks.length;i<len;i++) {
var bl = blocks[i];
if(AABBIntersect(bx,by,ball.r,ball.r,bl.x,bl.y,bl.w,bl.h)) {
blocks.splice(i,1);
i--;
len--;
}
}
if(bx < 0) {
bxv = bxv*-1;
}
if(bx > 1000) {
bxv = bxv*-1;
}
ctx.fillStyle = "#ff4b38"
ctx.fillRect(px,py,paddle.w,paddle.h);
for(var i = 0, len=blocks.length; i<len; i++){
if(blocks[i].c === 0) {
ctx.fillStyle = "#ff4b38"
}
else if(blocks[i].c === 1) {
ctx.fillStyle = "#ffba19"
}
else if(blocks[i].c === 2) {
ctx.fillStyle = "#fcee25"
}
else if(blocks[i].c === 3) {
ctx.fillStyle = "#26db02"
}
else if(blocks[i].c === 4) {
ctx.fillStyle = "#2d69ff"
}
ctx.fillRect(blocks[i].x,blocks[i].y,blocks[i].w,blocks[i].h);
ctx.beginPath();
ctx.arc(bx,by,ball.r,0,2*Math.PI,false);
ctx.fillStyle = "gray";
ctx.fill();
}
}
setInterval(draw,10);
I'm sure there are more ways to do it but this is how I would do it.
Inside your collision detection function you should have if-statements to detect if from the x or y side. You made need to tweak it as not sure if it will error later but the brunt of it all is like this:
function AABBIntersect(ax, ay, aw, ah, bx, by, bw, bh) {
var bool = ax < bx + bw && bx < ax + aw && ay < by + bh && by < ay + ah;
if(bool){
if(ax == bx || ax == bx + bw){
bxv *= -1;
cl("x");
}else{
byv *= -1;
cl("y");
}
}
return bool;
};
Your next issue is you have no paddle collision detection, so it will bounce back but it will go through your paddle. So you can do the following in your draw() function. I put it after your if(bx > 1000):
if(bx >= px && bx <= px + paddle.w && by >= py && by <= py + paddle.h){
byv *= -1;
}
I would also put your setInterval on a var so you can clear it when either all the blocks are gone or your ball goes below the paddle. Otherwise it's just going to go everywhere infinitely.

Lag in my Html Canvas Game

I started to make a video game with Html canvas and JavaScript: you are an alien have to shoot out other red aliens. If you come near an alien(enemy) the enemy starts to move in your direction. Now if the player comes near an Enemy, that is near another Enemy(but not as much to see the player) the game starts to lag.
This is the function of the distance and move to function:
this.moveto = function(vec,vel){
distX = vec.x - vec.offsetx - this.x
distY = vec.y - vec.offsety - this.y
dist = Math.sqrt(distX*distX + distY*distY)
distX /= dist
distY /= dist
i+= 1
if(dist >= 2){
this.x += (distX/100)*vel
this.y += (distY/100)*vel
}
}
this.dist = function(vec){
dist2X = vec.x - vec.offsetx - this.x
dist2Y = vec.y - vec.offsety - this.y
dist2 = Math.sqrt(dist2X*dist2X + dist2Y*dist2Y)
return(dist2)
}
and this is how it's used:
for(i = 0; i < this.enemies.length; i++){
this.enemies[i].update()
if(this.enemies[i].dist(this.player) > 100){
this.enemies[i].move()
}else{
this.enemies[i].moveto(this.player,30)
}
if(this.enemies[i].lives <= 0){
this.enemies.splice(i,1)
}
}
("enemies" is an array with 5 enemies)
This is the enemy.move():
this.vector = new Vector(x,y,534/8,1517/8)
this.vector.move = function(){
if(this.passi <= 2){ //1
game.rspe.play()
if(game.level.tick){
this.IndexX++;
}
this.currentImage = game.enemyl
this.x-=3;
if (this.IndexX > 10){
this.passi++
this.IndexX = 0;
}
}else if(this.passi > 2 && this.passi <= 5){ //2
game.rspe.play()
if(game.level.tick){
this.IndexX++;
}
this.currentImage = game.enemyr
this.x+=3;
if (this.IndexX > 10){
this.IndexX = 0;
this.passi++
}
}else{
this.passi = 0
}
}
return(this.vector)
this is the git repository: https://github.com/Lollipopper/A1bKJBABJQ-W6-hi-jH-

Changing color of Javascript class object dynamically?

I want to change the color of the balls to red when they collide. I tried using my function check() to change the color of the balls when they collide using balls[i].color but how do I know the positions of the balls to compare when they collide?
function randomXToY(minVal,maxVal,floatVal)
{
var randVal = minVal+(Math.random()*(maxVal-minVal));
return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
}
// The Ball class
Ball = (function() {
// constructor
function Ball(x,y,radius,color){
this.center = {x:x, y:y};
this.radius = radius;
this.color = color;
this.dx = 2;
this.dy = 2;
this.boundaryHeight = $('#ground').height();
this.boundaryWidth = $('#ground').width();
this.dom = $('<p class="circle"></p>').appendTo('#ground');
// the rectange div a circle
this.dom.width(radius*2);
this.dom.height(radius*2);
this.dom.css({'border-radius':radius,background:color});
this.placeAtCenter(x,y);
}
// Place the ball at center x, y
Ball.prototype.placeAtCenter = function(x,y){
this.dom.css({top: Math.round(y- this.radius), left: Math.round(x - this.radius)});
this.center.x = Math.round(x);
this.center.y = Math.round(y);
};
Ball.prototype.setColor = function(color) {
if(color) {
this.dom.css('background',color);
} else {
this.dom.css('background',this.color);
}
};
// move and bounce the ball
Ball.prototype.move = function(){
var diameter = this.radius * 2;
var radius = this.radius;
if (this.center.x - radius < 0 || this.center.x + radius > this.boundaryWidth ) {
this.dx = -this.dx;
}
if (this.center.y - radius < 0 || this.center.y + radius > this.boundaryHeight ) {
this.dy = -this.dy;
}
this.placeAtCenter(this.center.x + this.dx ,this.center.y +this.dy);
};
return Ball;
})();
var number_of_balls = 5;
var balls = [];
var x;
var y;
$('document').ready(function(){
for (i = 0; i < number_of_balls; i++) {
var boundaryHeight = $('#ground').height();
var boundaryWidth = $('#ground').width();
y = randomXToY(30,boundaryHeight - 50);
x = randomXToY(30,boundaryWidth - 50);
var radius = randomXToY(15,30);
balls.push(new Ball(x,y,radius, '#'+Math.floor(Math.random()*16777215).toString(16)));
}
loop();
check();
});
check = function(){
for (var i = 0; i < balls.length; i++){
for(var j=0;j<balls.length;j++){
if(x==y){
balls[i].color='#ff0000';
alert("y");
}
else{
}
}}
setTimeout(check,8);
};
loop = function(){
for (var i = 0; i < balls.length; i++){
balls[i].move();
}
setTimeout(loop, 8);
};
http://jsbin.com/imofat/743/edit
Calculate the Eucledian distance between the centers of each ball. Then, when this distance is smaller or equal to the sum of their radiuses, there's a collision:
check = function() {
for (var i = 0; i < balls.length; i++) {
for(var j = 0; j < balls.length; j++) {
if (i != j) { // ignore self-collision
if (Math.pow(balls[j].center.x - balls[i].center.x, 2) + Math.pow(balls[j].center.y - balls[i].center.y, 2) <= Math.pow(balls[i].radius + balls[j].radius, 2)) {
balls[j].setColor('red');
} else {
balls[j].setColor(balls[j].color);
}
}
}}
Here's a DEMO.
Edit:
for colliding with other balls, it will require more work.. check this post: Ball to Ball Collision
just setColor when the direction changes, assuming "collide" means "hit the wall":
// move and bounce the ball
Ball.prototype.move = function(){
var diameter = this.radius * 2;
var radius = this.radius;
if (this.center.x - radius < 0 || this.center.x + radius > this.boundaryWidth ) {
this.dx = -this.dx;
this.setColor( 'red' );
}
if (this.center.y - radius < 0 || this.center.y + radius > this.boundaryHeight ) {
this.dy = -this.dy;
this.setColor( 'red' );
}
this.placeAtCenter(this.center.x + this.dx ,this.center.y +this.dy);
};
I added an actual ball collision check inside the check method:
check = function(){
var dx, dy;
var x1, x2, y1, y2, r1, r2;
for (var i = 0; i < balls.length; i++){
x1 = balls[i].center.x;y1=balls[i].center.y;r1=balls[i].radius;
for(var j=0;j<balls.length;j++){
if (i===j) {continue;} // collision with self
x2 = balls[j].center.x;y2=balls[j].center.y;r2=balls[j].radius;
if( Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) <=(r1+r2) ){ // check collision
balls[i].setColor('#ff0000');
}
else{
}
}
}
setTimeout(check,8);
};

Categories

Resources