I am building this game in Java. Basically it is minecraft in 2D. I made it so that block objects are deleted when pressed. My block object rendering sometimes gives a nullpointerexception after clicking/deleting a block (randomly after about 200 blocks). It seems as if the object is sometimes deleted while the game is in the renderingloop. When I add a try-catch, the next render cycle does not have the error anymore. Any ideas what is causing this? Is this gameloop a solid one, I suspect that is what is causing my error.
Render method in my handler:
LinkedList<GameObject> object = new LinkedList<GameObject>();
public void render(Graphics g){
for(int i = 0; i < object.size(); i++){
GameObject tempObject = object.get(i);//sometimes nullpointer when getting the object I clicked on
tempObject.render(g);
}
}
Deleting with mouseInput
for(int i = 0; i < handler.object.size(); i++){
if(handler.object.get(i).getID() == ID.Block){
int x1 = (int) handler.object.get(i).getX();
int y1 = (int) handler.object.get(i).getY();
//if mouse is over object
if((MouseX >= x1+1 && MouseX <= (x1 +32-1)) && (MouseY >= y1+1 && MouseY <= (y1 +32-1))){
Block b = (Block) handler.object.get(i);
inventory.addInventoryBlocks(b.getType(), 1);
handler.removeObject(handler.object.get(i));
}
}
}
Gameloop:
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
//System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
I assume your mouse input handler runs as a seperate thread. In this case the deletion of a block can occure within your rendering loop.
A solution would be not to delete the blocks immediately in your mouse handler but to save the blocks to delete in a separate array. These blocks can be handled at a dedicated position in your main loop right before rendering.
Most likely your mouse handler is running in the AWT thread while the render is running in another thread. In this case you would be suffering of concurrency troubles.
Try using a critical section.
public static Object lock = new Object();
public void render(Graphics g){
synchronized(lock)
{
for(int i = 0; i < object.size(); i++){
GameObject tempObject = object.get(i);//sometimes nullpointer when getting the object I clicked on
tempObject.render(g);
}
}
}
void mouseInputHandler()
{
synchronized( lock )
{
code
}
}
This could be better refined knowing more about your code's structure but it should get you going in the right direction.
Assuming you are using different threads for updating the game state and rendering, this behavior does not seem that odd to me, as one thread might have deleted an object as the other tries to render it.
A good way to debug this is to force sequential execution of your code. Check if the current behavior persists. A nice introduction (Android) to game loops can be found here
Related
I built a small game in java in which i use a game loop. I add gameobjects which i render using render() and tick() methods. However, now the program gets bigger i encounterted a problem.
How do you solve that when i use velocity to move a picture, the object keeps rendering on old positions? For small programs this aint a problem, but when you get like 100 objects in the screen the FPS keeps dropping to the point the program doesnt work properly anymore. This is just because there are so many objects to render. Is there a way to remove the rendering of the old positions of the object? Here below is some code i have written.
The game loop i used:
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (running) {
try {
render();
} catch (IOException e) {
e.printStackTrace();
} catch (FontFormatException e) {
e.printStackTrace();
}
}
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
I used the Graphics class in Java to draw the images/strings/rectangles/etc. on the JFrame.
Here below is a picture of the problem. You can see that the object began all the way to the right. I changed the x-axis every tick of the game loop which made the object go to the left. Unfortunately, the object leaves a trace behind it and keeps rendering that, while i want it to only render the newest position.
Object rendering problem picture:
How can i solve this? Thanks in advance.
So I'm currently just learning how to do this, and someone said that the code is inefficient because the thread is still running when nothing is updating. When I look at the CPU usage in the task manager, it shoots up to 35 - 45% and 20 in the CPU column when only a black screen is being rendered. Is there a way to make the thread sleep when the CPU isn't updating anything?
Thanks!
public void run() {
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
final double ns = 1000000000.0 / 60.0;
double delta = 0;
int frames = 0;
int updates = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1) {
update();
updates++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000) {
timer += 1000;
updates = 0;
frames = 0;
}
}
stop();
}
You shouldn't render on your own threads. SWING is thread unsafe so all GUI operations should happen on the SWING thread. It just happens SWING has a thread specially made for this.
timer = new javax.swing.Timer(1000 / 60, this);
timer.start();
#Override
public void actionPerformed(ActionEvent e) {
// Do your stuff (ignore 'e')
}
The only good way of doing it, is to execute the yourThread.wait() when the game stops doing stuff, and then yourThread.notify() when the game makes an action again.
So I made a java game with jumping some time ago and I used this method for all the moving:
double height = 0, speed = 4;
public static final double gravity = 9.81;
double x = 25;
int a;
int y = (int) (500-(height*100));
boolean left = false, right = false, up = false;
public void the_jump() {
long previous = 0, start = 0;
while(true){
start = System.nanoTime();
if(previous != 0 && up){
double delta = start - previous;
height = (height + (delta/1000000000) * speed);
speed -= (delta/1000000000) * gravity;
y = (int) (500-(height * 100));
}
if(left){
x-= 3;
}
if(right){
x+= 3;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(height < 0){
height = 0;
speed = 4;
up = false;
}
previous = start;
}
}
Now It was okay when I did it all with just JComponents and such, but now when I want to implement it in a Slick enviroment, it fails.
The problem is in the while(true){} loop. If I change it against for(int i = 0; i < 1; i++) loop, then moving left and right will work. But this will not work for the jumping. I could increase the i < 1 to i < 5 and then the jump will work, but at the cost of a lot of performance.
So how would people implement this in slick? Right now I am calling the the_jump(); out in my public void update(GameContainer gc, int t) throws SlickException method, and if I use the while loop, the game will crash.
Slick already loop on update(GameContainer gc, int delta), you have to put all the code located in your while loop into the update method.
Moreover, you get the delta time between two update as parameter, and so not have to calculate it.
Feel free to ask me more question ;)
Off Topic, do you know if Slick2d is still maintain ? I switch to libGDX a few month ago, and I really advice you to test it, it's soooo fun :)
i am trying to draw a triangle unsing multiple threads, each thread will draw an independent piece of the triangle. But its runs a lot slower than using just one thread. whats is the problem?
here is the code:
(...)
int nCores = Runtime.getRuntime().availableProcessors();
Thread[] threads = new Thread[nCores];
int width = box[1][0] - box[0][0];
int incr = width / nCores;
int x = box[0][0];
for (int i = 0; i < nCores; i++) {
threads[i] = new Thread(new TriFiller(x, x + incr, z - nx * incr
* i));
threads[i].start();
x += incr;
}
try {
for (int i = 0; i < nCores; i++)
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
and the runnable:
public class TriFiller implements Runnable {
int xi, xf;
double z;
public TriFiller(int xi, int xf, double z) {
super();
this.xi = xi;
this.xf = xf;
this.z = z;
}
#Override
public void run() {
boolean inOut = false;
double z0 = z;
int rgbColor = shade.getRGB();
BufferedImage image = wd.getImage();
for (int i = xi; i < xf; i++) {
for (int j = box[0][1]; j < box[1][1]; j++) {
if (isOnSet(i, j, polyNormals, intBuffer)
&& z < zBuffer[i][j] && z > zd) {
image.setRGB(i, j, rgbColor);
zBuffer[i][j] = z;
inOut = true;
} else {
if (inOut) {
break;
}
}
z += -ny;
}
z0 += -nx;
z = z0;
inOut = false;
}
}
}
The reason you're having trouble is, that swing painting doesn't work with multithreading. Read this extract from another forum (jfree.org):
"I think the reason that you are not seeing any performance improvement is that you are not introducing any parrallelism by spinning off another thread.
The way updating the screen works in Swing is essentially:
1) As soon as the component decides that it should be repainted on the screen, JComponent.repaint() is called. This results in an asynchronous repaint request being sent to the RepaintManager, which uses invokeLater() to queue a Runnable on the EDT.
2) When the Runnable executes, it invokes the RepaintManager, which invokes paintImmediately() on the Component. The component then sets the clip rectangle and calls paint() which ends up calling paintComponent() which you have overridden. Remember that the screen is locked and will remain locked until the component has entirely repainted the dirty rectangle.
There is no point in spinning off a thread to generate the image buffer, because the RepaintManager HAS TO block until the buffer is ready so it can finish updating the dirty rectangle before releasing the lock on the screen.
All the toolkits that swing supports (windows, linux, mac) are single threaded by design. It is not possible to concurrently update more than one region of the screen."
I'm trying to learn making games with android using sensors. What I'm trying to do is to make a ball moving in the screen using acceleration sensor. Actually, I did some part of it. The ball moves in the screen when acceleration of x and y changes. But my problem is that it does not look smooth. It looks like the ball is not drawn on the screen in continuous paths. I use the SurfaceView class for this app and I made the drawing on different thread than the main thread.
Below part of code is from my MainActivity class and it is the sensor related part:
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
long actualTime = System.currentTimeMillis();
long delta_t = actualTime - lastUpdate;
lastUpdate = actualTime;
ax = event.values[0];
ay = event.values[1];
if (ax > 0) {
isleft = true;
delta_x = (float) (0.005 * ax * delta_t * delta_t);
}
if (ax < 0) {
isleft = false;
delta_x = (float) (-0.005 * ax * delta_t * delta_t);
}
if (ay > 0) {
isdown = true;
delta_y = (float) (0.005 * ay * delta_t * delta_t);
}
if (ay < 0) {
isdown = false;
delta_y = (float) (-0.005 * ay * delta_t * delta_t);
}
getBallPos();
}
}
private void getBallPos() {
delta_x /= 10000;
delta_y /= 10000;
for (int i = 1; i <= 10000; i++) {
if (isleft)
ballview.setX_loc(ballview.getX_loc() - delta_x);
if (!isleft)
ballview.setX_loc(ballview.getX_loc() + delta_x);
if (isdown)
ballview.setY_loc(ballview.getY_loc() + delta_y);
if (!isdown)
ballview.setY_loc(ballview.getY_loc() - delta_y);
}
}
Below part of code is from my BallGame class that extends SurfaceView and I do the drawings on a different thread:
#Override
public void run() {
// TODO Auto-generated method stub
while (isItOk) {
if (!holder.getSurface().isValid()) {
continue;
}
canvas = holder.lockCanvas();
canvas.drawARGB(255, 150, 150, 10);
// canvas.drawLine(lineStartX, lineStartY, lineEndX, lineEndY,
// paint);
checkBoundaries();
canvas.drawBitmap(ball, x_loc, y_loc, null);
holder.unlockCanvasAndPost(canvas);
}
}
private void checkBoundaries() {
if (x_loc > canvas.getWidth() - ballWidth) {
x_loc = canvas.getWidth() - ballWidth;
}
if (y_loc > canvas.getHeight() - ballHeight) {
y_loc = canvas.getHeight() - ballHeight;
}
if (x_loc < 0) {
x_loc = 0;
}
if (y_loc < 0) {
y_loc = 0;
}
}
Thank you in advance.
I think that there are two problems:
First is, that you are updating the ball position in onSensorChanged method. This method is called by the system and it is not guaranteed that the calling is done in constant frequency. In this case is ball movement depended on these calls. I think the better way would be to store the last ax and ay as a variables which would be accessible by both onSensorChanged method for writing values and drawing thread for reading. Then you can compute ball position in drawing thread, which could redraw canvas with constant frequency.
This brings us to the second problem which is drawing thread while loop. It is not controlled how often is the canvas redrawn. It is big load for system. Better way is to choose the refresh rate (for example 50 frames per second) and update the drawing at this frequency. It could be done at the end of the while loop, where Thread.sleep() function can be called. You can measure when the frame drawing started long frameStartTime = System.currentTimeMillis() at the start of the while loop and then call at the end of the while loop:
long sleepTime = refreshInterval-(System.currentTimeMillis()-frameStartTime );
if (sleepTime > 0) {
Thread.sleep(sleepTime);
}
(for 50 fps is refreshInterval = 1000/50 = 20 ms).
This calling sleeps the thread for the time of frame refresh interval minus time which was used to draw the ball. When you select adequate refresh rate system load will be lower and will have more time for redrawing.