Generate falling Graphics with loops and randomizers - java

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.

Related

Drawing to canvas

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.

Swing graphics in multithreaded program

I'm coding a game; something like this: http://i.stack.imgur.com/HBrEE.png
I have a class named Canvas which extends JLabel and in overriden paintComponent(), put an image of gridlines as background, then paint the player and obstacles (walls).
By using createGraphics() , I get a Graphics2D object. I need this to paint weapons and bullets from their classes, too. (As you see, there are several weapons that shoot bullets in specific time intervals.)
For implementing all these, using SwingUtilities.invokeLater() I paint the gridlines, player and walls in Canvas class. I thought of creating a thread per weapon and one per bullet; I know, it's an overkill but since I'm new to multithreading I have no other ideas!
And another problem is with Graphics2D object: I need to share this object between threads so I thought of using final keyword; but it's not possible because the value of Graphics2D object will be determined in paintComponent().
Thanks in advance for any help you are able to provide.
You shouldn't use multi-threaded rendering threads ever (well, in 99% of the cases at least). Most graphics programs keep the full scene state in some object tree that only one thread renders every so often (1/60th of a second). The rendering thread goes through each object in the render tree and invoke .paint or whatever else will get the object to be drawn. Rinse and repeat and you're done.

Overiding AWT and storing graphics

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

Java: Painting multiple objects to one frame

I've been working on a java game recently, and I have a lot of it figured out. One thing still plagues me, however. The way it's set up, a player moves across a background (the game board). Currently, every time the player moves, it repaints the whole frame, including the background. This causes a brief, yet annoying screen flicker whenever the player moves.
I've separated out my code to draw the background separately from the things that need to be repainted:
public void drawMap(Graphics pane) {...}
public void drawPlayer(Graphics pane) {...}
The problem is that I can't find a way to make the board stay on the screen when I use repaint(); , a necessity for the player to move. Any suggestions?
You should look into double buffering, basically you paint an image to the buffer, then paint the buffer. It should remove the flickering effect you are talking about. Below are a few helpful links:
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering
http://www.ecst.csuchico.edu/~amk/classes/csciOOP/double-buffering.html
Just comment if your having trouble understanding it.
UPDATE: I would also suggest you look in 'Killer game programming in java'. You can get a free ebook of one of the older versions. Some of it is a bit out dated, but the first few chapters about setting up a game loop and drawing to the screen etc are still very much relevant.
UPDATE 2: From the second link, try something like this:
private void drawStuff() {
BufferStrategy bf = this.getBufferStrategy();
Graphics g = null;
try {
g = bf.getDrawGraphics();
drawMap(g);
drawPlayer(g);
} finally {
// It is best to dispose() a Graphics object when done with it.
g.dispose();
}
// Shows the contents of the backbuffer on the screen.
bf.show();
//Tell the System to do the Drawing now, otherwise it can take a few extra ms until
//Drawing is done which looks very jerky
Toolkit.getDefaultToolkit().sync();
}
UPDATE 3: This post here gives a nice code sample that you can play with and adapt, that should give you the best idea on how to do double buffering
I suggest to avoid redrawing everything with every change. Instead draw the whole frame at a fixed interval, e.g. every 50ms. Just keep the status of every element in a class and if something changes just change the data value. Due to the fixed redrawing interval the display will pick up any changes at the next redraw.

java 2D and swing

I have trouble understanding a fundamental concept in Java 2D.
To give a specific example:
One can customize a swing component via implementing it's own version of the method paintComponent(Graphics g)
Graphics is available to the body of the method.
Question:
What is exactly this Graphics object, I mean how it is related to the object that has the method paintComponent? Ok, I understand that you can do something like:
g.setColor(Color.GRAY);
g.fillOval(0, 0, getWidth(), getHeight());
To get a gray oval painted. What I can not understand is how is the Graphics object related to the component and the canvas. How is this drawing actually done?
Another example:
public class MyComponent extends JComponent {
protected void paintComponent(Graphics g) {
System.out.println("Width:"+getWidth()+", Height:"+getHeight());
}
public static void main(String args[]) {
JFrame f = new JFrame("Some frame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200, 90);
MyComponent component = new MyComponent ();
f.add(component);
f.setVisible(true);
}
}
This prints
Width:184, Height:52
What does this size mean? I have not added anything to the frame of size(200,90).
UPDATE:
I understand that I must override paint to give in the Graphics g object the hints required to do the repaint and that I do not have to create a Graphics object as one will be given by platform.
What happens after that is what I can not understand.
E.g. does Graphics represent the screen and the object is painted accordingly on screen as soon as I start calling the various g.setXXX methods?
Does it get stored in a queue and there is a 1-1 association among g and each component? So the framework uses each g of each component to paint it one at a time?
How does this work?
Any help on this is highly welcome
Thanks
I understand your problem as I struggled with it for some time when I was learning Java graphics. It's not just Java 2D graphics - it is part of AWT.
When you create a JFrame or some other top-level object, it does a lot of work "behind the scenes" - part of which is creating a Graphics object. (There is not explicit notification of this, though if you stepped through the code with a debugger you may see classes which create the Graphics).
You then create components which you add, or register with, the top-level object. These all have to implement a call-back method, including
paint(Graphics g);
You will then #Override these methods so that when the component is rendered it uses YOUR paint method.
Do not try to save the Graphic or create a new one. Think of it as the framework taking the responsibility off you.
The size of components is often taken out of your hands. If you use a layout manager then it may decide to resize your component.
If you are coming from a procedural imperative background you may well have problems (I came from FORTRAN). My advice would be to try a number of tutorials and - at some stage - enlightenment will start to come.
The general documentation for Java graphics is poor. There are many concepts which are opaque (see How does Java Graphics.drawImage() work and what is the role of ImageObserver ). The early implementation was rushed through and had many bugs. Even now it is often unclear whether and in what order you should call methods such as setPack() and setVisible().
This doesn't mean you shouldn't use it! Just that the learning curve is a bit longer than IMO it should be.
MORE:
Also YOU don't decide when something is painted, the framework does. paint(g) really means "The framweork is repainting its components. What to you want this component to provide at this stage".
Maybe providePaintingInstructionsWhenRequiredForComponentGraphics(Graphics g) would be a useful name.
Similarly repaint() does not repaint at your orders, but when the system thinks it should. I haven't found it useful.
If you (say) resize a component interactively every slight change will normally trigger a paint(g). try putting a LOG.debug() in the paint code and seeing when it gets called.
What does this size mean? I have not added anything to the frame of size(200,90).
You added your component to the frame and set the size of the frame to be (200, 90). The default layout manager for the content pane of the frame is the BorderLayout, which means the component you added gets all the available space. The frame needs some space for the title bar and borders, so your component gets the remaining space.
The component does not create a static Graphics object association.
The graphics object is the wrapper for a platform handle giving access to a physical device, like the screen. It's valid for the time when "paint" is executed only, you can't store it and reuse it later. It is a resource managed by the "toolkit".
The component itself is an abstraction on top of the windowing system, that gets asociated shortly with this device for getting rendered.
EDIT
You can force such an association calling "getGraphics" if you feel the need to paint out of the "paint" callback. This should be a very rare case and you ALWAYS should dispose the Graphics afterwards.
Think of a Graphics like a piece of paper which you draw on to show how the Component looks like at that moment. After you've drawn it, the framework toolkit will trim off the edges and show what you've drawn to display the component. Moreover, the next time you draw the component, you'll be drawing on a different piece of paper, so don't keep the old Graphics around.

Categories

Resources