I have a question. I have a timer that looks like a progress bar moving backwards. Now it works good or I should say well on older phones but the newer one with the HD screens well it doesn't work well. The timer bar is set vert and match_parent in my xml.
I am including my method below can you look at it and tell me how i can improve it?
//used to animate timer bar
private Handler mHandler = new Handler();
//timer event code
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
final long start = startTime;
// startTime will come from a spinner it will be 0,1,2,3,4 or 5 (users choice)
// ** the bar is GREEN until the if condition is meet
long currentLength = System.currentTimeMillis() - start;
long remainingTime = gameTime - currentLength;
float x = (float)remainingTime / (float)gameTime;
if(remainingTime > 0)
{
//still have time remaining - update UI
LinearLayout timerUI = (LinearLayout) findViewById(R.id.timerUI);
timerUI.getLayoutParams().height = (int) (x * 400);
//update color
if(remainingTime < 15000)
timerUI.setBackgroundColor(Color.RED);
else if(remainingTime < 30000)
timerUI.setBackgroundColor(Color.YELLOW);
timerUI.requestLayout();
timerUI.invalidate();
mHandler.postDelayed(this, 500);
}
else
{
if(monitorThread != null)
monitorThread.interrupt();
//NEED to push user to final screen
Intent resultsIntent = new Intent(SingleGameActivity.this,
ResultsActivity.class);
startActivity(resultsIntent);
}
}
};
Related
I'm working on a java 2d game, using this simple game loop to cap the FPS and UpdatesPS to 60:
public void run() {
final int MAX_FPS = 60;
final int MAX_UPS = 60;
final double fOPTIMAL_TIME = 1000000000 / MAX_FPS;
final double uOPTIMAL_TIME = 1000000000 / MAX_UPS;
double uDeltaTime = 0, fDeltaTime = 0;
int frames = 0, updates = 0;
long startTime = System.nanoTime();
long timer = System.currentTimeMillis();
// GameLOOP starts here
while (running) {
long currentTime = System.nanoTime();
uDeltaTime += (currentTime - startTime);
fDeltaTime += (currentTime - startTime);
startTime = currentTime;
if (uDeltaTime >= uOPTIMAL_TIME) {
gameUpdate();
updates++;
uDeltaTime -= uOPTIMAL_TIME;
}
if (fDeltaTime >= fOPTIMAL_TIME) {
gameRender();
gameDraw();
frames++;
fDeltaTime -= fOPTIMAL_TIME;
}
if (System.currentTimeMillis() - timer >= 1000) {
fps = frames; //saves the current FPS
ups = updates; //saves the current UPS
updates = 0;
frames = 0;
timer += 1000;
}
}
}
The loop works, but I get only 30 FPS for the first ~10 Seconds after starting the game.
After I wait, the FPS raises up to the wanted 60. I don't have a problem to wait a few seconds to let the program stabilize and reach the wanted framerate. But I can't find the reason like a methode who drops the FPS because it's fetching a big file after startup.
Do you have any idea why my engine needs so long to stabilize the framerate?
Thanks for your help!
I think this should do the trick:
public static void run()
{
final int desiredFPS = 60;
final int desiredUPS = 60;
final long updateThreshold = 1000000000 / desiredUPS;
final long drawThreshold = 1000000000 / desiredFPS;
long lastFPS = 0, lastUPS = 0, lastFPSUPSOutput = 0;
int fps = 0, ups = 0;
loop:
while(true)
{
if((System.nanoTime() - lastFPSUPSOutput) > 1000000000)
{
System.out.println("FPS: " + (double)fps);
System.out.println("UPS: " + (double)ups);
fps = 0;
ups = 0;
lastFPSUPSOutput = System.nanoTime();
}
if((System.nanoTime() - lastUPS) > updateThreshold)
{
lastUPS = System.nanoTime();
updateGame();
ups++;
}
if((System.nanoTime() - lastFPS) > drawThreshold)
{
lastFPS = System.nanoTime();
drawGame();
fps++;
}
// Calculate next frame, or skip if we are running behind
if(!((System.nanoTime() - lastUPS) > updateThreshold || (System.nanoTime() - lastFPS) > drawThreshold))
{
long nextScheduledUP = lastUPS + updateThreshold;
long nextScheduledDraw = lastFPS + drawThreshold;
long minScheduled = Math.min(nextScheduledUP, nextScheduledDraw);
long nanosToWait = minScheduled - System.nanoTime();
// Just in case
if(nanosToWait <= 0)
continue loop;
try
{
Thread.sleep(nanosToWait / 1000000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
Edit: I fixed the issue now! The issue was that I was saving the lastFPS/lastUPS after the scene was updated/drawn, and when I set both lastUPS/lastFPS before the scene is drawn/updated, we get the desired fps!Another neat thing about this code is that it doesn't consume a whole cpu core(I measured the difference, your code was consuming 100%, whilest my code only consumed about 10%. If you want to measure it yourself, please note that for some reason, the core on which the code is executed regularly switches(at least this was the case when I measured the code))By the way if you use LWJGL (or have direct access to a windowing library like GLFW) you can activate V-Sync, which would cut your fps down to 60 fps.
I am making a game in Android Studio. Now my game is complete, but game speed is different on large displays...
I run my game with this timer:
if(timer == null){
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if (start_flg) {
handler.post(new Runnable() {
#Override
public void run() {
changePos();
}
});
}
}
}, 0, 20);
}
changePos() looks like this:
public void changePos() {
SPEED_BOX =(screenHeight/280);
long time = System.nanoTime();
double delta_time = (double) ((time - last_time) / 1000000)/10;
last_time = time;
// Move Box
if (action_flg) {
// Touching
boxY += SPEED_BOX*delta_time;
box.setImageDrawable(imageBox1);
} else {
// Releasing
boxY -= SPEED_BOX*delta_time;
box.setImageDrawable(imageBox2);
}
// Check box position.
if (boxY < 0) {
boxY = 0;
box.setImageDrawable(imageBox1);
}
if (frameWidth - boxSize < boxY) {
boxY = frameWidth - boxSize;
box.setImageDrawable(imageBox2);
}
box.setY(boxY);
}
id correct that my deltaTime is allways between 1.5 to 2.9?
but every time I try it in different ways always game speed is not correct.
Is it possible to make my game running same speed on different devices, different screen sizes?
The problem was that screenHeight was screens height in pixels but the game does not use the whole screen. This caused that the speed was different on different devices. So screenHeight should be changed to gamesLayout.getHeight().
I'd like a button that moves in increments (sort of as if animated) when clicked. This code causes the button to move, but it only shows the beginning and end position (and not the increments in between). I'd prefer to use code most similar to this present code for now, but I'm open to learning new ideas for the future as well.
How can I create a slowly moving button as if it is animated?
public void onButtonClick3(final View view) throws InterruptedException {
for (int i=0; i<10; i++) {
long timer1 = System.currentTimeMillis();
long timer2 = System.currentTimeMillis();
ViewGroup.MarginLayoutParams vlp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
do {
sleep(300);
timer2 = System.currentTimeMillis();
}
while (timer1 + 1 > timer2);
int leftMargin = vlp.leftMargin;
int topMargin = vlp.topMargin;
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
params.width = 200;
params.leftMargin = leftMargin + 100;
params.topMargin = topMargin + 100;
view.setLayoutParams(params);
}
}
Thanks!
hi am trying to make a small game using canvas and bitmaps i want my game to run the same on all devices i found delta time is the best practice for this but for some reason when i try to implement it into my code i have display issues for example am trying to move my coluds in the sky but when i add the delta they all disapere i dont know if im doing it wrong so please can sombody help me heres the code
private float c1x = 0.0f;
private float c2x = cloudWidth;
private float c3x = cloudWidth * 2;
private float cloudSpeed = 0.1f;
private long curentTime;
private long lastTime = 0;
private double delta;
#Override
public void run(){
while(running){
if(!holder.getSurface().isValid()){
continue;
}
curentTime = System.nanoTime();
delta = curentTime - lastTime;
lastTime = curentTime;
cloudMovement();
canvas = holder.lockCanvas();
canvas.drawBitmap(bg, 0, 0, null);
canvas.drawBitmap(sun, 20, 20, null);
canvas.drawBitmap(cloud1, c1x, c1y, null);
canvas.drawBitmap(cloud2, c2x, c2y, null);
canvas.drawBitmap(cloud3, c3x, c3y, null);
holder.unlockCanvasAndPost(canvas);
}
}
private void cloudMovement(){
if(c1x <= 0 - cloudWidth){
c1x = w;
c1y = y.nextInt(rand);
}
if(c2x <= 0 - cloudWidth){
c2x = w;
c2y = y.nextInt(rand);
}
if(c3x <= 0 - cloudWidth){
c3x = w;
c3y = y.nextInt(rand);
}
c1x-=cloudSpeed * delta;
c2x-=cloudSpeed * delta;
c3x-=cloudSpeed * delta;
}
You could use a global FPS mechanism instead which forces a steady FPS on your game :)
If you track the FPS the game will run the same way on any device and you dont need to include delta-times on all update processes.
Here's a code snippet from a FpsTracker i used in an old project:
private static final long SECOND = 1000;
private static final long TARGET_FPS = 40;
private static final long FRAME_PERIOD = SECOND / TARGET_FPS;
private long time = System.currentTimeMillis();
/**
*
* #param startTime
* #return <code>true</code> if the interval between startTime and the time
* when this method was called is smaller or equal to the given
* frame period.
*
* Will return <code>false</code> if the interval was longer.
*/
public boolean doFpsCheck(long startTime) {
if (System.currentTimeMillis() - time >= SECOND) {
time = System.currentTimeMillis();
}
long sleepTime = FRAME_PERIOD
- (System.currentTimeMillis() - startTime);
if (sleepTime >= 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
//TODO handle this properly
e.printStacktrace()
}
return true;
} else {
return false;
}
}
If this method returns false it means that your operations took longer that the timeperiod you gave to one frame. You can react to this by checking the doFpsCheckreturn parameter.
Implementing this in your code would look like this:
#Override
public void run()
{
while(running)
{
if(!holder.getSurface().isValid())
{
continue;
}
startTime = System.currentTimeMillis();
cloudMovement();
canvas = holder.lockCanvas();
canvas.drawBitmap(bg, 0, 0, null);
canvas.drawBitmap(sun, 20, 20, null);
canvas.drawBitmap(cloud1, c1x, c1y, null);
canvas.drawBitmap(cloud2, c2x, c2y, null);
canvas.drawBitmap(cloud3, c3x, c3y, null);
holder.unlockCanvasAndPost(canvas);
doFpsCheck(startTime);
}
}
By the way - it is good practice to devide your game loop into pro sub processes, one being the update process, the other being the draw process.
For many different Bitmaps you should consider extracting the fields and functionalities into seperate classes containing a draw(Canvas c) and update() method. So you wont get a trillion fields on your main class.
I have a JScrollPane with a moderately high block increment (125). I would like to apply smooth/slow scrolling to it so it doesn't jump (or skip) when scrolling. How can I do this?
I was thinking of scrolling like Windows 8.
Any help would be greatly appreciated!
You could use a javax.swing.Timer during the scroll to achieve the smooth scrolling effect. If you are triggering this from outside the component, somthing like this will work (where component is the component within the JScrollPane):
final int target = visible.y;
final Rectangle current = component.getVisibleRect();
final int start = current.y;
final int delta = target - start;
final int msBetweenIterations = 10;
Timer scrollTimer = new Timer(msBetweenIterations, new ActionListener() {
int currentIteration = 0;
final long animationTime = 150; // milliseconds
final long nsBetweenIterations = msBetweenIterations * 1000000; // nanoseconds
final long startTime = System.nanoTime() - nsBetweenIterations; // Make the animation move on the first iteration
final long targetCompletionTime = startTime + animationTime * 1000000;
final long targetElapsedTime = targetCompletionTime - startTime;
#Override
public void actionPerformed(ActionEvent e) {
long timeSinceStart = System.nanoTime() - startTime;
double percentComplete = Math.min(1.0, (double) timeSinceStart / targetElapsedTime);
double factor = getFactor(percentComplete);
current.y = (int) Math.round(start + delta * factor);
component.scrollRectToVisible(current);
if (timeSinceStart >= targetElapsedTime) {
((Timer) e.getSource()).stop();
}
}
});
scrollTimer.setInitialDelay(0);
scrollTimer.start();
The getFactor method is a conversion from linear to an easing function and would be implemented as one of these depending on how you want it to feel:
private double snap(double percent) {
return 1;
}
private double linear(double percent) {
return percent;
}
private double easeInCubic(double percent) {
return Math.pow(percent, 3);
}
private double easeOutCubic(double percent) {
return 1 - easeInCubic(1 - percent);
}
private double easeInOutCubic(double percent) {
return percent < 0.5
? easeInCubic(percent * 2) / 2
: easeInCubic(percent * -2 + 2) / -2 + 1;
}
This could probably be adapted to work within a component too so when the user scrolls it does something along these lines.
Or, if possible, you could use JavaFX which has much better support for animation than Swing.