The code I have here is an animation that shows one circle that moves the way I'd like it to. I'd like to have 10 circles and I assume I use a loop or possibly an array but I'm not quite sure how to do that. At the same time, I want to make it so that at first the animation doesn't move but starts moving when I press a specific key and stops when I press the same key.
color a = color(random(255), random(255), random(255), random(125, 250));
float dia = random(60, 80);
float x;
float y;
float speedX = random(-3, 3);
float speedY = random(-3, 3);
void setup() {
background(255);
size(400, 200);
x = random(dia/2, width-dia/2);
y = random(dia/2, height-dia/2);
}
void draw() {
background(255);
noStroke();
fill(a);
ellipse(x, y, dia, dia);
x = x + speedX;
y = y + speedY;
if(speedX > 0 && x >= width - dia/2) {
speedX = speedX * -1;
}
if(speedX < 0 && x <= dia/2) {
speedX = speedX * -1;
}
if(speedY > 0 && y >= height - dia/2) {
speedY = speedY * -1;
}
if(speedY < 0 && y <= dia/2) {
speedY = speedY * -1;
}
}
You can get multiple circles by encapsulating the data you need to draw a circle into a class. It might look something like this:
Circle c;
void setup() {
size(400, 200);
c = new Circle();
}
void draw() {
background(255);
c.draw();
}
class Circle {
color a = color(random(255), random(255), random(255), random(125, 250));
float dia = random(60, 80);
float x = random(dia/2, width-dia/2);
float y = random(dia/2, height-dia/2);
float speedX = random(-3, 3);
float speedY = random(-3, 3);
void draw() {
noStroke();
fill(a);
ellipse(x, y, dia, dia);
x = x + speedX;
y = y + speedY;
if (speedX > 0 && x >= width - dia/2) {
speedX = speedX * -1;
}
if (speedX < 0 && x <= dia/2) {
speedX = speedX * -1;
}
if (speedY > 0 && y >= height - dia/2) {
speedY = speedY * -1;
}
if (speedY < 0 && y <= dia/2) {
speedY = speedY * -1;
}
}
}
Then to get multiple circles, you'd just create multiple instances of your Circle class and add them to an ArrayList:
ArrayList<Circle> circles = new ArrayList<Circle>();
void setup() {
size(400, 200);
for (int i = 0; i < 5; i++) {
circles.add(new Circle());
}
}
void draw() {
background(255);
for (Circle c : circles) {
c.draw();
}
}
For the user interaction, have a look at the event methods like mousePressed() or keyPressed(). The Processing reference should be your first stop. Good luck.
Related
I'm currently trying to make a class in Processing that allows the user to create objects that can be dragged and dropped. It's not that hard to create individual objects, but I've had some trouble implementing them into a class so that the user can create as many as they wish. Do you have any guidance?
Here is the code I have so far.
dragndrop.pde
void setup() {
size(800, 600);
}
void draw() {
background(80);
noStroke();
DragObject d = new DragObject(width/2, height/2, 50, 245);
d.run();
}
DragObject.pde
class DragObject {
int x;
int y;
int r;
color col;
DragObject(int xx, int yy, int rr, int c) {
x = xx;
y = yy;
r = rr;
col = c;
}
void run() {
if(mouseX > (x - r/2) && mouseX < (x + r/2) && mouseY > (y - r/2) && mouseY < (y + r/2)) {
if(mousePressed) {
x = mouseX;
y = mouseY;
}
}
fill(col);
circle(x, y, r);
}
}
It lets you drag the circle, but only as long as the mouse is within the circle's radius.
Thank you!
The following code will allow you to drag the object around the screen. In order to have multiple circles you will need to create an object array, eg DragObject[] d; and then initialize it for as many as you want in setup(), eg d = new DragObject[numOfObjects];
int xOffset = 0;
int yOffset = 0;
DragObject d;
void setup() {
size(800, 600);
d = new DragObject(width/2, height/2, 50, 245);
}
void draw() {
background(80);
noStroke();
d.display();
}
void mousePressed() {
if (mouseX > (d.x - d.r) && mouseX < (d.x + d.r) && mouseY > (d.y - d.r) && mouseY < (d.y + d.r)) {
xOffset = mouseX-d.x;
yOffset = mouseY-d.y;
}
}
void mouseDragged() {
d.x = mouseX - xOffset;
d.y = mouseY - yOffset;
}
class DragObject {
int x;
int y;
int r;
color col;
DragObject(int xx, int yy, int rr, int c) {
x = xx;
y = yy;
r = rr;
col = c;
}
void display() {
fill(col);
circle(x, y, r);
}
}
Revision:
There is an issue in the code above with the method used to determine if the mouse was pressed inside the circle. The demo above will also move the circle if the mouse is clicked outside (but near) the circle. A more correct way to determine if the mouse is down inside of the circle is to use Processing's dist() function. To facilitate keeping track of when the mouse is down inside of the circle a boolean msOver (mouse over) was added to the object class. There is also a misleading variable label ('r') in the initial class declaration. I suggest that this be changed to 'diam' (diameter) to reflect the fact that the third parameter of circle() is the width/height and not the radius as the 'r' implies.
A revised (and hopefully improved) demo follows:
int xOffset = 0;
int yOffset = 0;
DragObject d;
void setup() {
size(800, 600);
d = new DragObject(width/2, height/2, 50, 245);
}
void draw() {
background(80);
noStroke();
d.display();
}
void mousePressed() {
if (dist(d.x, d.y, mouseX, mouseY) <= d.diam/2) {
d.msOver = true;
xOffset = mouseX-d.x;
yOffset = mouseY-d.y;
println("inside");
} else {
d.msOver = false;
println("outside");
}
}
void mouseDragged() {
if (d.msOver) {
d.x = mouseX - xOffset;
d.y = mouseY - yOffset;
}
}
class DragObject {
int x, y, diam;
color col;
boolean msOver;
DragObject(int xx, int yy, int rr, int c) {
x = xx;
y = yy;
diam = rr;
col = c;
}
void display() {
fill(col);
circle(x, y, diam);
}
}
I understand that there are a number of answered questions on here asking the exact same thing. However, I have tried to implement the solution (cosine correction) and have had little success. Note: it is not implemented in this version of the code.
In terms of my code, I'll upload the whole thing but the part that likely needs fixing is the Player class. The rest is fairly boring stuff. I also know that it runs based off of images that you won't have, but for testing feel free to use any 600x600 image that is only black and white. Or contact me for mine. White denotes walls. I'll also upload a screenshot of the warped walls. Controls are WASD for movement, plus some glitchy mouse controls to change the view (will be fixed) as well as hold m to see a map of the current level.
Screenshot of it running
PImage maze;
int stepSize, renderDistance;
float viewStep, fov, moveSpeed;
float minLine, maxLine;
Player p;
boolean w, s, a, d, map;
void setup() {
size(600, 600);
background(0);
strokeWeight(3);
maze = loadImage("testmaze3.png");
stepSize = 1;
fov = PI/4;
viewStep = fov/(width/4);
renderDistance = 300;
moveSpeed = 2;
minLine = 0;
maxLine = 200;
colorMode(RGB, renderDistance);
p = new Player(width/2, height/2, 0);
w = false;
s = false;
a = false;
d = false;
}
void draw() {
maze.loadPixels();
if (map) {
pushStyle();
background(maze);
fill(255, 0, 0);
noStroke();
ellipse(p.x, p.y, 10,10);
stroke(renderDistance);
pushMatrix();
translate(p.x, p.y);
line(0, 0, renderDistance*cos(p.direction), renderDistance*sin(p.direction));
popMatrix();
popStyle();
}
pushMatrix();
translate(p.x, p.y);
if (w) {
if (maze.get(int(p.x + moveSpeed*cos(p.direction)), int(p.y + moveSpeed*sin(p.direction))) != color(renderDistance)) {
p.x += moveSpeed*cos(p.direction);
p.y += moveSpeed*sin(p.direction);
}
}
if (s) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction)), int(p.y - moveSpeed*sin(p.direction))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction);
p.y -= moveSpeed*sin(p.direction);
}
}
if (d) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction-PI/2)), int(p.y - moveSpeed*sin(p.direction-PI/2))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction-PI/2);
p.y -= moveSpeed*sin(p.direction-PI/2);
}
}
if (a) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction+PI/2)), int(p.y - moveSpeed*sin(p.direction+PI/2))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction+PI/2);
p.y -= moveSpeed*sin(p.direction+PI/2);
}
}
popMatrix();
p.direction += ((float)mouseX-(float)pmouseX)/100;
if (!map) {
pushStyle();
noStroke();
fill(0, 0, renderDistance);
rect(0, 0, width, height/2);
fill(0, 0, renderDistance*0.6);
rect(0, height/2, width, height);
popStyle();
p.display();
}
}
void keyPressed() {
if (key == 'w') {
w = true;
}
if (key == 's') {
s = true;
}
if (key == 'a') {
a = true;
}
if (key == 'd') {
d = true;
}
if (key == 'm') {
map = true;
}
}
void keyReleased() {
if (key == 'w') {
w = false;
}
if (key == 's') {
s = false;
}
if (key == 'a') {
a = false;
}
if (key == 'd') {
d = false;
}
if (key == 'm') {
map = false;
}
}
class Player {
float x, y, direction;
Player(int x, int y, float direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
void display() {
maze.loadPixels();
for (float i = direction - fov; i < direction + fov; i += viewStep) {
FloatList line = new FloatList();
line = rayCast(i);
float length_ = (height - maxLine - minLine - map(line.get(2), 0, renderDistance, minLine, maxLine));
stroke(renderDistance - line.get(2), 0, 0);
if (line.get(3) == 1){
stroke(renderDistance - line.get(2));
}
if (renderDistance - line.get(2) > 1) {
line(map(i, direction - fov/2, direction + fov, 0, width), height/2 + length_/2, map(i, direction - fov/2, direction + fov, 0, width), height/2 - length_/2);
}
}
}
FloatList rayCast(float direction) {
FloatList out = new FloatList();
float rayx = x;
float rayy = y;
int steps = 0;
for (int i = 0; i < renderDistance; i++) {
if (maze.get(int(rayx), int(rayy)) != color(0)) {
break;
}
rayx += stepSize * cos(direction);
rayy += stepSize * sin(direction);
steps++;
}
out.append(rayx);
out.append(rayy);
out.append(steps);
if (rayx < 0 || rayx > width || rayy > height || rayy < 0) {
out.append(1);
} else {
out.append(0);
}
return out;
}
}
Your raycasting algorithm calculates the distance from the wall to an infinitely small focus point in the camera. When we try to project this onto our screen we get a distorted image because our screen is a plane and not a point or sphere.
To fix the distortion we have to calculate the distance from the wall to our screen instead of the focus point. This can be done with simple trigonometry:
multiply the raw (euclidean) distance by cos(angle) and you get the distance to the screen.
drawing
So after cleaning up the code and adding the correction it looks like this:
void display() {
maze.loadPixels();
float wallHalfHeight = 50;
float distanceFocusProjection = (height / 2) / tan(fov);
for (float angle = -fov; angle < fov; angle += viewStep) {
float euclideanDist = rayCast(direction + angle);
if (euclideanDist < renderDistance) {
float distToScreen = euclideanDist * cos(angle);
float scanLineHalfHeight = wallHalfHeight * (distanceFocusProjection / distToScreen);
float scanLineX = map(angle, -fov, fov, 0, width);
stroke(renderDistance - distToScreen, 0, 0);
line(scanLineX, height/2 + scanLineHalfHeight, scanLineX, height/2 - scanLineHalfHeight);
}
}
}
float rayCast(float angle) {
PVector position = new PVector(x, y);
PVector direction = PVector.fromAngle(angle); //new PVector(cos(angle), sin(angle));
int distance;
for(distance = 0; distance < renderDistance; distance++) {
if (maze.get(round(position.x), round(position.y)) != color(0)) {
break;
}
position.add(direction);
}
return distance;
}
I managed to create the Mandelbrot set in processing but am struggling to implement a zoom. Here is my code:
float minvalX = -1.5;
float minvalY = -1.5;
float maxvalX = 1.5;
float maxvalY = 1.5;
float angle = 0;
float di,dj;
int xPixel,yPixel;
void setup(){
size(500,500);
pixelDensity(1);
colorMode(HSB, 360);
}
void draw() {
scale(zoom);
float maxLoops = 100;
loadPixels();
float equationOneOriginal;
float equationTwoOriginal;
for (xPixel = 0; xPixel < width ; xPixel++) {
for (yPixel = 0; yPixel < height ; yPixel++) {
float a = map(xPixel+di, 0,width, minvalX, maxvalX);
float b = map(yPixel+dj, 0,height, minvalY, maxvalY);
equationOneOriginal = a;
equationTwoOriginal = b;
float n = 1;
while (n < maxLoops) {
float equationOne = a*a - b*b; //First part of the equation
float equationTwo = 2 * a * b; //Second part of the equation
a = equationOne + equationOneOriginal;
b = equationTwo + equationTwoOriginal;
if (abs(a+b) > 16) {
break;
}
n++;
}
if (n == maxLoops) {
pixels[xPixel+yPixel*width] = color(0);
}
else {
pixels[xPixel+yPixel*width] = color(n-(int)(n/360)*n, 360, (int)map(n*6, 1, maxLoops, 0, 360));
}
}
}
updatePixels();
}
void mousePressed()
{
if (mouseButton == LEFT) {
di = di + mouseX - int(width/2);
dj = dj + mouseY - int(height/2);
minvalX += 0.1;
maxvalX -= 0.1;
minvalY += 0.1;
maxvalY -= 0.1;
}
}
It zooms into where my mouse is but eventually it goes towards the middle and gets stuck there. I know it is to do with minvalX, maxvalX, minvalY and maxvalY but I don't know what to do to these values to get it to always zoom towards my mouse.
Still just learning... So my goal is for the sketch to have the font appear in front of the boxes. I understand why it is behind the row of boxes. It is because the loop immediately goes to the next box and layers it over the font. However, because the variables are defined locally.... I don't really know what else to do...The loop is also crucial for updating purposes.
// Considerations: How to determine if point lies within a rectangle? \
// Hover over rectangle and trigger event
int numOfIndices = 50;
float[][] indexes = new float[numOfIndices][2];
public void setup()
{
frameRate(60);
size(600, 600);
strokeWeight(1);
int offset = width/numOfIndices;
for (int i = 0; i < numOfIndices; i++) {
indexes[i][0] = i*offset + offset/2; // X Coordinate
indexes[i][1] = height/2; // Y Coordinate
}
}
public void draw()
{
background(255);
// loop over each rectangle per frame
for (int i = 0; i < numOfIndices; i++) {
float widthRect = 5;
float heightRect = 20;
// A
float topLeftX = indexes[i][0] - widthRect/2;
float topLeftY = height/2 + heightRect/2;
// C
float bottomRightX = indexes[i][0] + widthRect/2;
float bottomRightY = height/2 - heightRect/2;
if (
mouseX > topLeftX &&
mouseX < bottomRightX &&
mouseY > bottomRightY &&
mouseY < topLeftY
) {
// Inside rectangle. Do something.
stroke(100);
fill(100);
//text(i, indexes[i][0], indexes[i][1]);
} else {
// Not inside rectangle. Do something else.
stroke(200);
fill(200);
}
rectMode(CENTER);
rect(
indexes[i][0], // X
indexes[i][1], // Y
widthRect, // width
heightRect, // height
20 // radi for corners (rounded)
);
if (
mouseX > topLeftX &&
mouseX < bottomRightX &&
mouseY > bottomRightY &&
mouseY < topLeftY
) {
// Inside rectangle. Do something.
textSize(26);
text(i, indexes[i][0], indexes[i][1]);
}
}
}
There are some different ways of doing it. One is as simple as reversing the for loop as follows:
for (int i = numOfIndices-1; i >= 0; i--)
That way the rectangles will be rendered from right to left. It's not a great solution, it will only work in this case because the text location is at the rectangles' right.
A better way is to render all the rectangles and only then render the text. That's quite usual when dealing with UI stuff. That will become:
// Considerations: How to determine if point lies within a rectangle? \
// Hover over rectangle and trigger event
int numOfIndices = 50;
float[][] indexes = new float[numOfIndices][2];
public void setup()
{
frameRate(60);
size(600, 600);
strokeWeight(1);
int offset = width/numOfIndices;
for (int i = 0; i < numOfIndices; i++) {
indexes[i][0] = i*offset + offset/2; // X Coordinate
indexes[i][1] = height/2; // Y Coordinate
}
}
public void draw()
{
background(255);
float widthRect = 5;
float heightRect = 20;
// loop over each rectangle per frame
for (int i = 0; i < numOfIndices; i++) {
// A
float topLeftX = indexes[i][0] - widthRect/2;
float topLeftY = height/2 + heightRect/2;
// C
float bottomRightX = indexes[i][0] + widthRect/2;
float bottomRightY = height/2 - heightRect/2;
if (
mouseX > topLeftX &&
mouseX < bottomRightX &&
mouseY > bottomRightY &&
mouseY < topLeftY
) {
// Inside rectangle. Do something.
stroke(100);
fill(100);
//text(i, indexes[i][0], indexes[i][1]);
} else {
// Not inside rectangle. Do something else.
stroke(200);
fill(200);
}
rectMode(CENTER);
rect(
indexes[i][0], // X
indexes[i][1], // Y
widthRect, // width
heightRect, // height
20 // radi for corners (rounded)
);
}
stroke(100);
fill(100);
for (int i = 0; i < numOfIndices; i++) {
// A
float topLeftX = indexes[i][0] - widthRect/2;
float topLeftY = height/2 + heightRect/2;
// C
float bottomRightX = indexes[i][0] + widthRect/2;
float bottomRightY = height/2 - heightRect/2;
if (
mouseX > topLeftX &&
mouseX < bottomRightX &&
mouseY > bottomRightY &&
mouseY < topLeftY
) {
// Inside rectangle. Do something.
textSize(26);
text(i, indexes[i][0], indexes[i][1]);
}
}
}
How can I use the code I have now with an object where I can store the number of times the ball bounces and the color (when i add random color) and speed. Any pointers or tips would be greatful. I am new to OOP and it can get confusing for me. Thanks in advance
float x;
float y;
float yspeed = 0;
float xspeed = 0;
float balldiameter = 10;
float ballradius = balldiameter/2;
void setup() {
size (400,400);
background (255);
fill (0);
ellipseMode(CENTER);
smooth();
noStroke();
x = random(400);
y = 0;
}
void draw() {
mouseChecks();
boundaryChecks();
ballFunctions();
keyFunctions();
}
void mouseChecks() {
if (mousePressed == true) {
x = mouseX;
y = mouseY;
yspeed = mouseY - pmouseY;
xspeed = mouseX - pmouseX;
}
}
void boundaryChecks() {
if (y >= height - ballradius) {
y = height - ballradius;
yspeed = -yspeed/1.15;
}
if (y <= ballradius) {
y = ballradius;
yspeed = -yspeed/1.35;
}
if (x >= width -ballradius) {
x = width -ballradius;
xspeed = -xspeed/1.10;
}
if (x <= ballradius) {
x = ballradius;
xspeed = -xspeed/1.10;
}
}
void ballFunctions() {
if (balldiameter < 2) {
balldiameter = 2;
}
if (balldiameter > 400) {
balldiameter = 400;
}
ballradius = balldiameter/2;
background(255); //should this be in here?
ellipse (x,y,balldiameter,balldiameter);
yspeed = yspeed += 1.63;
// xspeed = xspeed+=1.63;
y = y + yspeed;
x = x + xspeed;
}
void keyFunctions() {
if (keyPressed) {
if(keyCode == UP) {
balldiameter +=1;
}
if (keyCode == DOWN) {
balldiameter -=1;
}
}
}
you will probably want to do the following:
create a new file called Ball.pde
In that file write:
public class Ball {
public float x;
public float y;
public float yspeed;
public float xspeed;
public float diameter;
public float radius;
public Ball(float initial_x, float initial_y, float diam) {
this.x = initial_x;
this.y = initial_y;
this.xspeed = 0;
this.yspeed = 0;
this.diameter = diam;
this.radius = diam/2;
}
public void move() {
// movement stuff here
}
}
This will give you a very basic Ball class. You can now use this class in your main sketch file like so:
Ball my_ball = new Ball(50, 50, 10);
you can access the balls members using:
my_ball.xspeed;
my_ball.yspeed;
my_ball.anything_you_defined_in_ball;
This will allow you yo store all relevent variables for the ball within its own class. you can even create more than 1.
Ball my_ball1 = new Ball(50, 50, 10);
Ball my_ball2 = new Ball(20, 20, 5);
Just to note that in Proccesing you don't need to create a new file for that, the code can go either in the same file (very bad practice as pointed below) or in a new tab of the IDE. If you are using the Processing IDE you can choose "new tab" from the arrow menu in the right and it will create the file for you. It will have ".pde" extension.