I'm writing a collision function to help the object stop moving in a certain direction when facing a block/wall. But it seems that the function has been overlapped because I have called this function multiple times in the draw function of the javascript. How do I prevent this from happening if I want to draw an entire level for the game? For reference, I'm recreating the Bounce game on Nokia.
let cX = 150, cY = 250, size = 50; // circle
let velY = 0;
let gravity = 0.3;
let blockX = new Array (999);
let blockY = new Array (999);
function draw() {
background(230);
velY += gravity; // ball falls faster with time
cY += velY;
if (cX - size/2 < 0) // ball touches left wall
{
cX = 0 + size/2;
}
if (cX + size/2 > width) // ball touches right wall
{
cX = width - size/2;
}
// creates object
for (i = 0; i < 13; i++)
{
blockX[i] = size * i;
blockY[i] = size * 7;
square(blockX[i], blockY[i], size);
collision();
}
for (i = 0; i < 4; i++)
{
blockX[i] = size * 7;
blockY[i] = size * (i+3);
square(blockX[i], blockY[i], size);
collision();
}
for (i = 0; i < 6; i++)
{
blockX[i] = 0;
blockY[i] = size * (i+1);
square(blockX[i], blockY[i], size);
collision();
}
if (keyIsDown(LEFT_ARROW)) // move left
{
cX += -3;
}
if (keyIsDown(RIGHT_ARROW)) // move right
{
cX += 3;
}
if (keyIsDown(UP_ARROW) && cY + size/2 == blockY[i]) // ball touches ground
{
velY = -12;
}
}
function collision()
{
if (cY + size/2 > blockY[i] && cY < blockY[i] && blockX[i]-5 <= cX && cX <= blockX[i]+5 + size) // ball touches top of block
{
cY = blockY[i] - size/2;
velY = -0.4 * velY;
}
if (cX - size/2 < blockX[i] + size && cX - size/2 > blockX[i] + size/2 && blockY[i] <= cY && cY <= blockY[i] + size) // ball touches right of block
{
cX = blockX[i] + size * 3/2;
}
if (cY - size/2 < blockY[i] + size && cY > blockY[i] + size/2 && blockX[i]-5 <= cX && cX <= blockX[i]+5 + size) // ball touches bottom of block
{
cY = blockY[i] + size * 3/2;
}
if (cX + size/2 > blockX[i] && cX + size/2 < blockX[i] + size/2 && blockY[i] <= cY && cY <= blockY[i] + size) // ball touches left of block
{
cX = blockX[i] - size/2;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>
The occurring problem is that the ball can't jump if it's standing on a higher block than the floor.
Related
I have the first moving object that moves down the screen by y axis, I have another object that is positioned 400 pixels below the first moving object, but I want the first moving object to go around the object that is stationary which is 400 pixels down.
How can I achieve this? I tried this:
var tX = target.x;
var tY = target.y;
var magnitude = 0.2;
dx = tX + player.x;
dy = tY + player.y;
angle = Math.atan(dy, dx);
player.x = player.x - magnitude * Math.cos(angle);
player.y = player.y - magnitude * Math.sin(angle);
What's happening is the first moving object is just bouncing off the object that's 400 pixels below but I need the first moving object to go around this below 400 pixels object. how can this be achieved?
More code:
var resArrayPlayerHome;
function nearestToPlayer(player) {
resArrayPlayerHome = arrayPlayerHome.filter(player2 => player2.shirtNumber != player.shirtNumber);
var numObj = findClosest2({ x: player.x, y: player.y });
const result = resArrayPlayerHome.filter(player => player.shirtNumber == numObj.shirtNumber);
return result;
}
const findClosest2 = (target) => resArrayPlayerHome
.reduce((a, item) => getDist(item, target) < getDist(a, target) ? item : a);
var nearPlayer = nearestToPlayer(player);
for (var j = 0; j < arrayPlayerHome.length; j++) {
topY = arrayPlayerHome[j].y - 15;
bottomY = arrayPlayerHome[j].y + 15;
var lengthTop = topY + bottomY;
leftX = arrayPlayerHome[j].x - 15;
rightX = arrayPlayerHome[j].x + 15;
var lengthLeft = leftX + rightX;
if (arrayPlayerHome[j].shirtNumber == nearPlayer[0].shirtNumber && (((player.y - 30) <= arrayPlayerHome[j].y && (player.y + 30) >= arrayPlayerHome[j].y) && ((player.x - 30) <= arrayPlayerHome[j].x && (player.x + 30) >= arrayPlayerHome[j].x))) {
//this.angle1 = Math.atan2(target.y - player.y, target.x - player.x);
//var tX = arrayPlayerHome[j].x - player.x;
//var tY = arrayPlayerHome[j].y - player.y;
var magnitude = 0.2;
dx = arrayPlayerHome[j].x - player.x;
dy = arrayPlayerHome[j].y - player.y;
let dist = Math.hypot(dx, dy);
dx /= dist;
dy /= dist;
if (dx != 0 || dy != 0) {
if (
player.x >= arrayPlayerHome[j].x + 30 ||
player.x <= arrayPlayerHome[j].x - 30 ||
player.y >= arrayPlayerHome[j].y + 30 ||
player.y <= arrayPlayerHome[j].y - 30
) {for (var x = 0; x < 4; x++) {
for (var y = 0; y < 4; y++) {
var tX = target.x;
var tY = target.y;
var magnitude = 0.2;
dx = tX + player.x;
dy = tY + player.y;
angle = Math.atan(dy, dx);
player.x = player.x - magnitude * Math.cos(angle);
player.y = player.y - magnitude * Math.sin(angle);
}
}
}else{
console.log("ssssss");
for (var x = 0; x < 4; x++) {
for (var y = 0; y < 4; y++) {
var tX = target.x;
var tY = target.y;
var magnitude = 0.2;
dx = tX + player.x;
dy = tY + player.y;
angle = Math.atan(dy, dx);
player.x = player.x - magnitude * Math.cos(angle);
player.y = player.y - magnitude * Math.sin(angle);
}
}
}
}
}
}
var rectx = 287.5;
var recty = 460;
var rectx2 = 287.5
var recty2 = 0
var rectwidth = 100
var rectheight = 25
//ball vars
var xBall = Math.floor(Math.random() * 300) + 50;
var yBall = 50;
var diameter = 75;
var xBallChange = 5;
var yBallChange = 5;
//Misc
var started = false;
var score = 0;
var score2 = 0;
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(0);
//main commands
xBall += xBallChange;
yBall += yBallChange;
if (xBall < diameter/2 || xBall > windowWidth - 0.5*diameter) {
xBallChange *= -1;
}
if (yBall < diameter/2 || yBall > windowHeight - diameter) {
yBallChange *= -1;
}
if ((xBall > rectx && xBall < rectx + rectwidth) && (yBall + (diameter/2) >= recty)) {
xBallChange *= -1;
yBallChange *= -1;
score++;
}
//Player 1
fill (0,255,255);
noStroke();
rect(rectx,recty,rectwidth,rectheight);
//Player 2
fill(0,255,255)
noStroke()
rect(rectx2,recty2,rectwidth,rectheight);
//The ball
fill (255,255,0);
noStroke();
ellipse(xBall,yBall,75,75)
// The partition
fill(148,0,211)
noStroke()
rect(0,257,750,1)
}
function keyPressed() {
//Player 1 Input
if (keyCode === LEFT_ARROW) {
rectx -= 50;
} else if (keyCode === RIGHT_ARROW) {
rectx += 50;
}
//Player 2 Input
if (keyCode === 65) {
rectx2 -= 50;
} else if (keyCode === 68) {
rectx2 += 50;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
This is my code. I want the circle/ball to reflect off the second rectangle placed on top. Please help me with the appropriate commands required for this program. I have tried many possibilities and have got the first rectangle to work as I want(the circle/ball reflects off the rectangle). I am trying to make the pong game for two people to play locally. THank you for helping me.
If the ball hits the paddle, then only invert the y component of the direction vector of the ball to reflect the ball on the inner side of the paddle. Correct the position of the ball so that it touches the paddle:
if (xBall > rectx && xBall < rectx + rectwidth && yBall + diameter/2 >= recty) {
yBallChange *= -1;
yBall = recty - diameter/2;
score++;
}
This is only an approximation of course, the reflection at the corners is incorrect and the ball does not bounce on the left or right edge of the paddle, but it is a good starting point.
Implement a similar algorithm for the 2nd paddle:
if (xBall > rectx2 && xBall < rectx2 + rectwidth && yBall - diameter/2 < recty2+rectheight) {
yBallChange *= -1;
yBall = recty2 + rectheight + diameter/2;
score2++;
}
Complete example:
//Rect vars
var rectx = 287.5;
var recty = 460;
var rectx2 = 287.5
var recty2 = 0
var rectwidth = 100
var rectheight = 25
//ball vars
var xBall = Math.floor(Math.random() * 300) + 50;
var yBall = 50;
var diameter = 75;
var xBallChange = 5;
var yBallChange = 5;
//Misc
var started = false;
var score = 0;
var score2 = 0;
function setup() {
createCanvas(750, 485);
}
function draw() {
background(0);
//main commands
xBall += xBallChange;
yBall += yBallChange;
if (xBall < diameter/2 || xBall > width - diameter/2) {
xBallChange *= -1;
}
if (yBall < diameter/2 || yBall > height - diameter/2) {
yBallChange *= -1;
}
if (xBall > rectx && xBall < rectx + rectwidth && yBall + diameter/2 >= recty) {
yBallChange *= -1;
yBall = recty - diameter/2;
score++;
}
if (xBall > rectx2 && xBall < rectx2 + rectwidth && yBall - diameter/2 < recty2+rectheight) {
yBallChange *= -1;
yBall = recty2 + rectheight + diameter/2;
score2++;
}
//Player 1
fill (0,255,255);
noStroke();
rect(rectx,recty,rectwidth,rectheight);
//Player 2
fill(0,255,255)
noStroke()
rect(rectx2,recty2,rectwidth,rectheight);
//The ball
fill (255,255,0);
noStroke();
ellipse(xBall,yBall,75,75)
// The partition
fill(148,0,211)
noStroke()
rect(0,257,750,1)
}
function keyPressed() {
//Player 1 Input
if (keyCode === LEFT_ARROW) {
rectx -= 50;
} else if (keyCode === RIGHT_ARROW) {
rectx += 50;
}
//Player 2 Input
if (keyCode === 65) {
rectx2 -= 50;
} else if (keyCode === 68) {
rectx2 += 50;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
I'm working on a project where I simulate physics with balls.
Here is the link to the p5 editor of the project.
My problem is the following, when I add a lot of ball (like 200), balls are stacking but some of them will eventually collapse and I don't know why.
Can somebody explain why it does this and how to solve the problem ?
Thanks.
Here is the code of the sketch.
document.oncontextmenu = function () {
return false;
}
let isFlushing = false;
let isBallDiameterRandom = false;
let displayInfos = true;
let displayWeight = false;
let clickOnce = false;
let FRAME_RATE = 60;
let SPEED_FLUSH = 3;
let Y_GROUND;
let lastFR;
let balls = [];
function setup() {
frameRate(FRAME_RATE);
createCanvas(window.innerWidth, window.innerHeight);
Y_GROUND = height / 20 * 19;
lastFR = FRAME_RATE;
}
function draw() {
background(255);
if (isFlushing) {
for (let i = 0; i < SPEED_FLUSH; i++) {
balls.pop();
}
if (balls.length === 0) {
isFlushing = false;
}
}
balls.forEach(ball => {
ball.collide();
ball.move();
ball.display(displayWeight);
ball.checkCollisions();
});
if (mouseIsPressed) {
let ballDiameter;
if (isBallDiameterRandom) {
ballDiameter = random(15, 101);
} else {
ballDiameter = 25;
}
if (canAddBall(mouseX, mouseY, ballDiameter)) {
isFlushing = false;
let newBall = new Ball(mouseX, mouseY, ballDiameter, balls);
if (mouseButton === LEFT && !clickOnce) {
balls.push(newBall);
clickOnce = true;
}
if (mouseButton === RIGHT) {
balls.push(newBall);
}
}
}
drawGround();
if (displayInfos) {
displayShortcuts();
displayFrameRate();
displayBallCount();
}
}
function mouseReleased() {
if (mouseButton === LEFT) {
clickOnce = false;
}
}
function keyPressed() {
if (keyCode === 32) {//SPACE
displayInfos = !displayInfos;
}
if (keyCode === 70) {//F
isFlushing = true;
}
if (keyCode === 71) {//G
isBallDiameterRandom = !isBallDiameterRandom;
}
if (keyCode === 72) {//H
displayWeight = !displayWeight;
}
}
function canAddBall(x, y, d) {
let isInScreen =
y + d / 2 < Y_GROUND &&
y - d / 2 > 0 &&
x + d / 2 < width &&
x - d / 2 > 0;
let isInAnotherBall = false;
for (let i = 0; i < balls.length; i++) {
let d = dist(x, y, balls[i].position.x, balls[i].position.y);
if (d < balls[i].w) {
isInAnotherBall = true;
break;
}
}
return isInScreen && !isInAnotherBall;
}
function drawGround() {
strokeWeight(0);
fill('rgba(200,200,200, 0.25)');
rect(0, height / 10 * 9, width, height / 10);
}
function displayFrameRate() {
if (frameCount % 30 === 0) {
lastFR = round(frameRate());
}
textSize(50);
fill(255, 0, 0);
let lastFRWidth = textWidth(lastFR);
text(lastFR, width - lastFRWidth - 25, 50);
textSize(10);
text('fps', width - 20, 50);
}
function displayBallCount() {
textSize(50);
fill(255, 0, 0);
text(balls.length, 10, 50);
let twBalls = textWidth(balls.length);
textSize(10);
text('balls', 15 + twBalls, 50);
}
function displayShortcuts() {
let hStart = 30;
let steps = 15;
let maxTW = 0;
let controlTexts = [
'LEFT CLICK : add 1 ball',
'RIGHT CLICK : add 1 ball continuously',
'SPACE : display infos',
'F : flush balls',
'G : set random ball diameter (' + isBallDiameterRandom + ')',
'H : display weight of balls (' + displayWeight + ')'
];
textSize(11);
fill(0);
for (let i = 0; i < controlTexts.length; i++) {
let currentTW = textWidth(controlTexts[i]);
if (currentTW > maxTW) {
maxTW = currentTW;
}
}
for (let i = 0; i < controlTexts.length; i++) {
text(controlTexts[i], width / 2 - maxTW / 2 + 5, hStart);
hStart += steps;
}
fill(200, 200, 200, 100);
rect(width / 2 - maxTW / 2,
hStart - (controlTexts.length + 1) * steps,
maxTW + steps,
(controlTexts.length + 1) * steps - steps / 2
);
}
Here is the code of the Ball class.
class Ball {
constructor(x, y, w, e) {
this.id = e.length;
this.w = w;
this.e = e;
this.progressiveWidth = 0;
this.rgb = [
floor(random(0, 256)),
floor(random(0, 256)),
floor(random(0, 256))
];
this.mass = w;
this.position = createVector(x + random(-1, 1), y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
this.gravity = 0.2;
this.friction = 0.5;
}
collide() {
for (let i = this.id + 1; i < this.e.length; i++) {
let dx = this.e[i].position.x - this.position.x;
let dy = this.e[i].position.y - this.position.y;
let distance = sqrt(dx * dx + dy * dy);
let minDist = this.e[i].w / 2 + this.w / 2;
if (distance < minDist) {
let angle = atan2(dy, dx);
let targetX = this.position.x + cos(angle) * minDist;
let targetY = this.position.y + sin(angle) * minDist;
this.acceleration.set(
targetX - this.e[i].position.x,
targetY - this.e[i].position.y
);
this.velocity.sub(this.acceleration);
this.e[i].velocity.add(this.acceleration);
//TODO : Effets bizarre quand on empile les boules (chevauchement)
this.velocity.mult(this.friction);
}
}
}
move() {
this.velocity.add(createVector(0, this.gravity));
this.position.add(this.velocity);
}
display(displayMass) {
if (this.progressiveWidth < this.w) {
this.progressiveWidth += this.w / 10;
}
stroke(0);
strokeWeight(2);
fill(this.rgb[0], this.rgb[1], this.rgb[2], 100);
ellipse(this.position.x, this.position.y, this.progressiveWidth);
if (displayMass) {
strokeWeight(1);
textSize(10);
let tempTW = textWidth(int(this.w));
text(int(this.w), this.position.x - tempTW / 2, this.position.y + 4);
}
}
checkCollisions() {
if (this.position.x > width - this.w / 2) {
this.velocity.x *= -this.friction;
this.position.x = width - this.w / 2;
} else if (this.position.x < this.w / 2) {
this.velocity.x *= -this.friction;
this.position.x = this.w / 2;
}
if (this.position.y > Y_GROUND - this.w / 2) {
this.velocity.x -= this.velocity.x / 100;
this.velocity.y *= -this.friction;
this.position.y = Y_GROUND - this.w / 2;
} else if (this.position.y < this.w / 2) {
this.velocity.y *= -this.friction;
this.position.y = this.w / 2;
}
}
}
I see this overlapping happen when the sum of ball masses gets bigger than the elasticity of the balls. At least it seems so. I made a copy with a smaller pool so it doesn't take so much time to reproduce the problem.
In the following example, with 6 balls (a mass of 150 units) pressing on the base row, we see that the 13 balls in the base row overlap. The base row has a width of ca. 300 pixels, which is only enough space for 12 balls of diameter 25. I think this is showing the limitation of the model: the balls are displayed circular but indeed have an amount of elasticity that they should display deformed instead. It's hard to say how this can be fixed without implementing drawing complicated shapes. Maybe less friction?
BTW: great physics engine you built there :-)
Meanwhile I was able to make another screenshot with even fewer balls. The weight of three of them (eq. 75 units) is sufficient to create overlapping in the base row.
I doubled the size of the balls and changed the pool dimensions as to detedt that there is a more serious error in the engine. I see that the balls are pressed so heavily under pressure that they have not enough space for their "volume" (area). Either they have to implode or it's elastic counter force must have greater impact of the whole scene. If you pay close attention to the pendulum movements made by the balls at the bottom, which have the least space, you will see that they are very violent, but apparently have no chance of reaching the outside.
Could it be that your evaluation order
balls.forEach(ball => {
ball.collide();
ball.move();
ball.display(displayWeight);
ball.checkCollisions();
});
is not able to propagate the collisions in a realistic way?
I am working with a javascript animation that shows ripples in water in html canvas.
This is the javascript code and the jfiddle link
(function(){
var canvas = document.getElementById('c'),
/** #type {CanvasRenderingContext2D} */
ctx = canvas.getContext('2d'),
width = 400,
height = 400,
half_width = width >> 1,
half_height = height >> 1,
size = width * (height + 2) * 2,
delay = 30,
oldind = width,
newind = width * (height + 3),
riprad = 3,
ripplemap = [],
last_map = [],
ripple,
texture,
line_width = 20,
step = line_width * 2,
count = height / line_width;
canvas.width = width;
canvas.height = height;
with (ctx) {
fillStyle = '#a2ddf8';
fillRect(0, 0, width, height);
fillStyle = '#07b';
save();
rotate(-0.785);
for (var i = 0; i < count; i++) {
fillRect(-width, i * step, width * 3, line_width);
}
restore();
}
texture = ctx.getImageData(0, 0, width, height);
ripple = ctx.getImageData(0, 0, width, height);
for (var i = 0; i < size; i++) {
last_map[i] = ripplemap[i] = 0;
}
/**
* Main loop
*/
function run() {
newframe();
ctx.putImageData(ripple, 0, 0);
}
/**
* Disturb water at specified point
*/
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var j = dy - riprad; j < dy + riprad; j++) {
for (var k = dx - riprad; k < dx + riprad; k++) {
ripplemap[oldind + (j * width) + k] += 128;
}
}
}
/**
* Generates new ripples
*/
function newframe() {
var a, b, data, cur_pixel, new_pixel, old_data;
var t = oldind; oldind = newind; newind = t;
var i = 0;
// create local copies of variables to decrease
// scope lookup time in Firefox
var _width = width,
_height = height,
_ripplemap = ripplemap,
_last_map = last_map,
_rd = ripple.data,
_td = texture.data,
_half_width = half_width,
_half_height = half_height;
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
data -= _ripplemap[_newind];
data -= data >> 5;
_ripplemap[_newind] = data;
//where data=0 then still, where data>0 then wave
data = 1024 - data;
old_data = _last_map[i];
_last_map[i] = data;
if (old_data != data) {
//offsets
a = (((x - _half_width) * data / 1024) << 0) + _half_width;
b = (((y - _half_height) * data / 1024) << 0) + _half_height;
//bounds check
if (a >= _width) a = _width - 1;
if (a < 0) a = 0;
if (b >= _height) b = _height - 1;
if (b < 0) b = 0;
new_pixel = (a + (b * _width)) * 4;
cur_pixel = i * 4;
_rd[cur_pixel] = _td[new_pixel];
_rd[cur_pixel + 1] = _td[new_pixel + 1];
_rd[cur_pixel + 2] = _td[new_pixel + 2];
}
++i;
}
}
}
canvas.onmousemove = function(/* Event */ evt) {
disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
};
setInterval(run, delay);
// generate random ripples
var rnd = Math.random;
setInterval(function() {
disturb(rnd() * width, rnd() * height);
}, 700);
})();
The issue is the ripple spills over from one side of the canvas and animates on the opposite side, I want to keep them from moving into the opposite sides.
Thanks!
Stopping waves at edges
To stop the propagation of the waves across the edges you need to limit the function that adds the disturbance so that it does not write past the edges.
So change...
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var y = dy - riprad; y < dy + riprad; y++) {
for (var x = dx - riprad; x < dx + riprad; x++) {
ripplemap[oldind + (y * width) + x] += 128;
}
}
}
to...
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var y = dy - riprad; y < dy + riprad; y++) {
for (var x = dx - riprad; x < dx + riprad; x++) {
// don't go past the edges.
if(y >= 0 && y < height && x >= 0 && x < width){
ripplemap[oldind + (y * width) + x] += 128;
}
}
}
}
And you also need to change the wave propagation that is in the function newFrame. The propagation is controlled by the value in data. A value of zero means no wave and no propagation. So test if the pixel is on the edge. If the pixel is an edge pixel then just stop the wave by setting data to zero. To save CPU cycles I have added to vars h, w that are height - 1 and width - 1 so you don't have to perform the subtraction twice for every pixel.
Change the code in the function newFrame from...
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
}
To...
var w = _width - 1; // to save having to subtract 1 for each pixel
var h = _height - 1; // dito
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
// is the pixel on the edge
if(y === 0 || x === 0 || y === h || x === w){
data = 0; // yes edge pixel so stop propagation.
}else{
// not on the edge so just do as befor.
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
}
This is not perfect as it will dampen the waves bouncing from the sides but you don't have much CPU time so it is a good solution.
Some notes.
Use requestAnimationFrame rather than setInterval(run, delay) to time the animation as you will cause some devices to crash the page with the code you currently have, if the device can not handle the CPU load. requestAnimationFrame will stop this happening.
Change the run function to
function run() {
newframe();
ctx.putImageData(ripple, 0, 0);
requestAnimationFrame(run);
}
At bottom of code remove setInterval(run,delay); and add
requestAnimationFrame(run);
And change the second setInterval to
var drops = function() {
disturb(rnd() * width, rnd() * height);
setTimeout(drops,700)
};
drops();
NEVER use setInterval, especially for this type of CPU intensive code. You will cause many machines to crash the page. Us setTimeout or requestAnimationFrame instead.
Also remove the with statement where you create the texture.
I'm trying to draw a one pixel width line going form the canvas center and evolving with the canvas width/height ratio as it's drawn.
var x = 0;
var y = 0;
var dx = 0;
var dy = -1;
var width = 200;
var height = 40;
//var i = width * height;
var counter = 0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
setInterval(function(){
//for (i = Math.pow(Math.max(width, height), 2); i>0; i--) {
if ((-width/2 < x <= width/2) && (-height/2 < y <= height/2)) {
console.log("[ " + x + " , " + y + " ]");
ctx.fillStyle = "#FF0000";
ctx.fillRect(width/2 + x, height/2 - y,1,1);
}
if (x === y || (x < 0 && x === -y) || (x > 0 && x === 1-y) || ( -width/2 > x > width/2 ) || ( -height/2 > y > height/2 ) ) {
// change direction
var tempdx = dx;
dx = -dy;
dy = tempdx;
}
counter += 1;
//alert (counter);
x += dx;
y += dy;
}, 1);
I want the spiral to evolve as such:
I'd like to be able to get the ratio between height and width on the equation, so I don't need to calculate the coordinates for points outside the canvas. Also, the purpose is for it to adjust the spiral drawing to the canvas proportions.
Any help would be appreciated.
A friend helped me handling a proper solution. I only have a 1 pixel offset to solve where I need to move all the drawing to the left by one pixel.
Here's the fiddle for the solution achieved: http://jsfiddle.net/hitbyatruck/c4Kd6/
And the Javascript code below:
var width = 150;
var height = 50;
var x = -(width - height)/2;
var y = 0;
var dx = 1;
var dy = 0;
var x_limit = (width - height)/2;
var y_limit = 0;
var counter = 0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
setInterval(function(){
if ((-width/2 < x && x <= width/2) && (-height/2 < y && y <= height/2)) {
console.log("[ " + x + " , " + y + " ]");
ctx.fillStyle = "#FF0000";
ctx.fillRect(width/2 + x, height/2 - y,1,1);
}
if( dx > 0 ){//Dir right
if(x > x_limit){
dx = 0;
dy = 1;
}
}
else if( dy > 0 ){ //Dir up
if(y > y_limit){
dx = -1;
dy = 0;
}
}
else if(dx < 0){ //Dir left
if(x < (-1 * x_limit)){
dx = 0;
dy = -1;
}
}
else if(dy < 0) { //Dir down
if(y < (-1 * y_limit)){
dx = 1;
dy = 0;
x_limit += 1;
y_limit += 1;
}
}
counter += 1;
//alert (counter);
x += dx;
y += dy;
}, 1);
I nearly crashed my browser trying this. Here, have some code before I hurt myself!
It computes y=f(x) for the diagonal, and y2=f(x) for the antidiagonal, then checks if we're above or below the diagonals when needed.
var x = 0;
var y = 0;
var dx = 0;
var dy = -1;
var width = 200;
var height = 40;
//var i = width * height;
var counter = 0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
function diag1(x) {
return x*height/width;
}
function diag2(x) {
return -1/diag(x);
}
setInterval(function(){
//for (i = Math.pow(Math.max(width, height), 2); i>0; i--) {
if ((-width/2 < x && x <= width/2) && (-height/2 < y && y <= height/2)) {
console.log("[ " + x + " , " + y + " ]");
ctx.fillStyle = "#FF0000";
ctx.fillRect(width/2 + x, height/2 - y,1,1);
}
if (dx == 0) {
if (dy == 1) {
// moving up
if (y >= diag1(x)) {
// then move left
dy = 0;
dx = -1;
}
}
else {
// moving down
if (y <= diag2(x)) {
// then move right
dy = 0;
dx = 1;
}
}
}
else {
if (dx == 1) {
// moving right
if (y <= diag1(x)) {
// then move up
dy = 1;
dx = 0;
}
}
else {
// moving left
if (y <= diag2(x)) {
// then move down
dy = -1;
dx = 0;
}
}
}
counter += 1;
//alert (counter);
x += dx;
y += dy;
}, 1);