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

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>

Related

How to push one object infront of another p5js javascript

I have been stuck on this for hours and am unsure on what to do.
Here is my code:
var circles = [];
var circles2 = [];
function setup() {
createCanvas(500, 500);
//there's a "b" for every "a"
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
//add the circles to the array at x = a and y = b
circles.push(new Circle(a, b));
circles2.push(new Conn(a, b));
}
}
for (var a = 250; a < width - 50; a += 20) {
for (var b = 250; b < height - 50; b += 20) {
//add the circles to the array at x = a and y = b
}
}
console.log(circles.length);
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles2[b].show();
circles[b].show();
//console.log("shown");
}
for (var b = 0; b < circles2.length; b++) {
//circles2[b].show();
//console.log("shown");
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
//console.log("showing");
push();
fill(255);
noStroke();
translate(250, 250);
ellipse(this.x, this.y, 10, 10);
pop();
}
}
function Conn(x, y) {
this.x = x;
this.y = y;
this.show = function() {
noStroke();
let h = 0;
for (let i = 0; i < 251; i++) {
fill(h, 90, 120);
h = (h + 1) % 500;
noStroke();
push()
ellipse(this.x + i, this.y + i, 10, 10);
noStroke();
noLoop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
It generates a grid of squares that is supposed to connect to a different grid of squares through gradient lines. However, only the bottom row and right most column of circles on the bottom right circle grid show up for some reason. How can I make it that all circles on the bottom right circle grid are in front of the gradient lines? I've tried push, pop, and everything else. I'm really confused as to why only some of the circles are showing up, but the others are stuck behind these gradients.
Unless you use p5.js in WEBGL mode then there is no object stacking order or z-index or z-buffer. Shapes that you draw always overlap whatever was drawn before them. So in order to make a shape appear on top of another you need to draw the shape underneath first, followed by the shape on top. I believe I was able to achieve this by rearranging your code a little:
var circles = [];
var connections = [];
function setup() {
createCanvas(500, 500);
//there's a "b" for every "a"
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
//add the circles to the array at x = a and y = b
circles.push(new Circle(a, b));
connections.push(new Conn(a, b));
}
}
for (var a = 250; a < width - 50; a += 20) {
for (var b = 250; b < height - 50; b += 20) {
//add the circles to the array at x = a and y = b
}
}
console.log(circles.length);
}
function draw() {
background(50);
// Show connections first
for (var b = 0; b < connections.length; b++) {
connections[b].show();
}
// Show circles second so that they appear on top of the connections
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);
//console.log("showing");
push();
fill(255);
noStroke();
translate(250, 250);
ellipse(this.x, this.y, 10, 10);
pop();
}
}
function Conn(x, y) {
this.x = x;
this.y = y;
this.show = function() {
noStroke();
let h = 0;
for (let i = 0; i < 251; i++) {
fill(h, 90, 120);
h = (h + 1) % 500;
noStroke();
push()
ellipse(this.x + i, this.y + i, 10, 10);
noStroke();
noLoop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Why my agent collision doesn't work (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)

How to color line in canvas?

EDIT: I'm trying to get a single line colored, not the whole grid
So, what I'm trying to do is that when the canvas gets clicked, the lines selected move and get colored.
I already have the lines moving but I cannot get them colored. I know I have to use the strokeStyle property, but how do I get the specific line colored?
I tried putting the strokeStyle under the draw_each method, but that doesn't work, and I don't know why. Here's my code:
//draw each line in array
function draw_each(p1, p2, p3, p4) {
$.moveTo(p1.x, p1.y);
$.lineTo(p2.x, p2.y);
$.moveTo(p1.x, p1.y);
$.lineTo(p4.x, p4.y);
if (p1.ind_x == gnum - 2) {
$.moveTo(p3.x, p3.y);
$.lineTo(p4.x, p4.y);
}
if (p1.ind_y == gnum - 2) {
$.moveTo(p3.x, p3.y);
$.lineTo(p2.x, p2.y);
}
}
https://codepen.io/diazabdulm/pen/qJyrZP?editors=0010
It seems to me that what you want is actually to generate a color per segment based on the force that's been applied to it, so that the wave effect keeps its effect.
What you can do, is to save the median of each node's velocity in both axis as a mean to represent the force they're currently experiencing, and in your drawing part to get the median of all nodes that will compose each segment of your grid and compose a color from it.
But this comes with a drawback: your code was well written enough to compose the whole grid a single sub-path, thus limiting the number of drawings necessary. But now, we have to make each segment its own sub-path (since they'll got their own color), so we'll loose a lot in terms of performances...
var gnum = 90; //num grids / frame
var _x = 2265; //x width (canvas width)
var _y = 1465; //y height (canvas height)
var w = _x / gnum; //grid sq width
var h = _y / gnum; //grid sq height
var $; //context
var parts; //particles
var frm = 0; //value from
var P1 = 0.0005; //point one
var P2 = 0.01; //point two
var n = 0.98; //n value for later
var n_vel = 0.03; //velocity
var ŭ = 0; //color update
var msX = 0; //mouse x
var msY = 0; //mouse y
var msdn = false; //mouse down flag
var Part = function() {
this.x = 0; //x pos
this.y = 0; //y pos
this.vx = 0; //velocity x
this.vy = 0; //velocity y
this.ind_x = 0; //index x
this.ind_y = 0; //index y
};
Part.prototype.frame = function() {
if (this.ind_x == 0 || this.ind_x == gnum - 1 || this.ind_y == 0 || this.ind_y == gnum - 1) {
return;
}
var ax = 0; //angle x
var ay = 0; //angle y
//off_dx, off_dy = offset distance x, y
var off_dx = this.ind_x * w - this.x;
var off_dy = this.ind_y * h - this.y;
ax = P1 * off_dx;
ay = P1 * off_dy;
ax -= P2 * (this.x - parts[this.ind_x - 1][this.ind_y].x);
ay -= P2 * (this.y - parts[this.ind_x - 1][this.ind_y].y);
ax -= P2 * (this.x - parts[this.ind_x + 1][this.ind_y].x);
ay -= P2 * (this.y - parts[this.ind_x + 1][this.ind_y].y);
ax -= P2 * (this.x - parts[this.ind_x][this.ind_y - 1].x);
ay -= P2 * (this.y - parts[this.ind_x][this.ind_y - 1].y);
ax -= P2 * (this.x - parts[this.ind_x][this.ind_y + 1].x);
ay -= P2 * (this.y - parts[this.ind_x][this.ind_y + 1].y);
this.vx += (ax - this.vx * n_vel);
this.vy += (ay - this.vy * n_vel);
//EDIT\\
// store the current velocity (here base on 100 since it will be used with hsl())
this.color = (Math.abs(this.vx)+Math.abs(this.vy)) * 50;
this.x += this.vx * n;
this.y += this.vy * n;
if (msdn) {
var dx = this.x - msX;
var dy = this.y - msY;
var ɋ = Math.sqrt(dx * dx + dy * dy);
if (ɋ > 50) {
ɋ = ɋ < 10 ? 10 : ɋ;
this.x -= dx / ɋ * 5;
this.y -= dy / ɋ * 5;
}
}
};
function go() {
parts = []; //particle array
for (var i = 0; i < gnum; i++) {
parts.push([]);
for (var j = 0; j < gnum; j++) {
var p = new Part();
p.ind_x = i;
p.ind_y = j;
p.x = i * w;
p.y = j * h;
parts[i][j] = p;
}
}
}
//move particles function
function mv_part() {
for (var i = 0; i < gnum; i++) {
for (var j = 0; j < gnum; j++) {
var p = parts[i][j];
p.frame();
}
}
}
//draw grid function
function draw() {
//EDIT
// we unfortunately have to break the drawing part
// since each segment has its own color, we can't have a single sub-path anymore...
ŭ -= .5;
for (var i = 0; i < gnum - 1; i += 1) {
for (var j = 0; j < gnum - 1; j += 1) {
var p1 = parts[i][j];
var p2 = parts[i][j + 1];
var p3 = parts[i + 1][j + 1];
var p4 = parts[i + 1][j];
draw_each(p1, p2, p3, p4);
}
}
}
//draw each in array
function draw_each(p1, p2, p3, p4) {
// for each segment we set the color
$.strokeStyle = `hsl(0deg, ${(p1.color+p2.color+p3.color+p4.color) / 4}%, 50%)`;
// begin a new sub-path
$.beginPath();
$.moveTo(p1.x, p1.y);
$.lineTo(p2.x, p2.y);
$.moveTo(p1.x, p1.y);
$.lineTo(p4.x, p4.y);
if (p1.ind_x == gnum - 2) {
$.moveTo(p3.x, p3.y);
$.lineTo(p4.x, p4.y);
}
if (p1.ind_y == gnum - 2) {
$.moveTo(p3.x, p3.y);
$.lineTo(p2.x, p2.y);
}
// and stroke it
$.stroke();
}
//call functions to run
function calls() {
$.fillStyle = "hsla(0, 0%, 7%, 1)";
$.fillRect(0, 0, _x, _y);
mv_part();
draw();
frm++;
}
var c = document.getElementById('canv');
var $ = c.getContext('2d');
$.fillStyle = "hsla(0, 0%, 7%, 1)";
$.fillRect(0, 0, _x, _y);
function resize() {
if (c.width < window.innerWidth) {
c.width = window.innerWidth;
}
if (c.height < window.innerHeight) {
c.height = window.innerHeight;
}
}
requestAnimationFrame(go);
document.addEventListener('click', MSMV, false);
document.addEventListener('click', MSDN, false);
function MSDN(e) {
msdn = true;
window.setTimeout(function() {
msdn = false;
}, 100);
}
function MSUP(e) {
msdn = false;
}
function MSMV(e) {
var rect = e.target.getBoundingClientRect();
msX = e.clientX - rect.left;
msY = e.clientY - rect.top;
}
window.onload = function() {
run();
function run() {
requestAnimationFrame(calls);
requestAnimationFrame(run);
}
resize();
};
onresize = resize;
body {
width: 100%;
overflow: hidden;
cursor:move;
}
<canvas id="canv" width="150" height="150"></canvas>
Now, a more performant way, but less good looking, would be to draw a radial-gradient where the click happened, with a bit of compositing, you'd be able to get something cheap that might work, but it would be quite a lot of coding actually to get multiple such gradients at the same time...
That works for me:
//draw each line in array
function draw_each(p1, p2, p3, p4) {
$.moveTo(p1.x, p1.y);
$.lineTo(p2.x, p2.y);
$.moveTo(p1.x, p1.y);
$.lineTo(p4.x, p4.y);
if (p1.ind_x == gnum - 2) {
$.moveTo(p3.x, p3.y);
$.lineTo(p4.x, p4.y);
}
if (p1.ind_y == gnum - 2) {
$.moveTo(p3.x, p3.y);
$.lineTo(p2.x, p2.y);
}
$.strokeStyle = '#458920';
}

Draw random coloured circles on canvas

I am trying to create a animation where circles run from right to left. The circles' colours are selected randomly by a function. I have created a fiddle where one circle runs from right to left. Now my function creates a random colour. This function is executed every second and the circle changes its colour every second, instead of a new circle with the random picked colour become created. How can I change it so that it draws a new circle every second on the canvas and doesn't only change the colour of the circle?
This is my function:
function getRandomElement(array) {
if (array.length == 0) {
return undefined;
}
return array[Math.floor(Math.random() * array.length)];
}
var circles = [
'#FFFF00',
'#FF0000',
'#0000FF'
];
function drawcircles() {
ctx.beginPath();
ctx.arc(ballx * 108, canvasHeight / 2, x*5, 0, 2*Math.PI, false);
ctx.fillStyle = getRandomElement(circles);
ctx.fill();
ctx.closePath;
}
Comments on your question:
You are changing the color of the fillStyle to a random color at each frame. This is the reason why it keeps "changing" color. Set it to the color of the circle:
context.fillStyle = circle.color;
make circles with x, y, diameter, bounciness, speed, and color using an array
draw and update them with requestAnimationFrame (mine is a custom function)
My answer:
I made this just last night, where some circles follow the cursor and "bounce" off the edges of the screen. I tested the code and it works.
I might post a link later, but here is all of the code right now...
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas"></canvas>
<script>
var lastTime = 0;
function requestMyAnimationFrame(callback, time)
{
var t = time || 16;
var currTime = new Date().getTime();
var timeToCall = Math.max(0, t - (currTime - lastTime));
var id = window.setTimeout(function(){ callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 20;
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var circles = [];
var mouse =
{
x: 0,
y: 0
}
function getCoordinates(x, y)
{
return "(" + x + ", " + y + ")";
}
function getRatio(n, d)
{
// prevent division by 0
if (d === 0 || n === 0)
{
return 0;
}
else
{
return n/d;
}
}
function Circle(x,y,d,b,s,c)
{
this.x = x;
this.y = y;
this.diameter = Math.round(d);
this.radius = Math.round(d/2);
this.bounciness = b;
this.speed = s;
this.color = c;
this.deltaX = 0;
this.deltaY = 0;
this.drawnPosition = "";
this.fill = function()
{
context.beginPath();
context.arc(this.x+this.radius,this.y+this.radius,this.radius,0,Math.PI*2,false);
context.closePath();
context.fill();
}
this.clear = function()
{
context.fillStyle = "#ffffff";
this.fill();
}
this.draw = function()
{
if (this.drawnPosition !== getCoordinates(this.x, this.y))
{
context.fillStyle = this.color;
// if commented, the circle will be drawn if it is in the same position
//this.drawnPosition = getCoordinates(this.x, this.y);
this.fill();
}
}
this.keepInBounds = function()
{
if (this.x < 0)
{
this.x = 0;
this.deltaX *= -1 * this.bounciness;
}
else if (this.x + this.diameter > canvas.width)
{
this.x = canvas.width - this.diameter;
this.deltaX *= -1 * this.bounciness;
}
if (this.y < 0)
{
this.y = 0;
this.deltaY *= -1 * this.bounciness;
}
else if (this.y+this.diameter > canvas.height)
{
this.y = canvas.height - this.diameter;
this.deltaY *= -1 * this.bounciness;
}
}
this.followMouse = function()
{
// deltaX/deltaY will currently cause the circles to "orbit" around the cursor forever unless it hits a wall
var centerX = Math.round(this.x + this.radius);
var centerY = Math.round(this.y + this.radius);
if (centerX < mouse.x)
{
// circle is to the left of the mouse, so move the circle to the right
this.deltaX += this.speed;
}
else if (centerX > mouse.x)
{
// circle is to the right of the mouse, so move the circle to the left
this.deltaX -= this.speed;
}
else
{
//this.deltaX = 0;
}
if (centerY < mouse.y)
{
// circle is above the mouse, so move the circle downwards
this.deltaY += this.speed;
}
else if (centerY > mouse.y)
{
// circle is under the mouse, so move the circle upwards
this.deltaY -= this.speed;
}
else
{
//this.deltaY = 0;
}
this.x += this.deltaX;
this.y += this.deltaY;
this.x = Math.round(this.x);
this.y = Math.round(this.y);
}
}
function getRandomDecimal(min, max)
{
return Math.random() * (max-min) + min;
}
function getRoundedNum(min, max)
{
return Math.round(getRandomDecimal(min, max));
}
function getRandomColor()
{
// array of three colors
var colors = [];
// go through loop and add three integers between 0 and 255 (min and max color values)
for (var i = 0; i < 3; i++)
{
colors[i] = getRoundedNum(0, 255);
}
// return rgb value (RED, GREEN, BLUE)
return "rgb(" + colors[0] + "," + colors[1] + ", " + colors[2] + ")";
}
function createCircle(i)
{
// diameter of circle
var minDiameter = 25;
var maxDiameter = 50;
// bounciness of circle (changes speed if it hits a wall)
var minBounciness = 0.2;
var maxBounciness = 0.65;
// speed of circle (how fast it moves)
var minSpeed = 0.3;
var maxSpeed = 0.45;
// getRoundedNum returns a random integer and getRandomDecimal returns a random decimal
var x = getRoundedNum(0, canvas.width);
var y = getRoundedNum(0, canvas.height);
var d = getRoundedNum(minDiameter, maxDiameter);
var c = getRandomColor();
var b = getRandomDecimal(minBounciness, maxBounciness);
var s = getRandomDecimal(minSpeed, maxSpeed);
// create the circle with x, y, diameter, bounciness, speed, and color
circles[i] = new Circle(x,y,d,b,s,c);
}
function makeCircles()
{
var maxCircles = getRoundedNum(2, 5);
for (var i = 0; i < maxCircles; i++)
{
createCircle(i);
}
}
function drawCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].draw();
ii++;
}
}
}
function clearCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].clear();
ii++;
}
}
}
function updateCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].keepInBounds();
circles[i].followMouse();
ii++;
}
}
}
function update()
{
requestMyAnimationFrame(update,10);
updateCircles();
}
function draw()
{
requestMyAnimationFrame(draw,1000/60);
context.clearRect(0,0,canvas.width,canvas.height);
drawCircles();
}
function handleError(e)
{
//e.preventDefault();
//console.error(" ERROR ------ " + e.message + " ------ ERROR ");
}
window.addEventListener("load", function()
{
window.addEventListener("error", function(e)
{
handleError(e);
});
window.addEventListener("resize", function()
{
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 20;
});
window.addEventListener("mousemove", function(e)
{
mouse.x = e.layerX || e.offsetX;
mouse.y = e.layerY || e.offsetY;
});
makeCircles();
update();
draw();
});
</script>
</body>
</html>

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