I'm trying to create a java game in which balls randomly drop from the top of the screen and we need to catch the balls using a catcher which is located at the bottom of the screen.
I'm having a difficult time figuring out how to actually draw this onto my JFrame.
I've got a class for my 'catcher', 'ball', 'game space' and I would like to put it all together.
How do I draw my 'catcher' onto my screen?
Currently, I have a 'Game' class which looks like this.
public class Game extends JFrame implements KeyListener {
GameScreen gameScreen;
Catcher playerOneCatcher;
public static void main (String[] args) {
new Game();
}
public Game() {
super("CATCH");
setSize(640,480);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLocationRelativeTo(null);
setResizable(false);
addKeyListener(this);
this.gameScreen = new GameScreen();
this.playerOneCatcher = new Catcher(40, 10);
}
I've tried something like this in my Catcher class...
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(positionX, positionY, this.width, this.height);
}
However, its not showing on my screen.
Any help would be greatly appreciated.
You need to rethink your strategy here. Swing is a component framework, with most components intended for building user interfaces. These components are not optimised for what's typically required in games. You want to look into double-buffering, sprites etc. The way to go will be to read up on Graphics2D class (or abandon Swing altogether!)
However answering to your question - if Catcher is a Swing component - you need to add it to the "parent" component, e.g. like this:
this.add(playerOneCatcher);
Same goes to gameScreen but from your snippet it is not obvious what this component is. I hope this helps.
Also, check this out for some ideas: 2D Java Game. Moving sprite above tiled images
Did you call super.paintComponent (g) ? That can cause a few bugs.
Did you call invalidate () or repaint () to repaint the thing you are painting on? I hope you have a special JComponent, and you are not drawing on a JFrame. That is NOT good.
Related
As a coursework piece for school, we had to come up with a self-defined project, which I chose a game idea I was originally going to write on actionscript but decided to push for it on Java. This was initially going well, with the game code working, the sprite animations were being handled fine and everything was being maintained within a game loop. That was until i began to try and add components such as buttons and labels to it.
Currently the structure of my game is as this( GameSystem[handles loop and redrawing] -- GameMenu [Simple intro screen with start game ] <---swaps between ---> GameContainer [holds information about the game] )
My loop inside the GameSystem updates all necessary objects, repaints and then tells all the objects to repaint after.
Game System:
/**/for(int i = 0; i < UpdateList.size();i++){
/**/UpdateList.get(i).Update(delta * 1.1); // tell list the element is an object that extends an interface
/**/}
/**/Game.repaint();
/**/#Override
/**/public void paint(Graphics g) {
/**/super.paint(g);
/**/Graphics2D g2d = (Graphics2D) g;
/**/g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
/**/ RenderingHints.VALUE_ANTIALIAS_ON);
/**/for(int i = 0; i < UpdateList.size();i++){
/**/UpdateList.get(i).paint(g2d); // tell list the element is an object that extends an interface
/**/}
/**/}
This is where it starts getting iffy, because the game system repaints it's self each loop, clearing the frame of previous stuff, the buttons which I add in my gamemenu which is created inside the game system get cleared and only reappear briefly when you mouse over them.
Game Menu:
//////////////////
// Start Button //
//////////////////
Buttons = new JPanel();
Buttons.add(Start_game = new JButton("Start Game"));
this.add(Buttons);
Start_game.addActionListener(new Load());
/**/}
///////////////////
//////////////////
//Paint sprite //
//////////////////
#Override
/**/public void paintComponent(Graphics g) {
/**///super.paintComponent(g);
/**/Buttons.paintComponents(g);
/**/}
////////////////////////////////////
At this point I've tried paint, paint component, revalidate() and a variety of other stuff I've gleamed from other posts but none have helped. The only way I've had the button appear visible is if I remove the call to repaint in the game loop. However this then impacts the game as none of the objects are repainted.
TL DR: How can I Handle repainting the various objects in my update list and refreshing the Gamesystem panel without making any components such buttons disappear? Sorry if this is a noobish question but this is my actual first time working with Java as I wanted to expand outwards from actionscript, if any more info is required i will gladly add to the post, thank you for your help.
The problem is that you are trying to handle the painting of the buttons differently than the painting of your game.
Game System
{
paint loop
{
painting Game
}
}
Components //managing the painting itself through paintComponent, trying to run at same time as Game System.
{
paintComponent
}
So in effect, you are wanting to switch one to the other. You could either use paintComponent() in the GameSystem instead of paint(), which manages disposing of the graphics and repainting for you (if it is already extending a jComponent)...
or you need to start managing the buttons' painting similar to how you do it for your game, instead of relying on paintComponent()
I'm looking to make it so I have a separate window that would show anything, but for my purpose I would like it to show things like the location of objects, their status(whether they have collided with something etc) and so on, the problem is, I have no idea how to go about this.
I would use System.out.println("Stuff: " + thing); but the information would move up too fast.
I made and awesome image to somewhat illustrate what I'm after.
(Edit)
So what I'm looking for is how to make two separate windows like in the picture. They are separate, yet still the one program. The blank behind it is the desktop(Which I should have made a bit more clear) The 2nd debug window can do anything the main window can(By that I mean it can render shapes, images and such). All I'm asking is, how do I achieve this?
What on this would I add/change and where, to make it work?
public class Game extends JFrame implements Runnable, KeyListener
{
JFrame frame;
Graphics2D g2d;
public static void main(String[] args)
{
new Game();
}
public Game()
{
frame = new JFrame();
setTitle("Battle for the Roids");
setSize(SCREENWIDTH, SCREENHEIGHT);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
// Set up assets and initialize loop
}
// Lots of lines later
public void paint(Graphics g)
{
// Set up double/triple buffering
BufferStrategy bs = getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3);
return;
}
g2d = (Graphics2D) g;
g2d = (Graphics2D) bs.getDrawGraphics();
// Add things to be rendered
g2d.dispose();
bs.show();
}
}
I have lots of extra code in there but nothing that would be required. Mostly moving, rotating, key handling etc code.
Idk if this would help you or not, but what you could possibly do is create a new JFrame and have it appear using another class. Create a JLabel object, and have it set all the information for how ever many objects you need to use.
For example, if you want to have it show the user data you might wanna try:
public class WindowSample extends JFrame {
JLabel userData = new JLabel();
add(userData);
userData.setText(//information for user data);
}
hope this helps!
You could use Log4J and write your own appender whose sole responsibility was to output to something like JTextArea or JList, this would decouple the two halves of your application. Then all you would need to do would be to use the Logger to write information about the state of your application.
If that didn't meet your needs, you could write some kind of listener/observer/call-back API that linked into your game model.
You would then be able to respond to changes to the model directly. This has the draw back of potentially slowing you game engine, as it would need to fire updates any time any part of the application changed.
You could over come this by using a separate thread to dispatch these events, but that's still adding overhead.
Personally, I like the second option, but the first is easier to implement ;)
I am trying to create a simple application that shows a red circle that when clicked displays different messages under it. I believe that this part of the code:
g.drawString("DO NOT PRESS", 100, 100);
is coded correctly but no text is displayed on the window that opens. Here is the full code so far:
import java.awt.Graphics;
import javax.swing.JFrame;
public class BigRedButton extends JFrame {
public BigRedButton() {
setTitle("Big Red Button");
setSize(500, 500);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void graphics(Graphics g) {
g.drawString("DO NOT PRESS", 100, 100);
}
public static void main(String[] args){
new BigRedButton();
}
}
There is no such method graphics in JFrame, so nothing is calling it.
You should avoid painting directly to top level containers, apart from everthing else, they're not double buffered and will flicker when painted. You should, instead, create a custom component (extending from something like JPanel) and override it's paintComponent method.
You should take the time to read through Performing Custom Painting, Painting in AWT and Swing and 2D Graphics
Also, while your reading up, you should have a read through Initial Threads
Amendment
As pointed out by Andrew, you should use the #Override annotation to ensure that the method you think you are overriding is actually the method being overridden in the first place. This would stop the program from being compiled and save lots of lost time trying to figure out why things aren't working the way you expect them.
I'm currently using an animation engine I designed that takes objects of type Drawable and adds them to a List. Drawable is an interface that has one method:
public void draw(Graphics2D g2d);
The extending animation manager iterates through this list and calls the draw() method on every object, passing the Graphics2D object obtained from the Swing component.
This method seemed to work well at first, but as I feared, it seems to be unable to handle multiple objects in the long run.
With merely two Drawables registered, both drawing images on screen, I'm seeing a bit of flashing after 30-60 seconds.
Is there a way to optimize this method? It currently calls upon the AWT thread (invokeLater) to handle all of the tasks. Concurrent drawing isn't really an option as this nearly always causes issues in Swing/AWT, in large part due to the fact that Graphics isn't synchronized.
If this just simply is a bad way of animating, what is a better method when you have multiple objects that all need things rendered with their own specific variables cough game cough?
Any help would be appreciated. Thanks!
EDIT:
I can't use repaint() beacuse my engine already calls the AWT thread to paint stuff. If I call invokeLater from the AWT thread, the image never gets painted for some reason.
I should also add that I'm using a system of ticks and fps. 60 ticks # 120 fps.
Each tick updates the game logic, while each frame render calls draw on the frame manager.
Is this a bad idea? Should I just use FPS and not ticks?
I think it would be more appropriate to override paintComponent(Graphics g) and regularly call the repaint method on the JPanel or whatever you're drawing on with a Timer. Your problems may be due to to you trying to draw and then Swing doing it's own draw.
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel() {
public void paintComponent(Graphics g) {
//draw here
}
};
panel.setPreferredSize(800, 600);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true)
new Timer(16, new ActionListener() {
public void actionPerformed(ActionEvent event) {
panel.repaint();
}
}).start();
}
}
I'm working on recreating "Legend of Zelda a Link to the Past" as part of an assignment.
And I've got the following problem, the game world is a BufferedImage of which I subImage() the part I need for the current location of the player. The game works but uses 80 / 110 percent of the CPU. A profile revealed that the culprit is the drawing of the image.
So I figured I put the background in a separate JPanel from the Player, enemies etc JPanel.
Render them on top off each other (JLayeredPane) and repaint the background panel far less often.
But how do I do this how do I tell swing to draw one panel x times a sec and the other y times? If you have a better way of optimizing let me know.
Here's what I've got at the moment:
public class Main extends JFrame
{
private ZeldaGame game = new ZeldaGame();
private View view = new View(game);
private BackgroundView bckView = new BackgroundView(game);
private Controller ctl = new Controller(game, view, bckView, this);
public Main()
{
setLayout(null);
view.setBounds(0, 0, game.getWidth(), game.getHeight());
bckView.setBounds(0, 0, game.getWidth(), game.getHeight());
JLayeredPane pane = new JLayeredPane();
pane.add(bckView, 1);
pane.add(view, 0);
setLayeredPane(pane);
setSize(game.getWidth(), game.getHeight());
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args)
{
new Main();
}
}
Thank You.
It's not really possible to have different render times because of the way the framebuffer works -- what the result would be is loads of nasty flickering. What you need to do is using Canvas instead of JPanel and JLayeredPane and you can either override the paint() method of the canvas or use bi.getGraphics() and blit the background and the characters on a loop using either of these methods in the correct order. I'd advise using a thin engine like GTGE which will abstract from all the messy details of optimisation. These high level components you're using seriously aren't designed for games, and you shouldn't be using them at all.
Ok I've found the error of my ways. I was using passive rendering while I should have used active rendering. Active rendering basically shuts down the automatic repaints by calling setIgnoreRepaint(true); on the frame and do the loop yourself.
And as an added bonus I don't need to use JPanels.