How may I get sub-pixel precision in position of the points plotted below? Only integer precision is used -- causing the observed wobble of the moving points.
int amount = 300;
float[] x = new float[amount];
float[] y = new float[amount];
float[] z = new float[amount];
void setup() {
size(500, 400, P3D);
stroke(255);
strokeWeight(1);
for(int i = 0; i<amount; i++) {
x[i] = float(random(-150, 150));
y[i] = float(random(-150, 150));
z[i] = float(random(-150, 150));
}
}
void draw() {
background(0);
translate(width/2, height/2);
rotateX(-0.1);
rotateY((frameCount/1000)*1);
for(int i = 0; i<amount; i++) {
point(x[i], y[i]/22, z[i]);
}
}
This is the same problem as your other question. You're using integer division, which truncates the decimal part.
This line:
rotateY((frameCount/1000)*1);
Needs to be this:
rotateY((frameCount/1000.0)*1);
For future reference, problems like these are easily spotted through some debugging. You need to go through your program and test every assumption you're making. In other words, print everything out. For example:
println(frameCount/1000);
That line would have shown you your entire problem.
Related
Can anyone help me?
So, I'm supposed to have a ball that is moving horizontally, such that every time I press the mouse, a ball would get shoot vertically, then slows down due to friction. The vertical ball would stay in the old position but the player would reset.
How do I go about doing that without using classes?
Here my code so far:
boolean circleupdatetostop = true;
float x = 100;
float yshot = 880;
float speedshot = random(4,10);
float speedx = 6;
void setup() {
size(1280,960);
}
void draw() {
background(255);
stroke(0);
fill(0);
circle(x,880,80);
if (x > width || x < 0 ) {
speedx = speedx * -1;
}
if (circleupdatetostop) {
x = x + speedx;
}
if (circleupdatetostop == false) {
float locationx = x;
stroke(0);
fill(255,0,255);
circle(locationx,yshot,30);
yshot = yshot - speedshot;
}
}
void mousePressed () {
circleupdatetostop = !circleupdatetostop;
}
I'm not entirely sure if this is what you meant, but you could achieve shooting multiple balls by using ArrayList as well as processing's PVector to better handle the x and y coordinate pairs. If you wanted to look at classes, see this post.
import java.util.*;
// Whether the ball is moving or not
boolean circleupdatetostop = true;
// Information about the main_ball
PVector position = new PVector(100, 880);
PVector speed = new PVector(6, 0);
float diameter = 80;
// Information about the sot balls
ArrayList<PVector> balls_loc = new ArrayList<PVector>();
ArrayList<PVector> balls_speed = new ArrayList<PVector>();
float diameter_shot = 30;
float friction = 0.994;
void setup() {
size(1280, 960);
}
void draw() {
background(255);
stroke(0);
fill(0);
circle(position.x, position.y, diameter);
// Remember to consider the radius of the ball when bouncing off the edges
if (position.x + diameter/2 > width || position.x - diameter/2 < 0 ) {
speed.mult(-1);
}
if (circleupdatetostop) {
position.add(speed);
}
// Cycle through the list updating their speed and draw each ball
for (int i = 0; i<balls_loc.size(); i++) {
balls_speed.get(i).mult(friction+random(-0.05, 0.05));
balls_loc.get(i).add(balls_speed.get(i));
stroke(0);
fill(255, 0, 255);
circle(balls_loc.get(i).x, balls_loc.get(i).y, diameter_shot);
}
}
void mousePressed(){
// Add a new ball to be drawn
if(circleupdatetostop){
balls_loc.add(new PVector(position.x, position.y));
balls_speed.add(new PVector(0, random(-4, -10)));
}
circleupdatetostop = !circleupdatetostop;
}
I am working on making a single ball bounce all over the screen but I have an issue with making the ball bounce the bounce() function is responsible for making the ball bounce but I run into an array out of bounds exception despite only going through 1 element in the array. I have provided the code below. This code utilizes 2 classes (Ball_Usage and Ball).
Ball_Usage code:
Ball ball1;
void setup(){
size(500,500);
ball1 = new Ball();
}
void draw(){
background(255);
ball1.bounce();
}
Ball:
class Ball{
float [] xPos = {};
float [] yPos = {};
float [] dia = {};
float [] xSpeed = {};
float [] ySpeed = {};
Ball(){
}
Ball(float x, float y, float argDia){
xPos = append(xPos, x);
yPos = append(yPos, y);
dia = append(dia, argDia);
}
void bounce(){
for(int i=0; i<1; i++){
ellipse(xPos[i], yPos[i], 50, 50);
xPos[i] += xSpeed[i];
yPos[i] += ySpeed[i];
if(xPos[i]<0 || xPos[i]>=width){
xSpeed[i] = -xSpeed[i];
}
if(yPos[i]<0 || yPos[i]>=height){
ySpeed[i] = -ySpeed[i];
}
}
}
}
I believe the confusion comes from the fact that your class has two constructors:
an empty constructor (that takes no arguments): Ball()
a constructor with position and argDia (guessing diameter ?) arguments: Ball(float x, float y, float argDia)
In setup() you call the empty constructor:
ball1 = new Ball();
This means the five float arrays still have a length of 0, hence the out of bounds exception.
Even if you call the position + diameter version of the constructor, the xSpeed, ySpeed arrays will still have length 0.
You could fix this by initialising the two two arrays as well as using this version of the constructor:
Ball ball1;
void setup() {
size(500, 500);
//ball1 = new Ball();
ball1 = new Ball(250, 250, 50);
}
void draw() {
background(255);
ball1.bounce();
}
class Ball {
float [] xPos = {};
float [] yPos = {};
float [] dia = {};
float [] xSpeed = {};
float [] ySpeed = {};
Ball() {
}
Ball(float x, float y, float argDia) {
xPos = append(xPos, x);
yPos = append(yPos, y);
dia = append(dia, argDia);
xSpeed = append(xSpeed, random(-1, 1));
ySpeed = append(ySpeed, random(-1, 1));
}
void bounce() {
for (int i=0; i<1; i++) {
ellipse(xPos[i], yPos[i], 50, 50);
xPos[i] += xSpeed[i];
yPos[i] += ySpeed[i];
if (xPos[i]<0 || xPos[i]>=width) {
xSpeed[i] = -xSpeed[i];
}
if (yPos[i]<0 || yPos[i]>=height) {
ySpeed[i] = -ySpeed[i];
}
}
}
}
This will work, however there is still a bit of confusion: why use the arrays at all if you're only looping once for the first element ? It makes the arrays and for loop mostly redundant.
You might choose to keep if you plan to change the diameter over time (which in your code is hardcoded to 50), maybe positions and velocities and render a changing history of a ball.
If you don't, you could simply use float properties instead of arrays:
Ball ball1;
void setup() {
size(500, 500);
ball1 = new Ball();
}
void draw() {
background(255);
ball1.bounce();
}
class Ball {
float xPos;
float yPos;
float diameter = 50;
float xSpeed;
float ySpeed;
Ball() {
xPos = width / 2;
yPos = height / 2;
xSpeed = random(-1, 1);
ySpeed = random(-1, 1);
}
void bounce() {
ellipse(xPos, yPos, diameter, diameter);
xPos += xSpeed;
yPos += ySpeed;
if (xPos < 0 || xPos >= width) {
xSpeed = -xSpeed;
}
if (yPos < 0 || yPos >= height) {
ySpeed = -ySpeed;
}
}
}
This looks more similar to the Bounce Processing Example.
You can at a later stage make an array of Ball objects.
Additionally it's worth formatting code as it saves you time reading/scrolling through it and visually it's easier to scan the structure of the program (how each part fits in) and therefore makes it easier to debug/run mentally. It takes no effort as you can simply press Ctrl+T on Windows/Linux or CMD+T on OSX. On the long run this will pay off, especially as programs get longer and more complex as you spend more time reading code than writing code. It's a good habit to pickup early while learning to code. Have fun!
In Processing, I'm trying to animate a spinning polygon. In the background, I have a series of 50 triangles that act as a gradient. These are both created in my draw function. How do I ensure that the polygon keeps spinning, but the triangles stay in the background without having to keep re-rendering the 50 triangles? Perhaps there's a cleaner way to create this triangular gradient?
int n = 9;
float ceiling = 350;
float floor = 250;
float diff = (ceiling - floor)/2;
float per = 0;
float dir = -1;
float rate = 0.01;
void setup() {
size(800, 800);
background(125,25,25);
frameRate(30);
}
void draw() {
background(125,25,25);
// Creates the triangles in background
for (float k=0; k<50; k++) {
strokeWeight(1);
stroke(#5E4622);
fill(47,74,57,100*(k/50));
triangle(100,height,width-100,height,width/2,height*k/50);
}
stroke(0);
// Creates spinning nonagons
pushMatrix();
translate(width/2, height/2);
rotate(2*PI*(dir*per));
stroke(#F4EA4A);
strokeWeight(6);
noFill();
polygon(0,0,floor+(diff*sin(2*PI*per))+10,n);
stroke(0);
strokeWeight(3);
float[] vertices = polygon(0, 0, floor+(diff*sin(2*PI*per)), n);
connect(vertices);
per += rate;
popMatrix();
}
// Takes a center (x,y) and draws an n-gon of radius r around it
// Returns an array of floats representing the points of the polygon
// Like: {x1,y1,x2,y2,...,xn,yn}
float[] polygon(float x, float y, float r, int n) {
float angle = 2*PI/n;
float[] vertices = new float[2*n];
beginShape();
for (int i=0; i<n; i++) {
float vX = r*cos(i*angle) + x;
float vY = r*sin(i*angle) + y;
vertex(vX, vY);
vertices[2*i] = vX;
vertices[2*i+1] = vY;
}
endShape(CLOSE);
return vertices;
}
// Takes in an array of vertices of a polygon and connects them together.
// Ignores neighboring vertices when considering which vertices to connect
// to a vertex.
void connect(float[] vertices) {
int n = vertices.length / 2;
for (int i=0; i<n; i++) {
float x = vertices[2*i];
float y = vertices[2*i+1];
for (int j=0; j<n; j++) {
if (j!=i || j!=(i-1)%n || j!=(i+1)%n) {
float endX = vertices[2*j];
float endY = vertices[2*j+1];
line(x, y, endX, endY);
}
}
}
}
This code creates what I want, but it runs pretty choppily due to having to re-render the triangles
How do I ensure that the polygon keeps spinning, but the triangles stay in the background without having to keep re-rendering the 50 triangles?
Render the static background to a PGraphics at initialization, in the setup function:
PGraphics pg;
void setup() {
size(800, 800);
// Creates the triangles in background
pg = createGraphics(800, 800);
pg.beginDraw();
pg.background(125,25,25);
for (float k=0; k<50; k++) {
pg.strokeWeight(1);
pg.stroke(#5E4622);
pg.fill(47,74,57,100*(k/50));
pg.triangle(100,height,width-100,height,width/2,height*k/50);
}
pg.endDraw();
frameRate(30);
}
Draw the background image to the scene by image(), in every frame, instead of filling the background by background():
void draw() {
// background image to screen
image(pg, 0, 0);
stroke(0);
// Creates spinning nonagons
// ...
}
Perhaps there's a cleaner way to create this triangular gradient?
If you want to get a smooth gradient background and get rid of the lines, then use pg.noStroke() rather than of pg.stroke(#5E4622);.
Additionally vary the size of the triangle on ist base, too:
for (float k=0; k<50; k++) {
pg.noStroke();
pg.fill(47,74,57,100*(k/50));
pg.triangle(k/50*width/2,height,width-k/50*width/2,height,width/2,height*k/50);
}
I am trying to create an array of circles which all move at different speeds and have different colours using classes which i have done however about 5 seconds into running it for some reason the ellipses all go to the edges of the window and the code doesn't work properly. Below I have provided my code including the class and setup:
circle circles = new circle(1, 8);
void setup() {
size(800, 600);
}
void draw() {
background(255);
circles.display();
circles.bounce();
}
class circle {
int[] posX = new int [10];
int[] posY = new int [10];
float[] speedX = new float[10];
float[] speedY = new float[10];
int[] red = new int [10];
int[] green = new int [10];
int[] blue = new int [10];
circle(float start, float end) {
for (int i = 0; i < 10; i++) {
speedX[i] = random(start, end);
speedY[i] = random(start, end);
posX[i] = int(random(500, 800));
posY[i] = int(random(500, 600));
red[i] = int(random(0, 255));
green[i] = int(random(0, 255));
blue[i] = int(random(0, 255));
}
}
void display() {
for (int i = 0; i < 10; i++) {
fill(red[i], green[i], blue[i]);
ellipse(posX[i], posY[i], 50, 50);
}
}
void bounce() {
for (int i = 0; i < 10; i++) {
posX[i] += speedX[i];
posY[i] += speedY[i];
if (posX[i] - 50 < 0 || posX[i] + 50 > width) {
speedX[i] = -speedX[i];
}
if (posY[i] - 50 < 0 || posY[i] + 50 > height) {
speedY[i] = -speedY[i];
}
}
}
}
The main problem is that you were not setting the balls to be inside the screen again! This is a very common problem, and Dan Shiffman used it to show the new Processing 3 Debugger.
But since i've found many stuff about your code i will also comment other stuff that might help you with programming.
But first let me show you the working code:
int n_of_circles = 10;
Circle[] circles = new Circle[n_of_circles];
void setup() {
size(800, 600);
for (int i = 0; i < n_of_circles; i++) {
circles[i] = new Circle(1, 8);
}
}
void draw() {
background(255);
for (int i = 0; i < n_of_circles; i++) {
circles[i].display();
circles[i].move();
}
}
class Circle {
float posX = random(0, width); //no need to set these value in constructor
float posY = random(0, height); //we can set it here
float speedX = 666; //we will change these on constructor
float speedY = 666; //666 is just a personal convention that i use to indicate that :p
//Similarly, no need to set the color variable in the constructor
//also, lets use a color variable instead of 3 separate variables
color circ_color = color(
(int) random(0, 255),
(int) random(0, 255),
(int) random(0, 255)
);
//defining circle diameter instead of using a literal ("50", in our case)
int diameter = 50;
int radius = diameter/2;
Circle(float min_speed, float max_speed) {
// The purpose of "min_speed" and "max_speed" are clearer than "start" and "end"
speedX = random(min_speed, max_speed);
speedY = random(min_speed, max_speed);
}
void display() {
//this push an pop commands ensure that this fill command won't
//interfere with any other stuff, if you ever reuse this code
pushStyle();
fill( circ_color );
ellipse(posX, posY, diameter, diameter);
popStyle();
}
//notice how i separated the move declartions form the bounce. It's good programming practice
//to keep stuff simpler. Functions should always have one single responsibility.
//In this case it won't helpĀ“much, but we're yoru move function more complex, it would!
void move(){
posX += speedX;
posY += speedY;
bounce();
}
void bounce() {
//note that you were using the diameter, but you should really use the radius!
//if it's touching left or side edges
if (posX - radius < 0 || posX + radius > width) {
speedX *= -1; //inverts the sign
//Here's the actual missing bits!
if (posX - radius < 0 ){ posX = radius; }
if (posX + radius > width ){ posX = width-radius; }
}
//if it's touching top or bottom edges
if (posY - radius < 0 || posY + radius > height) {
speedY *= -1; //inverts the sign
//Here's the actual missing bits!
if (posY - radius < 0 ){ posY = radius; }
if (posY + radius > height ){ posY = height-radius; }
}
}
} //end of class Circle
Just i few suggestions:
The convention is that Class names are upper case. This you you have Circle circles = new Circle(1,5); This is clearer.
Avoid using literals! (writing hard-coded numbers) For example, you we're using "ellipse(posX[i], posY[i], 50, 50);". By using a variable for diameter your code becomes more modular. Should you change the circles diameter, you just alter one line of code!
Use arrays of objects instead of classes that contains other stuff. That's good programming practice as it makes your code easier to understand. Now if you need to group lots of circles you use an array, or you can create another class "Group_of_circles" for ex.
I know i've presented some new concepts/syntaxes and changed a lot to your code, but i tried to comment everything to make it clear and instructive
Since i've already changed much thing i didn't use any Vectors, but when dealing with positions , you really should use PVectors! This free book have a great chapter on them!
Try to find good tutorials about software development. They will teach about godo programming practices like keeping your code as modular as possible and etc. But don't worry, it will come to you natrually over time!
Try learncpp.com, tutorialss 1-10a and 1-4b. Those 2 are part of a c++ tutorial, but are a good starting point and refer to programming in general.
I need to create a loop which will space circles equally around a circle in Processing.
I know I can somehow implement a FOR loop.
I need to be able to increase or decrease the number of circles around this circle (with button presses) but keep them equally spaced.
I know the formula's I need to include in the FOR loop to get the X and Y axis. The formulas:
being
X = R*cos(angle-90)+Y0
Y = R*sin(angle-90)+X0
I understand the three parameters of the FOR loop; when does it start, when does it finish, what changes when it runs.
What I can't see is how to implement the formulas into the FOR loop.
Many thanks
Here is the code I do have
void setup () {
size (600, 600);
background (255, 255, 255);
smooth ();
ellipse (width/2, height/2, 200, 200); // the guide circle. Not needed in final code.
}
void draw() {
for (int i = 0; i < 20; i ++) {
for (int j = 0; j < 20; j ++) {
ellipse (i *20, j * 20, 20, 20);
}
}
}
This code should do the trick:
float incrementalAngle = 0.0;
void setup(){
size(600, 600);
smooth();
background(0);
ellipse(width/2, height/2, 200, 200);
drawCircles(20, 200);
}
void draw(){
}
void drawCircles(int circlesNumber, int bigCircleNumber){
float angle = incrementalAngle;
for(int i = 0; i < circlesNumber; i++){
ellipse(bigCircleNumber * cos(incrementalAngle) + height/2,
bigCircleNumber * sin(incrementalAngle) + width/2,
circlesNumber, circlesNumber);
incrementalAngle += TWO_PI / circlesNumber;
}
}
So the second loop wasn't needed, and the formula you were trying to introduce would go in the X and Y position of your ellipse, there by playing whit the angle and the cos and sin you can get the result you were looking for.
What's left now is for you to get the number of circles you want by the clicking inside a mousePressed() method and drawing that amount.
Hope this comes useful and call me if you need more help
Regards
Jose.
Thank you to everyone who helped.
I managed to do it (slightly differently to you #Jose Gonzalez
int nbr_circles = 2;
void setup() {
size(600, 600);
smooth();
background(255);
}
void draw() {
background(255);
float cx = width/2.0;
float cy = height/2.0;
fill(0);
//float x, y; //
for (int i = 0; i < nbr_circles; i++)
{
float angle = i * TWO_PI / nbr_circles;
float x = cx + 110.0 * cos(angle);
float y = cy + 110.0 * sin(angle);
ellipse(x, y, 20, 20);
}
}
void mousePressed() {
if (mouseButton == LEFT) {
if (nbr_circles < 20)
nbr_circles = nbr_circles + 1;
} else if (mouseButton == RIGHT) {
if (nbr_circles > 2)
nbr_circles = nbr_circles - 1;
}
}