I've made this fairly simple View. It's supposed to animate a red line that travels from left to right over a period of time (DURATION). It should update it's position every DELAY, so that you can adjust the animation to be more smoother if you would want that. It should be noted that I'm testing this on the emulator. Well, if I increase DELAY then the animation finishes faster, even though it should have no effect on the total animation time. Am I simply animating too fast, hogging all the resources? Or is my math off?
public class AnimView extends View {
// Animation duration in milliseconds
private static final int DURATION = 4000;
// Update frame every delay (in milliseconds)
private static final int DELAY = 10;
private int pos;
private long lastTick;
private Paint paint;
public AnimView(Context context, AttributeSet attrs) {
super(context, attrs);
pos = 0;
lastTick = 0;
paint = new Paint();
paint.setColor(Color.RED);
}
#Override
protected void onDraw(Canvas canvas) {
if(System.currentTimeMillis() - lastTick >= DELAY) {
// Calculate a new position for the line
pos += (int) (((double) DELAY / DURATION) * getWidth());
lastTick = System.currentTimeMillis();
}
canvas.drawRect(pos, 0, pos + 1, getHeight(), paint);
if(pos < getWidth()) {
// Position is still below getWidth, keep animating
postInvalidate();
}
}
}
You should be updating lastTick in the if statement:
long currentTime = System.currentTimeMillis();
if(currentTime - lastTick >= DELAY) {
// Calculate a new position for the line
pos += (int) (((double) DELAY / DURATION) * getWidth());
lastTick = currentTime;
}
Otherwise you will draw each time after DELAY passes. So when you increase DELAY, less drawing happens and so the program finishes faster.
To add some additional color to this thread, this is a well known problem in game development. You can find lots of resources on it if you search for "Fixed time step vs Variable time step", for example: http://gafferongames.com/game-physics/fix-your-timestep/
The gist of it is that the speed of your animation is directly tied to your frame rate at the moment. This is why in the old NES megaman games, you'd have periods of slow down when there were lots of enemies on the screen at once (because the CPU was busier calculating all the data for those entities, so each frame took longer to process).
There are two ways around this problem:
Move to a variable time step where you multiply each movement by the amount of time that progressed between each frame of animation. That way, when that amount changes for any reason, your animation looks the same.
Separate the update and draw phases so that you can control the time diff that is passed into the update method, regardless of how fast you're drawing.
Related
I am currently developing a 2D game using Swing components.
Each time I run my game it stutters randomly at some points. This is my game loop code:
public class FixedTSGameLoop implements Runnable
{
private MapPanel _gamePanel;
public FixedTSGameLoop(MapPanel panel)
{
this._gamePanel = panel;
}
#Override
public void run()
{
long lastTime = System.nanoTime(), now;
double amountOfTicks = 60.0;
double amountOfRenders = 120.0;
double nsTick = 1000000000 / amountOfTicks;
double nsRender = 1000000000 / amountOfRenders;
double deltaTick = 0;
double deltaRender = 0;
while (this._gamePanel.isRunning())
{
now = System.nanoTime();
deltaTick += (now - lastTime) / nsTick;
deltaRender += (now - lastTime) / nsRender;
lastTime = now;
while (deltaTick >= 1)
{
tick();
deltaTick--;
}
while (deltaRender >= 1)
{
render();
deltaRender--;
}
}
}
private void tick()
{
/**
* Logic goes here:
*/
this._gamePanel.setLogic();
}
private void render()
{
/**
* Rendering the map panel
*/
this._gamePanel.repaint();
}
}
I have tried multiple times to omit certain code parts, thinking that they cause lag, but I have found nothing that caused it particularly, so I think the problem lies within my game loop mechanism.
Thank you for your help!
Your game loop must contain a "Thread.sleep" on order to sleep the amount of time needed to respect your target FPS.
The main loop is supposed to contain 1 tick() and 1 render().
Your current implementation is flooding the paint manager, slowdowns will appear when the underlying buffers will be full and when the garbage collector will do its job.
While it's good that you've split your render and logic in two different methods, the problem lies in that they exist in the same thread.
What needs to happen to reduce the lag is to have them in separate threads. The render thread would request a snapshot of the current state from the logic thread (to prevent concurrent modification) and render that snapshot.
Right now, if one render takes too long, or if one logic step takes too long, the other check is going to have to wait for it to finish before it can begin working.
My first posted question here, so I'm begging forgiveness in advance for my question-formatting inexperience.
My 2D graphics game normally runs perfectly on my system. But when Norton Internet Security’s ccSvcHst.exe process is running with very high CPU utilization, it has strange interactions with the game. I have identified the specific lines of Java code which are impacted.
// Graphics setup, just trying to give some background
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = e.getDefaultScreenDevice();
GraphicsConfiguration grafConf = device.getDefaultConfiguration();
Frame f = new JFrame(grafConf);
device.setFullScreenWindow(f);
f.createBufferStrategy(2);
BufferStrategy buffStrat = f.getBufferStrategy();
Graphics grafx = buffStrat.getDrawGraphics();
// Create some sprites to draw here...
// Launch a game loop to execute every 15ms
Timer timer = new Timer();
TimerTask task = new TimerTask() { public void run() { gameLoop(); }};
timer.schedule(task,0,15);
public void gameLoop() {
BufferedImage erase = getEraseBI();
// Erase each the 64x64 sprites...
int x, y; x = getX(1); y = getY(1);
long t1start = System.currentTimeMillis();
grafx.drawImage(erase, x, y, null);
long t1end = System.currentTimeMillis();
x = getX(2); y = getY(2);
long t2start = System.currentTimeMillis();
grafx.drawImage(erase, x, y, null);
long t2end = System.currentTimeMillis();
// and so on, for each sprite to erase
// Move stuff and redraw it; no problems here...
// Now flip the page to show what we’ve drawn
long show1 = System.currentTimeMillis();
buffStrat.show();
long show2 = System.currentTimeMillis();
grafx.dispose();
grafx = buffStrat.getDrawGraphics();
}
Normally, the drawImage() and buffStrat.show() calls execute so fast that the difference between the two times shows as 0. But after a couple of minutes, when there are more than about a dozen sprites to erase, one or more of the drawImage() calls (but not all of them), as well as the buffStrat.show() call suddenly take 25-35ms instead of 0. This behavior persists until the game is stopped. Rebooting the system clears the high-CPU ccSvcHst condition, restoring normal, stable, play-for-3-hours-straight-without-any-issues game performance.
Without getting into a political discussion about the merits of Norton tools, I'm just curious - has anyone else seen this interaction between Java graphics and NIS ccSvcHst.exe?
What is the best way to render in game loop on android?
When I'm rendering in java I know how to do this. I create buffer strategy, than graphics, I draw, than dispose and than flip buffer. Is there Andorid equivalent of that?
I looked into view, but it doesn't work correctly when I try draw a lot. I looked into SurfaceView than, but I can't understand how I can refresh drawing on it. invalidate breaks the loop, postInvalidate doesn't work. I lock canvas and draw on it, and than unlock and post in "create" method from surface view (locking canvas in loop doesn't work, only white screen in app appears). So I don't get it.
What's the most efficient way to render heavily in Android?
The common approach to render within a SurfaceView is through its SurfaceHolder.
Usually you'll get a Canvas through the holder and draw on it:
SurfaceHolder surfaceHolder = surfaceView.getHolder();
Canvas canvas = surfaceHolder.getSurface().lockCanvas();
//draw in the canvas
canvas.drawPoint(...);
surfaceHolder.unlockCanvasAndPost(canvas);
The correct approach is to loop all the code between the lockCanvas() and unlockCanvasAndPost() (inclusive) in a separate thread (the render thread) and control the framerate with a Thread.sleep() inside the loop.
EDIT:
There are many ways to control the FPS of the render thread, this is a basic one, just set the wanted FPS on a constant:
public class RenderThread extends Thread {
private boolean running;
private final static int MAX_FPS = 30;
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
#Override
public void run() {
long beginTime;
long timeDiff;
int sleepTime;
sleepTime = 0;
while (running) {
beginTime = System.currentTimeMillis();
//RENDER
// How long did the render take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
}
}
}
There are lots of references if you search for game loops.
I have recently started on developing my own game engines for fun. I implemented a method to load Blender .OBJ models from files, and I am successfully rendering them. However, when doing a stress-test I ran into an unusual predicament with my Delta-time based fps system. While running at 1500FPS, it takes me 4 seconds to look from one end of a wall of models to another. If I cap the FPS at 120FPS, however, it only takes my 0.84 seconds to look from one end of the wall to another. As I explored further it would seem that, in fact, the game-movement speed decreases as FPS increases.
Here is my Timer class:
class Timer
{
long lastFrame;
int fps;
long lastFPS;
int delta;
int fpsToReturn;
public Timer()
{
lastFPS = getTime();
}
public long getTime()
{
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
public int getDelta()
{
long time = getTime();
delta = (int) (time - lastFrame);
lastFrame = time;
return delta;
}
public void updateFPS()
{
if (getTime() - lastFPS > 1000)
{
fpsToReturn = fps;
fps = 0;
lastFPS += 1000;
}
fps++;
}
public int getFPS()
{
return fpsToReturn;
}
}
And of course movement is just something along the lines of:
camera.rotX += (0.5 * timer.getDelta());
Does anyone have any ideas? Is this how delta-time is supposed to work? When running at 16FPS it returns around 65, at 120FPS Delta is returning around 8-9, while uncapped FPS it always returns 0 or 1 if that makes a difference or helps you spot if something is wrong with the uncapped FPS. I really appreciate any help, thank you guys.
Solved my own question, and glad I learned in the process.
My issue, which I later discovered when I was implementing angular movement, was that I was using the method getDelta() and getFPS() every time i needed it more than once-per-frame, which was throwing off the delta variable. I solved the issue by using a static variable, one for FPS and one for Delta, and updating each variable at the end of each frame.
Pseudo Code:
public static double globalDelta;
while(nextFrame) //Loops once per frame
{
updateGame();
globalDelta = calculateDelta();
}
I;m making a game in which I have to move little squares on an n by n grid, and they have to transition smoothly. This is the swap method I made which should be able to paint my transition on screen, but for some reason it is not doing it. I tried a much simpler version of my code on a simple project to move a Square back and forth and it worked like a charm, so I'm really not sure why this isn't repainting. This is just a bit of my code so if there's doubts about anything else on my code, ask away.
Thanks in advance. (:
public void swap( int y, int x ) {
long time = System.currentTimeMillis();
int counter = 0;
swapNum = tiles[y][x];
rect = (Rectangle) rectangles[y][x].clone();
while(counter < rect.height) {
if(System.currentTimeMillis() - time > 5) {
rect.translate(this.y-y, this.x-x);
time = System.currentTimeMillis();
counter++;
repaint();
}
}
swapNum = 0;
rect = new Rectangle();
int temporary = tiles[this.y][this.x];
tiles[this.y][this.x] = tiles[y][x];
tiles[y][x] = temporary;
this.x = x;
this.y = y;
}
If this block of code is running on the Event/Dispatch thread, which is used for drawing to the screen, then this will block the screen from updating.
Instead of doing the entire animation in one loop, consider designing an update method to do the animation, that will be called once every 15-30 milliseconds, and update the rectangle's position accordingly. Even better for smooth graphics is to draw to an image buffer and then have the actual draw method paint that buffer to the screen (double buffering).
Java3D has animations built-in, so it may be worth a look.