Static method is slow - java

I'm programming a simple game in java.
I've made a collision test with 30 FPS, where I had to get the size of the window.
Because I haven't had access to the GUI instance, I thought I'd make a shared instance, because this is pretty standard in Objective-C, where I come from.
class GUI extends JFrame {
private static GUI _sharedInstance;
public static GUI sharedInstance() {
if (_sharedInstance == null) {
_sharedInstance = new GUI();
}
return _sharedInstance;
}
}
But for some reason, it was really slow.
Then I replaced the shared instance with public static final instances for the size, and it works fast now, even with 60 FPS or higher.
Can anyone explain me why this happens?
EDIT
So instead of calling GUI.sharedInstance().getWidth(), I'm just calling GUI.windowSize.width.
I have used the public static final Dimension windowSize instead.
EDIT
Here's the collision detection.
So, instead of calling int width = GUI.kWindowWidth;,
I was calling int width = GUI.sharedInstance().getWidth(); before.
// Appears on other side
if (kAppearsOnOtherSide) {
int width = GUI.kWindowWidth;
int height = GUI.kWindowHeight;
// Slow
// int width = GUI.sharedInstance().getWidth();
// int width = GUI.sharedInstance().getHeight();
Point p = this.getSnakeHead().getLocation();
int headX = p.x;
int headY = p.y;
if (headX >= width) {
this.getSnakeHead().setLocation(new Point(headX - width, headY));
} else if (headX < 0) {
this.getSnakeHead().setLocation(new Point(headX + width, headY));
} else if (headY >= height) {
this.getSnakeHead().setLocation(new Point(headX, headY - height));
} else if (headY < 0) {
this.getSnakeHead().setLocation(new Point(headX, headY + height));
}
}

I know that this might not be the real answer to the question, but there could be a problem with a race condition.
I assume that you are trying to use the lazy/singleton pattern, because the construction of the GUI class is quite expensive and you need only one instance.
Now, what happens? If a thread runs into the if statement body, it creates a new GUI instance. Just before the next assignment, it gets paused by the scheduler.
Now another thread pops in, sees that _sharedInstance is still null and creates another GUI instance (and so on...).
Lets assume that there are only two threads.
The first thread runs to the end and the second one is continued, now you have two instances of the GUI class. Nobody says that the unassigned GUI instance gets destroyed or garbage collected.
That could explain tha 50 % performance loss compared to using finally and assigning the GUI instance directly to _sharedInstance.
See e.g. the Java examples at http://en.wikipedia.org/wiki/Singleton_pattern
Double checked locking, inner classes or an enum are the ways you can use.

Related

How to close one canvas in java swing, and replace with another one, without opening new window?

So, for a project I'm currently working on, I'm creating a Mario-like game, with three different levels. I have finished level one so far, and have run into a problem I can't seem to figure out. When I am done the level (I have this door that the player runs into), level one is supposed to close and go back to the main class, which I called BaseClass, and then the BaseClass is supposed to open level 2.
However, instead of doing that, the program opens a new window on top of the old one, with the new level. I believe this might have something to do with the fact that I refer back to BaseClass by creating a new window with the new level. This new window is also a mixture of the two and is repeatedly flashing between yellow and green (the two background colours I have placed temporarily to differentiate between the two levels).
Is there a way for me to close one canvas, and open the other one, without having that problem? Also, the project is for a school course, and we are not allowed to use any non-basic Java libraries.
I have tried using JFrame closing, using a method that I found that involved the Principal class from the java.security package. I have also tried several random things, none of which seem to work.
Here is my BaseClass code for both the constructor and the method that is supposed to change the level.
int currentLevel = 1;
public BaseClass() {
super("Epic Math Sprint");
start();
currentLevel++;
this.setSize(800, 600);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setVisible(true);
}
public void start() {
LevelOne firstLevel = new LevelOne();
LevelTwo secondLevel = new LevelTwo();
LevelThree thirdLevel = new LevelThree();
switch (currentLevel) {
case 1:
this.add(firstLevel);
break;
case 2:
this.remove(firstLevel);
this.add(secondLevel);
break;
case 3:
this.remove(secondLevel);
this.add(thirdLevel);
break;
}
}
Here is the code I have in the actionPerformed method that checks whether the player is at the door, and if the door is open (drawPaper is false), and at that stage, changes the level. BTW, if you have any tips on how to check whether the player is on top of the door in a better way, please let me know.
if (!drawPaper && (xPos >= 575 && xPos <= 625 && yPos >= 150 && yPos <= 280) && !reachedGoal) {
BaseClass main = new BaseClass();
main.currentLevel = 2;
main.start();
reachedGoal = true;
}
The reachedGoal is to prevent the program from continuously opening new windows every 5 milliseconds (what my timer is set to).

Java game keeps crashing after about 2 minutes of runtime (Intellij)

I am using Intellij to program Java.
I am currently trying to make a top down tile based shooter.
My issue is that my game, after approximately 2 minutes, crashes with a popup saying "Java(TM) Platform SE Binary has stopped working. I recorded the time it took for it to crash 3 times: 1m57s, 1m59s, 1m58s.
The game is in a very simple state right now and I am not sure what could be causing the crash. All of the relevant code is in just two classes: GameFrame.java (extends JFrame) and GamePanel.java (which extends JPanel).
GameFrame.java:
package net.magnusfrater.tds.game;
import javax.swing.*;
public class GameFrame extends JFrame {
public static final int width = 1000;
public static final int height = width / 16 * 10;
private GamePanel gp;
public GameFrame () {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
setResizable(false);
setLocationRelativeTo(null);
setTitle("Time Based Fast Paced Top Down Shooter Demo");
gp = new GamePanel();
add(gp);
setVisible(true);
}
public static void main (String[] args) {
GameFrame gf = new GameFrame();
}
}
GamePanel.java
package net.magnusfrater.tds.game;
import net.magnusfrater.tds.input.Keyboard;
import javax.swing.*;
import java.awt.*;
public class GamePanel extends JPanel implements Runnable {
//panel
private Thread thread;
private static boolean running;
private boolean fpsLock;
//input
private Keyboard kb;
//game
private Game game;
public GamePanel () {
//panel
thread = new Thread(this, "Time Based Fast Paced Top Down Shooter Demo");
running = true;
fpsLock = true;
//input
//kb = new Keyboard();
//addKeyListener(kb);
//game
//game = new Game(1);
thread.start();
}
public void run () {
long iTimeNS = System.nanoTime();
int tickRate = 60;
long ns = 1000000000 / tickRate;
int ups = 0;
int fps = 0;
long iTimeS = System.nanoTime();
long s = 1000000000;
while (running) {
long fTimeNS = System.nanoTime();
if (fTimeNS - iTimeNS >= ns){
iTimeNS = System.nanoTime();
tick();
ups++;
if (fpsLock){
repaint();
fps++;
}
}
if (!fpsLock){
repaint();
fps++;
}
long fTimeS = System.nanoTime();
if (fTimeS - iTimeS >= s){
iTimeS = System.nanoTime();
System.out.println("ups: " + ups + "\tfps: " + fps);
ups = 0;
fps = 0;
}
}
System.exit(0);
}
public void tick () {
if (kb != null)
kb.tick();
if (game != null)
game.tick();
}
#Override
public void update (Graphics g) {
paint(g);
}
#Override
public void paint (Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0,0,GameFrame.width, GameFrame.height);
//if (game != null)
//game.paint(g);
}
public static void quitGame () {
running = false;
}
}
I originally thought that the issue was because of the way that I was loading images for spritesheets or maybe the way I was loading text files for the level design but after reworking both of those, the issue remained.
That left me curious and a little bit fed up so I tried finding out more about the explanation for the crash. First I read more from the popup but it didn't say anything useful: (See below)
Second I looked at the exit code given by Intellij: (See below)
I looked up what exit code 255 was but there wasn't anything useful. The best explanation I could find was that exit code 255 meant that the real exit code was out of range: (See below)
I was out of ideas at this point so I just started plain old googling everything I could think of. The problem with googling "Java(TM) Platform SE Binary has stopped working" is that almost every suggested link is a question about Minecraft. Limiting my search to Stack Overflow yielded me some results, but nothing conclusive. Some of the fixes I found were stuff I already tried (such as not handling input streams properly, not handling buffered reader properly, not disposing of elements, etc). I found these links but none of them were truly related to my issue:
(See below)
(See below)
(See below)
(See below)
(See below)
(See below)
The last fix I tried was to re-install Java SE Development Kit 8u101 AND Java SE Development Kit 8u102. I then restarted Intellij. I then restarted my computer.
Nothing worked.
At this point I think I'm just dumb. I've overlooked something easy I can tell. What am I missing?
(ps~ This is a possibly related issue. So if I run my game with almost no content in it with the fps not locked to 60, I get really absurd numbers of frames per second. I didn't think that fps as high as 7,000,000 was possible. I think. I don't know. Have I programmed that wrong as well? Here is a related picture of my ups/fps output: [see below])
(SEE HERE) So Stack Overflow doesn't allow members with a score within a certain threshold post more than 2 links and allows absolutely no posting of images. So here is a link to a google doc with all of the links and images I mentioned above:
https://docs.google.com/document/d/1XrBuVio19GmkFz0EfRzXVp5AJmM5zPfVO6vK3oS3Eaw/edit?usp=sharing
Try and set your -Xmx to something like 2G and see if it runs longer. If so, something is allocating memory and maybe you have that other setting set that exits instead of garbage collecting for some reason.
Also, try changing your code to limit things using Guava's RateLimiter.
…
// class level
final RateLimiter frameLimiter = RateLimiter.create(60.0);
final RateLimiter outputLimiter = RateLimiter.create(1.0);
…
// in run method
while (running) {
frameLimiter.acquire();
repaint();
fps++;
if (outputLimiter.tryAcquire()){
System.out.println("fps: " + fps);
fps = 0;
}
}
I've removed ups and tick(). You should do your work after repainting and I don't think you want to do more work than needed for the next frame, which at the soonest should be at your max rate. Later you'll need to add logic to handle skipping work when frames are being skipped. I might make more sense to increment the fps within repaint.
You could put the output in its own thread and only acquire that limiter if you synchronized the increments and resetting of fps.

Android - Getting return value of a thread

I start with Android and Java, and my English is not very good (sorry).
I'm doing a application which compare 2 pictures taking by the camera and return a float value = a ratio of identical pixels in the 2 pictures.
public static float comparePic(String img_1, String img_2){
Bitmap bitmap1 = BitmapFactory.decodeFile(img_1);
Bitmap bitmap2 = BitmapFactory.decodeFile(img_2);
int equ = 0;
//get one height and one width because we assume that pictures have always same sizes
int h = bitmap1.getHeight();
int w = bitmap1.getWidth();
for(int y=0;y<h;y++){
for (int x=0;x<w;x++){
int pixel1 = bitmap1.getPixel(x,y);
int pixel2 = bitmap2.getPixel(x,y);
//alpha doesn't matter, they're jpg
int redValue1 = Color.red(pixel1);
int redValue2 = Color.red(pixel2);
int greenValue1 = Color.green(pixel1);
int greenValue2 = Color.green(pixel2);
int blueValue1 = Color.blue(pixel1);
int blueValue2 = Color.blue(pixel2);
if (redValue1==redValue2 && greenValue1==greenValue2 && blueValue1==blueValue2){
equ++;
}
}
}
return (float)equ/(h*w);
}
When I execute it, I have this message : "I/Choreographer﹕ Skipped 730 frames! The application may be doing too much work on its main thread."
So I tried to do it with a thread, but I'm always failing because I don't know how to return the value.
Futhermore, by skipping frames I guess, the ratio is not correct.
I know that it's an asynchonous work, so what can I do ?
Thanks !
You can simply add a public (setter-)method in your main class (or wherever you need the value).
When your async thread is done call the method with equ as the parameter.
You obviously need to care about thread-safety so consider making the method sychronized.
You should give a try to AsyncTask. It's a class specifically prepared for background processing. It has some drawbacks (it's not good idea to do networking with AsyncTask), but for some picture comparison stuff it is a great tool.
Define an Asynctask with a interface and implement that interface in the main Activity.
That way you can notify that host activity that the background asynctask has completed.

Variables are being reset, but effects are not taking place

I am programming a game, but I have ran into an error.
When the player collided with an object, player.hasCollided is set to true.
if(playerBounds.intersects(wolfBounds)){
player.hasCollided = true;
player.dead();
}
Now, when hasCollided is true, something from the LoseScreen class is printed out onto the screen:
if(player.hasCollided){
lose.start(g);
}
In player.dead(), the player's speed is set to 0.
public void dead(){
playerSpeed = 0;
coinBank += coinsCollected;
}
The problem is that in my InputHandler class I make it so that on the lose screen, when the choice is 1, and enter is pressed, restartGame() is called.
public void restartGame(){
obstacleWolf.getNewPosition();
obstacleHole.getNewPosition();
hasLost = false;
player.hasCollided = false;
player.playerSpeed = 5;
player.nextX = 1000;
player.coinsCollected = 0;
player.xElapsed = 0;
}
if(lose.choice == 1 && enter){
game.hasLost = false;
game.restartGame();
System.out.println(player.hasCollided + " " + player.playerSpeed);
}
Those variables ARE being set to what they are meant to be set to (for example playerSpeed becomes 5 from 0, and hasCollided is becoming false from true) but the effects are not taking place. So, like I showed before, lose.start(g); is only meant to be called when hasCollided is true, but even when it becomes false, it is still printed out on the screen.
Here is how the relevant variables/methods are being used:
public void move() {
x = x - player.playerSpeed;
}
(All moving objects share the same move method)
Parts of the game class:
public void tick(){
input.tick();
if(gameState){
player.tick();
player.move();
collision();
treeline.move();
obstacleHole.move();
obstacleWolf.move();
coin.move();
coin.tick();
}
I am not sure if I can make this question clearer. I can provide more code from different classes if needed.
The question can't be answered in its current form (see 2 comments above).
The reason for that is current code structure.
You need to refactor code, then you will find the problem.
Put all modification of player fields in methods of Player class.
Access fields only through methods. Making fields private is old good practice.
Then the only code you need to share would be this Player class.
In one thread environment, that's all.

Methods and decomposition

I'm just starting learning Java after a few years of HTML/CSS coding so hopefully I'm not asking a old or stupid question here but any help explaining this problem would be very much appreciated.
I'm currently working through the Stanford CS106A online material and I've reached week 6, Assignment 2, Question 3 (http://see.stanford.edu/materials/icspmcs106a/13-assignment-2-simple-java.pdf).
As you can see it requires the placement of various objects on the screen to create the Graphics Hierarchy, as described. My plan was to use the centre coordinates to relatively place all the objects on the screen. However I've hit a problem that I can't seem to find an answer to. The course describes how Method Decomposition should allow each method to handle one problem (Single Responsibility Principle, I believe) so I have written the first part of my code as such:
//Import any libraries
import acm.program.*;
import acm.graphics.*;
public class GraphicsHierarchy extends GraphicsProgram {
//Define constants
static final int BOX_WIDTH = 200;
static final int BOX_HEIGHT = 75;
public void run() {
placeGRect();
}
//Find centre x & y
double centre_x = getWidth() / 2; //check this
double centre_y = getHeight() * 0.5;//and this
//placeGRect method
public void placeGRect() {
for (int count = 0; count < 4; count++) {
GRect box = new GRect (BOX_WIDTH, BOX_HEIGHT);
add(box);
switch (count) {
case 0:
box.setLocation(centre_x, 75);
break;
case 1:
box.setLocation((centre_x * 0.5), 250);
break;
case 2:
box.setLocation(centre_x, 250);
break;
case 3:
box.setLocation((centre_x * 1.5), 250);
break;
}
}
}
}
However this doesn't work due to the centre_x & centre_y producing zero values. I discovered this by changing the program to a ConsoleProgram and having the getWidth & getHeight lines inside the run() method (and println their values on screen), which then produced the required values but didn't pass them to the GRect method (so still didn't work). However if I have the getWidth/getHeight lines listed out of the run() then they don't produce any values for relative positioning.
My question is given that each method should handle one task and (as much as possible) methods should be defined out of the run() method, then how I can I get the getWidth/getHeight values to the placeGRect() method without having one big block of code within the run() method. Which I understand is bad practise.
I'm not after any code to solve this, I really need to understand the principles of this so I can write effective code in the future. I prefer understanding to parrot-fashion code copying.
Thanks in advance for any help.
In your specific example:
You have declared centre_x and centre_y as instance variables. When your program first creates an instance of GraphicsHierarchy the order of object creation is as such:
ClassLoader loads the class... static variables (BOX_WIDTH,BOX_HEIGHT) are assigned specified values;
Space is allocated on the heap for an instance of GraphicsHierarchy (enough space to hold the instance variables - a double for centre_x and a double for centre_y- including space for base class instance variables)
Instance variables are set to default values: centre_x = 0, centre_y = 0
The GraphicsHierarchy default constructor is called (which does nothing other than call the base class constructor - GraphicsProgram).
The base class will go through steps 1-4 and when it's finished execution returns to GraphicsHiearchy which now evaluates explicit instance variable initializers before executing any remaining constructor statements (which in the case of the default constructor, there are none).
(additional reference on this process http://java.dzone.com/articles/java-object-initialization)
Having said all of that, it would appear that when your class GraphicsHierarchy gets to step 5 and tries to assign values to centre_x and centre_y, the subsystem that getWidth and getHeight rely upon is not ready (i.e. a window or canvas has not been created yet, so the methods return 0). But when you moved your assignments inside run and getWidth/getHeight returned values, that would imply whatever method is calling run has first gone through the necessary window creation steps.
Etienne de Martel's suggestion is fine. It delays assignment of your centre values until right before they are needed. If you'd rather, you could create an init method and move the assignments inside the init method, and then call init as the first step of run
private void init() {
centre_x = getWidth / 2;
centre_y = getHeight * 0.5;
}
public void run() {
init();
placeGRect();
}
This is nearly the same thing as Martel's suggestion, although if you find later you have other initialization code that needs to happen, you can throw it in the same place.
As for crafting flexible code you might think about renaming placeGRect to placeGRects and passing in array of points (or Collection if you prefer) placeGRects(Point[] points)
(you can use Java.awt.Point or define your own Point class)
In this way, your placeGRects method is simplified. It no longer decides how many boxes to render (the array that is passed in does). It also doesn't determine where those new boxes are located (again the array of Point objects do). It simply loops through the size of the array, makes a new box, adds it, and sets the location.
private Point[] boxPoints;
public void run() {
init();
placeGRects(boxPoints);
}
public void placeGRects(Point[] points) {
for(int i=0;i<points.length;i++) {
GRect b = new GRect(BOX_WIDTH,BOX_HEIGHT);
add(b);
b.setLocation(points[i].x,points[i].y);
}
}
And you can put your Point array initialization inside your new init() method.
private void init() {
centre_x = getWidth / 2;
centre_y = getHeight * 0.5;
boxPoints = {new Point(centre_x, 75),new Point(centre_x * 0.5, 250)};
}
It makes your code easier to understand and modify when needed.
Perhaps I don't understand your question, but why not pass them as parameters?
protected void placeGRect(double centre_x, double centre_y) {
// ...
}
You can then call placeGRect like so:
public void run() {
placeGRect(getWidth() / 2, getHeight() * 0.5);
}
Very nice question! How to compose your methods is a matter of intuition rather than strict guidelines.
Certainly, methods should be focused on doing one thing and one thing only. Firstly, having short methods (even one-liners!) improves the understandability of the code. As a very rough example, think of this:
if (DateUtils.before(ticket.getExpirationDate(), new Date())) {
accept(ticket);
}
and then this
if (isNotExpired(ticket)) {
accept(ticket);
}
...
private boolean isNotExpired(Ticket t) {
return DateUtils.before(t.getExpirationDate(), now());
}
private Date now() {
return (new Date());
}
Pay attention to how the introduction of one line methods isNotExpired() and now() significantly improved your undestanding of what the code does.
Here's another example, this time that has to do with constructing objects:
Loan l1 = new Loan(15000, 36, f7.2, 2.5);
Loan l2 = new Loan(15000, 36, f7.2);
vs.
Loan l1 = Loan.newSubsidizedLoan(15000, 36, f7.2, 2.5);
Loan l2 = Loan.newNormalLoan(15000, 36, f7.2);
Note in this example how wrapping the constructors in two different methods significantly improves the documentation of code (without even needing to write comments);
If you are interested on the general topic of coding style, you should read this book.
Cheers
L.
Your code doesn't seem to include the getWidth() and getHeight() methods. Also, the following piece of code is totally wrong as a placement and should be placed in a constructor:
double centre_x = getWidth() / 2; //check this
double centre_y = getHeight() * 0.5;//and this
Should become
private double centre_x;
private double centre_y;
GraphicsHierarchy(){
centre_x = GraphicsHierarchy.BOX_WIDTH / 2;
centre_y = GraphicsHierarchy.BOX_HEIGHT * 0.5;
}
This code will at least compile, but consider the solution described below, which is even better.
Considering that you have defined BOX_WIDTH and BOX_HEIGHT as static variables, you can always find centre_x and centre_y. Therefore, you don't even need to define BOX_WIDTH and BOX_HEIGHT
You can define your class like this:
//Import any libraries
import acm.program.*;
import acm.graphics.*;
public class GraphicsHierarchy extends GraphicsProgram {
public void run() {
placeGRect();
}
//Define constants
public static final double CENTRE_X= 100.00;
public static final double CENTRE_Y = 37.50;
//placeGRect method
public void placeGRect() {
for (int count = 0; count < 4; count++) {
GRect box = new GRect (200, 75);
add(box);
switch (count) {
case 0:
box.setLocation(GraphicsHierarchy.CENTRE_X, 75);
break;
case 1:
box.setLocation((GraphicsHierarchy.CENTRE_X * 0.5), 250);
break;
case 2:
box.setLocation(GraphicsHierarchy.CENTRE_X, 250);
break;
case 3:
box.setLocation((GraphicsHierarchy.CENTRE_X * 1.5), 250);
break;
}
}
}
}
In my opinion, you can go even further by eliminating all computations and replace such stuff
GraphicsHierarchy.CENTRE_X * 1.5
with
150
Come on, have it easy on your Virtual Machine! Your class uses a whole load of static information, so there is no need for so much computation. But having a BOX_WIDTH and BOX_HEIGHT is completely useless as constants, as they are used only internally and only on one place. Calculating centre_x and centre_y out of the BOX_WIDTH and BOX_HEIGHT is also useless, as as they are final, you can easily do the computation yourself and reduce unnecessary creation of variables.
In addition, you don't use the centre_y value anywhere, so you should ditch it.
To further add some helpful advice, a decent IDE, like NetBeans, Eclipse, or IntellIJIDEA should have code completion and syntax highlighting and will help you immensely in becoming a better (or more knowledgable, which is even better) programmer.

Categories

Resources