Is there a way to make my 2048 game run faster?
I made a setting called high speed mode so that if moves were made really fast I would just skip the spawning, combining and moving animations, however even with that I am still usually one or two moves behind when I spam a bunch of keys at once.
Right now I have a tilePanel class to handle displaying my tiles, and use a timer(very basic code) with paintComponent(drawing the tiles constantly) to make sure it continually updates the board.
public void doAnimation() {
System.nanoTime();
Timer timer = new Timer(2, this);
timer.start();
}
The way I have structured my game is that I have an ArrayList of commands(ie pressing the right key adds "right" to the arraylist and eventually the arraylist gets to it and executes) I receive to make sure that it always does a move, spawns before doing the next move in the sequence.
To make sure the board continually updates itself, i made a very basic run thread:
public void run(){
while(true) {
if(canDoNewMove&&commands.size()>0&&parent.spawnsLeft==0) {
move(commands.get(0));
commands.remove(0);
canDoNewMove=false;
}
if(commands.size()>=2) {
board.isBehind=true;
}
else {
board.isBehind=false;
}
if(totalMovements==0&&moveDone) {
moveDone=false;
if(parent.changed) {
parent.spawn(parent);
}
canDoNewMove=true;
}
//moveDone=false;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}};
Thread sampleThread = new Thread(backGroundRunnable);
sampleThread.start();
}
Would reducing method calls produce a noticeable enough difference that the actions would finish right after I press the keys or is the problem within the tilePanel class that draws the board?
thanks guys
Related
I am using a Thread to do some calculations related to the app that need to be done simultaneously but this Thread causes the FPS to drop (logically) and I wanted to know how to resolve the issue as the Thread is not doing any heavy calculations at all. Here is the code where I implement the Thread and the Thread itself.
incrementMass = new IncrementMass();
incrementMass.start();
// I added some extra functionality to the InputProcessor but I assume that is irrelevant
if(InputProcessor.isButtonUp() && InputProcessor.getButtonLetGo() == RIGHT && !isJustPressed) {
isJustPressed = true;
try {
incrementMass.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
} else if(Gdx.input.isButtonJustPressed(RIGHT)) {
isJustPressed = false;
incrementMass.restart();
}
The Thread:
/**
* Thread to increment the mass in a while loop.
*/
public class IncrementMass extends Thread {
/**
* Increments the mass when started.
*/
#Override
public void run() {
super.run();
while(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
MainScreen.m += 100;
System.out.println(MainScreen.m);
}
}
/**
* Resets the mass so the whole thing starts over (for the creation of a new planet)
*/
public void restart() {
MainScreen.m = 100000;
}
}
All this is called in the render() function of my Screen by the way.
I have one idea as to what is causing this: Every frame I create a new Thread which is not optimal but everything else I tried failed to actually perform my calculations correctly. It definitely solves the FPS problem to have the initiation of the Thread and the ´start()´ function in the constructor of my Screen but that for some reason messes with the incrementing of the mass and makes it a fixed value: the value I reset it to in ´restart()´
I've been trying to solve this but I'm baffled so here I am.
As said in the comment, there was no function for isButtonJustUp() which made it not be able to run sequentially. Therefore I made a Thread so that it was sequential which is not a good implementation of Threads. I've come up with a solution:
if(Gdx.input.isButtonPressed(RIGHT)) {
m += 100;
} else if(InputProcessor.isButtonJustUp() && InputProcessor.getButtonLetGo() == RIGHT) {
planets.add(new Planet(10, m, mouseOnWorld2.x, mouseOnWorld2.y));
m=0;
}
I haven't made isButtonJustUp() yet but it is the best way rather than implementing an unnecessary Thread.
Trying to draw something every ms on single canvas. I mean only adding details to canvas, not redrawing it all every frame. So this code gives me three different canvases. Third, then first again. Why?
public void run() {
this.run = true;
Canvas canvas = null;
while (run) {
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (this.surfaceHolder) {
Thread.sleep(delay);
draw(new Img(canvas, size));
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (canvas != null) {
this.surfaceHolder.unlockCanvasAndPost(canvas);
}
}
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) {}
}
}
}
}
If it is android triple buffering - how to turn it off, or do something with it?
Android 4.2.1
If you like to preserve your previous draw you should draw them in an off-screen canvas and draw them to the canvas you got from lock canvas.
The puesd-code to illustrate the idea:
Bitmap offScreenBitmap = Bitmap.createBitmap(100,200,Bitmap.ARGB_8888);
Canvas offScreenCanvas = new Canvas(offScreenBitmap);
onScreenCanvas = this.surfaceHolder.lockCanvas();
//always draw to te offScreenCanvas
offScreenCanvas.drawXxxx
//copy the data to on-screen canvas you got from the lock
onScreenCanvas.drawBitmap(offScreenBitmap);
unlockAndPost(onScreenCanvas)
That should get your task done. Right?
Then, a little bit under the hood stuff:
Yes, android view (surface IS A view) has multiply buffers: one is used by apps for drawing and one is used by system for rendering and sometimes there is a third one when if the app can not finish drawing timely. No way to turn it off and you won't want to. And it is the reason you get different canvas when lock as you have already observed.
I would recommend against naming a boolean field, "run" in a Runnable implementation (in which the method returns void). Even if problems don't surface from the conflict, it's confusing. Maybe "running", or something (anything), would make more sense - easier to debug.
Don't use Object.wait when you are multi-threading. It won't always (generally, will not) act as you might expect.
You are most likely getting multiple instances of your Canvas member because somewhere (maybe in the Android framework, or maybe in your code... hard to tell), "new Canvas(args)" is being called while what you believe to be your only Canvas instance is out on another thread. While you have only one reference, more than one instance can be created.
I wouldn't recommend using synchronized(whatever) unless you are sure you need to do so.
Hang in there. This problem is very confusing - I worked through it last Spring and it wasn't easy or fun.
Hope any of the above helps in some way.
-Brandon
At first I did this:
public SpaceCanvas(){
new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
int fcount = 0;
#Override
public void run() {
System.out.println("Update thread started!");
while(!Thread.interrupted()){
fcount++;
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
}
while(entities.iterator().hasNext()){
entities.iterator().next().update(fcount);
}
System.out.println("About to paint");
repaint();
System.out.println("Done with paints");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
in the initializer of a thing I call a SpaceCanvas.
However, that doesn't allow the canvas, and therefore the applet it is within, to be created, because the Thread doesn't actually run asynchronously. Then, I replaced ".start()" with ".run()" and the thread only ran once, but the SpaceCanvas initialized perfectly.
What did I do wrong, and how do I fix this?
I'm not sure this sort of code works the way you expect it to:
while(players.iterator().hasNext()){
players.iterator().next().update(fcount);
players.iterator() gets a new iterator for the players collection. If there are 0 items in the collection then it will be false but if there are any items, you will be in an infinite loop, creating a new iterator each time. The iterator() call inside of players generates another new iterator object as well.
I think you should doing something like:
Iterator iterator = players.iterator();
while (iterator.hasNext()) {
iterator.next().update(fcount);
}
This is the same with your entities loop as well. A better pattern (as of Java 5) is to use the for loop:
for (Player player : players) {
player.update(fcount);
}
Also, if multiple threads are accessing these collections, they have to be somehow synchronized. You can either use a concurrent collection or you have to make sure every access (read and write) is within a synchronized block.
synchronized (players) {
for (Player player : players) {
player.update(fcount);
}
}
...
// down in the outer thread
synchronized (players) {
players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}
Obviously the entities will need to be synchronized in the same manner.
In this millennium, use Swing (JApplet/JPanel) rather than AWT (Applet/Canvas)
When using Swing, establish a Swing Timer that calls repaint() every 500 msec.
(When using Swing/Timer) Don't call Thread.sleep(n) on the EDT (Event Dispatch Thread).
..can you draw on a JPanel?
Sure thing. To do so, override the paintComponent(Graphics) method. You might also extend a JComponent and do the same, but there are some quirks to dealing with a JComponent that make the JPanel the better choice to extend.
On the other hand, there is another approach entirely.
Create a BufferedImage of the size required for whatever custom graphic is needed.
Add the image to an ImageIcon.
Add the icon to a JLabel.
Add the label to the GUI.
On each Timer action.
Call image.getGraphics() to obtain the drawing surface.
Replicate what you might have done in paint() or paintComponent()
(If needed) erase all previous drawing.
Draw the current custom rendering.
dispose() of the Graphics instance of the image.
call label.repaint()
I am working on a game using the thread-per-client model. The game operates so that every half a second all of the players need to be updated. The updates all have to happen within the half a second interval, so they need to all be executed at the same time. My idea is to have a class that keeps track of when the "global update" needs to happen and then when the time comes, go through all of the players and tell it to update:
for(Player p : currentPlayers) {
p.update();
}
The problem is that since every player has their own thread, I want the player to take advantage of that fact since it is already there. If I go through the updates from a different class, then there is one thread executing what a couple hundred threads could be doing individually. How can I design it so that if a thread calls method 'update()' in class Player, a different thread than the one that called it executes it, or perhaps a different approach that can achieve the same goal?
If you need any clarification, please ask! Thanks a lot!
UPDATE: What do you guys think of this (I can't figure out how to format long amounts of code in posts!):
UPDATE 2: Just realized I would need to know when all of the players finish updating to reset the last time...
public class PseudoExample implements Runnable
{
// Assume 'players' is full of active players.
private Player[] players = new Player[100];
private long lastUpdate = System.currentTimeMillis();
public void run()
{
while (true)
{
if (System.currentTimeMillis() - lastUpdate >= 500)
{
for (Player p : players)
{
p.update = true;
}
}
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
}
}
}
private class Player implements Runnable
{
private boolean update = false;
public void run()
{
while (true)
{
if (update)
{
// Do updating here ...
}
try
{
Thread.sleep(10);
} catch (InterruptedException e)
{
}
}
}
}
}
I think the best way to handle this would be instead of calling p.update(), you could send an asynchronous message to p. This would use the Handler functionality. This is probably the cleanest way, although I believe some (likely trivial) overhead will occur from the message passing.
So, in your ticking thread (i.e. the one that calls the global update), you would have a reference to a Handler object for each client thread. Then, you look would look like
for (Player p : currentPlayers) {
p.handler().sendMessage(); // this isn't exactly the syntax
}
and in your Player, you would have a PlayerHandler object that extends Handler and overrides handleMessage(Message).
EDIT: the comments on the question are good ones - don't use more threads than you need to. They might seem to be the "right" abstraction, but they introduce a ton of potentially tricky issues. If all of your computation needs to be done in between ticks, it might not matter whether it's done sequentially or not.
I’m writing a Tetris-like game for Android and I’m trying to implement the “real-time part”. I have something which seems to work, but I want to be sure that my implementation is correct.
What I want is:
The shapes are going down at a fixed rate (say that I want to wait n milliseconds each time the y of the shape is decremented)
The player can drop the shape at any time and the timer waiting for the n milliseconds must then be immediately interrupted and start again only for the next shape
When the shape is droped or when the shape cannot go down anymore, the game waits m milliseconds before creating another shape
The system have to be able to stop the thread at any time
What I am doing is the following (the system can stop the thread with interrupt()):
class TetrisThread extends Thread {
private int n = 3000; // for testing purposes, in the real game n will be smaller ;)
private int m = 1000;
#Override
public void run() {
doDraw();
while(!interrupted())
{
try {
synchronized (this) {
wait(n);
}
doPhysics();
doDraw();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
// This method is the one which will drop the shape, it is called from another thread
synchronized public boolean onTouch([…]) {
[…]
// The shape has to be dropped
dropShape();
notify();
[…]
}
private void doPhysics() throws InterruptedException {
[…]
// The shape cannot go down or has been dropped
sleep(m);
createNewShape();
[…]
}
}
In particular, the part synchronized(this) { wait(n); } looks funny because if I understand correctly this will take a lock on this and release it immediately.
But wait() requires to be used in a synchronized(this) block (why?) and I cannot either synchronize the whole run() method, because then if I try to drop three times the shape during the sleep(m) call, then the three next shapes will be automatically dropped (which is not what I want).
Does this seem correct to you?
Do you have any correction, advice, or remark?
Thank you :-)
The wait() method is used to make the current running thread to wait the object invoking wait() invoke notify() (in this case this). The synchronized(this) part needed to make sure only one thread at that time accessing this.
You can't synchronize the whole run() method, because the run() is from the parent (Thread) class and the parent didn't use synchonized in the declaration.
I don't know how to solve your other problem because I don't get how your program works right now.