I am trying to program a Battleship game with different states depending on user input. I am implementing the State Design Pattern for the different types of game types, the instructions panel and other features it is going to have. My question is, when I make the JFrame for my game, should the logic be invoked during construction, or should it be during the update of the window?
For example:
public class BattleshipGui extends JFrame
{
public BattleshipGui()
{
initizalizeFrame();
executeLogic();
}
}
The execute logic contains the game loop that changes according to the game events.
The GUI should only be responsible for rendering. All actual game logic should be handled on your main thread, while the EDT is painting for you (repaint posts events to the EDT). As for "invokingGameLogic", this should first never be done in the constructor (considering that method contains the loop thats updating your game). You should initFrame then start your loop dedicated to updating/rendering your game. Create an interface between updating and rendering; have variables that both rendering code and updating code can access. That way, your render code renders whatever the current state is, while update code changes it.
class Game extends Canvas {
//the items used between render and update
Player player;
Enemy player;
//render values
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLUE);
g.fillRect(player.x, player.y, 50, 50);
g.setColor(Color.RED);
g.fillRect(enemy.x, enemy.y, 50, 50);
}
//affect values
public void update() {
player.x++;
}
}
Keep your game logic away from your rendering. It makes programming a game easier, since you'll be able to easily find code that handles graphics, and what code handles moving players and what not.
If you are using Component#paint(Graphics), then you REALLY want to seperate the game logic from rendering. Code within the paint method executes om the Event Dispatch Thread, meaning issues with updating will cause very apparent issues in GUI.
Related
I need a code, more specifically a game, in which meteorites fall down and the user has to dodge them with the arrow keys.
Moving the player is not my problem. I will do this at the end.
I figured out how to create an animated object falling down, from top to bottom.
How can I create a loop which creates one new falling element every 2 seconds? The position of the element should be randomized.
This is my code at the moment:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel {
int x = 135;
int y = 0;
private void moveBall() {
y = y + 1;
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, 30, 30);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Meteorites");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
}
You will need a game loop (gl) first of all. The gl updates the state and position of every object on the screen and other state related objects not seen on the screen.
It should be easy for objects to register themselves to the gl. The gl is not responsible for updating the state of every object, but it does call back every registered object to update themselves (or update other objects that it is responsible for, for example the collision detection object will update any objects on the screen that have collided).
The gl passes the current time in nano-seconds (typically) to all the objects that have registered with the gl. For example check out the AnimationTimer in Javafx. In JavaFX, by creating an AnimationTimer, and calling the start method on it, JavaFX will call your handle method on every frame... essentially registering it to JavaFX's main thread (or game loop).
So you will need to create a gl. Register objects to it, maybe create an interface or abstract class similar to JavaFX's AnimationTimer so that objects can register themselves to your gl. The gl should not have any Thread.sleeps in it, but if it does it should be very short and I imagine you would add it in only if your gl is going to fast, because maybe there is not a lot of stuff being calculated (hence no use crippling the CPU), but you can adjust this. I know that working on JavaFX games I can tell you that we work very hard to keep any delays in he gl down to a minimum, hence no Thread sleeps, as this will halt the smooth flow of your animation.
The objects that get updated will track the passage of time and can execute events based on how much time has passed by. For example you can have an object that registers itself to the gl and is responsible for putting new falling animated objects on the screen. It can have a field for how long to wait before dropping the next item. Since it is called every frame by the gl, it can see how much time is passing by, and when x seconds pass by, it can create and drop the next object, then reset its timer.
The animated objects falling would also be called by the gl so they can smoothly drop down. At every frame these falling objects will calculate their new position. Typically this is done using an interpolator (its a good idea to look into this). Interpolators make it easy to abstract out where the position of an animating object should be relative to a fraction of time passing by. For example if I am moving an item linearly over X distance and Y time, an interpolater will tell you how far along X distance the object should be after a percentage of Y time has passed. Interpolators are very powerful because you can create an interpolator that moves your object not just linearly but can slow it up or speed it up (like gravity effect), it can even add bouncing effects to your objects. So you'll want to get a firm understanding of this. JavaFX comes with interpolators. There are also online tools I have seen in the past that let you construct your own JavaFX interpolators based on the kind of animation effect you are trying to get.
So to put it all together, have a gl, have an object that registers to the gl that is responsible for putting new falling objects on the screen, lets call this object ObjectDropper. The ObjectDropper will implement something like AnimationTimer so it can get called every frame by your gl. It will decide when to drop objects and can also decide the random point from where that object will drop. You will have objects that will drop, they will be given information like where their starting point is, where their ending point is, and how long it will take to drop, and maybe even an interpolator. These objects will also be registered to the gl and be called every frame so that they can adjust their position according to their interpolator.
This is all a very broad generic outline that tends to be true for most animated games. There might be tools and libraries that make this all easily implemented in Swing. As you can see JavaFX was already designed to handle many of these concepts.
I am creating a java 2D game and have come to a point where I am thinking of creating "pop-up graphics" i.e graphics that will populate the screen when a certain event occurs. Say, you pick up a certain item, I want this item to be displayed in the middle of the screen in a box containing information about said item.
Currently I have one big paintComponent that paints all of the graphics for the game (tiles, entities, players etc (which has been done efficiently I might add)). I know that I can probably have a boolean value which checks if an item has been picked up in that method, but it feels wrong.
What I am wondering is, is there a way for items to have their own paintComponent so that when it is called, it will show say a bo for a brief period WITHOUT having a boolean value in the big paintComponent method that I currently use for everything?
Small code example (won't execute)
public class popUpGraphics extends (JComponent or JPanel or whatever works best for this scenario)
{
public popUpGraphics(){
}
#Override
protected void paintComponent(Graphics g){
//g.Draw(stuff);
}
}
and then somewhere in an event I instantiate this or somesuch.
I do not want this to override the other paintcomponent, I just want to add to it
(as if it was another layer) to the paintComponent
In short I want to know:
1. Is is possible to have brief graphics shown without including in the huge paintComponent method
2. What Swing library should be extended (JComponent, JPanel etc)
Thanks in advance!
so i am dabbling in making a game and i am a fairly messy worker and then i go back and tidy it up. So please ignore any stupid naming conventions or methods or anything. As I go back later and tidy up.
So basically I am trying to make a main menu, i just want to draw something to the screen and have it stay there. I am writing the graphics to a image ATM and displaying the image as i tried just drawing to the canvas and it just flickered up onto the screen and then it went blank. I changed it to a runnable so i could put in sleep() to try and error hunt. I've removed all my error hunting code now. It turns out when i have a sleep() before or after the image is put on the screen for longer than 50ms the rectangle stays on screen and doesn't flicker away like 1ms after it was drawn.
I'm not sure what's going on. I am probably not that clear and I apologies.
import java.awt.Canvas;
import java.awt.Graphics;
import javax.swing.JFrame;
public class test extends Thread{
public static void main(String[] args){
test t = new test();
t.start();
}
#Override
public void run() {
JFrame f = new JFrame("Test");
Canvas c = new Canvas();
Graphics g;
c.setSize(400, 400);
f.add(c);
f.pack();
f.setVisible(true);
c.setVisible(true);
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
g = c.getGraphics();
g.drawRect(10, 10, 40, 68);
}
}
Basically, this is not how painting in AWT works. Painting should be done within the context of a component's paint method. In AWT Canvas seems to be the preferred base component to use.
You should never use getGraphics, apart from been able to return null, it will only represent the Graphics context from the last paint cycle, anything added to it could be wiped about by newer paint events...which is probably happening to you.
Take a look at Painting in AWT and Swing for details about how painting works.
Having said all that, I would discourage you from using AWT based API as it was replaced by Swing some 15 years ago.
Take a look at Performing Custom Painting for more details about painting in Swing
You're kind of getting the idea, but there are a few standard design patterns of creating a game, for starters check out this code.
Basically, you'll need something called a game loop which will update and render to the display a certain amount of times every second (framerate or fps). When it renders, it will clear and redraw the image in a new location at a certain interval, if your fps was 60 you would be rendering (clearing, and redrawing) 60 times a second. We can also introduce more advanced concepts such as buffer strategies (shown in the example above) to reduce tearing and flickering.
To sum it up, you're kind of there, you just need to constantly do that g = c.getGraphics() so...
while (true) {
g = c.getGraphics();
// set color
// draw a rectangle
g.dispose();
}
Note how I added the dispose, this will just free up any unused memory. Just to clarify, this is by no means good code, but it will give you a place to start :)
The flickering is due to only having 1 screen, to stop this flickering you need a buffer strategy. Basically having two buffers is like having two screens, whilst you render on one 'screen' you can clear and draw the next step on the second screen and switch between the two buffers; this reduces the flickering.
I'm currently in the process of making a 2D turn based strategy game in Java. At this stage in development I am testing out different varieties of AIs.
The AIs interact with the game by sending a x and y variable to a function called gameLoop, which would would normally be called by a mouseClicked function. This allows them to directly emulate a human user which has made having them interact with the game much easier. Below is an overview for some of my code:
paintComponent() {
drawTiles();
drawUnits();
if(unitSelected && gameState == DISP_MOVE)
drawMoveSpots();
}
gameLoop(int x, int y) {
// various logic based
// on the values of x and y
// logic may set unitSelected to true or false
// may also change gameState bteween normal and displayMoveSpots
repaint();
}
My issue right now stems from the fact that the AI is executing code faster than repaint happens. When this happens, I start getting errors such as NullPointerException's and ConcurrentModificationException's in my various drawing functions because the logic inside of gameLoop is changing variables faster than repaint can happen. If I add in a manual delay to how often the AI calls gameLoop or only have 2 humans playing, the errors disappear.
From my research and reading of the Java docs, I understand that repaint returns immediately and all the graphics calls are put onto the EventQueue until Java decides that there are enough calls to warrant an actual repaint. The only solution I have been able to find so far is putting the logic code that happens in gameLoop into a anonymous runnable class and call the code using SwingUtilities.invokeAndWait, but this is not a valid solution for me, because this causes actual human interaction from clicking to bug out. I have considered using a lock to provide mutual exclusion to gameLoop's logic section/repaint (so only one can execute at a time), but I'm not sure if this is a good practice when dealing with Java graphics.
At this point I'm open to any suggestions on what I can do to alleviate my problem.
Thanks.
My advise is that you should use a swing timer
import javax.swing.Timer;
public static void main(String[] args) {
/*this is 1 sec/ 1000ms*/
Timer aiTimer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//move AI
//repaint
}
});
aiTimer.start();
}
By doing that you will not repaint so often. Hope that helps!
-Hi all! I'm making a Java applet that simulates wave interference, which I have almost finished (will license under GPL). However, I have two questions regarding the AWT paint cycle that I am having difficulty finding answers to.
I want to make an 'about' overlay that appears when I press a button. The way I want to do this is to draw over the entire applet window with my static message and legend objects. The problem is stopping the AWT components from drawing themselves in the foreground without using remove(). Is there a way I can stop AWT from drawing itself temporarily?
For my standing waves mode I want to have node and anti-node markers calculated and drawn to a secondary graphics every time the standing wave reaches a maximum amplitude (all of which I can do myself), but drawn to the primary graphics (and thus displayed) every paint cycle. Could someone explain the steps to do so? I imagine it would involve creating a second graphics object, drawing to it once, then drawing it to the primary graphics every cycle.
If you are able to answer either of my questions I would be very grateful!
Cheers, Jack Allison
Responding to your first question:
You can't disable the paint()/paintComponent() method if you've inlcluded it in your code. If its there, it runs. However, you can create a flag so that only if the flag is true, the stuff gets drawn. Let me show you what I mean:
boolean flag;
...
public void paintComponent(Graphics comp) {
if (flag) {
Graphics2D comp2D = (Graphics2D) comp;
//drawing statements
}
}
public void actionPerformed(ActionEvent event) {
flag = true;
repaint();
}