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?
Related
So I was messing with Swing for the first time in a while and I came across a strange issue. So I am adding "shapes" to a list every so often, and then in the paintComponent method of a JPanel I am looping through the list and drawing the shapes. I also draw a shape outside of the for loop for testing purposes.
What happens is the shapes in the for loop will jump around the screen randomly. This only happens when the shapes are drawn in this loop.
What I have tried already:
Updating graphics drivers for both the integrated GPU and discrete GPU
Using java.util.Timer instead of Swing Timer
Using Thread/Runnable
Using things other than ArrayList, such as LinkedList, Vector, and a normal Array.
Trimmed literally everything out of my code except the basics, which is what we're left with here. I was drawing more complex things before when I noticed it.
Changed the timing (PERIOD variable, in millis). It will get worse if I increase or decrease it.
Changed from using System time in milliseconds to the System time in nanoseconds, converted to milliseconds. I know this should be the same but I was running out of ideas.
Here is a gif of the problem (15 seconds long):
image
You'll notice that the small squares will jump around at random intervals. This should not occur. I'm just trying to "spawn" a square at random coords.
Here is the code in a pastebin:
code
I have included all 3 classes in this order: the JPanel class, the Main class (extends JFrame), and the shape class
If any of the links don't work, inform me and I will promptly post other links.
Thanks.
This setup ...
#Override
public final void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (this.startTime == -1L) {
this.startTime = Main.timeMillis();
}
final long timeDiff = Main.timeMillis() - this.startTime;
if (this.circlesIndex <= 19 && timeDiff > 2000) {
final int randX = this.rand.nextInt(this.WIDTH);
final int randY = this.rand.nextInt(this.HEIGHT);
this.testShapes.add(new TestShape(randX, randY));
this.startTime = Main.timeMillis();
}
for (TestShape ts : this.testShapes) {
ts.draw(g);
}
g2.setColor(Color.gray);
g2.fill3DRect(350, 400, 100, 60, true);
}
#Override
public final void actionPerformed(final ActionEvent event) {
x++;
if (x > WIDTH) {
x = -50;
}
repaint();
}
is wrong.
Paint is for painting - you should not modify the state of the UI from inside any paint method, do this within your ActionListener. The problem is, your component can be painted for any number of reasons, many of which you don't control or know about
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 am making a game and all is going well except for the game loop. I am using a SurfaceView and drawing 2D Sprites (Bitmaps). Currently the game is a ship moving through an asteroid field. The ship stays in the center of the screen and the phone is tilted in either direction to move the the asteroids (asteroids change location instead of player). New asteroids spawn as old ones fall off the screen creating an infinite asteroid field feeling.
Running on my Nexus 5, I noticed that after about 3 seconds, the asteroids moving down the screen became choppy, despite my game loop set to run at 60fps. Here was the code:
#Override
public void run() {
Canvas canvas;
long startTime;
long timeTaken;
long sleepTime;
while (running) {
canvas = null;
//Update and Draw
try {
startTime = System.nanoTime();
canvas = gameView.getHolder().lockCanvas();
//Update
gameModel.update(gameController.getPlayerShots(), gameController.getCurrentTilt());
//Game Over?
if (gameModel.isGameOver()) { running = false; }
//Draw
synchronized (gameView.getHolder()) { gameModel.drawToCanvas(canvas); }
}
finally {
if (canvas != null) {
gameView.getHolder().unlockCanvasAndPost(canvas);
}
}
//Sleep if needed
timeTaken = System.nanoTime() - startTime;
sleepTime = FRAME_TIME - timeTaken;
try {
if (sleepTime > 0) {
sleep(Math.abs((int)sleepTime/1000000), Math.abs((int)sleepTime % 1000000));
}
}
catch (InterruptedException e) {}
}
//Load menu after game over
if (gameModel.isGameOver()) {
gameController.launchContinueMenu();
}
}
I thought the problem may be that my model was doing the drawing to canvas and that I wasn't using my surfaceview's onDraw() method. Refactored to use onDraw() and same result as before. I printed out the sleep time of each frame and my thread was consistently sleeping for 5-10ms (16.667ms in a frame), so my nexus was not short on computing power.
I read on stackoverflow that I shouldn't use synchronize() on the view holder. Still no luck.
Then I read again on stackoverflow that using Thread.sleep() may be causing the issue because it is not always accurate. I did a major refactor as shown below.
#SuppressLint("WrongCall")
#Override
public void run() {
Canvas canvas;
while (running) {
canvas = null;
//Update and Draw
try {
canvas = gameView.getHolder().lockCanvas();
//Calc and smooth time
long currentTimeMS = SystemClock.uptimeMillis();
double currentDeltaTimeMS;
if (lastTimeMS > 0) {
currentDeltaTimeMS = (currentTimeMS - lastTimeMS);
}
else {
currentDeltaTimeMS = smoothedDeltaTimeMS; // just the first time
}
avgDeltaTimeMS = (currentDeltaTimeMS + avgDeltaTimeMS * (avgPeriod - 1)) / avgPeriod;
// Calc a better aproximation for smooth stepTime
smoothedDeltaTimeMS = smoothedDeltaTimeMS + (avgDeltaTimeMS - smoothedDeltaTimeMS) * smoothFactor;
lastTimeMS = currentTimeMS;
//Update
gameModel.update(smoothedDeltaTimeMS / 1000.0d, gameController.getCurrentTilt());
//Game Over?
if (gameModel.isGameOver()) { running = false; }
//Draw
// synchronized (gameView.getHolder()) {
// gameModel.drawToCanvas(canvas);
gameView.onDraw(canvas);
// }
}
//Release canvas
finally {
if (canvas != null) {
gameView.getHolder().unlockCanvasAndPost(canvas);
}
}
}
//Load menu after game over
if (gameModel.isGameOver()) {
gameController.launchContinueMenu();
}
}
This new approach should just draw as fast as possible using delta time to draw next frame instead of a set increment as before. Still no luck.
I changed my bitmap locations from Rect's to a new positions class I created that uses doubles instead of ints to simulate sub-pixel movement. Still no luck.
Recap of things I've tried:
Use onDraw() instead of gameModel drawing to canvas
Don't use synchronize() on the view's holder
Using time since last update to update next frame instead of advancing one frame each update() call.
Remove Thread.sleep()
Sub-pixel movement
After all this, I noticed that the game run fine while the phone was charging. 3 seconds after I unplug the phone, the game becomes choppy again. Then I noticed that if I tap the screen when the game becomes choppy, everything smoothes out again for another 3 seconds. I'm guessing that there is some kind of battery saving feature that is affecting my SurfaceView performance? What is going on here, and how can I disable it? This is quite maddening...
I tested out my first game loop again out of curiosity (1st code block) and tapped the screen while playing and everything ran smoothly. Man... all that work adding complexity for nothing. I guess it's a good learning experience. Any ideas to how I can keep my SurfaceView running at full speed? Help is greatly appreciated.
:)
Your observation is correct. In short, the power management in the N5 aggressively throttles the power down. If your finger is in contact with the screen, the clock speeds are increased to ensure that interactions are smooth. (For more, see my answer to this question.)
The best way to handle this is to recognize that you will need to drop frames sometimes. The "Record GL app" activity in Grafika uses a simple trick with Choreographer to do this. See also this article for some additional thoughts about game loops.
I think you should try to make your game more battery saving,darker the game(using background layout #000) more power for game ,
also you can use Intent flags like clear top to kill previous activity for saving battery , clearing ram(avoid out of memory)
but for your situation you can use wakelock
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.
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.