Related
I am currently working with the Ani Library in Processing.
I'm trying to fade in some rectangles one by one (on a PGraphics). To let the rectangles appear I use a loop - whose size I can control with MouseX. So one rectangle appears after the other. But I also want to fade in each one individually using the Ani Library. Currently I can only get the fade in to affect all of them at once.
So I tried to make an object out of the rectangle and put the FadeIn inside the object. But it behaves similar here – all fade in at once.
How can I solve this? Do I need an Array or an Array List for this?
This is my Code without an object:
import de.looksgood.ani.*;
PGraphics pg;
float alpha;
void setup() {
size(1920, 1920);
rectMode(CENTER);
Ani.init(this);
pg = createGraphics(width, height);
}
void draw() {
drawPG();
image(pg, 0,0);
}
void drawPG () {
pg.beginDraw();
pg.pushMatrix();
pg.translate(100, height/4.75);
pg.background(255);
pg.noStroke();
Ani.to(this, 10, "alpha", 255, Ani.EXPO_OUT);
color black = color(0, 0, 0, alpha);
pg.fill(black);
int blocks = int(map(mouseX, 0, width, 0, 7));
for (int i = 0; i < blocks; i++) {
pg.pushMatrix();
pg.translate(i * 200 + i*100, 0);
pg.rect(0, 0, 200, 200);
pg.popMatrix();
}
pg.popMatrix();
pg.endDraw();
}
And this is my tried out version with an Object:
import de.looksgood.ani.*;
PGraphics pg;
Rectangle myRect;
void setup() {
size(1920, 1920);
rectMode(CENTER);
myRect = new Rectangle();
Ani.init(this);
pg = createGraphics(width, height);
}
void draw() {
drawPG();
image(pg, 0,0);
}
void drawPG () {
pg.beginDraw();
pg.pushMatrix();
pg.translate(100, height/4.75);
pg.background(255);
pg.noStroke();
int blocks = int(map(mouseX, 0, width, 0, 7));
for (int i = 0; i < blocks; i++) {
pg.pushMatrix();
pg.translate(i * 200 + i*100, 0);
myRect.display(pg);
pg.popMatrix();
}
pg.popMatrix();
pg.endDraw();
}
class Rectangle {
float alpha;
Rectangle() {
}
void display(PGraphics pg) {
Ani.to(this, 10, "alpha", 255, Ani.EXPO_OUT);
color black = color(0, 0, 0, alpha);
pg.fill(black);
pg.rect(0, 0, 200, 200);
}
}
+++ EDIT +++
Found a solution here:
https://processing.org/tutorials/objects
And this gave me the hint to really work with an array. And then it says for the PGraphic:
void drawPG () {
pg.beginDraw();
pg.pushMatrix();
pg.translate(100, height/4.75);
pg.background(255);
pg.noStroke();
int blocks = int(map(mouseX, 0, width, 0, rectangles.length));
for (int i = 0; i < blocks; i++) {
pg.pushMatrix();
pg.translate(i * 200 + i*100, 0);
rectangles[i].display(pg);
pg.popMatrix();
}
pg.popMatrix();
pg.endDraw();
}
Above setup();
Rectangle[] rectangles = new Rectangle[7];
And in setup();
for (int i = 0; i < rectangles.length; i++) {
rectangles[i] = new Rectangle();
}
This is my current code:
int doorCounter = 0;
void setup()
{
size(512, 348); //width and height of screen
doorCounter = (int)random(180,300);
}
void draw()
{
display();
doorCounter = doorCounter - 1; // Decrease count by 1
if (doorCounter <= 0)
{
fill(255);
rect(420, 190, 55, 100); //house door outline
rect(435, 210, 25, 25, 7); // house door window
ellipse(435, 255, 8, 8); // house door handle
doorCounter = (int)random(180,480);
}
}
void display()
{
fill(255);
rect(420, 190, 55, 100); //house door outline
fill(0,0,0); // fill the following polygons in black
rect(435, 210, 25, 25, 7); // house door window
ellipse(435, 255, 8, 8); // house door handle
}
However what this code does is just makes the object disappear for a fraction of a second and just makes it reappear instantly. How do I make it so that the object stays disappeared for 3-8 seconds on a random interval just like how the object disappears every 3-8 seconds given that its still on the screen?
P.s I don't know if what I'm trying to achieve makes sense so please feel free to question.
An idea is to use a timestamp and check the time elapsed from it, something like this:
int min_time = 3000; // in ms
int max_time = 8000; // in ms
int time_frame = (int)random(min_time, max_time);
int time_stamp = 0;
boolean show_door = true;
void setup()
{
size(512, 348); //width and height of screen
}
void draw()
{
background(200);
int time_passed = millis() - time_stamp;
if (time_passed < time_frame && show_door) {
display();
} else if (time_passed >= time_frame) {
time_stamp = millis();
time_frame = (int)random(min_time, max_time);
show_door = !show_door;
}
}
void display()
{
fill(255);
rect(420, 190, 55, 100); //house door outline
fill(0, 0, 0); // fill the following polygons in black
rect(435, 210, 25, 25, 7); // house door window
ellipse(435, 255, 8, 8); // house door handle
}
Completing a graphics program in Java, I'm trying to animate rain falling using a timer. Right now I am testing my code with a big blue rectangle so I can see where it's going but the animation isn't working for me. I'm very new to Java graphics so I could be making mistakes that just aren't clear to me.
When I try to repaint the square to move, and the paint function is called the whole screen blinks, this may be because I was using recursive functions to draw fractal trees, but I'm not sure. Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain? Any guidance or tips would be appreciated.
import java.awt.*;
import javax.swing.*;
import java.lang.Math;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FractalTree extends JFrame {
private int frameWidth = 1440;
private int frameHeight = 850;
private int rainX = 0;
private int rainY = 0;
public FractalTree()
{
setBounds(1000, 1000, frameWidth, frameHeight ); //graphics window size
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ActionListener listener = new TimerListener();
final int DELAY = 1500;
Timer t = new Timer(DELAY, listener);
t.start();
setResizable(false);
}
public void setRain(int newRainX, int newRainY)
{
rainX = newRainX;
rainY = newRainY;
}
public void setSkyGround(Graphics g)
{
Color sky = new Color(180, 225, 255);
g.setColor(sky);
g.fillRect(0, 0, frameWidth, 550);
Color sun = new Color(225, 225, 150);
g.setColor(sun);
g.fillOval(1380, -40, 100, 100);
g.drawLine(frameWidth, 0, 1350, 550);
g.drawLine(frameWidth, 0, 1450, 550);
g.drawLine(1350, 550, 1450, 550);
int xpoints[] = {frameWidth, 1450, 1350};
int ypoints[] = {0, 550, 550};
int npoints = 3;
g.fillPolygon(xpoints, ypoints, npoints);
g.drawLine(frameWidth, 0, 1080, 550);
g.drawLine(frameWidth, 0, 880, 550);
g.drawLine(880, 550, 1080, 550);
int xpoints2[] = {frameWidth, 1080, 880};
int ypoints2[] = {0, 550, 550};
int npoints2 = 3;
g.fillPolygon(xpoints2, ypoints2, npoints2);
g.drawLine(frameWidth, 0, 480, 550);
g.drawLine(frameWidth, 0, 280, 550);
g.drawLine(480, 550, 280, 550);
int xpoints3[] = {frameWidth, 480, 280};
int ypoints3[] = {0, 550, 550};
int npoints3 = 3;
g.fillPolygon(xpoints3, ypoints3, npoints3);
g.drawLine(frameWidth, 0, 0, 430);
g.drawLine(frameWidth, 0, 0, 300);
g.drawLine(0, 430, 0, 300);
int xpoints4[] = {frameWidth, 0, 0};
int ypoints4[] = {0, 430, 300};
int npoints4 = 3;
g.fillPolygon(xpoints4, ypoints4, npoints4);
g.drawLine(frameWidth, 0, 0, 100);
g.drawLine(frameWidth, 0, 0, 0);
g.drawLine(0, 100, 0, 0);
int xpoints5[] = {frameWidth, 0, 0};
int ypoints5[] = {0, 0, 100};
int npoints5 = 3;
g.fillPolygon(xpoints5, ypoints5, npoints5);
Color grassBackground = new Color(150, 255, 170);
g.setColor(grassBackground);
g.fillRect(0, 550, frameWidth, frameHeight);
}
public void drawTree(Graphics g, int x1, int y1, double angle, int depth, int red, int green, int blue)
{
if (depth == 0)
{
Color doodle = new Color(red, green, blue);
g.setColor(doodle);
g.fillOval(x1, y1, 10, 10);
}
else
{
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(depth));
Color brown = new Color(100, 25, 0);
g.setColor(brown);
int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 10);
int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 10);
g.drawLine(x1, y1, x2, y2);
drawTree(g, x2, y2, angle - 40, depth - 1, red, green, blue);
drawTree(g, x2, y2, angle + 20, depth - 1, red, green, blue);
}
}
public void realFlowers(Graphics g, int x, int y, int lenWid, int petals)
{
//calculates the increment
double inc = (2*Math.PI/petals);
g.setColor(Color.YELLOW);
//draws petals
for(int i = 0; i < petals; i++){
//keeps spacing consistent depandng on number of petals
double value = i * inc;
//draws petals with calculated spacing relative to number of petals
g.fillOval((int)((lenWid)*Math.cos(value)+x-lenWid/4),(int)((lenWid)*Math.sin(value)+y-lenWid/4), lenWid + lenWid/2, lenWid + lenWid/2);
}
//draws middle flower bud;
g.setColor(Color.ORANGE);
g.fillOval(x - lenWid/4, y - lenWid/4, lenWid + lenWid/2 , lenWid + lenWid/2);
}
public void drawGrass(Graphics g, int width, int height, int interval, int red, int green, int blue)
{
height = frameHeight - height;
Color grass = new Color(red, green, blue);
for(int i = 0; i < width; i= i + interval)
{
for(int j = frameHeight; j > height; j = j - interval)
{
g.setColor(grass);
g.fillRect(i, j, 3, 5);
}
}
}
public void rainDrops(Graphics g, int x, int y, int w, int h)
{
setRain(x, y);
Color rain = new Color(0, 76, 153);
g.setColor(rain);
g.fillRect(x, y, w, h);
}
public void moveRainBy(int dx, int dy)
{
rainX = rainX + dx;
rainY = rainY + dy;
repaint();
}
class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
moveRainBy(1, 1);
}
}
public void paint(Graphics g) {
setSkyGround(g);
drawGrass(g, 1440, 315, 5, 0, 255, 0);
drawGrass(g, 1430, 310, 10, 0, 204, 0);
drawTree(g, 1085, 730, -90, 10, 255, 102, 102);
drawTree(g, 250, 600, -90, 8, 255, 255, 255);
drawTree(g, 1110, 740, -90, 4, 255, 102, 102);
drawTree(g, 1060, 745, -90, 2, 255, 102, 102);
realFlowers(g, 700,700, 8, 8);
rainDrops(g, 200, 200, 30, 30);
}
public static void main(String[] args) {
new FractalTree().setVisible(true);
}
}
When I try to repaint the square to move, and the paint function is called the whole screen blinks
This is because you've override paint of the a top level container (JFrame) which is not double buffered.
As a general recommendation, you should be basing your core functionality around a JPanel and override it's paintComponent method. Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
You might like to also have a look at How to get the EXACT middle of a screen, even when re-sized and How can I set in the midst? for more details why it's not recommended to extend directly from JFrame and try to paint to it.
Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain?
Painting is destructive, that is, each time paint/paintComponent is called, you are expected to repaint the entire state of the component from scratch.
You could use a buffering technique, using something like BufferedImage to paint your state to and simply have the paint methods draw the image, but that would depend on how complex a solution you want. If you were to use buffering technique, I would consider which elements are "static" and which elements are "dynamic". Painting those static elements to the buffer and then, when paint is called, painting the dynamic elements over the top the buffer
Please help me how to make this eye move or to make it blink using repaint, thread and implements runnable. I don't know where to place the right codes to make it work. Please help me guys! Thank you!
Here is the code:
import java.awt.*;
import java.applet.*;
public class Pucca extends Applet {
public Pucca(){
setSize(700, 700); }
//paint method
public void paint(Graphics g){
Color white = new Color(255,255,255);
g.setColor(white);
g.fillOval(600, 100, 125, 125); //left white fill eye
g.setColor(Color.BLACK);
g.drawOval(600, 100, 125, 125); // left big black line eye
g.setColor(white);
g.fillOval(700, 100, 125, 125); //right white fill eye
g.setColor(Color.BLACK);
g.drawOval(700, 100, 125, 125); //right big black line eye
Color blue = new Color(0, 160, 198);
g.setColor(blue);
g.fillOval(635, 130, 51, 51); // left blue fill eye
g.setColor(Color.BLACK);
g.drawOval(635, 130, 50, 50); // left black small line eye
g.setColor(blue);
g.fillOval(735, 130, 51, 51); // right blue fill eye
g.setColor(Color.BLACK);
g.drawOval(735, 130, 50, 50); // right black small line eye
g.setColor(Color.BLACK);
g.fillOval(650, 145, 20, 20); // left black iris
g.setColor(Color.BLACK);
g.fillOval(750, 145, 20, 20); // right black iris
}
}
When it comes to animation, everything becomes variable. You also have a lot of repeated code (seriously, if you can paint one eye, you can paint lots).
The first thing you need to is make all the values of the eye as variable as possible.
The follow makes the eye size and position variable and the iris and pupil a scaled value of the eye size, which makes the whole process simpler to animate.
Next, you need an updated loop, which can update the state of the values you want to change. To keep it simple, I've set it up so that the pupil has a variable offset, which is changed over time.
import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
public class Pucca extends Applet {
public Pucca() {
setSize(700, 700);
Thread t = new Thread(new Runnable() {
private int xDelta = -1;
private int yDelta = 0;
private int blinkCount = 0;
#Override
public void run() {
while (true) {
try {
Thread.sleep(40);
} catch (InterruptedException ex) {
}
xOffset += xDelta;
double irisSize = eyeSize.width * irisScale;
double range = ((eyeSize.width - irisSize) / 2);
if (xOffset <= -range) {
xOffset = -(int) range;
xDelta *= -1;
} else if (xOffset >= range) {
xOffset = (int) range;
xDelta *= -1;
}
blinkCount++;
if (blink && blinkCount > 10) {
blink = false;
blinkCount = 0;
} else if (blinkCount > 25) {
blink = true;
blinkCount = 0;
}
repaint();
}
}
});
t.setDaemon(true);
t.start();
}
private boolean blink = false;
private int xOffset, yOffset = 0;
private Dimension eyeSize = new Dimension(125, 125);
private Point left = new Point(20, 20);
private Point right = new Point(left.x + 100, left.y);
private double irisScale = 0.4;
private double pupilScale = 0.16;
//paint method
#Override
public void paint(Graphics g) {
super.paint(g);
paintEye(g, new Rectangle(left, eyeSize));
paintEye(g, new Rectangle(right, eyeSize));
}
protected void paintEye(Graphics g, Rectangle bounds) {
Color white = new Color(255, 255, 255);
if (blink) {
g.setColor(Color.YELLOW);
} else {
g.setColor(white);
}
g.fillOval(bounds.x, bounds.y, bounds.width, bounds.height); //left white fill eye
g.setColor(Color.BLACK);
g.drawOval(bounds.x, bounds.y, bounds.width, bounds.height); // left big black line eye
if (!blink) {
Color blue = new Color(0, 160, 198);
paintEyePartAt(g, bounds, irisScale, blue);
paintEyePartAt(g, bounds, pupilScale, Color.BLACK);
}
}
private void paintEyePartAt(Graphics g, Rectangle bounds, double delta, Color color) {
int width = (int) (bounds.width * delta);
int height = (int) (bounds.height * delta);
g.setColor(color);
g.fillOval(
xOffset + bounds.x + ((bounds.width - width) / 2),
yOffset + bounds.y + ((bounds.height - height) / 2),
width, height); // left blue fill eye
g.setColor(Color.BLACK);
g.drawOval(
xOffset + bounds.x + ((bounds.width - width) / 2),
yOffset + bounds.y + ((bounds.height - height) / 2),
width,
height); // left blue fill eye
}
}
This complicates things, as painting can occur for any number of reasons, many of which you don't have control over or will be notified about, so you should be very careful about where and when you change values.
You should also have a look at Java Plugin support deprecated and Moving to a Plugin-Free Web and Why CS teachers should stop teaching Java applets.
Applets are simply a dead technology and given the inherent complexities involved in using them, you should instead focus you should probably attention towards window based programs.
Personally, I'd start with having a look at Painting in AWT and Swing and Performing Custom Painting
I am having a some difficulty with developing of my code. Since I am not too advanced with Java I need some help. I am trying to develop Mini Tennis game using Threads. The aim of this game is to catch the balls moving on the window with the paddle that can be controlled with the left and right buttons on the keyboard.
Those balls should move diagonally on the window and when they touch to any of the corner (out of bottom) they should change their ways like light reflection. Apart from this, when a ball touches to one of the obstacles they should change their ways as well.
Paddle on the bottom of the window can be controlled with left and right keys.The task of the player is to catch the balls. The number of balls that the user catches will be shown on the Score part with the total number of balls going to the bottom corner.
User may need to save the state of the game. When the user clicks to the “save game” button; ball locations and score should save to the file. And when the user clicks to the open button, the state of game should be reloaded.
My source code files are:
public class BallPanel extends JPanel implements Runnable {
int RED, GREEN, BLUE;
int Xdirection = 1, Ydirection = 1;
boolean pleaseWait = false;
BallPanel(int X, int Y){
locateBall(X, Y, 30, 30);
/* Random r = new Random();
RED = r.nextInt(255);
GREEN = r.nextInt(255);
BLUE = r.nextInt(255);
*/
}
public void paint(Graphics g){
int panelWidth = this.getWidth();
int panelHeight = this.getHeight();
// g.setColor( new Color(RED, GREEN, BLUE ));
g.setColor(Color.ORANGE);
g.fillOval(panelWidth/2, panelHeight/2,panelWidth/2, panelHeight/2);
}
public void locateBall(int x, int y, int width, int height){
setBounds(x, y, width, height);
repaint();
}
public void run() {
int width = this.getWidth();
int height = this.getHeight();
Random r = new Random();
while(true){
if(!pleaseWait){
int lastX = this.getX();
int lastY = this.getY();
if (lastX > 675) Xdirection = -1;
if (lastY > 485) Ydirection = -1;
if (lastX < -5) Xdirection = 1;
if (lastY < -5) Ydirection = 1;
/* if(lastX > 280 && lastY > 170){
Xdirection = -1;
Ydirection = -1;
}
*/
locateBall(lastX + Xdirection*r.nextInt(3),
lastY + Ydirection*r.nextInt(3),
width, height );
}
try{
Thread.sleep(5);
}catch(Exception e){};
}
}
}
public class BallWindow extends JFrame implements ActionListener{
JButton btnStop = new JButton("STOP");
JButton btnSave = new JButton("SAVE");
Vector<BallPanel> ballVector = new Vector<BallPanel>();
JPanel p1 = createPanel(280, 200, 200, 20, Color.gray);
JPanel p2 = createPanel(280, 300, 200, 20, Color.gray);
JPanel bottomp = createPanel(345, 540, 70, 15, Color.black);
JPanel lborder = createPanel(10, 10, 2, 560, Color.black);
JPanel rborder = createPanel(720, 10, 2, 560, Color.black);
JPanel tborder = createPanel(10, 10, 710, 2, Color.black);
public BallWindow() {
setLayout(null);
btnStop.setBounds(12, 15, 100, 30);
btnStop.addActionListener(this);
add(btnStop);
btnSave.setBounds(12, 50, 100, 30);
//btnSave.addActionListener(this);
add(btnSave);
Random r = new Random();
for(int i=0; i<7; i++){
BallPanel bp = new BallPanel(r.nextInt(740), r.nextInt(590));
Thread t = new Thread(bp);
ballVector.add(bp);
t.start();
add(bp);
}
add(p1);
add(p2);
add(bottomp);
add(lborder);
add(rborder);
add(tborder);
setSize(740, 590);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
repaint();
}
JPanel createPanel(int x, int y, int width, int height, Color pColor){
JPanel temp = new JPanel();
temp.setBackground(pColor);
temp.setBounds(x, y, width, height);
return temp;
}
public static void main(String[] args) {
new BallWindow();
}
public void actionPerformed(ActionEvent arg0) {
for (BallPanel ball : ballVector) {
ball.pleaseWait = !ball.pleaseWait;
}
if( btnStop.getText().equalsIgnoreCase("STOP"))
btnStop.setText("START");
else
btnStop.setText("STOP");
// if(arg0.getSource())
}
}
I'm stuck with obstacles part and the keylistener. Any type of help will be greatly appreciated.
Hava a look at http://zetcode.com/tutorials/javagamestutorial/
You should especially check out the Basics and the Animation section. It will help clean up the animation and thread stuff you are doing. It also shows a general pattern how one could implement a java game.