I am currently working on a small project where I'm creating a simple boardgame-like spinning wheel. The user will press a button and the spinner will randomly land on one of the four colors (red, green, yellow, or blue). The trouble I'm having is getting the spinner to rotate in a circle (or clockwise) and randomly land in a random position in one of the four squares.
Screenshot of game thus far
And source code:
void setup() { // this is run once
size(800, 800);
}
void draw() { // this is run repeatedly
background(255);
strokeWeight(2);
fill(255,0,0);
rect(100,100,300,300);
fill(0,96,255);
rect(100, 400, 300, 300);
fill(255,240,0);
rect(400, 100, 300, 300);
fill(0,255,0);
rect(400, 400, 300, 300);
// how to rotate this part like a spinner?
strokeWeight(20);
line(400, 400, 400, 600);
}
I then need to figure out how to determine which color the spinner landed on, and print out text that says "You have landed on [the color the spinner lands on]". I am having difficulty understanding the Matrix aspect of determining the coordinates after the rotation.
I am coding in Java in the Processing development platform.
Unfortunately, working with both circles and coordinates can be a little tricky in programming. You're going to have to do some conversion between Polar and Cartesian coordinates.
Here's a great reference to the difference between the two.
So you'll need to first generate a random number between 0 and 2 PI (Radians), this is done easily in processing:
float rnd = random(0, TWO_PI);
Next need let's convert it to normal coordinates:
float x = 200 * cos(rnd);
float y = 200 * sin(rnd);
Lastly draw the line: line(400, 400, x + 400, y + 400);
Edit: Forgot processing had rotate(), that'd be a much better solution than this mess
Your first step will be to learn about rotations that are isolated to one shape without rotating the entire sketch. There's a code pattern involving pushMatrix, popMatrix, translate, and rotate - all in conjunction with one another.
// inside draw
pushMatrix();
translate(400, 400);
rotate(radians(rotation));
line(0, 0, 100, 100);
popMatrix();
rotation += 5;
The translate function moves the origin to a new position, in this case 400, 400. Any shapes drawn after the origin moves are relative to it. That is the reason line is drawn at 0, 0 on the new origin which is actually 400, 400. The functions pushMatrix and popMatrix isolate this code so as not to affect the rest of your sketch. It's a nice trick to create independent rotations (and anything else really) in your sketch without having to come up with math formulas to counteract all your movements. Imagine five spinners going different speeds and directions.
For a gradually slowing spinner, I introduce a stepSize variable and slowly decrease it and subtract it from rotation until rotation hits zero and the spinner stops.
// still inside draw
if (stepSize > 0) {
rotation += stepSize;
stepSize -= 0.05; // play around with this value
}
Here's a demo program putting all the pieces together to achieve a spinner that will move for a while then stop.
float rotation = 1, stepSize = 10;
void setup() {
size(800, 800);
}
void draw() {
background(255);
strokeWeight(2);
fill(255, 0, 0);
rect(100, 100, 300, 300);
fill(0, 96, 255);
rect(100, 400, 300, 300);
fill(255, 240, 0);
rect(400, 100, 300, 300);
fill(0, 255, 0);
rect(400, 400, 300, 300);
strokeWeight(20);
pushMatrix();
translate(400, 400);
rotate(radians(rotation));
line(0, 0, 100, 100);
popMatrix();
if (stepSize > 0) {
rotation += stepSize;
stepSize -= 0.05; // play around with this value
}
}
void mousePressed() {
stepSize = random(5,15); // try adjusting these values
}
Related
I'm a total beginner so forgive me if this is probably silly or improper of me to ask.
I'm trying to make my own virtual oscillograph in processing. I don't really know how to explain it, but I want to "zoom out" from where I am getting the peaks in waveforms, which is the window size. I'm not sure what I'm doing wrong here or what's wrong with my code. I've tried changing the buffer size, and changing the multiplier for x/y. My sketch is adapted from a minim example Sketch.
All Help is greatly appreciated.
import ddf.minim.*;
Minim minim;
AudioInput in;
int frames;
int refresh = 7;
float fade = 32;
void setup()
{
size(800, 800, P3D);
minim = new Minim(this);
ellipseMode(RADIUS);
// use the getLineIn method of the Minim object to get an AudioInput
in = minim.getLineIn(Minim.STEREO);
println (in.bufferSize());
//in.enableMonitoring();
frameRate(1000);
background(0);
}
void draw()
{
frames++; //same saying frames = frames+1
if (frames%refresh == 0){
fill (0, 32, 0, fade);
rect (0, 0, width, height);
}
float x;
float y;
stroke (0, 0);
fill (0,255,0);
// draw the waveforms so we can see what we are monitoring
for(int i = 0; i < in.bufferSize() - 1; i++)
{
x = width/2 + in.left.get(i) * height/2;
y = height/2- in.right.get(i) * height/2;
ellipse(x, y, .5, .5);
}
}
Thanks
Edit: you don't need push and pop matrix here. Guess my understanding of it is lacking too. You can just use translate.
You can use matrices to create a camera object, there is tons of material out there that you can read up on to understand the math behind this and implement it anywhere.
However, there might be an easier solution here. You can use pushMatrix and popMatrix in combination with translate. Push and popping the matrix will manipulate the matrix stack - you create a new "frame" where you can play around with translations, then pop back the original frame (so you don't get lost by applying new translations on each frame).
push the matrix, translate the z coordinate once before drawing everything you want zoomed out, pop the matrix. You can set up a variable for the translation so that you can control this with your mouse.
Here's a crude example (I don't have all those libraries so couldn't add it to your code):
float scroll = 0;
float scroll_multiplier = 10;
void setup()
{
size(800, 800, P3D);
frameRate(1000);
background(0);
}
void draw()
{
background(0);
//draw HUD - things that don't zoom.
fill(255,0,0);
rect(400,300,100,100);
//We don't want to mess up our coordinate system, we push a new "frame" on the matrix stack
pushMatrix();
//We can now safely translate the Y axis, creating a zoom effect. In reality, whatever we pass to translate gets added to the coordinates of draw calls.
translate(0,0,scroll);
//Draw zoomed elements
fill(0,255,0);
rect(400,400,100,100);
//Pop the matrix - if we don't push and pop around our translation, the translation will be applied every frame, making our drawables dissapear in the distance.
popMatrix();
}
void mouseWheel(MouseEvent event) {
scroll += scroll_multiplier * event.getCount();
}
Im writing a 3D sketch in which the user rotates the camera with peasyCam while left clicking and moving the mouse. The thing is that I want to move the objects while right click is pressed so that the user can drag the object across the screen's X and Y axis. Of course I know how to use mouseX and mouseY inputs to modify the translation but only across the 3D space coordinates as it shows on the GIF below:
example code of whats happening in the image:
import peasy.*;
import peasy.org.apache.commons.math.*;
import peasy.org.apache.commons.math.geometry.*;
PeasyCam cam;
float x=15;float y=15; float z=15;
float e;
void setup(){
size (700,700,P3D);
cam = new PeasyCam(this, 200);
cam.setRightDragHandler(null);
}
void draw(){
background(0);
pushMatrix();
translate(5, 5, 0);
fill(255);
stroke(255);
sphere(5);
popMatrix();
pushMatrix();
fill(255,0,0);
stroke(255,0,0);
translate(x, y, z);
sphere(5);
popMatrix();
stroke(0,0,255);
line(5,5,0,x,y,z);
//obvoiusly not working method
if(mousePressed && (mouseButton == RIGHT)){
x= x+(mouseX-pmouseX);
y= y+(mouseY-pmouseY);
}
}
void mouseWheel(MouseEvent event) {
e = event.getCount();
z=z+e;
println(e);
}
void mousePressed(){
if (mouseButton==RIGHT){
cam.setActive(false);
}
}
void mouseReleased(){
cam.setActive(true);
}
What I would need is to be able to drag the sphere only on the screens X/Y axis, at a fixed Z just like image below shows(simple simulation I made of the behaviour im looking for).
PeasyCam is for exploring the 3D space. The question might be difficult to undesrtand. The problem is about moving the object on the 3D world, using the screen/canvas 2D coordinates to make the object follow the cursor's movement. If the mouse goes to the left (x axis decreases), the object should move to the left on the screen, and not just on the worlds X axis. This is how the second example image behaves, but achieved by just simulating the 3D space with no actual rotations to the x,y,z axis.
I've been scratching my head with this thing and I cant seem to figure it out. I wouldn't have asked here otherwise. Thanks in advance guys.
PeasyCam is a library that gives you a camera that by default is controlled by the mouse. This allows you to render 3D scenes and not worry about the camera, since the library handles it for you.
But it sounds like that's not what you want. You want to render a 3D scene and use the mouse to control the position of the shapes in that scene. Basically, your controls are fighting with the default controls provided by the PeasyCam library.
I see that you've already tried disabling the right-click controls here:
cam.setRightDragHandler(null);
So at the very least you probably want to do the same thing with the left drag handler.
But at that point, why are you using the PeasyCam library at all?
And even if you disable the default left controls, you'll notice that the dragging of shapes is "exaggerated" because the camera is closer to the red shape, so moving it a little bit looks like it's moving more. Just like an object right in front of your face looks like it's moving a lot more than an object that's far away.
It sounds like what you really want to do is get rid of the PeasyCam library, and then use standard Processing functions to calculate the position of the spheres based on the user input. Check out the modelX(), modelY(), and modelZ() function in the reference.
Edit: Here is a simple example that shows the model functions in action:
float x;
float y;
void setup() {
size (700, 700, P3D);
}
void draw() {
background(0);
pushMatrix();
translate(width/2, height/2, 0);
fill(255);
stroke(255);
sphere(5);
popMatrix();
fill(255, 0, 0);
stroke(255, 0, 0);
if (mousePressed) {
x= modelX(mouseX, mouseY, 0);
y= modelY(mouseX, mouseY, 0);
}
translate(x, y, 15);
sphere(5);
}
May be you should be looking in beginHUD() and endHUD();
Here is the example code:
(Code from https://forum.processing.org/one/topic/2-questions-on-camera-view.html)
import peasy.*;
PeasyCam cam;
void setup() {
size(300,200,P3D);
// either put it here like this:
// cam = new PeasyCam(this, 50, 0, 0, 100);
cam = new PeasyCam(this, 0, 0, 0, 100);
cam.setMinimumDistance(50);
cam.setMaximumDistance(500);
// or separate like this:
cam.lookAt(50,0,0);
}
void draw() {
background(0);
//3D object
pushMatrix();
fill(255,0,0);
translate(50,0,0);
rotateX(-.5);
rotateY(-.5);
box(30);
popMatrix();
//2D object that is not affected by the camera
cam.beginHUD();
fill(0,0,255);
rect(200, height/2 -25 , 50, 50);
cam.endHUD();
}
I'm currently working on a project with the theme of earth hour, and we are only allowed to use rectangles, circles and triangles. Here's the image i'm tring to create (not exactly, mine will be much more simplified!):
https://www.google.com/search?q=earth+hour&biw=1366&bih=586&source=lnms&tbm=isch&sa=X&ved=0ahUKEwj__5H0vtvQAhXLrlQKHTi8BagQ_AUIBygC#imgrc=fQkBxn0a8LnwbM%3A
(not sure if you could see the link)
But when i'm coding it, i'm running into trouble to rotate those rectangles to stand on the tangent line of the circle. I'm a student just learnt some basics of java, like loops and arrays. So my quesiton is that if there's some understandable way that doesn't involve some complex and exotic methods that could rotate those rectangles? I know it will probably involve some complicated solutions that is beyond my knowledge. But any help is much appreciated.
this is part of the code that i build the building standing perpendicularly to the circle(earth):
// create mid buildings
Color blc = new Color(0, 0, 0);
Rectangle midBld = new Rectangle(240, 220, 20, 40, blc);
midBld.draw(g);
Rectangle midBld1 = new Rectangle(242, 190, 16, 30, blc);
midBld1.draw(g);
Triangle midBld2 = new Triangle(250, 160, 8, 30, blc);
midBld2.draw(g);
Triangle midBld3 = new Triangle(250, 160, -8, 30, blc);
midBld3.draw(g);
A Rectangle cannot be rotated, its edges are always in parallel to the axis. But you can rotate and translate the coordinate system in witch you draw the shapes. From Graphics2D API doc.
All coordinates passed to a Graphics2D object are specified in a device-independent coordinate system called User Space, which is used by applications. The Graphics2D object contains an AffineTransform object as part of its rendering state that defines how to convert coordinates from user space to device-dependent coordinates in Device Space.
Graphics2D also provide two methods that are useful in this task: translate that moves the origin of the coordinates and rotate that, well, rotates the system.
package graphics;
import javax.swing.*;
import java.awt.*;
/**
* Earth Hour
*/
public class RotateRect extends JFrame {
private static final int WIDTH = 400;
private static final int HEIGHT = 400;
public RotateRect() {
this.setSize(WIDTH, HEIGHT);
this.setTitle("Rotate Rectangles");
this.setContentPane(new JPanel() {
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Background: White
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
// Draw "Earth": Center(200, 400), Radius=200
g2.setColor(Color.BLACK);
g2.fillOval(0, 200, 400, 400);
// Move origin to center of the canvas (surface of earth)
g2.translate(200, 200);
// Rotate the coordinate system, relative to the center of earth.
// note x, y are in the translated system
// Transforms are accumulative
g2.rotate(-Math.PI/6, 0, 200);
// Fill a rectangle with top-left corner at (-20, 80) in the rotated system
// It's important to make the rectangle symmetrical to the y-axis, otherwise the building looks
// funny.
// Also, make the building "sunk" a little, so that it's fully on the ground.
g2.fillRect(-20, -80, 40, 100);
g2.rotate(Math.PI/3, 0, 200);
g2.fillRect(-20, -80, 40, 100);
g2.rotate(-Math.PI/6, 0, 200);
g2.fill(new Rectangle(-20, -80, 40, 100));
}
});
}
public static void main(String [] args) {
RotateRect rr = new RotateRect();
rr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EventQueue.invokeLater(()->rr.setVisible(true));
}
}
I want to construct TRIANGLE_STRIP shape with different texture in each sector.
Is it possible to use TRIANGLE_STRIP shape in this case?
I can't understand how to set horizontal and vertical coordinate for the texture mapping in this shape mode because each triangle shares vertex points with each other and because of that I can set horizontal and vertical coordinate for the texture mapping only for one image.
PImage img1, img2, img3, img4, img5;
void setup() {
size(800, 300, P3D);
img1 = loadImage("img1.png");
img2 = loadImage("img2.png");
....
textureMode(NORMAL);
// textureWrap(REPEAT);
}
void draw(){
background(0);
stroke(255);
beginShape(TRIANGLE_STRIP);
texture(img1);
vertex(30, 286,0,1);
vertex(158, 30, 0.5, 0);
vertex(286, 286,1,1);
texture(img2);
vertex(414, 30, ?, ?);
texture(img3);
vertex(542, 286, ?, ?);
texture(img4);
vertex(670, 30,?,?);
texture(img4);
vertex(798, 286,?,?);
endShape();
}
UPD
I wand to acheive the result similar to that animation:
https://mir-s3-cdn-cf.behance.net/project_modules/disp/7d7bf511219015.560f42336f0bd.gif
First of all I want to construct complicated object based on TRIANGLE_STRIP or QUAD_STRIP shape mode and after that just change z coordinate of vertexes.
So I just took image with such inscription and cut it on different images for each sector of shape.
If someone knows how to make it in more easy way I will be very thankful for help.
Step 1: Create a small sketch that simply displays a triangle strip (without any texturing) over the entire space you want to take up. Here's an example that fills the whole screen:
void setup() {
size(300, 200);
}
void draw() {
background(0);
stroke(0);
beginShape(TRIANGLE_STRIP);
vertex(0, 200);
vertex(0, 0);
vertex(50, 200);
vertex(100, 0);
vertex(150, 200);
vertex(200, 0);
vertex(250, 200);
vertex(300, 0);
vertex(300, 200);
endShape();
}
The goal is to make sure your vertexes cover the area you want your image to cover. You want something that looks like this:
This will also make it easier to map the vertex coordinates to image texture coordinates.
Step 2: Create an image that you want to use as a texture. I'll use this one:
Step 3: For each vertex you're drawing on the screen, figure out where in the image that point is. If a point is in the middle of the screen, then you need to figure out the position of the middle of the image. That's your values for u and v.
Alternatively, you can use textureMode(NORMAL) so you can specify u and v as normalized values between 0 and 1. The middle of the image becomes point (.5, .5).
Which approach you take is up to you, but in either case you have to map the screen vertex positions to the image u, v positions. I'll use the normalized values here:
PImage img;
void setup() {
size(300, 200, P3D);
img = loadImage("test.png");
textureMode(NORMAL);
}
void draw() {
background(0);
stroke(0);
beginShape(TRIANGLE_STRIP);
texture(img);
vertex(0, 200, 0, 1);
vertex(0, 0, 0, 0);
vertex(50, 200, .16, 1);
vertex(100, 0, .33, 0);
vertex(150, 200, .5, 1);
vertex(200, 0, .66, 0);
vertex(250, 200, .83, 1);
vertex(300, 0, 1, 0);
vertex(300, 200, 1, 1);
endShape();
}
Step 4: Now you can modify the position of one of the vertexes, and you'll morph the image drawn on screen:
PImage img;
void setup() {
size(300, 200, P3D);
img = loadImage("test.png");
textureMode(NORMAL);
}
void draw() {
background(0);
stroke(0);
beginShape(TRIANGLE_STRIP);
texture(img);
vertex(0, 200, 0, 1);
vertex(0, 0, 0, 0);
vertex(50, 200, .16, 1);
vertex(100, 0, .33, 0);
vertex(mouseX, mouseY, .5, 1);
vertex(200, 0, .66, 0);
vertex(250, 200, .83, 1);
vertex(300, 0, 1, 0);
vertex(300, 200, 1, 1);
endShape();
}
You can play around with it to get the exact effect you're looking for, but following these steps should be your general approach. Note that you only need to use a single image, and you need to figure out the u and v values for every vertex you draw on screen. Start with a triangle mesh that displays the image normally, and then modify that to morph your image.
Also note that I could have done a lot of this calculation programatically. For example, instead of hard-coding the value 150, I could have used width/2.0. But first you need to understand the relationship between the x,y on screen and the u,v in the texture. Once you understand that relationship, you can calculate them programatically if you want.
I'm working on a 3D scene in Java using the Processing API. It's a force-directed graph layout algorithm (although that isn't too important). I've got all the graph drawing done -- the nodes, edges, layout, etc. are looking good. Each node on the graph has a label, though, and I'd like to be able to display said label as text next to the node. I've tried working with the text() function, but so far it seems like my code just doesn't work. I see no text anywhere in the scene.
My code looks like the following:
pushMatrix();
translate(width/2, height/2, 0); // put 0,0,0 at the center of the screen
text("foo!", 20, 20, 20);
popMatrix();
And I don't see anything. Just the graph. So what am I missing?
Everything is fine with the tiny bit of code you displayed. You can see a modified version running here:
void setup() {
size(400,400,P3D);
textSize(20);
}
void draw() {
background(0);
translate(width * .5, height*.5,0);
rotateY(map(mouseX,0,width,-PI,PI));
rotateX(map(mouseY,0,height,-PI,PI));
pushMatrix();
text("foo!", -20, 0, 20);
popMatrix();
}
There might be something else along the way. Care to share more information ?
The fill color controls the text color, and defaults to white. So if you are painting white text on a white background, it won't show up. Add fill(0); before you draw text.
Also remember that shapes drawn after you send your text to the screen may over-write your text. The last 'hidden' statement in draw is to paint the screen.
Here's an example of drawing a series of vertical lines (in 2D) with a row of labels at the top:
int startX;
void setup() {
size(400,400);
textSize(12);
startX = width/10;
}
void draw() {
background(255);
int curX = startX;
fill(0); // Set the text color
while (curX < width)
{
line(curX, 30, curX, height-10);
text(curX, curX-(curX/20), 20);
curX += width/10;
}
} // end draw