P5 rotate a shape with maths - javascript

I'm trying to get a red and blue circle spinning in P5 using some maths. It's comprised of two semi-circles. As you can see the two circles are currently orbiting a 10 pixel radius, rather than spinning. If I change the radius to 0, it loses that relationship. I don't want to use the rotate function...
let angle = 0; //declare a variable for the initial angle
function setup() {
createCanvas(400, 400);
noStroke();
}
function draw() {
background(255);
noStroke;
angleMode(DEGREES);
ellipseMode(CENTER);
let posX = 200; //change the x axis
let posY = 200; //change the y axis
let reSize = 200; //change the size
let rotationSpeed = 1; //change the rotation speed
let radius = 10;
let x = radius * cos(angle);
let y = radius * sin(angle);
fill('red');
arc(posX+x, posY+y, reSize, reSize, 0, 180);
fill('blue');
arc(posX+x, posY+y, reSize, reSize, 180, 360);
angle += rotationSpeed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>

let angle = 0; //declare a variable for the initial angle
let currentAnglePercentage = 0;
function getCurrentAngle() {
return map(currentAnglePercentage % 100, 0, 100, 0, 360);
}
function setup() {
createCanvas(400, 400);
noStroke();
}
function draw() {
currentAnglePercentage++;
background(255);
noStroke;
angleMode(DEGREES);
ellipseMode(CENTER);
let posX = 200; //change the x axis
let posY = 200; //change the y axis
let reSize = 200; //change the size
let rotationSpeed = 1; //change the rotation speed
let radius = 10;
let x = radius * cos(angle);
let y = radius * sin(angle);
const c1a1 = 0 + getCurrentAngle();
const c1a2 = 180 + getCurrentAngle();
const c2a1 = 180 + getCurrentAngle();
const c2a2 = 360 + getCurrentAngle();
fill('red');
arc(posX + x, posY + y, reSize, reSize, c1a1, c1a2);
fill('blue');
arc(posX + x, posY + y, reSize, reSize, c2a1, c2a2);
angle += rotationSpeed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>
you could change the angle when you draw the arc.

Related

How do I rotate a plane based on noise?

let inc = 15;
let scaleN = 0.005;
let sizeB = 250;
let range =500;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
}
function draw() {
background(255);
orbitControl();
colorMode(HSB);
angleMode(DEGREES)
noStroke();
rotateX(60);
translate(-sizeB / 2, -inc, -sizeB / 2);
for (let x = inc; x < sizeB; x += inc) {
for (let y = inc; y < sizeB; y += inc) {
let noiseV = noise(x * scaleN, y * scaleN);
let rotateR = 23.5/noiseV
fill(0, 0, noiseV*100);
push();
translate(x, y, noiseV * range);
rotateY(-rotateR)
plane(inc);
pop();
}
}
}
Here's my code. It displaces a plane based on noise, but i've yet to figure out how to rotate them so they sync properly, instead of there being visible holes between them. The ones with noise levels of 1 or 0 will be rotated none, as they are flat. The ones in between have to be rotate somehow to link with each other without seams.

How do you stretch a sine graph while retaining resolution in p5.js?

I have written a sine graph plotting program. It works apart from the fact that the graph is choppy. I need to make it so that I can stretch the line without changing the x values of the points.
Here is the project: https://editor.p5js.org/korczaka6052/sketches/49-sJW6wz
let slidery;
let sliderx
width_ = 800
height_ = 400
linelen = width_ - 100
function setup() {
createCanvas(width_, height_);
//create sliders controlling xstep and ystep
slidery = createSlider(0, 100);
slidery.position(10, 10);
slidery.style('width', '200px');
sliderx = createSlider(0, 100);
sliderx.position(250, 10);
sliderx.style('width', '200px');
}
class createPoint { //create a point with its own x and y coordinate, ik could use vectors
constructor(x_, y_) {
this.x = 50 + x_;
this.y = height_ / 2 - y_;
}
show() {
fill(0)
circle(this.x, this.y, 1)
}
writetext() {
textSize(10)
text(this.x, this.x, height / 2 + 10)
}
}
//where all the points will be stored
points = [];
xstep = 1;
ystep = 50;
looper = 0;
function draw() {
//set xstep and ystep to their slider values
ystep = slidery.value()
xstep = sliderx.value()
stroke(0)
background(220);
//create graph lines
line(50, height / 2, width - 50, height / 2);
line(50, 50, 50, height - 50);
//for every [ystep] pixels calculate y based off equation
for (i = 0; i < 800; i++) {
points[i] = new createPoint(i * xstep, sin(i) * ystep); //creates that point as object with x and y value, y = sin(x)
}
//create line between current and previous point
for (i = 1; i < 800; i++) {
stroke(255, 0, 0)
//create only if point is inside canvas
if (points[i - 1].y < height) {
line(points[i - 1].x, points[i - 1].y, points[i].x, points[i].y)
}
}
//create white borders to cut off extreme points
noStroke(0)
fill(220)
rect(width - 50, 0, width, height)
rect(width, height, width - 50, 0)
rect(0, 0, width, 50)
rect(0, height, width, -50)
looper++
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
I am relatively new to p5.js so please excuse bad code.
The reason your line is choppy is because when xstep is greater than 1, the horizontal distance between each pair of points is relatively large. When you start out with an xstep of 50 you may have 800 points but only the first 16 or so are actually on the screen. Instead of advancing your x coordinate by xstep you should just advance by 1 (i.e., use i for the first argument to createPoint instead of i * xstep). When you do so, in order to draw the desired curve, you need to change the input to the sin() function used to calculate the corresponding y value. Because when you move forward by one pixel you are only moving to the right by 1 / xstep in the graph coordinate system, you simply need to use sin(i / xstep) instead of sin(i).
let slidery;
let sliderx;
let smooothCheckbox;
const width_ = 800;
const height_ = 400;
const linelen = width_ - 100;
function setup() {
createCanvas(width_, height_);
//create sliders controlling xstep and ystep
slidery = createSlider(0, 100);
slidery.position(10, 10);
slidery.style('width', '200px');
sliderx = createSlider(0, 100);
sliderx.position(250, 10);
sliderx.style('width', '200px');
smoothCheckbox = createCheckbox('Smooth?', true);
smoothCheckbox.position(10, 30);
}
class createPoint { //create a point with its own x and y coordinate, ik could use vectors
constructor(x_, y_) {
this.x = 50 + x_;
this.y = height_ / 2 - y_;
}
show() {
fill(0)
circle(this.x, this.y, 1)
}
writetext() {
textSize(10)
text(this.x, this.x, height / 2 + 10)
}
}
//where all the points will be stored
let points = [];
let xstep = 1;
let ystep = 50;
let looper = 0;
function draw() {
//set xstep and ystep to their slider values
ystep = slidery.value();
xstep = sliderx.value();
stroke(0);
background(220);
//create graph lines
line(50, height / 2, width - 50, height / 2);
line(50, 50, 50, height - 50);
//for every [xstep] pixels calculate y based off equation
for (i = 0; i < 800; i++) {
if (smoothCheckbox.checked()) {
points[i] = new createPoint(i, sin(i / xstep) * ystep); //creates that point as object with x and y value, y = sin(x)
} else {
points[i] = new createPoint(i * xstep, sin(i) * ystep);
}
}
//create line between current and previous point
for (i = 1; i < 800; i++) {
stroke(255, 0, 0);
//create only if point is inside canvas
if (points[i - 1].y < height) {
line(points[i - 1].x, points[i - 1].y, points[i].x, points[i].y);
}
}
//create white borders to cut off extreme points
noStroke(0);
fill(220);
rect(width - 50, 0, width, height);
rect(width, height, width - 50, 0);
rect(0, 0, width, 50);
rect(0, height, width, -50);
looper++;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Set circumference as boundary for loop-ed line in P5.js

I am trying to limit the height of the looped lines to the boundary/circumference of a circle()
I couldn't find any solution to solve the issue...
let numCols = 10
let margin = 100
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
test = circle(100,100,100);
for (let i = 0; i < numCols; i++) {
let iMapped = map(i, 0, numCols - 1, 50, 150);
line(iMapped, 100, iMapped, 200);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
Thanks!
Define the center and the radius of the circle:
let centerx = 100;
let centery = 100;
let radius = 50;
Compute the angle from the center to circle dependent on the x coordinate by acos and the y distance by sin:
let x = iMapped - centerx;
let angle = acos(x/50);
line(iMapped, centery, iMapped, centery + 50 * sin(angle));
See the example:
let numCols = 10
let margin = 100
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
let centerx = 100;
let centery = 100;
let radius = 50;
test = circle(centerx, centery, radius*2);
for (let i = 0; i < numCols; i++) {
let iMapped = map(i, 0, numCols - 1, 50, 150);
let x = iMapped - centerx;
let angle = acos(x/50);
line(iMapped, centery, iMapped, centery + 50 * sin(angle));
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>

Circle Following Mouse HTML5 Canvas jQuery

I am trying to make a circle follow the mouse in HTML Canvas which I am using in a game. I am trying to make the circle move 5px per iteration, but it goes slower when traveling horizontal and faster when it goes vertical. Here's the math that I used:
x=distance between mouse and circle on the x-axis
y=distance between mouse and circle on the y-axis
z=shortest distance between mouse and circle
a=number of units circle should move along the x-axis
b=number of units circle should move along the y axis
x^2 + y^2=z^2
Want the total distance traveled every iteration to be five pixels
a^2 + b^2 = 25
b/a=y/x
b=ay/x
a=sqrt(25-ay/x^2)
a^2+ay/x-25=0
Use Quadratic formula to find both answers
a=(-y/x+-sqrt(y/x)^2+100)/2
I replicated the problem in the code below
$(function(){
let canvas = $("canvas")[0];
let ctx = canvas.getContext("2d");
//Gets position of mouse and stores the value in variables mouseX and mouseY
let mouseX = mouseY = 0;
$("canvas").mousemove(function(e){
mouseX = e.pageX;
mouseY = e.pageY;
}).trigger("mousemove");
let circleX = 0;
let circleY = 0;
function loop(t){
//Background
ctx.fillStyle="blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
let xFromMouse = mouseX-circleX;
let yFromMouse = mouseY-circleY;
let yxRatio = yFromMouse/xFromMouse;
let xyRatio = xFromMouse/yFromMouse;
let speed = 25;
let possibleXValues = [(-yxRatio+Math.sqrt(Math.pow(yxRatio,2)+(4*speed)))/2,(-yxRatio-Math.sqrt(Math.pow(yxRatio,2)+(4*speed)))/2];
//I use this code as a temporary fix to stop the circle from completely disappearing
if(xFromMouse === 0 || isNaN(yxRatio) || isNaN(possibleXValues[0]) || isNaN(possibleXValues[1])){
possibleXValues = [0,0];
yxRatio = 0;
}
//Uses b=ay/x to calculate for y values
let possibleYValues = [possibleXValues[0]*yxRatio,possibleXValues[1]*yxRatio];
if(xFromMouse >= 0){
circleX += possibleXValues[0];
circleY += possibleYValues[0];
} else {
circleX += possibleXValues[1];
circleY += possibleYValues[1];
}
ctx.beginPath();
ctx.arc(circleX, circleY, 25, 0, 2 * Math.PI,false);
ctx.fillStyle = "red";
ctx.lineWidth = 0;
ctx.fill();
window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas width="450" height="250"></canvas>
I think you may be better using a cartesian to polar conversion. Here's an example from something I made previously. This will allow you to have a consistent step per iteration "speed".
//Canvas, context, mouse.
let c, a, m = { x:0, y:0};
//onload.
window.onload = function(){
let circle = {},
w, h,
speed = 5; //step speed = 5 "pixels" (this will be fractional in any one direction depending on direction of travel).
//setup
c = document.getElementById('canvas');
a = c.getContext('2d');
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
function move(){
//get distance and angle from mouse to circle.
let v1m = circle.x - m.x,
v2m = circle.y - m.y,
vDm = Math.sqrt(v1m*v1m + v2m*v2m),
vAm = Math.atan2(v2m, v1m);
//if distance is above some threshold, to stop jittering, move the circle by 'speed' towards mouse.
if(vDm > speed) {
circle.x -= Math.cos(vAm) * speed;
circle.y -= Math.sin(vAm) * speed;
}
}
function draw(){
//draw it all.
a.fillStyle = "blue";
a.fillRect(0,0,w,h);
a.fillStyle = "red";
a.beginPath();
a.arc(circle.x, circle.y, circle.r, Math.PI * 2, false);
a.closePath();
a.fill();
}
circle = {x:w/2, y:h/2, r:25};
function animate(){
requestAnimationFrame(animate);
move();
draw();
}
c.onmousemove = function(e){
m.x = e.pageX;
m.y = e.pageY;
};
animate();
}
<canvas id="canvas" width="450" height="250"></canvas>

JS HTMLCanvas help required

I am trying to create a game (at beginning stages). I am trying to create balls that bounce around a canvas, I have created balls, randomized them and have animated them.
But when trying to add a boundary I can only seem to get the balls to act as one object rather than separate ones. If NumShapes is changed to 1 it works perfectly.
if( shapes[i].x<0 || shapes[i].x>width) dx=-dx;
if( shapes[i].y<0 || shapes[i].y>height) dy=-dy;
For movement:
shapes[i].x+=dx;
shapes[i].y+=dy;
See this:
var ctx;
var numShapes;
var shapes;
var dx = 5; // speed on the X axis
var dy = 5; // speed on the Y axis
var ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
function init() // draws on the Canvas in the HTML
// calling functions here would not run them in the setInterval
{
numShapes = 10;
shapes = [];
drawScreen();
ctx = canvas.getContext('2d');
setInterval(draw, 10); // Runs the Draw function with nestled functions
makeShapes();
}
function draw() {
clear();
drawShapes();
}
function clear() {
ctx.clearRect(0, 0, width, height); // clears the canvas by WIDTH and HEIGHT variables
}
function makeShapes() {
var i;
var tempRad;
var tempR;
var tempG;
var tempB;
var tempX;
var tempY;
var tempColor;
for (i = 0; i < numShapes; i++) { // runs while i is less than numShapes
tempRad = 10 + Math.floor(Math.random() * 25); // random radius number
tempX = Math.random() * (width - tempRad); // random X value
tempY = Math.random() * (height - tempRad); // random Y value
tempR = Math.floor(Math.random() * 255); // random red value
tempG = Math.floor(Math.random() * 255); // random green value
tempB = Math.floor(Math.random() * 255); // random blue value
tempColor = "rgb(" + tempR + "," + tempG + "," + tempB + ")"; // creates a random colour
tempShape = {
x: tempX,
y: tempY,
rad: tempRad,
color: tempColor
}; // creates a random shape based on X, Y and R
shapes.push(tempShape); // pushes the shape into the array
}
}
function drawShapes() {
var i;
for (i = 0; i < numShapes; i++) {
ctx.fillStyle = shapes[i].color;
ctx.beginPath();
ctx.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
shapes[i].x += dx; // increases the X value of Shape
shapes[i].y += dy; // increases the Y value of Shape
// Boundary, but applies to all shapes as one shape
if (shapes[i].x < 0 || shapes[i].x > width) dx = -dx;
if (shapes[i].y < 0 || shapes[i].y > height) dy = -dy;
}
}
function drawScreen() {
//bg
ctx.fillStyle = '#EEEEEE';
ctx.fillRect(0, 0, width, height);
//Box
ctx.strokeStyle = '#000000';
ctx.strokeRect(1, 1, width - 2, height - 2);
}
canvas {
border: 1px solid #333;
}
<body onLoad="init();">
<div class="container container-main">
<div class="container-canvas">
<canvas id="canvas" width="800" height="600">
This is my fallback content.
</canvas>
</div>
</div>
</body>
Your dx and dy are globals, they should be unique for each ball object that you are simulating. Either clear them to 0 in your rendering loop (draw) or actually implement a ball object/class to hold variables unique to that object.
When you do your collision detection you change dx and dy which then persists to the next ball object as they are global.
Your fiddle, edited to add local dx and dy per shape: https://jsfiddle.net/a9b3rm5u/3/
tempDx = Math.random()*5; // random DX value
tempDy = Math.random()*5; // random DY value
shapes[i].x+=shapes[i].dx;// increases the X value of Shape
shapes[i].y+=shapes[i].dy;// increases the Y value of Shape
if( shapes[i].x<0 || shapes[i].x>width) shapes[i].dx= - shapes[i].dx;
if( shapes[i].y<0 || shapes[i].y>height) shapes[i].dy= -shapes[i].dy;

Categories