I have written this code which, on a mouse button press, increases or decreases the number of circles visible, equally spaced around a circle.
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;
}
}
I would like to alter the code so that, with nbr_circles fixed at 10, only one circle is visible at a time, each in turn in successive frames.
I have changed the code a little. The mouse buttons do nothing and the nbr_circles is fixed at 10.
How can I now show one circle at a time?
show circle #1 -> hide circle #1, show circle #2 -> hide circle #2, show circle #3 … -> hide circle #9, show circle #10 -> hide circle #1, show circle #1…
Adjusted code - where is it going wrong?
int nbr_circles = 2;
int i = 1;
void setup () {
size (600, 600);
}
void draw () {
background (255);
fill (0);
float cx = width/2.0;
float cy = height/2.0;
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);
}
if (mouseButton == LEFT) {
if (ellipse(x,y,20,20))
rotate (angle);
}
Thanks in advance.
Taking a step back, I really suggest you start a bit smaller, instead of posting a new question every time you get stuck. It looks like you've got a fundamental misunderstanding of the basic syntax of Processing, so maybe you should go back and do some tutorials until you're more comfortable in it. That's probably the most "correct" answer I can give you, even though it's probably not what you're looking for.
To answer the question of why your adjusted code doesn't work, it's because none of the syntax makes sense. First of all, you've got an if statement outside of a function, which isn't valid. When do you expect that if statement to be executed?
Secondly, you've got the ellipse() function inside an if statement, but the ellipse() function doesn't return a boolean. What do you expect that to do? And finally, what do you expect that rotate function to do?
It seems like you're trying to copy-paste code you found on the internet without really understanding any of it. That's not going to work. You have to take a step back and understand the basics before you can expect to make a program that actually does what you want it to do.
If you edit your "adjusted code" to fix the problems I pointed out, I'll try to help you through the process, but you really should consider going back and starting smaller before trying to get somebody else's code you found on the internet to work.
Related
I have been working on a doom/wolfenstein style raycaster for a while now. I implemented the "floor raycasting" to the best of my ability, roughly following a well known raycaster tutorial. It almost works, but the floor tiles seem slightly bigger than they should be, and they don't "stick", as in they don't seem to align properly and they slide slightly as the player moves/rotates. Additionally, the effect seems worsened as the FOV is increased. I cannot figure out where my floor casting is going wrong, so any help is appreciated.
Here is a (crappy) gif of the glitch happening
Here is the most relevant part of my code:
void render(PVector pos, float dir) {
ArrayList<FloatList> dists = new ArrayList<FloatList>();
for (int i = 0; i < numColumns; i++) {
float curDir = atan((i - (numColumns/2.0)) / projectionDistance) + dir;
// FloatList because it returns a few pieces of data
FloatList curHit = cast(pos, curDir);
// normalize distances with cos
curHit.set(0, curHit.get(0) * cos(curDir - dir));
dists.add(curHit);
}
screen.beginDraw();
screen.background(50);
screen.fill(0, 30, 100);
screen.noStroke();
screen.rect(0, 0, screen.width, screen.height/2);
screen.loadPixels();
PImage floor = textures.get(4);
// DRAW FLOOR
for (int y = screen.height/2 + 1; y < screen.height; y++) {
float rowDistance = 0.5 * projectionDistance / ((float)y - (float)rY/2);
// leftmost and rightmost (on screen) floor positions
PVector left = PVector.fromAngle(dir - fov/2).mult(rowDistance).add(p.pos);
PVector right = PVector.fromAngle(dir + fov/2).mult(rowDistance).add(p.pos);
// current position on the floor
PVector curPos = left.copy();
PVector stepVec = right.sub(left).div(screen.width);
float b = constrain(map(rowDistance, 0, maxDist, 1, 0), 0, 1);
for (int x = 0; x < screen.width; x++) {
color sample = floor.get(floor((curPos.x - floor(curPos.x)) * floor.width), floor((curPos.y - floor(curPos.y)) * floor.height));
screen.pixels[x + y*screen.width] = color(red(sample) * b, green(sample) * b, blue(sample) * b);
curPos.add(stepVec);
}
}
updatePixels();
}
If anyone wants to look at the full code or has any questions, ask away.
Ok, I seem to have found a "solution". I will be the first to admit that I do not understand why it works, but it does work. As per my comment above, I noticed that my rowDistance variable was off, which caused all of the problems. In desperation, I changed the FOV and then hardcoded the rowDistance until things looked right. I plotted the ratio between the projectionDistance and the numerator of the rowDistance. I noticed that it neatly conformed to a scaled cos function. So after some simplification, here is the formula I came up with:
float rowDistance = (rX / (4*sin(fov/2))) / ((float)y - (float)rY/2);
where rX is the width of the screen in pixels.
If anyone has an intuitive explanation as to why this formula makes sense, PLEASE enlighten me. I hope this helps anyone else who may have this problem.
i have a task to make a pattern of circles and squares as described on photo, and i need to animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated. i tried but i cant understand problem
{
size(500,500);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a, int b)
{
boolean isShrinking = false;
for(int x = 0; x <= width; x += a){
for(int y = 0; y <= height; y += a){
stroke(#1B08FF);
ellipse(x,y,a,a);
stroke(#FF0000);
rect(x,y,a,a);
stroke(#0BFF00);
ellipse(x+25,y+25,a/2,a/2);
if (isShrinking){a -= b;}
else {a += b;}
if (a == 50 || a == 200){
isShrinking = !isShrinking ; }
}
}
}
void draw()
{
pattern(50,1);
}
this is what pattern need to look like
Great that you've posted your attempt.
From what you presented I can't understand the problem either. If this is an assignment, perhaps try to get more clarifications ?
If you comment you the isShrinking part of the code indeed you have an drawing similar to image you posted.
animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated
Does that simply mean scaling the whole pattern ?
If so, you can make use of the sine function (sin()) and the map() function to achieve that:
sin(), as the reference mentions, returns a value between -1 and 1 when you pass it an angle between 0 and 2 * PI (because in Processing trig. functions use radians not degrees for angles)
You can use frameCount divided by a fractional value to mimic an even increasing angle. (Even if you go around the circle multiple times (angle > 2 * PI), sin() will still return a value between -1 and 1)
map() takes a single value from one number range and maps it to another. (In your case from sin()'s result (-1,1) to the scale range (1,4)
Here's a tweaked version of your code with the above notes:
void setup()
{
size(500, 500, FX2D);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a)
{
for (int x = 0; x <= width; x += a) {
for (int y = 0; y <= height; y += a) {
stroke(#1B08FF);
ellipse(x, y, a, a);
stroke(#FF0000);
rect(x, y, a, a);
stroke(#0BFF00);
ellipse(x+25, y+25, a/2, a/2);
}
}
}
void draw()
{
// clear frame (previous drawings)
background(255);
// use the frame number as if it's an angle
float angleInRadians = frameCount * .01;
// map the sin of the frame based angle to the scale range
float sinAsScale = map(sin(angleInRadians), -1, 1, 1, 4);
// apply the scale
scale(sinAsScale);
// render the pattern (at current scale)
pattern(50);
}
(I've chosen the FX2D renderer because it's smoother in this case.
Additionally I advise in the future formatting the code. It makes it so much easier to read and it barely takes any effort (press Ctrl+T). On the long run you'll read code more than you'll write it, especially on large programs and heaving code that's easy to read will save you plenty of time and potentially headaches.)
I want to achieve a slow fade in size on every collapse into itself. In other words, when the circle is at its biggest, the ellipses will be at the largest in size and conversely the opposite for the retraction. So far I am trying to achieve this affect by remapping the cSize from the distance of the center point, but somewhere along the way something is going wrong. At the moment I am getting a slow transition from small to large in ellipse size, but the inner ellipses are noticeably larger. I want an equal distribution of size amongst all ellipses in relation to center point distance.
I've simplified the code down to 4 ellipses rather than an array of rows of ellipses in order to hopefully simplify this example. This is done in the for (int x = -50; x <= 50; x+=100).
I've seen one or two examples that slightly does what I want, but is more or less static. This example is kind of similar because the ellipse size gets smaller or larger in relation to the mouse position
Distance2D
Here is an additional diagram of the grid of ellipses I am trying to create, In addition, I am trying to scale that "square grid" of ellipses by a center point.
Multiple ellipses + Scale by center
Any pointers?
float cSize;
float shrinkOrGrow;
void setup() {
size(640, 640);
noStroke();
smooth();
fill(255);
}
void draw() {
background(#202020);
translate(width/2, height/2);
if (cSize > 10) {
shrinkOrGrow = 0;
} else if (cSize < 1 ) {
shrinkOrGrow = 1;
}
if (shrinkOrGrow == 1) {
cSize += .1;
} else if (shrinkOrGrow == 0) {
cSize -= .1;
}
for (int x = -50; x <= 50; x+=100) {
for (int y = -50; y <= 50; y+=100) {
float d = dist(x, y, 0, 0);
float fromCenter = map(cSize, 0, d, 1, 10);
pushMatrix();
translate(x, y);
rotate(radians(d + frameCount));
ellipse(x, y, fromCenter, fromCenter);
popMatrix();
}
}
}
The values you're passing into the map() function don't make a lot of sense to me:
float fromCenter = map(cSize, 0, d, 1, 100);
The cSize variable bounces from 1 to 10 independent of anything else. The d variable is the distance of each ellipse to the center of the circle, but that's going to be static for each one since you're using the rotate() function to "move" the circle, which never actually moves. That's based only on the frameCount variable, which you never use to calculate the size of your ellipses.
In other words, the position of the ellipses and their size are completely unrelated in your code.
You need to refactor your code so that the size is based on the distance. I see two main options for doing this:
Option 1: Right now you're moving the circles on screen using the translate() and rotate() functions. You could think of this as the camera moving, not the ellipses moving. So if you want to base the size of the ellipse on its distance from some point, you have to get the distance of the transformed point, not the original point.
Luckily, Processing gives you the screenX() and screenY() functions for figuring out where a point will be after you transform it.
Here's an example of how you might use it:
for (int x = -50; x <= 50; x+=100) {
for (int y = -50; y <= 50; y+=100) {
pushMatrix();
//transform the point
//in other words, move the camera
translate(x, y);
rotate(radians(frameCount));
//get the position of the transformed point on the screen
float screenX = screenX(x, y);
float screenY = screenY(x, y);
//get the distance of that position from the center
float distanceFromCenter = dist(screenX, screenY, width/2, height/2);
//use that distance to create a diameter
float diameter = 141 - distanceFromCenter;
//draw the ellipse using that diameter
ellipse(x, y, diameter, diameter);
popMatrix();
}
}
Option 2: Stop using translate() and rotate(), and use the positions of the ellipses directly.
You might create a class that encapsulates everything you need to move and draw an ellipse. Then just create instances of that class and iterate over them. You'd need some basic trig to figure out the positions, but you could then use them directly.
Here's a little example of doing it that way:
ArrayList<RotatingEllipse> ellipses = new ArrayList<RotatingEllipse>();
void setup() {
size(500, 500);
ellipses.add(new RotatingEllipse(width*.25, height*.25));
ellipses.add(new RotatingEllipse(width*.75, height*.25));
ellipses.add(new RotatingEllipse(width*.75, height*.75));
ellipses.add(new RotatingEllipse(width*.25, height*.75));
}
void draw() {
background(0);
for (RotatingEllipse e : ellipses) {
e.stepAndDraw();
}
}
void mouseClicked() {
ellipses.add(new RotatingEllipse(mouseX, mouseY));
}
void mouseDragged() {
ellipses.add(new RotatingEllipse(mouseX, mouseY));
}
class RotatingEllipse {
float rotateAroundX;
float rotateAroundY;
float distanceFromRotatingPoint;
float angle;
public RotatingEllipse(float startX, float startY) {
rotateAroundX = (width/2 + startX)/2;
rotateAroundY = (height/2 + startY)/2;
distanceFromRotatingPoint = dist(startX, startY, rotateAroundX, rotateAroundY);
angle = atan2(startY-height/2, startX-width/2);
}
public void stepAndDraw() {
angle += PI/64;
float x = rotateAroundX + cos(angle)*distanceFromRotatingPoint;
float y = rotateAroundY + sin(angle)*distanceFromRotatingPoint;
float distance = dist(x, y, width/2, height/2);
float diameter = 50*(500-distance)/500;
ellipse(x, y, diameter, diameter);
}
}
Try clicking or dragging in this example. User interaction makes more sense to me using this approach, but which option you choose really depends on what fits inside your head the best.
My pixels are updating every frame causing the effect to be re-applied to the previous frame. How can i make this effect only happen once and without using noLoop(). I just want there to be a large circle around the triangle. Please help. Thanks.
Here is the whole program. I set the frameRate to 1 so you can see the problem easier:
boolean up;
int x =-300;
int y =-300;
void setup()
{
size(600, 600);
frameRate(1);
}
void draw()
{
pushMatrix();
translate(300, 300);
float a = atan2(mouseY-300, mouseX-300);
rotate(a);
for (int i = x; i < x+width; i+=40)
for (int j = y; j < y+height; j+=40)
rect(i, j, 40, 40);
loadPixels();
for (int i = 0; i < pixels.length; i++)
{
x = i%width;
y = i/width;
color c = pixels[x+y*width];
float d = dist(x, y, width/2, height/2);
pixels[x+y*width] = color(brightness(c) - d);
}
updatePixels();
popMatrix();
fill(255, 0, 0);
triangle(280, 300, 300, 200, 320, 300);
if (up)
{
x += sin(a)*5;
y += cos(a)*5;
}
}
void keyPressed()
{
if (key=='w')up=true;
}
void keyReleased()
{
if (key=='w')up=false;
}
Re-draw everything in one frame.
Remember before you use your filter, you must undo the filter effects of the last time.
The usual ordering in your draw() function goes as follows:
Add a background / clear all the objects you added in the last frame & clearing the filter of your last frame.
Add your objects.
Lay your filter on top.
Try to refrain from doing any graphic related stuff in setup, hence it will be destroyed by this draw() function - paradigma.
This should already suffice as your answer. Quick note:
When you work with for e.g. a 3D - Shadow filter, applying the filter can take a very long time. Instead we try to store as many calculations we did on the previous frame, so we don't need to calculate everything over again. The same goes for the objects-layer. You don't want to calculate the shortest-path for a minion every frame, instead you calculate the shortest path once and only recalculate it, when something changes: Position of a box, player position, etc..
If you want just use your filter and move fluently around update your effect like this:
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
color c = pixels[x+y*width];
float d = dist(x, y, width/2, height/2);
pixels[x+y*width] = color(brightness(c) - d);
}
}
You had unnecessary calculation that consume lot of CPU resources. Redrawing background also helps to make clearer animation.
If you want generate this effect only once and then apply it. PGraphics could achieve something similar.
I'm currently working on a Processing sketch featuring a very basic gravity simulation (based on an example given in Daniel Schiffman's book Learning Processing) but my gravity keeps behaving in a bizarre way and I'm at a loss to know what to do about it. Here's the simplest example I can come up with:
float x = 50;
float y = 50;
float speed = 2;
float gravity = 0.1;
void setup() {
size(400, 400);
}
void draw() {
background(255);
fill(175);
stroke(0);
ellipseMode(CENTER);
ellipse(x, y, 10, 10);
y = y + speed;
speed = speed + gravity;
//Dampening bounce effect when the ball hits bottom
if (y > height) {
speed = speed * -0.95;
}
}
The above is virtually identical to what's in Schiffman's book aside from a different starting speed and a different window size. It seems to work fine for the first two bounces but on the third bounce the ball becomes stuck to the bottom of the window.
I have no idea where to even begin trying to debug this. Can anyone give any pointers?
If y remains greater than height, your code just keeps flipping the speed over and over without giving the ball a chance to bounce. You want the ball to move away from the boundary whenever it is at or past the boundary.
Setting y to height in the (if y > height) block helps, but the ball never comes to 'rest' (sit on the bottom line when done).
There are two problems with Shiffman's example 5.9 which is where you probably started:
1) y can become greater than (height + speed), which makes it seem to go thud on the ground or bounce wildly
-- fixed with the suggestion
2) The algorithm to update y does things in the wrong order, so the ball never comes to rest
Correct order is:
if it is time to 'bounce
negate speed including dampening (* 0.95)
set y to location of the 'ground'
Add gravity to speed
Add speed to y
This way, when it is time to bounce (y is > height), and speed is positive (going downward):
speed is set to negative (times dampening)
y is set to height
speed is set less negative by the gravity factor
y is made less positive by adding the (still negative) speed
In my example, I didn't want the object to disappear so I use a variable named 'limit' to be the lowest (most positive y) location for the center of the object.
float x = 50;
float y = 50;
float speed = 2;
float gravity = 0.1;
void setup() {
size(400, 400);
y = height - 20;
}
void draw() {
background(255);
fill(175);
stroke(0);
ellipseMode(CENTER);
ellipse(x, y, 10, 10);
float limit = height - (speed + 5);
//Dampening bounce effect when the ball hits bottom
if (y > limit) {
speed = speed * -0.95;
y = limit;
}
speed = speed + gravity;
y = y + speed;
}