How can I display Time to my game - java

I have a falling square game that I am currently making. I need to have a score system, but I don't know how to integrate a and display that onto the game frame.
My question is how can I make a timer that counts upwards and display that in real time onto the frame of my game.
My code:
package GamePackage;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
import javax.swing.ImageIcon;
public class Game extends JPanel {
//changing these values will change the size of the game, while still remaining functional
//within the size limit specified.
public static final int WINDOW_WIDTH = 875;
public static final int WINDOW_HEIGHT = 720;
private Timer countdownTimer;
private javax.swing.JLabel lblTimer;
private String Highscore = "";
private int count;
int Health = 1;
//Creates a Square object Array
Square[] squareArray = new Square[20];
//Triangle[] TriangleArray = new Triangle[10];
Player thePlayer = new Player();
public Game() {
//initializes square objects
for (int i = 0; i < squareArray.length; i++)
squareArray[i] = new Square();
}
public static void music(){
try{
AudioStream Music = new AudioStream (new FileInputStream("/SplashDemoPackage/URF.wav"));
AudioPlayer.player.start(Music);
}catch (IOException error){}
}
private void StartGame(){
count = 14;
countdownTimer = new Timer(1000,new ActionListener() {
public void actionPerformed(ActionEvent e) {
lblTimer.setText(Integer.toString(count));
count = count -1;
if(count<0){
lblTimer.setText("0");
}
}
});
countdownTimer.start();
}
public void paint(Graphics graphics) {
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
//paints square objects to the screen
for (Square aSquareArray : squareArray) {
aSquareArray.paint(graphics);
}
// for (Triangle aTriangleArray : TriangleArray) {
// aTriangleArray.paint(graphics);
// }
thePlayer.paint(graphics);
// if(Highscore.equals("")){
// Highscore = this.GetHighScore();
// }
}
// public void DrawScore(Graphics g){
// g.drawString("Score: " + score, 0, B);
// g.drawString("HighScore: " + HighScore, 0,);
// }
public void update() {
// calls the Square class update method on the square objects
if(Health > 0){
for (Square aSquareArray : squareArray) aSquareArray.update();
}
// if(Health > 0){
// for (Triangle aTriangleArray : TriangleArray) aTriangleArray.update();
// }
}
private void mouseMove(MouseEvent evt) {
if(Health > 0){
thePlayer.PlayerMove(evt);
}
}
public void collision(){
Rectangle rectangle1 = thePlayer.bounds();//player rectangle
for (Square square: squareArray) {
if(square.GetBounds().intersects(rectangle1)){//testing all squares vs player
Health = Health - 1;
System.out.println("HIT");
if (Health == 0){
System.out.println("LOST");
}
}
}
// for (Triangle triangle: TriangleArray) {
// if(triangle.GetBounds().intersects(rectangle1)){//testing all triangles vs player
// Health = Health - 1;
// System.out.println("HIT");
// if (Health == 0){
// System.out.println("LOST");
// }
// }
// }
}
private static void GUI() throws InterruptedException {
Game game = new Game();
Player thePlayer = new Player();
JLabel lblStart = new JLabel();
JFrame frame = new JFrame();
frame.add(game);
frame.setVisible(true);
frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setTitle("Dodge The Squares");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
cursorImg, new Point(0, 0), "blank cursor");
// Set the blank cursor to the JFrame.
frame.getContentPane().setCursor(blankCursor);
frame.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(java.awt.event.MouseEvent evt) {
mouseMove(evt);
}
private void mouseMove(MouseEvent evt){
game.mouseMove(evt);
}
});
while (true) {
game.update();
game.repaint();
game.collision();
Thread.sleep(10);
}
}
public void DrawScore(Graphics g) throws InterruptedException{
while (true) {
int time = 0;
time = time + 1;
g.drawString("Score: " + time, 0, WINDOW_WIDTH * WINDOW_HEIGHT + 10);
Thread.sleep(1000);
}
}
public static void main(String[] args) throws InterruptedException {
new Scoreboards().setVisible(true);
music();
GUI();
}
}

For game usages I would suggest System.currentTimeMillis() because it is better performance wise than System.nanoTime(). An example of how you could track the time in a game:
public class Stopwatch {
private long startTime;
public void start() {
startTime = System.currentTimeMillis();
}
public float getElapsedTimeSeconds() {
return (System.currentTimeMillis() - startTime) / 1000f;
}
}
Usage:
Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
Thread.sleep(5000);
System.out.println("Time elapsed in seconds: " + stopwatch.getElapsedTimeSeconds());

Related

How to spawn multiple circles in a 2d grid? (JAVA)

I am currently trying to make a game where circles are spawned and the player must click on it to gain a score. There are a bunch of details there but I want to ask this question.
Some variables are unused there or out of place since the original code was from a snake game made by "Bro Code" on youtube. I am trying to use his code as a foundation.
How to spawn multiple circles without limit in a 2d grid? (I tested the spawnTarget() method in the always-triggering listener and it only allows a single circle to exist.)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class GamePanel extends JPanel implements ActionListener {
static final int SCREEN_WIDTH = 1600;
static final int SCREEN_HEIGHT = 1000;
static final int UNIT_SIZE = 25;
static final int GAME_UNITS = (SCREEN_WIDTH*SCREEN_HEIGHT)/UNIT_SIZE;
static final int DELAY = 75;
final int x[] = new int[GAME_UNITS];
final int y[] = new int[GAME_UNITS];
int bodyParts = 6;
int applesEaten = 0;
int appleX;
int appleY;
boolean running = false;
Timer timer;
Random random;
//
JPanel clockPanel;
JLabel clock;
long startTime;
long endTime;
//
long elapsedSeconds;
long elapsedTenthSeconds;
//
//
GamePanel() {
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
public void startGame() {
running = true;
timer = new Timer(DELAY,this);
timer.start();
clockMethod();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
if (running) {
// optional grid
for(int i=0; i<SCREEN_WIDTH/UNIT_SIZE; i++) {
g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
}
// apple
g.setColor(Color.red);
g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);
// score
g.setColor(Color.white);
g.setFont(new Font("Courier New", Font.BOLD, 40));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString(String.valueOf(applesEaten),(SCREEN_WIDTH - metrics.stringWidth(String.valueOf(applesEaten)))/2,2*g.getFont().getSize());
}
else {
gameOver(g);
}
}
public void newTargetCoords() {
appleX = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
appleY = random.nextInt((int)(SCREEN_HEIGHT/UNIT_SIZE))*UNIT_SIZE;
}
public void move() {
}
public void spawnTarget() {
newTargetCoords();
}
public void checkApple() {
if ((x[0] == appleX)&&(y[0] == appleY)) {
bodyParts++;
applesEaten++;
}
}
public void checkCollisions() {
if (!running) {
timer.stop();
}
}
public void gameOver(Graphics g) {
// score
g.setColor(Color.white);
g.setFont(new Font("Courier New", Font.BOLD, 20));
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString("score: " + applesEaten,(SCREEN_WIDTH - metrics1.stringWidth("score: " + applesEaten))/2,g.getFont().getSize());
// Game Over text
g.setColor(Color.green);
g.setFont(new Font("Courier New", Font.PLAIN, 40));
FontMetrics metrics2 = getFontMetrics(g.getFont());
g.drawString("game over",(SCREEN_WIDTH - metrics2.stringWidth("game over"))/2,SCREEN_HEIGHT/2);
}
public void restartGame() {
setVisible(false);
new GameFrame();
}
public void clockMethod() {
clockPanel = new JPanel();
clock = new JLabel("00:00");
clockPanel.add(clock);
startTime = System.currentTimeMillis();
add(clockPanel);
}
#Override
public void actionPerformed(ActionEvent e) {
if (running) {
move();
checkApple();
checkCollisions();
}
repaint();
if(timer.isRunning())
{
endTime = System.currentTimeMillis();
// elapsed quarter seconds for spawns
elapsedTenthSeconds = (endTime-startTime)/100;
// put elapsed seconds into variable
elapsedSeconds = (endTime-startTime)/1000;
// declare formatting
int min = (int)elapsedSeconds/60;
int sec = (int)elapsedSeconds%60;
String minStr = (min<10 ? "0" : "")+min;
String secStr = (sec<10 ? "0" : "")+sec;
// display elapsed time (minutes:seconds)
clock.setText(minStr+":"+secStr);
// spawn circle
spawnTarget();
}
}
public class MyKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_R) {
restartGame();
}
}
}
}
since the original code was from a snake game made by "Bro Code" on youtube
As a "general" recommendation, I'd avoid YouTube for learning code, apart from going out of date really fast, SO seems to spending an lot of time correcting the code examples coming from YouTube.
First, I'd recommend you take the time to read through Painting in AWT and Swing and Performing Custom Painting to make sure you have a baseline understanding of the painting process in Swing.
As to your question, if need to keep track what is visible. Depending on how you want it to workflow, I might have a pool of "entities" which which you can randomly pick and move them to a "visible entities" pool. When a new paint cycle runs, you'd simply paint the "visible entities".
You need to take into consideration how long an entity should be displayed and each time your "game loop" runs, you'd need to check to see if any of the visible entities have "died", at which point you'd remove from the "visible entities" pool and put them back in the "entities pool".
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class StopWatch {
private Instant startedAt;
private Duration duration;
public void setDuration(Duration duration) {
this.duration = duration;
}
public Duration getDuration() {
return duration;
}
public void start() {
startedAt = Instant.now();
}
public Instant getStartedAt() {
return startedAt;
}
public Duration getTimeRemaining() {
Instant startedAt = getStartedAt();
Duration duration = getDuration();
if (startedAt == null || duration == null) {
return Duration.ZERO;
}
Duration runtime = Duration.between(startedAt, Instant.now());
return duration.minus(runtime);
}
public boolean hasTimeRemaining() {
Duration timeRemaining = getTimeRemaining();
return timeRemaining.toMillis() > 0;
}
}
public class Target {
private int row;
private int col;
private StopWatch stopWatch = new StopWatch();
public Target(int row, int col) {
this.row = row;
this.col = col;
}
public int getColumn() {
return col;
}
public int getRow() {
return row;
}
public void spawn(Duration lifeSpan) {
stopWatch = new StopWatch();
stopWatch.setDuration(lifeSpan);
stopWatch.start();
}
public void die() {
stopWatch = null;
}
public Instant getBirthDate() {
if (stopWatch == null) {
return null;
}
return stopWatch.getStartedAt();
}
public Duration getLifeSpan() {
if (stopWatch == null) {
return null;
}
return stopWatch.getDuration();
}
public Duration getTimeRemaining() {
if (stopWatch == null) {
return Duration.ZERO;
}
return stopWatch.getTimeRemaining();
}
public boolean isAlive() {
if (stopWatch == null) {
return false;
}
return stopWatch.hasTimeRemaining();
}
}
public class TestPane extends JPanel {
private List<Target> targets;
private List<Target> visibleTargets;
private int rows = 4;
private int cols = 4;
private Target clickedTarget;
public TestPane() {
targets = new ArrayList<>(getRows() * getColumns());
visibleTargets = new ArrayList<>(getRows() * getColumns());
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
targets.add(new Target(row, col));
}
}
Timer timer = new Timer(5, new ActionListener() {
private Random rnd = new Random();
private List<Target> deadTargets = new ArrayList<>(getRows() * getColumns());
private StopWatch respawnStopWatch;
protected void restartRespawnClock() {
// Spawn a new target every second
respawnStopWatch.setDuration(Duration.ofSeconds(rnd.nextInt(1) + 1));
respawnStopWatch.start();
}
#Override
public void actionPerformed(ActionEvent e) {
if (respawnStopWatch == null) {
respawnStopWatch = new StopWatch();
restartRespawnClock();
}
if (!respawnStopWatch.hasTimeRemaining()) {
restartRespawnClock();
if (!targets.isEmpty()) {
Collections.shuffle(targets);
Target target = targets.remove(0);
Duration lifeSpan = Duration.ofSeconds(rnd.nextInt(5) + 3);
target.spawn(lifeSpan);
visibleTargets.add(target);
}
}
deadTargets.clear();
for (Target target : visibleTargets) {
if (!target.isAlive()) {
deadTargets.add(target);
}
}
visibleTargets.removeAll(deadTargets);
targets.addAll(deadTargets);
repaint();
}
});
timer.start();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
for (Target target : visibleTargets) {
Rectangle bounds = getBoundsFor(target);
if (bounds.contains(e.getPoint())) {
clickedTarget = target;
return;
}
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public int getRows() {
return rows;
}
public int getColumns() {
return cols;
}
protected Rectangle getBoundsFor(Target target) {
int width = getWidth() / getColumns();
int height = getHeight() / getRows();
int x = target.getColumn() * width;
int y = target.getRow() * height;
return new Rectangle(x, y, width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Target target : visibleTargets) {
Rectangle bounds = getBoundsFor(target);
if (target == clickedTarget) {
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
} else {
g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
g2d.dispose();
}
}
}
A couple of things to note...
I'm not caching the Target bounds as they are dynamically calculate based on the current size of the component. Realistically, you could use a ComponentListener and when componentResized is called, invalidate the cache, but this is an additional enhancement you could investigate yourself.
The time between spawning a new target is randomly between 1-2 seconds, this could be tweaked to use milliseconds instead of seconds, but I'm sure most users won't see the difference
A target has a random live span of between 2-7 seconds, feel free to modify it.
The example also demonstrates a simple way to detect when a target has been clicked, in the example above, it will simple cause the target to be filled in.
I would also consider using seperate components for the game and game over screens, possibly switching between them using a CardLayout. This reduces the complexity of the classes.

Sprites not loading

Me and a partner have been creating a game for our class. And while we are able to make shapes, we are unable load the sprite. I'm not sure all this code is necessary but it seemed like the necessary classes, and any other help with our code here would be most appreciated.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class BoardGraphics extends JPanel{
public BoardGraphics(){
initGraphics();
}
//Image Url's
String grassTS = "src/Resources/Sprites/GrassTile_1.png";
//Image objects
BufferedImage grassTI;
public void layTiles(Graphics g){
for(int i = 0; i < 21; i++){
for(int k = 0; k < 21; k++){
}
}
}
public void loadImage(String url, Image image){
try {
image = ImageIO.read(new File(url));
if(image != null){
System.out.println(url + ", has been loaded!");
}
}catch (IOException e){
e.printStackTrace();
}
}
public void initGraphics(){
setBackground(Color.WHITE);
setDoubleBuffered(true);
loadImage(grassTS, grassTI);
}
public void drawPlayer(Graphics g){
g.fillOval(5,5,32,32);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawImage(grassTI,21,21,null);
drawPlayer(g);
layTiles(g);
}
}
My partner has done most of this code, and I know very little about graphical programming in java. Also i'm trying to split these two classes apart.
import java.nio.file.Paths;
import javafx.embed.swing.*;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;
import javax.swing.*;
import java.awt.*;
public class Game extends Canvas implements Runnable {
boolean running = true;
public final int Wid = 480;
public final int Hei = 480;
public final int scale = 3;
public final String name = "Hasty Harvester";
private JFrame frame;
JFXPanel in = new JFXPanel();
public Board b;
public KeyIn input;
public BoardGraphics g = new BoardGraphics();
public boolean start = true;
public Game(){
init();
frame = new JFrame(name);
frame.setPreferredSize(new Dimension(Wid, Hei));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
input = new KeyIn(in);
frame.add(in);
frame.add(g);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void run(){
long lastTime = System.nanoTime();
double ns = 100000000.0 / 60.0;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
Farm farmville = new Farm("src/Resources/Levels/levels.txt");
b = farmville.getMap(0);
music("src/Resources/Music/CasualGameTrack_Alexandr_Zhelanov_Ingame.mp3");
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
boolean shouldrender = false;
while (delta >= 1) {
ticks++;
tick(b);
delta--;
shouldrender = true;
}
if(shouldrender) {
frames++;
render();
}
//Per second record the amount of frames + ticks, and reset them
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer +=1000;
System.out.println("Frames: " + frames + ", Ticks:" + ticks);
frames = 0;
ticks = 0;
}
}
}
public void init(){
in.setFocusable(true);
}
public void music(String mus){
Media sung = new Media(Paths.get(mus).toUri().toString());
MediaPlayer med = new MediaPlayer(sung);
med.play();
}
public void tick(Board b){
if(input.up.isPressed() == true){
System.out.println("Up");
input.up.toggle(false);
b.movePlayer("Up");
}
if(input.down.isPressed() == true){
System.out.println("down");
input.down.toggle(false);
b.movePlayer("Down");
}
if(input.right.isPressed() == true){
System.out.println("right");
input.right.toggle(false);
b.movePlayer("Right");
}
if(input.left.isPressed() == true){
System.out.println("left");
input.left.toggle(false);
b.movePlayer("Left");
}
}
public void render(){
}
public void start(){
new Thread(this).start();
running = true;
}
public void stop(){
running = false;
}
public static void main(String[] args){
new Game().start();
}
}
I found the issue was in the loadImage method as it was loading the image into a new image object.

Moving an image across a GUI in java

So I have to move my (multiple) images across a GUI, but for whatever reason my paint method is only being called twice, even though my x variable and my timer, which I am using to try and move the image, are incrementing correctly. Any help would be appriciated! Thanks
import javax.swing.*;
import java.awt.*;
import java.lang.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class Races extends JFrame
{
public int threadCount = 5;
public int x = 0;
public ImageIcon picture = new ImageIcon("races.jpeg");
public int height = picture.getIconHeight();
public int width = picture.getIconHeight();
public Races(int _threadCount)
{
threadCount = _threadCount;
int counter = 0;
while(counter<threadCount)
{
(new Thread(new RacesInner(threadCount))).start();
counter++;
}
initialize();
}
public static void main(String[] args)
{
if(args.length == 0)
{
JFrame f = new Races(5);
}
else
{
JFrame f = new Races(Integer.parseInt(args[0]));
}
}
public void initialize()
{
this.setVisible(true);
this.setTitle("Off to the Races - By ");
RacesInner inner = new RacesInner(threadCount);
this.add(inner);
this.setSize((width*20),(height*3)*threadCount);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.repaint();
}
protected class RacesInner extends JPanel implements Runnable
{
public int j = (int)(Math.random() * 50) + 20;
public void timer()
{
Timer timer1 = new Timer(j, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
x += 2;
repaint();
}
});
timer1.start();
}
public void run()
{
timer();
}
#Override
public void paint(Graphics g)
{
super.paintComponent(g);
//drawing the correct amount of icons based on input(or lack of input, default 5)
//Get the current size of this component
Dimension d = this.getSize();
//draw in black
g.setColor(Color.BLACK);
//calculating where finish line should be and drawing the line
int finishLine;
finishLine = (width*20)-(width*2);
g.drawLine(finishLine,0,finishLine,2000);
for(int i =0; i<threadCount; i++)
{
picture.paintIcon(this,g,1+x,(50*i));
}
}
public RacesInner(int _threadCount)
{
threadCount = _threadCount;
System.out.println(threadCount);
//JPanel
this.setVisible(true);
this.setLayout(new GridLayout(threadCount,1));
}
}//closes RacesInner class
}//closes races class

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);
}
});
}
}

Graphics wont clear properly

I am having problems, I want a square (fly) to be drawn and redrawn to show movement. Fine in this code when the button is pressed the fly does "move", but the old squares do not delete. I have tried enviromentPanel.repaint() updateui() and removeall() and I cannot get it to work, if I use any of them then none of the shapes appear and I get a blank screen.
import java.util.Random;
public class Fly implements Runnable{
private int xPosition;
private int yPosition;
private boolean eaten;
public Fly(){
Random randomGenerator = new Random();
xPosition = randomGenerator.nextInt(690) + 10;
yPosition = randomGenerator.nextInt(690) + 10;
eaten = false;
}
public int getxPosition() {
return xPosition;
}
public void setxPosition(int xPosition) {
this.xPosition = xPosition;
}
public int getyPosition() {
return yPosition;
}
public void setyPosition(int yPosition) {
this.yPosition = yPosition;
}
public boolean isEaten() {
return eaten;
}
public void setEaten(boolean eaten) {
this.eaten = eaten;
}
public void move(){
Random randomGenerator = new Random();
int xChange = -10 + randomGenerator.nextInt(20);
int yChange = -10 + randomGenerator.nextInt(20);
xPosition = xPosition + xChange;
yPosition = yPosition + yChange;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
move();
}
#Override
public String toString() {
return "Fly [xPosition=" + xPosition + ", yPosition=" + yPosition
+ ", eaten=" + eaten + "]";
}
#Override
public void run() {
move();
}
}
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.*;
import java.awt.*;
import javax.imageio.ImageIO;
public class Enviroment2 implements Runnable,ActionListener{
private JFrame frame;
private JPanel enviromentPanel,totalGUI,enviromentButtonPanel;
private JButton newFrogButton, resetButton, hungryButton;
private JTextField enterName;
private JLabel hungryLabel;
private ArrayList<Frog> frogs;
private ArrayList<Fly> flys;
public Enviroment2(){
totalGUI = new JPanel();
flys = new ArrayList<Fly>();
frogs = new ArrayList<Frog>();
enviromentPanel = new JPanel();
enviromentButtonPanel = new JPanel();
newFrogButton = new JButton("New Frog");
enterName = new JTextField("Enter name");
hungryButton = new JButton("Hungry!");
resetButton = new JButton("Reset");
frame = new JFrame("[=] Hungry Cyber Pet [=]");
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setContentPane(runEnviroment());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(740, 800);
frame.setVisible(true);
}
public JPanel runEnviroment(){
totalGUI.setLayout(null);
enviromentPanel.setLayout(null);
enviromentPanel.setLocation(10, 10);
enviromentPanel.setSize(700, 700);
enviromentPanel.setBackground(Color.WHITE);
totalGUI.add(enviromentPanel);
FlowLayout experimentLayout = new FlowLayout();
enviromentButtonPanel.setLayout(experimentLayout);
enviromentButtonPanel.setLocation(10, 710);
enviromentButtonPanel.setSize(700, 50);
totalGUI.add(enviromentButtonPanel);
newFrogButton.setLocation(0, 0);
newFrogButton.setSize(120, 30);
newFrogButton.addActionListener(this);
enviromentButtonPanel.add(newFrogButton);
enterName.setLocation(140,0);
enterName.setSize(120,30);
enviromentButtonPanel.add(enterName);
hungryButton.setLocation(280, 0);
hungryButton.setSize(120, 30);
hungryButton.addActionListener(this);
enviromentButtonPanel.add(hungryButton);
resetButton.setLocation(420, 0);
resetButton.setSize(120, 30);
resetButton.addActionListener(this);
enviromentButtonPanel.add(resetButton);
totalGUI.setOpaque(true);
return totalGUI;
}
public void draw(){
Graphics paper = enviromentPanel.getGraphics();
for (int i = 0; i <= flys.size()-1; i++){
System.out.println("hi");
paper.setColor(Color.BLACK);
paper.fillRect(flys.get(i).getxPosition(), flys.get(i).getyPosition(), 10, 10);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
draw();
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == newFrogButton){
Frog frog = new Frog(enterName.getText());
frogs.add(frog);
Fly fly = new Fly();
Thread t = new Thread(fly);
t.start();
flys.add(fly);
showFlys();
}
else if(e.getSource() == hungryButton){
}
else if(e.getSource() == resetButton){
frogs.clear();
flys.clear();
System.out.println(frogs);
System.out.println(flys);
}
}
public void showFlys(){
for (int i = 0; i <= flys.size()-1; i++){
System.out.println(flys.get(i));
}
}
#Override
public void run() {
draw();
}
}
This Graphics paper = enviromentPanel.getGraphics() is the start of your problems, this is not how custom painting is done.
getGraphics returns the graphics context that was used in the last paint cycle, at best it's a snap shot, at worst it can be null.
You should never maintain a reference to any Graphics context you didn't create. They can change and painting on it out of turn can produce unexpected results.
Instead, you should override the paintComponent method (probably in environmentPanel) and do all your custom painting in it.
Your second problem is your violating the thread rules of Swing - you should never create or modify any UI component in any thread other then the EDT
You might like to take a read through
Performing Custom Painting
Painting in AWT and Swing
Concurrency in Swing

Categories

Resources