I currently have a game loop that looks like this
new AnimationTimer() {
public void handle(long currentNanoTime) {
if (isPaused == false) {
double t = (currentNanoTime - startNanoTime) / 1000000000.0;
timerCorner = Math.round(t * 100.0) / 100.0;
} else {
...
}
}
I would like to pause my timer without stopping the AnimationTimer loop. I thought it simplest to just accumulate an offset during the else statement, but you can't overwrite variables within the AnimationTimer loop. I think I can overcome this by updating a value within a class object, but don't know how to do so accurately? Or is there a better method.
My game is a time challenge so it's important the clock stops when the pause menu is active. The pause looks like this
else if (event.getCode() == KeyCode.ESCAPE) {
// System.out.println("Escape key is pressed");
isPaused = true;
...
}
Basically, I want to calculate a value X such that
double t = currentNanoTime - startNanoTime - X
counts up from when the game was paused, rather then jumping ahead to where CurrentNanoTime is now.
Related
Okay, so i've been trying to make smooth jumps in a 2D pure android with no game engine for a week now. I am using ScheduledThreadPoolExecutor right now.
So i have a variable called FPS. This is how many time the character has to go up before reaching 180 Y value;
Note: FPS is not really Frames per Second in the whole game.
When FPS is set to 45, the app never freezes (Unless I repeatly spam the jump button)
But on 90, AT RANDOM OCCASIONS WHEN I PLAY THE GAME the game FREEZES and logcat indicates:
E/WindowManager: Performed 6 layouts in a row. Skipping
It dosent matter what I use (EX: Handler Runnable and Thread), app
Here is the jump code:
public void jump() {
final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
if(!isRunning) {
executor.scheduleWithFixedDelay(new Runnable() {
boolean moveUpBln = true;
int timesLooped = 0;
float FPS = 90; //Never freezes with value of 45 (or under)
float charMovementFPS = 180 / FPS;
#Override
public void run() {
if(moveUpBln) {
isRunning = true;
characterModel.setY(characterModel.getY() - charMovementFPS);
if (timesLooped == FPS || timesLooped > FPS) {
moveUpBln = false;
timesLooped = -1;
}
timesLooped++;
}else{
isRunning = true;
characterModel.setY(characterModel.getY() + charMovementFPS);
if (timesLooped == FPS || timesLooped > FPS) {
executor.shutdownNow();
isRunning = false;
}
timesLooped++;
}
}
}, 0, 3, TimeUnit.MILLISECONDS);
}
}
NOTE: the -1 isn't the problem, this is intentional
What are these layouts the logcat is talking about? Am I putting too much pressure on my Non-Engine game?
this is my first game and I'm not that experienced of a programmer but I've researched a lot and I've worked on this game every day for the last couple of weeks. I research different things on this website every day and I find your posts here tremendously helpful :)
I have a question regarding fixed timestep loops, can't wrap my head around why changing the time to wait between updates affects the speed of which my entire game moves. Maybe there's something I'm missing or something I don't understand yet
My loop looks like this:
private void gameLoop(){
final double updateWaitTime = 1000000000/50;
double nextUpdateTime = System.nanoTime();
while(running) {
double now = System.nanoTime();
while( now > nextUpdateTime) {
updateGame(now);
nextUpdateTime += updateWaitTime;
}
double interpolation = (now+updateWaitTime-nextUpdateTime)/updateWaitTime;
drawGame(interpolation);
}
}
If I decrease the value of updateWaitTime, my game moves much faster because it is getting updated so much more.
The methods that execute my movement looks like this, they both get the current time with getNanoSecond() which holds the same value that the gameLoop sets "now" as.
protected void travel(){
if(moveShotTime <= c.getNanoSecond()){
setX(getX()+dx);
setY(getY()+dy);
moveShotTime = c.getNanoSecond()+bulletMoveDelay;
}
}
//[0] = degree. [1] = distance. [2] = movementspeed
public void move(){
if(moves.isEmpty() == false){
ArrayList<double[]> movementDirection = moves.get(0);
if(movementDirection.isEmpty() == false){
double[] oneMove = movementDirection.get(0);
if(getNextMoveTime() <= c.getNanoSecond()){
else if(oneMove[1] > distanceMoved){
double radian = (oneMove[0]/360)*2*Math.PI;
double dx = round((Math.cos(radian)*oneMove[2]), 9);
double dy = round((Math.sin(radian)*oneMove[2]), 9);
double dz;
if(dx<0){
dz = round(dx/(Math.cos(radian)), 5);
}
else if(dx==0){
dz = dy;
}
else if(dy==0){
dz = dx;
}
else{
dz = round((dx/(Math.cos(radian))), 5);
}
setX(getX()+dx);
setY(getY()+dy);
if(dz<0){
distanceMoved = distanceMoved-dz;
}
else{
distanceMoved = distanceMoved+dz;
}
movedX = movedX + dx;
movedY = movedY + dy;
}
else{
movementDirection.remove(0);
distanceMoved = 0;
}
}
}
else{
setPreviousX(getX()-movedX);
setPreviousY(getY()-movedY);
moves.remove(0);
}
}
else{
}
}
So what I'm wondering is why changing the updateWaitTime affects the speed of everything. Since I'm using timestamps as a reference for when to execute the movement again, in my mind it shouldn't make a difference how often the game is updated as long as it's more often than the timesteps inside of the game. I'm new to this and I'm surely missing something here. I would also like to ask what a common update-time for games are on PC and android? If I can't figure this out I'm gonna have to set an update-time that I can't change to work with from here on (since i would have to adjust everything in the game).
Thanks in advance and thanks for all the great info on this website!! :)
Please look at the following structure of my pong game.
gameLoop(); method
//Only run this in another Thread!
private void gameLoop()
{
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running)
{
double now = System.nanoTime();
int updateCount = 0;
if (!paused)
{
//Do as many game updates as we need to, potentially playing catchup.
while( now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER )
{
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if ( now - lastUpdateTime > TIME_BETWEEN_UPDATES)
{
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES) );
//float interpolation = 1.0f;
drawGame(interpolation);
lastRenderTime = now;
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while ( now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES)
{
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
try {Thread.sleep(1);} catch(Exception e) {}
now = System.nanoTime();
}
}
}
}
updateGame(); method
if(p1_up){
if(player.equals("p1")){
p1.moveUp();
}
else
{
p2.moveUp();
}
}
else if(p1_down){
if(player.equals("p1")){
p1.moveDown();
}
else
{
p2.moveDown();
}
}
moveUp(); moveDown(); method of paddle
public void moveUp(){
last_y = y;
last_x = x;
y -= 50.0;
}
public void moveDown(){
last_y = y;
last_x = x;
y += 50.0;
}
drawGame(interpolation); method
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<balls.size();i++){
paintBall(g, balls.get(i));
}
drawPaddle(g, p1);
drawPaddle(g, p2);
}
public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)((p.x - p.last_x)*interpolation + p.last_x);
paddle_drawY = (int)((p.y - p.last_y)*interpolation + p.last_y);
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}
I am a beginner in game programming so i don't have a good idea about game loops. I found the above fixed time-step game loop in the internet and used it as the game loop for my game. The loop makes the ball move smoothly but the paddle isn't staying at one place when moved. When I move my paddle by pressing one down key stroke then the paddle keeps shaking
without stopping in one spot. The y coordinates of the paddle keeps changing like
33, 45, 20, 59, 34, 59, 34, 59, 33, 59, 34, 58
I know the problem is in interpolation value as it keeps changing value that will change the y coordinate of paddle in render. I have been thinking about this for a while and i don't know how to make the game loop work for any movements so i have come here for some help. I appreciate any suggestion/help!
Here is my full Paddle class.
public class Paddle
{
float x;
float y;
float last_y;
float last_x;
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
this.last_x = x;
this.last_y = y;
}
public void setNewX(int d){
last_y = y;
last_x = x;
x = d;
}
public void setNewY(int d){
last_y = y;
last_x = x;
y = d;
}
public void moveUp(){
last_y = y;
last_x = x;
y -= 50.0;
}
public void moveDown(){
last_y = y;
last_x = x;
y += 50.0;
}
}
and i initiate the paddle position in the main class through global variable.
public Paddle p1 = new Paddle(10, 10);
public Paddle p2 = new Paddle(950, 10);
I have following event listeners for handling key strokes.
Action handle_up_action = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_up = true;
}
};
Action handle_up_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_up = false;
}
};
Action handle_down_action = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_down = true;
}
};
Action handle_down_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_down = false;
}
};
What are you trying to achieve with interpolation? From my understanding, it represents the percentage of time elapsed between previous previous and next "update time".
So it should progress continuously from 0 to 1 each 33.3 ms.
I don't know how you use this interpolation variable in the paintBall method, but for the paddles, it will draw your paddle at a "pseudo random position" between p.x;p.y and p.last_x;p.last_y (depending on the time between the two updateGame()).
In order to correct this, from your loop logic, you should understand that every game entity (balls, paddles, ...) must have two states (the positions):
- the logical state, which is updated only each TIME_BETWEEN_UPDATES
- the visual state, which can be updated anytime, at each render.
It is the same as if you have a set of points (which represent the logical states) and you want to interpolate anywhere between this points (reprensenting the visual state).
Your code is like this.
First solution
The simplest way to correct the paddle shaking, is to avoid the interpolation and use:
public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)p.x;
paddle_drawY = (int)p.y;
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}
But your movement will look like this (visual position will be changed only each TIME_BETWEEN_UPDATES)
Second solution
You want p.x;p.y to be the logical position, but the visual position should be interpolated between p.last_x;p.last_y and the logical position if the rendering is done between the input processing and the next updateGame(): you must reset p.last_x;p.last_y when updateGame() is called. To achieve this, call the paddles' updateMovement() method inside updateGame().
public void updateMovement(){
last_y = y;
last_x = x;
}
You can have other solutions, such as to use a speed variable or a movement function, in order to have a smooth movement, accelerations, and so on. It is mainly a generalisation of second solution. It requires bigger changes, but it is more flexible and powerful. To achieve this, you may want to store in paddles the last "update position", and all movement-related variables, such as movement start date. Add a method to retrieve the "visual position" that can be called with any date between two updates, and a method to update the "logical position" called each updateGame().
I am making a java 2d side scroller and im having problems with multiple keys at the same time. Such as right + up. Whenever you release the up you stop moving right as you slowly go back to the ground even though right is still being pressed. Here are the keyboard listeners I have setup. dx is my horizontal movement speed and dy is the vertical height. Below is from the character class
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -5;
mainCharacterImageFacing = l.getImage();
}
if (key == KeyEvent.VK_RIGHT) {
dx = 5;
mainCharacterImageFacing = r.getImage();
}
if (key == KeyEvent.VK_UP) {
dy = 1;
mainCharacterImageFacing = r.getImage();
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT);
dx = 0;
if (key == KeyEvent.VK_RIGHT)
dx = 0;
if (key == KeyEvent.VK_UP)
{dy = 0;
mainCharacterImageFacing = r.getImage();
}
This is some code from the main game window that deals with calling the key press/release methods as well as dealing with the jump.
private class AL extends KeyAdapter{
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
}
#Override
public void run()
{
long beforeTime;
long timeDiff;
long sleep;
beforeTime = System.currentTimeMillis();
while(done == false)
{
cycle();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = 10 - timeDiff;
if (sleep < 0 )
sleep = 2;
try {
Thread.sleep(sleep);
} catch (Exception e)
{}
beforeTime = System.currentTimeMillis();
}
done = false;
h = false;
k = false;
}
boolean h = false;
boolean done = false;
public void cycle() {
if (h == false)
v = v - 2; //jump speed falling
if (v == 350) //max y value of jump. Lower numbers = higher jumps
h = true;
if (h == true && v <= 470) //starting y value
{
v = v + 2; //jump speed rising
if (v == 470)
done = true;
}
}
Do not handle your movement directly in the AL class. Instead, use booleans and set them to true/false accordingly:
private class AL extends KeyAdapter{
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
left = true;
}
if (key == KeyEvent.VK_RIGHT) {
right = true
}
if (key == KeyEvent.VK_UP) {
//...
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
left = false
if (key == KeyEvent.VK_RIGHT)
right = false
if (key == KeyEvent.VK_UP)
//...
}
}
The reason for this is because keyPressed and keyReleased are called when the keys are acted upon, though that means it will not be in sync with your main loop.
To move your sprite call a method in the loop which, if your conditions are true, moves your sprite accordingly, else does nothing.
EDIT: After reviewing your code some more I have a few suggestions.
First of all, look up sub-pixel rendering. Sub-pixel rendering is used to make the movement of sprites look smoother.
Another thing to look up is variable timesteps (sometimes referred to as delta timesteps). Delta time can be used to make sure that actions are performed in sync with a players fps. If one player has 60fps and another has 30fps, the player with 30fps will see actions performed at half the speed. With a delta timestep however, actions are always performed at the same speed. Here's a good article.
The third thing is your timing. Currently you're using System.getCurrentTimeMills. This is bad, and not precise. Instead, use System.nanoTime.
A fourth thing I've spotted is your jumping algorithm. A better way is to include acceleration. First you need to declare a constant for acceleration (0.1 or 0.2 are good) and tally a vertical speed. You can then fall when the vertical speed gets to a certain value. Here's a small snippet, though if you have gravity you may want to edit it. First of all set vSpeed to say -8 by default.
public void jump() {
vSpeed += ACCELERATION;
if(vSpeed < 8)
dy += vSpeed;
else
vSpeed = -8;
falling = false;
}
I just wrote this off the top of my head, but basically, since moving upwards is taking away a number, you appear to jump when it adds negative numbers, then you'll start falling when it reaches 0, and land when reaches 8 again.
The problem is the way the OS handles key events and passes them to your application. When you press a key, it fires an event for down. Then based on your settings for repeating, it will start pressing the key again after some amount of time, at some amount of frequency. (you can see this when typing. Press a key, and hold it).
When you press another key, it stops the repeated triggers for the other key. You can see this while typing as well. Hold a key, then start holding another. The original key stops, as you would expect.
This won't even be consistent with every os, and people could cheat in your game as it is, by making the repeat timer on their keyboard faster.
For these reasons, it's a very bad idea to do animations inside of key listeners. You should be settings flags to true/false and reading them in a game loop. (As demonstrated in #Troubleshoot's answer).
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.