I'm making a game and I'm having trouble getting variables from another class. I have a Sprite class and a JPanel class. In my game, I want my score to go up once I hit a coin. My intersect coin code is in my Sprite class. How would I make it so when I hit the coin, my score goes up my 1?
This code is from my JPanel class. These are variables declared all the way up top.
public static int CoinScore = 0;
private String Score = "Score :";
private String TextOnScreen="";
This is my paintcomponent method from the JPanel.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(BackgroundImage,0,0,720,480,0,0,720,480,null);
g2d.setColor(Color.black);
g2d.fillRoundRect(25, 2, 100, 30, 10, 10);
g2d.setColor(Color.orange);
Font cp = new Font("Courier", Font.BOLD, 20);
g2d.setFont(cp);
TextOnScreen = Score + Integer.toString(CoinScore);
g2d.drawString(TextOnScreen,30,30); 30,30.
for (int i=0; i<mySprites.length; i++)
mySprites[i].drawSprite(g2d);
}
This is from my Sprite class.
if (SpriteFilename == "Resources/sprite-concepts.png" && sprites[i].SpriteFilename == "Resources/coin2.png")
{
sprites[i].SpriteVisible = false;
sprites[i].SpriteBounds.width = 0;
sprites[i].SpriteBounds.height = 0;
}
I tried putting CoinScore = CoinScore + 1 before the } in my if from the sprite class, but it says that CoinScore cannot be resolved to a variable? How would I fix it?
did you call it with the class name? If not that is your problem.
Class.Coinshare = Class.Coinshare +1;
Something similar to that? Since it is static and public you must call it with the class's name that it belongs to first, to access it.
If you're asking about basic variable scope in Java must read oracle documentation
CoinScore has been declared as static isn't it? so it's a class variable so it's possible to so smth similar to
ClassName.publicStaticVariable
Does your drawSprite() method return anything? This could return the result of the intersection and you could check that to increment the score.
Or simply have another method in Sprite that let you know if an intersection occurred.
There are plenty of answers here that will let you do exactly what you asked for (static access through class name, maybe make a singleton etc.)
However I would like to point out that
This is only the first of a load of problems you will soon be facing
(Unless, of course, the score is the only game state you have)
This is because you are mixing your model and your view. MVC is not always an easy answer (and not always the right answer either), but it will likely be best for you to think over your architecture. Having state altering logic in your draw logic is not a great idea. What if you later need to do some extra logic to determine bonuses for getting a sprite, and those turn out to be somewhat CPU-intensive? If you set an asych update in the model it would be fine, but since it's in the draw method your game will suddenly start freezing every now and again.
Another 2 arguments against such logic in the EDT to consider:
If the colliding sprite was covered by another panel or window during the collision - it will not count. Simply because the draw method was never called on the area.
Your movements may actually be fairly rare compared to the number of redraws per second (likely, unless you are building something realtime). Hence you are wasting a huge amount of resources doing the same collision check against objects that haven't even moved.
All in all, my advice would be to update the state of objects in a model and do collision checks there, while leaving the drawing thread, to, well, draw. You can even leave the collision logic in the Sprite class (that seems like a reasonable place for it), just not called from draw, but rather from a centralized state update method.
(Also, Global Variables are EVIL, most languages that have proper support for those have an according anti-pattern)
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'm new to Java's graphics library and I'm still coming to grips with its limitations. Below I have a draw function for a Grid class, which draws a 2D array of tiles as filled rectangles.
Not that it's pertinent to the question but the the scale and offset arguments are there to adjust the Grid's tiles and tileSize variables such that it's drawn in the correct position and scale on the screen.
My question is it normal for this to lag considerably when the tiles variable is quite big? I normally get around 500 fps without any Grids on screen, and no noticeable reduction with a Grid of tiles[10][10] to [50][50]. But at tiles[1000][1000], or 1,000,000 total rectangles to draw, fps drops to 7.
I know a million is a lot, but they are just rectangles after all, and my pc can play a game like Skyrim on full settings no problem. I'd imagine there's more than a million polygons on display in Skyrim, and they comes with all sorts of highres textures and lighting and all so, why should a million gray squares be such a problem? Is Java's graphics library really poor? Am I expecting too much? Or, as I suspect, is there a much better way of drawing something like this?
I can provide the main class's paintComponent if that's important, but it's just a call to _Grid.draw() so I don't think the problem's there..
public Graphics draw(Graphics g, double scale, Point offset) {
Graphics2D g2 = (Graphics2D) g;
for(int i = 0; i != this.tiles.length; i++) {
for(int j = 0; j != this.tiles[0].length; j++) {
boolean draw = true;
if(this.tiles[i][j].type.equals("EMPTY")) {
draw = false;
} else if(this.tiles[i][j].type.equals("PATH")) {
g2.setColor(Color.LIGHT_GRAY);
} else if(this.tiles[i][j].type.equals("WALL")) {
g2.setColor(Color.DARK_GRAY);
}
if(draw) {
g2.fillRect((int)((this.xPos+i*this.tileSize)*scale + offset.x),
(int)((this.yPos+j*this.tileSize)*scale + offset.y),
(int)(this.tileSize*scale),
(int)(this.tileSize*scale));
}
}
}
return g2;
}
Java's BufferedImage class is slow. It's a known fact. If you want to do fast image manipulation then it's the wrong tool to use.
Additionally games like Skyrim are using the graphics card to do most of the work, using the Java Image stuff it is all being done in the CPU.
You should really look into using a game framework - there are 2d ones like Slick2d and 3d ones like jMonkeyEngine3.
A few things you might consider trying:
If your original Graphics object is being created by a BufferedImage, consider using VolatileImage instead. As others have said, everything in this draw method is happening on the CPU via the Swing Event Dispatch Thread, so you are limited to a single CPU for drawing (unless you spawn more Threads somewhere). VolatileImage, when used for double-buffering, takes advantage of the graphics hardware and can be MUCH faster for this kind of thing.
You're doing a TON of String comparisons, which can be very slow. I'd consider refactoring your type field to be a custom enum instead, then have that enum define its own draw method that takes a Graphics object and draws itself. That way, you could call this.tyles[i][j].type.draw(g2) and rely on late binding to draw the right colored rectangle, thereby eliminating the String comparisons.
Make sure you're only drawing the stuff that's on screen. I don't know anything about your tiles array, but if it's significantly larger than what's actually being rendered to screen, you could be wasting a lot of CPU cycles there.
This might sound silly, but you're actually doing twice as many memory accesses as you really need. I'm going to assume you have Tile[][] tiles ... defined somewhere in your source code. In the outer loop, grab the row first by writing something like Tile[] row = tiles[i];, then in your inner loop, get the type by calling row[j].type. This will cut your memory access count in half when iterating over the tile array.
I am looking at making pong using LWJGL.
Well I was doing the LWJGL tutorials, by thebennybox, and had it working, I then wrote it out again when my old hard drive died (R.I.P). What I am trying to do is add multiple GameObjects and have them show up, I worked out that they are being added to the GameObject objects list. Here is the code in my dropbox: https://www.dropbox.com/s/ccs37jqm1b5oi84/lwjglGame.zip
It is a little too big to have on here but here is a main part:
This is from Game.java:
private ArrayList<GameObject> objects;
public Game() {
objects = new ArrayList<GameObject>();
GOplayer player = new GOplayer(0, Display.getDisplayMode().getHeight()/2);
GOball ball = new GOball(Display.getDisplayMode().getWidth()/2-GOball.SIZE-2, Display.getDisplayMode().getHeight()/2);
objects.add(player);
objects.add(ball);
}
Your problem occur because of two problems.
1: Within the GameObject class your float variables x and y are static. Which they should not be!
2: Within the Draw class you call glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); this should not be there as well, because what that does is clearing the depth and color buffer, which results in each time your render a "rect" using you Draw.rect that clears the screen, so in the end, only the last rendered "rect" will be shown!
Also you don't really need to clear the GL_DEPTH_BUFFER_BIT, since within the initGL() you disable it using glDisable(GL_DEPTH_TEST); (though GL_DEPTH_TEST is disabled by default). And since your only working in 2D space then there are no actual depth, unless you're using the GL_DEPTH_TEST to sort the 2D space, while still using Z values.
Advice
Here is just some advice from me, if you don't 100% know all the main/basic keywords within Java, or just don't know how to use them correctly then starting off by creating a Game with OpenGL using LWJGL, will become extremly hard for you at some point. I suggest you start with something a lot easier or start off by reading or watching multiple tutorials about the basics of Java.
The reason I'm saying this is that you create a new instance of the class GameObject through GOball, GOplayer and GObox though inside the GameObject you have the float variables x and y those variables you've set as static, which mean that variables are shared and will always be the same. So when you create an GOball and set the x and y that sets the x and y though when you then create the GOplayer and set it's x and y to something else, that will affect the GOball as well so then they will have equally the same x and y always, since the variables are shared!
I have an array that holds the names and then displays the appropriate graphics using:
public void paintComponent(Graphics g){
for(int i = 0; i<20; i++)
{
for(int j = 0; j<20; j++)
{
if(testMap.getData(i+(rowX-7), j+(columnY-7)).indexOf("rock") >= 0)
{
g.drawImage(image3, j*50 + 5*add, i*50 + 5*add2, 50, 50, this);
}
}
}
This works well displaying the actual graphics of my game. However, for my minimap, I do the same thing, with different values and increased numbers in the 'i' and 'j' in the for loop. This creates a smaller version of the map with a bigger scope, which leaves me with this. (Note, I only included one of the drawImage() methods, I removed the rest here to make the code more readable):
This is pretty much my desired effect (aside from the positioning, which I can change easily), however, this only shows a smaller version of what I already see on the screen. Any larger than about 20 x20, though, and the game begins to lag heavily -- probably something to do with the terrible way that I coded it.
I have tried replacing the images with squares using fillRect, but it does not help the issue.
Here is the code of my main class if anybody would like to take a look: http://pastebin.com/eEQWs2DS
The for loop within the paintComponent method begins at around line 3160, the loop for the main display is around 2678. I set up the Jframe at around 1260.
So, with all that said, basically my question is this:
Is there a better, more efficient way to create my minimap? My idea was to generate an image at the beginning of the program so that the game wouldn't have to recalculate every time the frame refreshes. I could create the map in advance, but I would have to manually update that every time I changed the map, which is definitely a hassle. I am having trouble researching how to do the former. My other idea is to slow the refresh rate of the minimap only, but I also do not know how to do that.
Other than that, if there are any simple fixes to the lag issue, please enlighten me. I apologize for the very, very messy code -- This is my first time programming anything with a display so I sort of just...hacked at it until it worked.
I don't know how easy this would be with your implementation, but instead of drawing an image, perhaps you could draw a square of a certain color based on what type of tile it should be?
For instance if you're looping through your list of tiles and you find a grass tile, you would first draw the grass tile at its proper location, then draw a smaller green square on the minimap.
The downside to this is that first you'd have to define what colors to use for the tiles, or perhaps when you load the tiles you can compute an average color for each one, and then just use that. Another issue is that the houses may not translate well on to the minimap, since the tiles have much more detail. You could draw some kind of house icon on the minimap instead of actually drawing any of the house tiles, though.
Basically, you want to use simpler representations of the objects in your map on the minimap, since it's smaller and less detail can be drawn anyway.
Have a look at how I do it in Tyrant (a Java roguelike):
https://github.com/mikera/tyrant/blob/master/src/main/java/mikera/tyrant/LevelMapPanel.java
Key tricks:
Use an offscreen BufferedImage. Cache this to avoid recreating it each time you paint.
Use an int[] array to setup up a single colour for each tile
Use setRGB with the array to draw all the map at once
Draw the mini-map at x2 zoom to get 2x2 pixel blocks for each tile.
If you want to be even more efficient, keep a changed flag and only update the mini-map BufferedImage when something visible on the mini-map changes. I didn't think it was worth it as the above is already very efficient, but YMMV.
Edit: uses awt...
I am trying to display random numbers in an applet based maths game, and have run into an issue. Either one of two things happen depending on where I call the method:
The numbers generate and display properly, without automatically updating each frame but get drawn over by the background and artwork each frame as they're being updated at runtime, or...
The number displayed on-screen appear above the background elements but are redrawn fresh every frame.
Quick illustration:
private int setNumberOne() {
return rand.nextInt(11) + 2;
}
private int setNumberTwo() {
return rand.nextInt(11) + 2;
}
private int setAnswer() {
return setNumberTwo() * setNumberOne();
}
private void displayOutput() {
Graphics2D g2d = graphics();
int one = setNumberOne();
int ans = setAnswer();
setNumberTwo();
g2d.setColor(Color.WHITE);
g2d.drawString(one + " x ? = " + ans, 480, 480);
}
Calling this function in the initialisation method displays a static question that I can update elsewhere when specific triggers are met, however everything else gets drawn on top of it by the update event, rendering it invisible. The only way I've managed to see this working is to remove the other images from the game for testing.
Is there a way to set the "precedence" of GUI elements in an applet?
I'm currently looking at attempting to include the displayOutput() method in it's own thread, but I'm not so experienced with Java and its proving very hard to resolve.
I also tried to not allow the background to update at runtime, but the result was that the moving game objects left trails all over the screen.
What am I missing? If anyone has any suggestions as to how this can be correctly implemented, I'd be delighted to hear them.
update: "...draw in a [...] Component's paint(...) method if AWT, and use the Graphics object passed in by the JVM" -
Resolved, Thank you!
Don't use getGraphics() for your Graphics component as this will return a non-persisting object that will get drawn over with the next repaint. Instead draw in a JComponent's paintComponent(...) method if this is a Swing app (you don't say) or a Component's paint(...) method if AWT, and use the Graphics object passed in by the JVM. Mostly read the tutorials on how to draw with Java as this has been well explained there.