"Infinite" Loop with Timer - java

I was wondering if anybody here knows how to make a seamlessly endless loop with shapes using a timer. Basically I'm trying to make a new set of moving shapes while the current set of shapes is moving so that it looks like it's just infinitely moving along the top of the screen. I have tried the if statements alongside the public int getX(){return x;)}, but I have not succeeded in doing so. Maybe it's possible to have a second timer linked with a second set of shapes and set a delay time? (However, I do not know how to go about writing a second timer and I do not know how to set a delay, help me??)
Any solutions or suggestions?
Here is an example, notice how the set of shapes is redrawn after all of the shapes pass the screen. This is not what I want. I want it to appear as if it were infinitely running along the top of the screen in smooth succession.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ExampleLoop extends JPanel implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ExampleLoop());
frame.setVisible(true);
}
Timer timer = new Timer(50, this);
int x = 0, velX = 7;
// CHRISTMAS THEME :D
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.GREEN);
for (int z = 0; z <= 500; z += 100)
g.fillRect(x + z, 0, 20, 20);
timer.start();
}
public void actionPerformed(ActionEvent e) {
if (x < 500) {
velX = velX;
x = x + velX;
}
else {
x = 0;
}
repaint();
}
}

I can't really figure out what going on in your code, but I reproduce the effect you're looking for. You can examine it. It runs.
What i did was make 5 different xPoints. You could have done this by using an array of int but I thouhgt it would be easier to read this way.
For each xPoint, I incremented each timer iteration. If the xPoint reached the screen width, I made it equal 0. Then repaint. I did that for all the points.
Code Edited: to use arrays and loops
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class GreenRects extends JPanel {
private static final int SCREEN_WIDTH = 500;
private static final int SCREEN_HEIGHT = 500;
private static final int OFFSET = 100;
private static final int SIZE = 20;
private static final int INC = 5;
int[] xPoints = new int[5];
public GreenRects() {
int x = 0;
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] = x;
x += OFFSET;
}
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < xPoints.length; i++) {
if (xPoints[i] + INC < SCREEN_WIDTH) {
xPoints[i] += INC;
} else {
xPoints[i] = 0;
}
}
repaint();
}
});
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g.setColor(Color.green);
for (int i = 0; i < xPoints.length; i++) {
g.fillRect(xPoints[i], 0, SIZE, SIZE);
}
}
public Dimension getPreferredSize() {
return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
}
public static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new GreenRects());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

You can try this code in if clause
if (x < 80)
{
velX = velX;
x = x + velX;
}

Related

Repaint doesn't work when changing variable

I am very new to developing with java but I have some general coding experience. I know wanted to draw a "picture/fractal" with a function I created. I got all the code done and I wanted to automatically move the "fractal" by just adding to the function XOFF, (I have a timer) now I wanted the variable to automatically increase so that it scrolls through the picture. I tried using repaint and revalidate but it doesnt work :(
and i know that i wrote MandelBrotSet even though it doesn't have anything to do with it ^^
package Pack1;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.Timer;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Main extends JComponent implements ActionListener {
public static void main(String[] args) {
new Main();
}
public static final int WIDTH = 1000;
public static final int HEIGHT = 800;
public int XOFF = 0;
public int YOFF = 0;
private BufferedImage buffer;
private Timer timer;
public Main(){
buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
timer = new Timer(10, this);
renderMandelBrotSet();
JFrame frame = new JFrame("Mandelbrot Set");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.getContentPane().add(this);
frame.pack();
frame.setVisible(true);
}
#Override
public void addNotify() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
timer.start();
}
public void renderMandelBrotSet() {
System.out.println(XOFF);
int vx = 0;
int vy = 0;
int zoom = 1;
for(int x = 0; x < WIDTH; x++)
for(int y = 0; y < HEIGHT; y++) {
vx = ((x - WIDTH/2));
vy = ((y - HEIGHT/2));
vx = vx + XOFF;
vy = vy + 0;
int color = (int) (Math.abs(vx)/Math.sqrt(Math.abs(vy))*(vx/zoom)); //calculatePoint((x - WIDTH/2), (y - HEIGHT/2) );
buffer.setRGB(x, y, color);
}
}
#Override
public void paint(Graphics g) {
g.drawImage(buffer, 0, 0, null);
}
#Override
public void actionPerformed(ActionEvent e) {
XOFF++;
renderMandelBrotSet();
revalidate();
repaint();
}
}
I hope the code makes sense..., I am sorry if I forgot to mention anything. Feel free to ask me if you need something.
I think addNotify is your problem. That method already does something, and the way you overrode it you don't seem to perform any of the actions that its documentation says it should. Just get rid of it, and move its code elsewhere.
This seems to work for me. I also slowed your timer down to 100 ms since I know from experience that Java Swing isn't really capable of updating as quickly as that. 100 ms to 250 ms is a good range for updating Swing.
I also got rid of revalidate because that's only for when a component is added or removed, or changes size. You only need to repaint since your image doesn't change size.
(Hovercraft pointed out that the code really should override paintComponent, not paint. He is quite correct; this is explained in the tutorial: https://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html )
(And while I'm fixing stuff up I might as well point out that Swing is not thread safe, and the GUI creation (including the image and the timer) really needs to be done on the GUI thread.)
package quicktest;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
/**
*
* #author Brenden
*/
public class MandelbrotSet {
}
class Main extends JComponent implements ActionListener {
public static void main(String[] args) {
new Main();
}
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public int XOFF = 0;
public int YOFF = 0;
private BufferedImage buffer;
private Timer timer;
public Main(){
SwingUtilities.invokeLater( this::createGui );
}
private void createGui() {
buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
timer = new Timer(100, this);
setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
renderMandelBrotSet();
JFrame frame = new JFrame("Mandelbrot Set");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.getContentPane().add(this);
frame.pack();
frame.setVisible(true);
timer.start();
}
// #Override
// public void addNotify() {
// setPreferredSize(new Dimension(WIDTH, HEIGHT));
// timer.start();
// }
public void renderMandelBrotSet() {
System.out.println(XOFF);
int vx = 0;
int vy = 0;
int zoom = 1;
for(int x = 0; x < WIDTH; x++)
for(int y = 0; y < HEIGHT; y++) {
vx = ((x - WIDTH/2));
vy = ((y - HEIGHT/2));
vx = vx + XOFF;
vy = vy + 0;
int color = (int) (Math.abs(vx)/Math.sqrt(Math.abs(vy))*(vx/zoom)); //calculatePoint((x - WIDTH/2), (y - HEIGHT/2) );
buffer.setRGB(x, y, color);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent( g );
System.err.println( "Repainting..." );
g.drawImage(buffer, 0, 0, null);
}
#Override
public void actionPerformed(ActionEvent e) {
System.err.println( "Timer: XOFF=" + XOFF );
XOFF++;
renderMandelBrotSet();
// revalidate();
repaint();
}
}

Loop drawing rectangles

I am trying to make a basic tetris game, first I am looking to draw a grid to make sure that I am creating blocks as I want to, however I can't get my program to access my paintComponent method.
package tetris;
import javax.swing.*;
import java.awt.*;
public class TetrisMain extends JFrame {
final int BoardWidth = 10;
final int BoardHeight = 20;
public static int HEIGHT = 400;
public static int WIDTH = 200;
Timer timer;
boolean isFallingFinished = false;
boolean isStarted = false;
boolean isPaused = false;
int score = 0;
int curX = 0;
int curY = 0;
int[][] grid = new int[BoardWidth][BoardHeight];
public static void main(String[] args) {
JFrame frame = new JFrame("Charles Walker - 1504185");
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.repaint();
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.BLACK);
for (int i = 0; i < BoardWidth; i++) {
for (int j = 0; j < BoardHeight; j++) {
curX = grid[i][curY];
curY = grid[curX][j];
g.fillRect(WIDTH / BoardWidth, HEIGHT / BoardHeight, curX, curY);
}
}
}
}
Here is a basic code to do what you want :
import javax.swing.JFrame;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.*;
public class Name extends JFrame {
public Name() {
super("Name");
setTitle("Application");
setContentPane(new Pane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setResizable(true);
setVisible(true);
while (true){
try { //Update screen every 33 miliseconds = 25 FPS
Thread.sleep(33);
} catch(InterruptedException bug) {
Thread.currentThread().interrupt();
System.out.println(bug);
}
repaint();
}
}
class Pane extends JPanel {
public void paintComponent(Graphics g) { //Here is were you can draw your stuff
g.drawString("Hello World",0,20); //Display text
}
}
public static void main(String[] args){
new Name();
}
}
I think you forgot that line to set the content pane :
setContentPane(new Pane());
and, important, you need a while loop to redraw :
while (true){
try { //Update screen every 33 miliseconds = 25 FPS
Thread.sleep(33);
} catch(InterruptedException bug) {
Thread.currentThread().interrupt();
System.out.println(bug);
}
repaint();
}

repaint() paints slower than paintComponent()?

I am painting vehicle objects that I defined using the paintComponent().
Because the vehicles can move, I implement ActionListener and set a Timer() to trigger.
As a result, my vehicles can move. But it is kind of "shaking". When I keep resizing the window to call the paintComponent(), the movement becomes smooth. When I do not resize the window (not calling paintComponent), it gets skaking again. Why? How to fix it?
public class VehiclesComponent extends JComponent implements ActionListener{
private Vehicle[] vehicles;
private Timer timer;
public VehiclesComponent(int n){
vehicles = Vehicle.generateVehicle(n);
timer = new Timer(5,this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (int i=0; i<vehicles.length; i++) {
vehicles[i].draw(g2);
}
// may change later
timer.start();
}
#Override
public void actionPerformed(ActionEvent e){
//check collision in here
for (Vehicle v : vehicles) {
if (Vehicle.intersectsOther(v, vehicles)) {
v.collisionSideEffect();
}
}
//move all in here
for (Vehicle v : vehicles ) {
v.move();
}
repaint();
//?? repaint slower than paintComponent
}
}
Start by taking a look at Painting in AWT and Swing. Remember, repaint is only a suggest made to the RepaintManager, the RepaintManager may choose to consolidate multiple repaint calls into a smaller number of actual paint events.
Make sure you are calling super.paintComponent, otherwise you will end up with no end of strange paint artifacts.
Don't, directly or indirectly, modify the state of the component or ant other components from within any paint method, this will result in a new repaint request been made, which could lead to a cycle of paint events which could consume your CPU cycles. This means, don't call timer.start()!
Without a runable example to go by, I hobbled this together. Now this is animating 10, 000 individual Vehicles (rectangles), so it's massively over kill, but it should provide the point...
(the gif is only running at 7fps, not your 200fps)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new VehiclesComponent(10000));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class VehiclesComponent extends JComponent implements ActionListener {
private Vehicle[] vehicles;
private Timer timer;
public VehiclesComponent(int n) {
vehicles = Vehicle.generateVehicle(n, getPreferredSize());
timer = new Timer(5, this);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < vehicles.length; i++) {
vehicles[i].draw(g2);
}
}
#Override
public void actionPerformed(ActionEvent e) {
//check collision in here
// for (Vehicle v : vehicles) {
// if (Vehicle.intersectsOther(v, vehicles)) {
// v.collisionSideEffect();
// }
// }
//move all in here
for (Vehicle v : vehicles) {
v.move(this.getSize());
}
repaint();
//?? repaint slower than paintComponent
}
}
public static class Vehicle {
protected static final int SIZE = 5;
protected static final Color[] COLORS = new Color[]{
Color.BLACK,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GREEN,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.RED,
Color.WHITE,
Color.YELLOW
};
private int x = 0;
private int y = 0;
private int xDelta;
private int yDelta;
private Shape car;
private Color color;
public static Vehicle[] generateVehicle(int count, Dimension bounds) {
Vehicle[] vehicles = new Vehicle[count];
for (int index = 0; index < vehicles.length; index++) {
vehicles[index] = new Vehicle(bounds);
}
return vehicles;
}
public Vehicle(Dimension size) {
x = (int)(Math.random() * (size.width - SIZE));
y = (int)(Math.random() * (size.height - SIZE));
xDelta = (int)(Math.random() * 3) + 1;
yDelta = (int)(Math.random() * 3) + 1;
car = new Rectangle(SIZE, SIZE);
color = COLORS[(int)(Math.random() * COLORS.length)];
}
public void move(Dimension size) {
x += xDelta;
y += yDelta;
if (x < 0) {
x = 0;
xDelta *= -1;
} else if (x + SIZE > size.width) {
x = size.width - SIZE;
xDelta *= -1;
}
if (y < 0) {
y = 0;
yDelta *= -1;
} else if (y + SIZE > size.height) {
y = size.height - SIZE;
yDelta *= -1;
}
}
public void draw(Graphics2D g2) {
g2.translate(x, y);
g2.setColor(color);
g2.fill(car);
g2.translate(-x, -y);
}
}
}
You could also take a look at this example which renders upwards of 4500 images in random directions and demonstrates some optimisation techniques.
You can also take a look at this example which is capable of animating both in direction and rotation, upwards of 10, 000 images

Pause Graphics?

So I have this JPanel Graphics code:
public void paint(Graphics g){
super.paint(g);
for(int y=0 ;y < 50; y++){
for(int x = 0; x < 50; x++){
if(m.getMaze(x, y).equals("g")){
g.drawImage(m.getGround(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("w")){
g.drawImage(m.getWall(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("S")){
g.drawImage(m.getStart(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("E")){
g.drawImage(m.getEnd(), x * 16, y * 16,null);
}
}
}
}
And inside the for loop (the second one) I would like to pause it for half a second, so you can see it drawing each tile. The thing is, is when I use
Thread.sleep(500);
After the second for loop, it just stops the whole thing forever. If I use
g.wait(500);
it keeps spamming
java.lang.IllegalMonitorStateException
in the console. And yes, it is surrounded with try/catch. How can I pause this?
On a swing Timer call repaint(50L, x*16, y*16, 16, 16);. Use fields for the current state (x, y),
and on every paintComponent draw only that state/tile.
1) use paintComponent() method for custom paintings intead of paint(). Read about custom paintings in java
2) Don't block EDT with Thread.sleep(500); or g.wait(500);.
Seems you need to use swing Timer for loading. Here is simple example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class TestFrame extends JFrame {
private Timer timer;
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
final DrawPanel p = new DrawPanel();
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(p.drawingTiles < 16){
p.addDrawingTile();
p.repaint();
} else {
timer.stop();
System.out.println("done");
}
}
});
timer.start();
add(p);
}
public static void main(String args[]) {
new TestFrame();
}
private class DrawPanel extends JPanel{
protected int drawingTiles = 0;
private int tiles[][] = new int[4][4];
public DrawPanel(){
Random r = new Random();
for(int i=0;i<tiles.length;i++){
for(int j=0;j<tiles.length;j++){
tiles[i][j] = r.nextInt(5);
}
}
}
public void addDrawingTile() {
drawingTiles++;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int curTiles = 0;
for(int i=0;i<tiles.length;i++){
for(int j=0;j<tiles.length;j++){
if(curTiles <drawingTiles){
curTiles++;
g.drawString(tiles[i][j]+"", (j+1)*10, (i+1)*10);
}
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50,50);
}
}
}

How can I scroll more than one object at the same time?

New question was asked after this one, found here.
I'm new to Java, but I am working on a recreation of "Flappy Bird" to learn more about java and the way that graphics are displayed. Any solutions or suggestions to any of my questions is greatly appreciated. Thanks!
Right now, my program makes a random pipe and scrolls it, but I don't need it to keep scrolling when x1-3 = -83 (this is when the pipe will be off of the screen completely and is no longer needed).
Questions
How can I make my Game.class scroll more than one instance of Pipes.class while adding a preset distance between them? I could find out the distance to put between them, but as far as displaying more than one, I'm not sure how to do that. At most, 3 pipes have to be displayed at the same time.
How can I display a panel for the main menu, and then switch to the pipes panel after a start button is pressed?
Classes
Game.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Game {
Pipes panel = new Pipes();
public Game() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.setTitle("Pipe Game");
f.setResizable(false);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
Timer timer = new Timer(10, new ActionListener() { //pipe speed
#Override
public void actionPerformed(ActionEvent e) {
panel.move();
}
});
timer.start();
Timer refresh = new Timer(30, new ActionListener() { //refresh rate
#Override
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
});
refresh.start();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Game();
}
});
}
}
Pipes.java
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Pipes extends JPanel {
//Declare and initialiaze variables
int x1 = 754; //xVal start
int x2 = 75; //pipe width
//total width is 83
int y1 = -1; //yVal start
int y2 = setHeightVal(); //pipe height
int gap = 130; //gap height
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0,0,750,500); //Clear screen
g.drawRect(x1,y1,x2,y2); //Draw part 1
g.drawRect(x1-3,y2-1,x2+6,25); //Draw part 2
g.drawRect(x1-3,y2+25+gap,x2+6,25); //Draw part 3
g.drawRect(x1,y2+25+gap+25,x2,500-y2-49-gap); //Draw part 4
}
public void move() {
x1--;
}
public int getMyX() { //To determine where the pipe is horizontally
return x1-3;
}
public int getMyY() { //To determine where the pipe is vertically
return y2+25;
}
public int setHeightVal() { //Get a random number and select a preset height
int num = (int)(9*Math.random() + 1);
int val = 0;
if (num == 9)
{
val = 295;
}
else if (num == 8)
{
val = 246;
}
else if (num == 7)
{
val = 216;
}
else if (num == 6)
{
val = 185;
}
else if (num == 5)
{
val = 156;
}
else if (num == 4)
{
val = 125;
}
else if (num == 3)
{
val = 96;
}
else if (num == 2)
{
val = 66;
}
else
{
val = 25;
}
return val;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(751, 501);
}
}
"How can I make my Game.class scroll more than one instance of Pipes.class while adding a preset distance between them? "
Here's some simple logic. You want to use a data structure to hold you pipes. What this data structure will hold is whatever data is required to paint then, like x, y, coordinates. For this task, I prefer just to create a new class with it's own draw method, that I pass the paintComponent's Graphics context to. For example
public class Pipe {
int x;
int y;
public class Pipe(int x, int y) {
this.x = x;
this.y = y;
}
public void drawPipe(Graphics g) {
g.fillRect(x, y, 50, 100);
}
}
Now this is just an example class. The above only draws a rectangle, but this is just to show you what you should be doing.
So next you want to have the data structure to hold three Pipe objects, like an array. I prefer to use a List. You'll want that List in your Pipes class, and add three Pipe object to it. You can specify the x to be anything you like, to keep them the same distance apart
public class Pipes extends JPanel {
List<Pipe> pipes = new ArrayList<Pipe>();
public Pipes() {
pipes.add(new Pipe(50, 100));
pipes.add(new Pipe(150, 100));
pipes.add(new Pipe(250, 100));
}
}
Now in the paintComponent method, all you need to do is loop through them and use its drawPipe method
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for ( Pipe pipe : pipes ){
pipe.drawPipe(g);
}
}
Now you move them all you need to do is move there x positions in the timer, and call repaint. You may also want to check against the x to make sure it doesn't do off the screen, or if you moving them the right, you could put them the the very left then whey go off the screen, like a conveyor belt. So you could do something like this
private static final int X_INC = 5;
...
Timer timer = new Timer(40, new ActionListener(){
public void actionPerformed(ActionEvent e) {
for (Pipe pipe : pipes ){
if (pipe.x >= screenWidth) {
pipe.x = 0;
} else {
pipe.x += X_INC;
}
}
repaint();
}
});
As you can see, what I do is loop through the List and just change all their x coordinates, then repaint(). So you can create your own Pipe class with whatever values you need to paint, and just move them around in the loop.
For the changing of speed, instead of using a hard coded vakue like 10 for the timer, use a variable delay, that you can change like with the click of a button
int delay = 100;
JButton speedUp = new JButton("Speed UP");
JButton slowDown = new JButton("Slow Down");
Timer timer = null;
public Pipes() {
timer = new Timer(delay, new ActionListener(){
...
});
timer.start();
speedUp.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (!((delay - 20) < 0)) {
delay -=20;
timer.setDelay(delay);
}
}
});
// do the same for slowDown, but decrease the delay
}
Test this out
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Mario extends JPanel {
private static final int D_W = 800;
private static final int D_H = 300;
private static final int X_INC = 5;
BufferedImage bg;
BufferedImage pipeImg;
List<Pipe> pipes = new ArrayList<>();
int delay = 50;
Timer timer = null;
public Mario() {
try {
bg = ImageIO.read(new URL("http://farm8.staticflickr.com/7341/12338164043_0f68c73fe4_o.png"));
pipeImg = ImageIO.read(new URL("http://farm3.staticflickr.com/2882/12338452484_7c72da0929_o.png"));
} catch (IOException ex) {
Logger.getLogger(Mario.class.getName()).log(Level.SEVERE, null, ex);
}
pipes.add(new Pipe(100, 150, pipeImg));
pipes.add(new Pipe(400, 150, pipeImg));
pipes.add(new Pipe(700, 150, pipeImg));
timer = new Timer(delay, new ActionListener(){
public void actionPerformed(ActionEvent e) {
for (Pipe pipe : pipes) {
if (pipe.x > D_W) {
pipe.x = 0;
} else {
pipe.x += X_INC;
}
}
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
for (Pipe pipe : pipes) {
pipe.drawPipe(g);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
public class Pipe {
int x;
int y;
Image pipe;
public Pipe(int x, int y, Image pipe) {
this.x = x;
this.y = y;
this.pipe = pipe;
}
public void drawPipe(Graphics g) {
g.drawImage(pipe, x, y, 75, 150, Mario.this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Mario Pipes");
frame.add(new Mario());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Categories

Resources