I am learning processing right now and I am trying to make a sketch that could change colour when the sound changes.
(When Amplitude + ,
Then Brightness+ )
Because changing colour does not need to change as rapid as the draw() function. So how could I build a clock so that the color would not change in every draw?
This is the code I am using right now:
import ddf.minim.*;
import ddf.minim.signals.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
Minim minim;
AudioPlayer song;
FFT fft;
BeatDetect beat;
color start=color(0,0,0);
color finish;
float amt = 0.0;
void setup()
{
frameRate(50);
size(600,600,P3D);
minim = new Minim(this);
song = minim.loadFile("song2.mp3", 512);
song.loop();
fft = new FFT(song.bufferSize(), song.sampleRate());
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
}
// draw is run many times
void draw()
{
float brightness = map( 0, 0, song.bufferSize(), 0, 255 );
background( brightness );
// println(song.bufferSize());
stroke(100);
// draw the waveforms
for( int i = 0; i < song.bufferSize() - 1; i++ )
{
// find the x position of each buffer value
float x1 = map( i, 0, song.bufferSize(), 0, width );
float x2 = map( i+1, 0, song.bufferSize(), 0, width );
// draw a line from one buffer position to the next for both channels
line( x1, 50 + song.left.get(i)*50, x2, 50 + song.left.get(i+1)*50);
line( x1, 150 + song.right.get(i)*50, x2, 150 + song.right.get(i+1)*50);
println(x1);
}
}
When you call frameRate(50); you are telling Processing to (try to) update the draw() 50 times a second. You can tell how many frames have passed since the start of the sketch by checking the built-in variable frameCount.
This can then be divided by a number which represents how many frames you want to draw before doing something special - I would use modulus for this, it will divide the numbers and return the remainder. If it equals 0, then that number of frames have passed.
int updateTriggerCount = 10;
void setup() {
...
}
void draw()
{
if((frameCount % updateTriggerCount) == 0)
{
// Another 10 frames have passed! Do something special
}
....
}
Trusting in frameRate to control timing is ok, but is, of course, frameRate dependent. Meaning that if your frameRate drops the timimg will drop together.
To avoid that, you may use millis() and attach your timing to, well time :)
Here a very simple timer example:
PFont font;
String time = "000";
int initialTime;
int interval = 1000;//one second
color bg = color (255);
void setup()
{
size(300, 300);
font = createFont("Arial", 30);
background(255);
fill(0);
initialTime = millis();
frameRate(30);// changed framerate to exemplify
}
void draw()
{
background(bg);
if (millis() - initialTime > interval)
{
time = nf(int(millis()/1000), 3);
initialTime = millis();
bg = color (random(255), random(100), random(255));
}
text(time, width/2, height/2);
}
Related
I'm completely new to Java Processing and I am trying to figure out a way to deign a fan which will rotate and increase the speed when press the plus(+) button and decrease when press the negative(-) button. As well as a way to display the speed which the fan is rotating.
final int coverSize=250;
final int centralDiskSize=30;
final int rectSize=50;
final int bladeSize=30;
float xPos=0, yPos=0;
float angle=250;
float bladePosX=0, bladePosY=0;
boolean button = false;
void setup(){
size(500,500);
bladePosX=width/2+coverSize;
bladePosY=height/2;
}
void draw(){
//rotateFan();
drawFan();
btton();
}
void drawFan(){
background(200);
strokeWeight(2);
noFill();
ellipse(xPos+250,yPos+250,coverSize,coverSize);
ellipse(xPos+250,yPos+250,coverSize-40,coverSize-40);
ellipse(xPos+250,yPos+250,coverSize-90,coverSize-90);
ellipse(xPos+250,yPos+250,coverSize-130,coverSize-130);
ellipse(xPos+250,yPos+250,coverSize-180,coverSize-180);
fill(0);
ellipse(xPos+250,yPos+250,centralDiskSize,centralDiskSize);
noFill();
rect(xPos+175,yPos+375,rectSize,rectSize);
rect(xPos+225,yPos+375,rectSize,rectSize);
rect(xPos+275,yPos+375,rectSize,rectSize);
}
void rotateFan(){
background(200);
ellipse(bladePosX,bladePosY,bladeSize,bladeSize);
bladePosX=width/2+coverSize*cos(angle);
bladePosY=height/2+coverSize*sin(angle);
angle=angle+(PI/90);
ellipse(bladePosX,bladePosY,bladeSize,bladeSize);
//ellipse(xPos+250,yPos+250,centralDiskSize,centralDiskSize);
//buttons();
}
void btton(){
if(button){
background(255);
stroke(0);
if (button){
void mousePressed (){
if (mouseX > xPos && mouseX < xPos+rectSize && mouseY > yPos && mouseY < yPos+rectSize){
button = !button;
}
}
Based on the code you posted, I'm guessing that you want to draw a fan, as opposed to having a sprite. The code below is a minimal example of the functionality you want. I highly suggest you familiarize yourself with the translate() and rotate() methods.
The position and rotation of the fan are handled by the translate and rotate methods respectively. By applying these transformations to the entire canvas, we can draw the desired fan with simple statements, without too much math. You can adapt the complexity of the graphic according to your needs, but this is a minimal example.
The rotation speed is expressed in degrees per second, to be intuitive. Thus, when calculating the angle of the fan, the elapsed time between frames must be taken into account. You could use the global time (e.g. millis) instead of the delta time (time between frames), but you would eventually run into overflow problems.
Finally, you can change the speed by adding (a positive or negative) number of degrees per second to the existing fan speed, for every frame the relevant keys are pressed.
You can easily adapt the code to more complex control mechanics, better graphics, using sprites instead of manually drawing the fan etc.
Fan fan;
void setup(){
size(500, 500);
fan = new Fan(width/2, height/2, 50, 360);
}
void draw(){
background(255);
fan.display();
if (keyPressed && key == '+') fan.changeSpeed(1);
if (keyPressed && key == '-') fan.changeSpeed(-1);
}
class Fan {
int x, y;
int size;
float speed; // in degrees per second
private long lastUpdate; // in milliseconds
private float angle; // in degrees
Fan(int x, int y, int size, float speed){
this.x = x;
this.y = y;
this.size = size;
this.speed = speed;
lastUpdate = 0;
angle = 0;
}
void display(){
translate(x, y);
// Update the fan's angle
angle += speed*(millis()-lastUpdate)/1000 % 360;
rotate(radians(angle));
lastUpdate = millis();
// Draw red blade
fill(255, 0, 0);
triangle(0, 0, -size, -3*size, size, -3*size);
// Draw blue blade
rotate(radians(120));
fill(0, 255, 0);
triangle(0, 0, -size, -3*size, size, -3*size);
// Draw green blade
rotate(radians(120));
fill(0, 0, 255);
triangle(0, 0, -size, -3*size, size, -3*size);
translate(-x, -y);
}
void changeSpeed(float amount){
speed += amount;
}
}
I was basically trying to use a slider that would change the brightness of any image that the user loads.
The code below at the moment has a slider and a button that loads the image. What I want is once the image has been loaded using the load button, if the user slides the slider up and down to change the brightness of the image.
There is another file connected to the current file, but I am not able to send that one as it is too big
Here is the link for the whole file https://github.com/Muhammad-786/Test2
PImage sourceImage;
PImage outputImage;
SimpleUI myUI;
void setup() {
size(1000, 1000);
myUI = new SimpleUI();
Slider slider = myUI.addSlider("greys", 155, 885);
slider.setSliderValue(0.5);
myUI.addSimpleButton("Load file", 350,885);
}
void draw() {
loadPixels();
updatePixels();
if( sourceImage != null ){
image(sourceImage,100,50);
}
if(outputImage != null){
image(outputImage, 100, 50);
}
myUI.update();
}
void handleUIEvent(UIEventData uied) {
uied.print(2);
if(uied.eventIsFromWidget("Load file")){
myUI.openFileLoadDialog("Load an image");
}
if(uied.eventIsFromWidget("fileLoadDialog")){
sourceImage = loadImage(uied.fileSelection);
}
if (uied.eventIsFromWidget("greys")) {
outputImage = SLIDER(sourceImage);
}
}
PImage SLIDER(PImage sliderw){
PImage outputImage = createImage(sliderw.width,sliderw.height,RGB);
outputImage.loadPixels();
for (int x = 0; x < sliderw.width; x++ ) {
for (int y = 0; y < sliderw.height; y++ ) {
int loc = x + y*sliderw.width;
float r = red (sliderw.pixels[loc]);
float g = green(sliderw.pixels[loc]);
float b = blue (sliderw.pixels[loc]);
float adjustBrightness = map(height, 0, width, 0, 8);
r *= adjustBrightness;
g *= adjustBrightness;
b *= adjustBrightness;
r = constrain(r, 0, 255);
g = constrain(g, 0, 255);
b = constrain(b, 0, 255);
color c = color(r, g, b);
pixels[loc] = c;
outputImage.set(x,y, color(r,g, b));
}
}
outputImage.loadPixels();
return outputImage;
}
You were setting the brightness wrong.
In your code, you use:
float adjustBrightness = map(height, 0, width, 0, 8);
You are mapping height which is the height of the canvas size from 0~width to 0~8. Since the canvas size never changes, the value of adjustBrightness also never changes. That is why it suddenly becomes bright once in the beginning, then never change.
I've edited that part of the code to below (and other changes to make it work):
//declared globally
int sliderStartX = 155;
...
Slider slider = myUI.addSlider("greys", sliderStartX, 885);
...
float adjustBrightness = map(mouseX, sliderStartX, sliderStartX + 102, 0, 8);
I saved the x position of the left of slider in sliderStartX, and used that as the lower limit of the source range in map, and 102 is the width of the slider element that I found on SimpleUI.pde, hence sliderStartX + 102 is the upper limit of the source range.
So now, you are mapping mouseX from this range to your desired range.
However, this approach does not utilize the slider AT ALL. As you can see, we are only using slider's xpos and width. A more elegant approach would be to actually use the sliderValue inside the Slider instance, and map it from 0~1 (as sliderValue seems to be in that range, looking at the console) to your desired range 0~8. I'm not familiar at all with this SimpleUI library, so I couldn't really get the time to study it and make that part of it work.
Hope this helps you in writing the code you need!
I am trying to create a little game for a project in university. Since I need to update the screen permanently I am looking for a good render loop implementation. It should be full screen. I found this on gamedev.net - Java Games: Active Rendering:
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
public class SimpleFullScreenGame {
static boolean running;
public static void main( String[] args ) {
// Create game window...
JFrame app = new JFrame();
app.setIgnoreRepaint( true );
app.setUndecorated( true );
// Add ESC listener to quit...
app.addKeyListener( new KeyAdapter() {
public void keyPressed( KeyEvent e ) {
if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
running = false;
}
});
// Get graphics configuration...
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
// Change to full screen
gd.setFullScreenWindow( app );
if( gd.isDisplayChangeSupported() ) {
gd.setDisplayMode(
new DisplayMode( 640, 480, 32, DisplayMode.REFRESH_RATE_UNKNOWN )
);
}
// Create BackBuffer...
app.createBufferStrategy( 2 );
BufferStrategy buffer = app.getBufferStrategy();
// Create off-screen drawing surface
BufferedImage bi = gc.createCompatibleImage( 640, 480 );
// Objects needed for rendering...
Graphics graphics = null;
Graphics2D g2d = null;
Color background = Color.BLACK;
Random rand = new Random();
// Variables for counting frames per seconds
int fps = 0;
int frames = 0;
long totalTime = 0;
long curTime = System.currentTimeMillis();
long lastTime = curTime;
running = true;
while( running ) {
try {
// count Frames per second...
lastTime = curTime;
curTime = System.currentTimeMillis();
totalTime += curTime - lastTime;
if( totalTime > 1000 ) {
totalTime -= 1000;
fps = frames;
frames = 0;
}
++frames;
// clear back buffer...
g2d = bi.createGraphics();
g2d.setColor( background );
g2d.fillRect( 0, 0, 639, 479 );
// draw some rectangles...
for( int i = 0; i < 20; ++i ) {
int r = rand.nextInt(256);
int g = rand.nextInt(256);
int b = rand.nextInt(256);
g2d.setColor( new Color(r,g,b) );
int x = rand.nextInt( 640/2 );
int y = rand.nextInt( 480/2 );
int w = rand.nextInt( 640/2 );
int h = rand.nextInt( 480/2 );
g2d.fillRect( x, y, w, h );
}
// display frames per second...
g2d.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
g2d.setColor( Color.GREEN );
g2d.drawString( String.format( "FPS: %s", fps ), 20, 20 );
// Blit image and flip...
graphics = buffer.getDrawGraphics();
graphics.drawImage( bi, 0, 0, null );
if( !buffer.contentsLost() )
buffer.show();
} finally {
// release resources
if( graphics != null )
graphics.dispose();
if( g2d != null )
g2d.dispose();
}
}
gd.setFullScreenWindow( null );
System.exit(0);
}
}
I executed the code and there are two things I am wondering about:
My display resolution is 1920x1080. The code is using 640x480. Therefore the rendered rectangles look like a 640x480 picture upscaled to 1920x1080 meaning you have huge pixels and the code doesn't take avantage of the higher posible resolution of the display. How can I adapt the code to actually use the native display resolution of the user?
Second, usually what you see when you take a look on games code is a rendering loop living in its own thread to not block the main thread. However thats not the case here. Why? I assume because the JFrame already lives in its own thread created by swing?
Thanks for the help.
There are lots of issues with this code.
First of all, when you are checking (polling) a flag variable in the main thread, that will be updated by a key listener, which will be called in the event dispatch thread, the minimum you have to do, is to declare that variable volatile.
Then, there is no point in using JFrame when you don’t use the Swing framework at all. Further, it’s nonsensical to request double buffering from the AWT and then, use a BufferedImage for another buffering atop the already buffered operation.
Using the native resolution is as easy as removing the setDisplayMode(…) call. After turning the window to full screen, you can simply use getWidth() and getHeight() on it to get the actual dimensions for the operations (it’s not needed for the buffered image, as that was obsolete anyway).
public class SimpleFullScreenGame {
static volatile boolean running = true;
public static void main(String[] args) {
// Create game window...
Frame app = new Frame();
app.setIgnoreRepaint(true);
app.setUndecorated(true);
// Add ESC listener to quit...
app.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) running = false;
}
});
GraphicsDevice dev = app.getGraphicsConfiguration().getDevice();
// Change to full screen
dev.setFullScreenWindow(app);
int width = app.getWidth(), height = app.getHeight();
// Create BackBuffer...
app.createBufferStrategy(2);
BufferStrategy buffer = app.getBufferStrategy();
// Objects needed for rendering...
Color background = Color.BLACK, textColor = Color.GREEN;
Font font = new Font("Courier New", Font.PLAIN, 12);
ThreadLocalRandom rand = ThreadLocalRandom.current();
// Variables for counting frames per seconds
int fps = 0, frames = 0, totalTime = 0;
long currTime = System.nanoTime(), lastTime;
while(running) {
// count Frames per second...
lastTime = currTime;
currTime = System.nanoTime();
totalTime += currTime - lastTime;
if(totalTime > 1_000_000_000) {
totalTime -= 1_000_000_000;
fps = frames;
frames = 0;
}
frames++;
Graphics gfx = buffer.getDrawGraphics();
gfx.setColor(background);
gfx.fillRect(0, 0, width, height);
// draw some rectangles...
for(int i = 0; i < 20; ++i) {
gfx.setColor(new Color(rand.nextInt(0x1000000)));
int x = rand.nextInt(width/2), y = rand.nextInt(height/2);
int w = rand.nextInt(width/2), h = rand.nextInt(height/2);
gfx.fillRect(x, y, w, h);
}
// display frames per second...
gfx.setFont(font);
gfx.setColor(textColor);
gfx.drawString("FPS: " + fps, 20, 20);
gfx.dispose();
if(!buffer.contentsLost()) buffer.show();
}
dev.setFullScreenWindow(null);
System.exit(0);
}
}
I made some other small improvements.
I am working on a dusk cleaner simulator on Java, in this case the shape of the cleaner is a circular ball.
The program is quite simple, the user puts in the width and length of the "room" and coordinates x and y.
What I want to do and cannot is create a series of commands, each represented by a character. There are three commands that I want to imnplement:
1. char 'A' = Move forward 1 meter
2. char 'L' = Turn left 90 degrees
3. R Turn right 90 degrees
Example of user input AALA, in this case the expected output is that the machine moves 2 meters and then turns left 90 degrees and then moves 1 meter again. Hope I am clear.
As you can see in the code, I have tried to create an array of chars but I dont know what the next step should be...
The code:
public class Cleaner extends JPanel {
/* int lx = 1, ly = 1;
int x = 200, y = 250;
*/
int x, y;
int width = 52, height = 50; // width and height of the "dust sucker"
int lx , ly;
// an array of chars
char[] charArray ={ 'A', 'L', 'R'};
java.util.Timer move; // making the instance of Timer class from the util package
static JFrame frame;
Cleaner()
{
frame = new JFrame ("Cleaner started!"); // passing attributes to our fame
frame.setSize (400, 400); // setting size of the starting window
frame.setVisible (true);
setForeground(Color.black); // setting color
move = new java.util.Timer();
move.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
if(x<0)
lx = 1;
if(x>=getWidth()-45)
lx = -1; // -1 sets boundry for the dusk sucker
if(y<0)
ly = 1;
if(y>=getHeight()-45)
ly = -1; // -1 sets boundry for the dusk sucker
x+=lx; // to make the machine move
y+=ly;
repaint();
}
}, 0, 5// speed of the machine
);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint (Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, width, height);
}
public static void main (String[] args)
{
// lx value
String lxValue =
JOptionPane.showInputDialog( "Enter lx" );
// ly value
String lyValue =
JOptionPane.showInputDialog( "Enter ly" );
String xValue =
JOptionPane.showInputDialog( "Enter x value" );
// ly value
String yValue =
JOptionPane.showInputDialog( "Enter y value" );
// convert String inputs to int values
int firstInput = Integer.parseInt( lxValue );
int secondInput = Integer.parseInt( lyValue );
int thirdInput = Integer.parseInt( xValue );
int forthInput = Integer.parseInt( yValue );
Cleaner cleaner = new Cleaner();
frame.add(cleaner);
cleaner.lx = firstInput;
cleaner.ly = secondInput;
cleaner.x = thirdInput;
cleaner.y = forthInput;
}
}
All help is appreciated!
First some basics:
override paintComponent(), not paint() when doing custom painting.
use a Swing Timer for animation. All updates to Swing components need to be done on the Event Dispatch Thread (EDT).
in this case the shape of the cleaner is a circular ball.
So you need to create a class to represent the ball. It will have basic properties like:
size
location
direction of movement.
speed of movement.
You will then need to create methods to change the properties. Maybe:
move() - move in the current direction at the current speed
turnRight() - adjust direction
turnLeft() - adjust direction
Then you can create an ArrayList to store the moves and a Swing Timer to execute the moves.
Whenever the Timer fires you remove the command from the ArrayList and execute the command. By invoking one of the above 3 methods.
Check out: get width and height of JPanel outside of the class for an example that is similiar (not exact) to what you want. It demonstrates the concept if creating an object with the properties needed to control its motion.
I have been doing a small little project using Processing, and the effect I wanted to achieve was a kind of "mountains" forming and moving, using Perlin Noise with the noise() function, with 2 parameters.
I was originally using a image for the background, but for illustrational purposes, I made the background black, and it's basically the same effect.
My issue is that I want to have a "history" of the mountains because they should fade away after some time, and so I made a history of PShapes, and draw the history and update it each frame.
Updating it is no issue, but drawing the PShapes seems to take a lot of time, reducing the frame rate from 60 to 10 when the length of the history is 100 elements.
Below is the code I used :
float noise_y = 0;
float noise_increment = 0.01;
// increment x in the loop by this amount instead of 1
// makes the drawing faster, since the PShapes have less vertices
// however, mountains look sharper, not as smooth
// bigger inc = better fps
final int xInc = 1;
// maximum length of the array
// bigger = less frames :(
final int arrLen = 100;
int lastIndex = 0;
PShape[] history = new PShape[arrLen];
boolean full = false;
// use this to add shapes in the history
PShape aux;
void setup() {
size(1280, 720);
}
void draw() {
background(0);
// create PShape object
aux = createShape();
aux.beginShape();
aux.noFill();
aux.stroke(255);
aux.strokeWeight(0.5);
for (float x = 0; x < width + xInc; x = x + xInc) {
float noise = noise(x / 150, noise_y) ;
// get the actual y coordinate
float y = map(noise, 0, 1, height / 2, 0);
// create vertex of shape at x, y
aux.vertex(x, y);
}
aux.endShape();
// push the current one in the history
history[lastIndex++] = aux;
// if it reached the maximum length, start it over ( kinda works like a queue )
if (lastIndex == arrLen) {
lastIndex = 0;
full = true;
}
// draw the history
// this part takes the MOST TIME to draw, need to fix it.
// without it is running at 60 FPS, with it goes as low as 10 FPS
if (full) {
for (int i = 0; i < arrLen; i++) {
shape(history[i]);
}
} else {
for (int i = 0; i < lastIndex; i++) {
shape(history[i]);
}
}
noise_y = noise_y - noise_increment;
println(frameRate);
}
I have tried to use different ways of rendering the "mountains" : I tried writing my own class of a curve and draw lines that link the points, but I get the same performance. I tried grouping the PShapes into a PShape group object like
PShape p = new PShape(GROUP);
p.addChild(someShape);
and I got the same performance.
I was thinking of using multiple threads to render each shape individually, but after doing some research, there's only one thread that is responsible with rendering - the Animation Thread, so that won't do me any good, either.
I really want to finish this, it seems really simple but I can't figure it out.
One possible solution would be, not to draw all the generated shapes, but to draw only the new shape.
To "see" the shapes of the previous frames, the scene can't be cleared at the begin of the frame, of course.
Since the scene is never cleared, this would cause, that the entire view is covered, by shapes over time. But if the scene would be slightly faded out at the begin of a new frame, instead of clearing it, then the "older" shapes would get darker and darker by time. This gives a feeling as the "older" frames would drift away into the depth by time.
Clear the background at the initlization:
void setup() {
size(1280, 720);
background(0);
}
Create the scene with the fade effect:
void draw() {
// "fade" the entire view
blendMode(DIFFERENCE);
fill(1, 1, 1, 255);
rect(0, 0, width, height);
blendMode(ADD);
// create PShape object
aux = createShape();
aux.beginShape();
aux.stroke(255);
aux.strokeWeight(0.5);
aux.noFill();
for (float x = 0; x < width + xInc; x = x + xInc) {
float noise = noise(x / 150, noise_y) ;
// get the actual y coordinate
float y = map(noise, 0, 1, height / 2, 0);
// create vertex of shape at x, y
aux.vertex(x, y);
}
aux.endShape();
// push the current one in the history
int currentIndex = lastIndex;
history[lastIndex++] = aux;
if (lastIndex == arrLen)
lastIndex = 0;
// draw the newes shape
shape(history[currentIndex]);
noise_y = noise_y - noise_increment;
println(frameRate, full ? arrLen : lastIndex);
}
See the preview: