I'm fairly new to java and am having trouble calling a mini tennis game I coded, following a tutorial, into another java file. Essentially a button in the Main File will call my game and display it in another JFrame. I haven't been able to get my game frame to open and I know it has something to do with the layout of my code for the game but I have tried rearranging and I haven't been able to call it because the main function throws an interrupted exception because there is a thread in there that keeps the game looping. What would I put in my main program to call it and how can I modify my mini tennis game to be able to be called? Basically, how can I modify the code below to be able to be called using a Game2 game = new Game2(); in another program? Or is there another method?
#SuppressWarnings("serial")
public class Game2 extends JPanel {
Ball ball = new Ball(this);
Racquet racquet = new Racquet(this);
int speed = 1;
private int getScore() {
return speed - 1;
}
public Game2() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
Sound.BACK.loop();
}
private void move() {
ball.move();
racquet.move();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
racquet.paint(g2d);
g2d.setColor(Color.GREEN);
g2d.setFont(new Font("Verdana", Font.BOLD, 30));
g2d.drawString(String.valueOf(getScore()), 10, 30);
}
public void gameOver() {
Sound.BACK.stop();
Sound.GAMEOVER.play();
JOptionPane.showMessageDialog(this,
"You caught it this many times " + getScore(),
"Game Over",
JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Catch the Snowball");
Game2 game = new Game2();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
}
I am not sure if i understand you correctly, but if you want to access Game2 game = new Game2(); from another class you can create static object game.
public class Game2 extends JPanel {
public static Game2 game;
...
Then you need to initialize it.
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Catch the Snowball");
game = new Game2();
and then you can access it by
Game2.game.something();
Related
I'd like to create an animation of a few objects ("Spaceships") on the screen, with a start button. This is what I have so far:
public class SpaceGame extends JPanel implements ActionListener {
//The list of spaceships that should be painted
LinkedList<Spaceship> playingList = new LinkedList<Spaceship>();
Timer t = new Timer(5, this);
#Override
public void actionPerformed(ActionEvent e) {
ListIterator<Spaceship> iter = playingList.listIterator();
while (iter.hasNext()) {
Spaceship s = iter.next();
s.moveSpaceship();
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Spaceship s : playingList)
s.drawSpaceship(g);
t.start();
}
public static void main(String[] args) {
SpaceGame game = new SpaceGame();
JFrame fr = new JFrame();
fr.setTitle("SPACE GAME");
fr.setSize(990,690);
fr.add(game);
game.playingList .add(new Spaceship(3, 0, 570));
game.playingList .add(new Spaceship(1, 250, 570));
game.playingList .add(new Spaceship(2, 500, 570));
JButton start = new JButton("START");
start.addActionListener(game);
fr.add(start,BorderLayout.SOUTH);
fr.setVisible(true);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
where:
import java.awt.Graphics;
public class Spaceship {
int initialSpeed;
int locX, locY; //current location
public Spaceship(int initalSpeed, int initX, int initY) {
this.initialSpeed = initalSpeed;
locX = initX;
locY = initY;
}
public void drawSpaceship(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(locX, locY, 100, 40);
}
public void moveSpaceship() {
locY -= initialSpeed;
}
}
Of cousre the idea is that pressing the button would trigger the animation. The problem is that the animation would start automaticaly without the start button being pressed, and then when it ends, the button has no effect. How can I fix this?
Let's start with the glaringly obvious...
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Spaceship s : playingList)
s.drawSpaceship(g);
t.start();
}
Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.
You should have a look at Painting in AWT and Swing for more details about how painting works in Swing
Painting should simply paint the current state of the component and nothing else.
The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.
So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...
public class SpaceGame extends JPanel implements ActionListener {
//The list of spaceships that should be painted
LinkedList<Spaceship> playingList = new LinkedList<Spaceship>();
Timer t = new Timer(5, this);
public void start() {
if (t.isRunning()) {
return;
}
t.start();
}
#Override
public void actionPerformed(ActionEvent e) {
ListIterator<Spaceship> iter = playingList.listIterator();
while (iter.hasNext()) {
Spaceship s = iter.next();
s.moveSpaceship();
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Spaceship s : playingList) {
s.drawSpaceship(g);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SpaceGame game = new SpaceGame();
JFrame fr = new JFrame();
fr.setTitle("SPACE GAME");
// This is unadvisable :/
fr.setSize(990, 690);
fr.add(game);
game.playingList.add(new Spaceship(3, 0, 570));
game.playingList.add(new Spaceship(1, 250, 570));
game.playingList.add(new Spaceship(2, 500, 570));
JButton start = new JButton("START");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
game.start();
}
});
fr.add(start, BorderLayout.SOUTH);
fr.setVisible(true);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
}
Then update your main method to call it...
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SpaceGame game = new SpaceGame();
JFrame fr = new JFrame();
fr.setTitle("SPACE GAME");
// This is unadvisable :/
fr.setSize(990, 690);
fr.add(game);
game.playingList.add(new Spaceship(3, 0, 570));
game.playingList.add(new Spaceship(1, 250, 570));
game.playingList.add(new Spaceship(2, 500, 570));
JButton start = new JButton("START");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
game.start();
}
});
fr.add(start, BorderLayout.SOUTH);
fr.setVisible(true);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
This question already has an answer here:
Best way to animate in Java?
(1 answer)
Closed 5 years ago.
I have made a small platformer game, but I can't get any game logic to execute. I have figured out that this is caused because for some reason, the game gets caught on createFrame().
How can I get customUpdate() to run when the code gets caught on createFrame()? I have tried calling the code inside of createFrame(), but that creates infinite JFrame windows.
import javax.swing.*;
import java.awt.*;
public class Main extends JPanel {
private boolean running = true;
private Player player = new Player(50,50,25,50,100, 100);
public static void main(String[] args) {
Main main = new Main();
main.createFrame();
while (main.running) {
try {
Thread.sleep(1000 / 60);
main.customUpdate();
} catch(Exception e) {
e.printStackTrace();
}
}
}
private void createFrame() {
JFrame frame = new JFrame("Matt's game");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(800,500);
frame.setResizable(false);
frame.add(this);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void customUpdate() {
this.revalidate();
player.changePlayerX(1);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(player.getPlayerX(), player.getPlayerY(), player.getPlayerWidth(), player.getPlayerHeight());
}
}
While I agree with comments, here is an example (without thread) and basically "repainting" based on some events...
Since your Player class was not available, I tried with "boolean" that changes the color of player. :) And it changes player based on mouse event. You can update based on your event.. Also I need to call repaint..
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Main extends JPanel {
private boolean running = true;
//private Player player = new Player(50, 50, 25, 50, 100, 100);
public static void main(String[] args) {
Main main = new Main();
main.createFrame();
main.addMouseListener( new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent ex)
{
main.customUpdate();
}
});
// main.customUpdate();
/* while (main.running) {
try {
Thread.sleep(1000 / 60);
main.customUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}*/
}
private void createFrame() {
JFrame frame = new JFrame("Matt's game");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(800, 500);
frame.setResizable(false);
frame.add(this);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void customUpdate() {
this.revalidate();
this.repaint();
//player.changePlayerX(1);
System.out.println("Player changed...");
}
boolean isRed=false;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("red..."+isRed);
if(isRed)
{
g.setColor(Color.GREEN);
}
else
{
g.setColor(Color.red);
}
isRed=!isRed;
g.fillRect(10, 10, 100, 100);
//g.fillRect(player.getPlayerX(), player.getPlayerY(), player.getPlayerWidth(), player.getPlayerHeight());
}
}
I am doing a java assignment for next Saturday.
Its going really well, however I'm struggling with one section.
Here I want to reveal a set of numbers in a String, one at a time.
I tried slowing down the loop with 'Thread.sleep(1000);'
however nothing is displaying until the thread is finished
the following is a section of the graphics class where the problem is occuring
is there something I'm missing?
public void paint(Graphics g)
{
setSize(550, 300);
//this draws all the random numbers, revealing the ans to the user
if (revealNum == 0)
{
g.setColor(Color.BLUE);
g.drawString(randomNumber, 20, 20); //draw String ("the String", x, y)
}
//this reveals the numbers 1 by 1 to the user at the start of the game
if (revealNum==1)
{
for (int x = 0; x < limit; x++)
{
g.setColor(Color.BLUE);
g.drawString(""+x, 20, 20); //draw String ("the String", x, y)
try{
Thread.sleep(1000);
}catch(InterruptedException ex){
System.out.print("Error");
}
repaint();
}
//slow down the loop to show the user
}
Since yours is a GUI, calling Thread.sleep will put the entire app to sleep. Instead use a Swing Timer. Inside the Timer's ActionListener, add another letter to the displayed String, and then stop the Timer via the stop() method once the String is complete.
e.g.,
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class SimpleAnimation extends JPanel {
public static final int TIMER_DELAY = 1000;
private JTextField textField = new JTextField(10);
private JLabel displayLabel = new JLabel("", SwingConstants.CENTER);
public SimpleAnimation() {
Action btnAction = new DoItBtnAction("Do It!", KeyEvent.VK_D);
JPanel topPanel = new JPanel();
topPanel.add(textField);
topPanel.add(new JButton(btnAction));
textField.addActionListener(btnAction);
setLayout(new GridLayout(2, 1));
add(topPanel);
add(displayLabel);
}
private class DoItBtnAction extends AbstractAction {
private String textFieldText = "";
public DoItBtnAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
displayLabel.setText("");
setEnabled(false);
textFieldText = textField.getText();
new Timer(TIMER_DELAY, new ActionListener() {
private int i = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (i >= textFieldText.length()) {
((Timer) e.getSource()).stop();
DoItBtnAction.this.setEnabled(true);
} else {
displayLabel.setText(displayLabel.getText() + textFieldText.charAt(i));
i++;
}
}
}).start();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SimpleAnimation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleAnimation());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also,
If yours is a Swing GUI, it would be easier to display your text in a JLabel or a JTextField rather than trying to paint it on the GUI.
If this is Swing, don't override paint(Graphics g) but rather the paintComponent(Graphics g) method of a JPanel or JComponent.
You should use a javax.swing.Timer
Here is an example
JLabel l = ...;
Timer t = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (l.getText().equals("1")) l.setText("2");
else if (l.getText().equals("2)) l.setText("1");
}
});
I am making a little game applet, and I have gotten to where the player should move around with the controls.
Main:
public class Main extends JApplet implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
private static DoubleBufferedCanvas canvas = new DoubleBufferedCanvas();
public static int width = 900;
public static int height = 600;
public static int fps = 60;
public static Ailoid ailoid = new Ailoid();
public static Player player = new Player();
// Initialize
public void init() {
setSize(width, height);
setBackground(Color.white);
add(canvas);
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
ailoid.setLocation(new Location(100, 100));
AlienManager.registerAlien(ailoid);
player.setLocation(new Location(400, 400));
}
// Paint graphics
public void paint(Graphics g) {
super.paint(g);
}
// Thread start
#Override
public void start() {
Thread thread = new Thread(this);
thread.start();
}
// Thread stop
#Override
public void destroy() {
}
// Thread run
#Override
public void run() {
Thread thread = new Thread(this);
while (thread != null) {
Updater.run();
canvas.repaint();
try {
// 1000 divided by fps to get frames per second
Thread.sleep(1000 / fps);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void keyPressed(KeyEvent evt) {
KeyPress.run(evt);
System.out.println("DEBUG");
}
#Override
public void keyReleased(KeyEvent evt) {
}
#Override
public void keyTyped(KeyEvent evt) {
}
}
What happens is that it only starts saying "debug" after I press tab. How would I make it work even if the player doesn't press tab before?
Your Applet most likely does not have the input focus.Try adding
this.requestFocus ()
to your init method.
Also note that a JApplet is a part of the Swing framework and thus not threadsafe as mentioned in the documentation
public static void main(String[] args) {
JFrame frame = new JFrame(GAME_TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
sGame = new Game(GAME_WIDTH, GAME_HEIGHT);
frame.add(sGame);
frame.pack();
frame.setVisible(true);
frame.setIconImage(Resources.iconimage);
}
I had the same problem, it was caused in main by not calling everything in the correct order.
Originally I had setVisible(true) before I had passed sGame to .add and called frame.pack().
This code is what worked for me.
As shown below in code, i'm getting x and y values of line from the database. And then storing them in an array x. After that i'm trying to draw this line on the Frame, but it is not getting drawn. How can i draw line on Frame?
public class TestFrame{
static JFrame test;
public static void main(String ar[]){
test=new JFrame("Test");
JButton openLine=new JButton(new AbstractAction("Open Line"){
public void actionPerformed(ActionEvent e) {
String lineId=JOptionPane.showInputDialog("Enter Line id");
ImageComponent image=new ImageComponent();
image.openLine(lineId);
}
});
test.add(openLine, BorderLayout.NORTH);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(600,600);
test.setVisible(true);
}
static class ImageComponent extends JComponent{
static int[] x=new int[100];
static ArrayList al=new ArrayList();
public void openLine(String line_id){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con=DriverManager.getConnection("jdbc:odbc:image");
Statement pstm=con.createStatement();
ResultSet rs=pstm.executeQuery("select * from Line where ID= '"+line_id+"'");
while(rs.next()){
x[0]=rs.getInt(3);
x[1]=rs.getInt(4);
x[2]=rs.getInt(5);
x[3]=rs.getInt(6);
al.add(x);
}
repaint();
} catch (Exception ex) {
System.out.println("Exception : "+ex);
}
}
public Graphics2D gd;
Line2D[] line=new Line2D[100];
protected void paintComponent(Graphics g) {
super.paintComponent(g);
gd=(Graphics2D)g;
gd.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(int i=0;i<al.size();i++){
line[i]=new Line2D.Double(x[0], x[1],x[2],x[3]);
gd.draw(line[i]);
}
}
}
}
Here is one approach that uses a BufferedImage as a rendering surface.
The OP in that question was asking about an applet, but I displayed the image in an option pane. It is just as well suited to display in a frame etc. without any confusion over whether to override paint(Graphics) or paintComponent(Graphics). ;)
You can use the Graphics object and override the paint() method like so:
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.gray);
int x = 5;
int y = 7;
g2.draw(new Line2D.Double(x, y, 200, 200));
g2.drawString("Line2D", x, 250);
}
Taken from here
You shouldn't directly on a JFrame. All rendering in the main body of JFrame is done in the contentpane. Menu content is done in the JMenuBar
One issue is that you create a new ImageComponent every time the button is clicked but it is not added to your frame.
Another one is that you fill in an arraylist (al) but don't use it to actually draw your line.
This works for me with dummy values for x[0], x[1], x[2], x[3]:
static JFrame test;
static ImageComponent image = new ImageComponent(); //declared as a class member
public static void main(String ar[]) {
test = new JFrame("Test");
JButton openLine = new JButton(new AbstractAction("Open Line") {
public void actionPerformed(ActionEvent e) {
String lineId = JOptionPane.showInputDialog("Enter Line id");
image.openLine(lineId);
}
});
test.add(openLine, BorderLayout.NORTH);
test.add(image); //ADD THE IMAGE TO THE FRAME
image.setVisible(true);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(600, 600);
test.setVisible(true);
}