Major Lag with my Application and a 2D Ball collision question

Well, check it. Basically I'm running an application that looks something like this:

publicclass Gameextends Canvasimplements KeyListener,MouseInputListener{

/*-Variable Declarations-*/

...

//GameApp Objects

BufferStrategy strategy;

JFrame gameWindow;

Graphics g;

public Game(){

version=2.0;//see update history for details

debug=false;

//all basic variable setups

stage=1;

fps=0;

gridSize=10;

numCols=80;

numRows=60;

WIDTH=numCols*gridSize;

HEIGHT=numRows*gridSize;

//sets all booleans related to game states

isPaused=false;

isFinished=false;

//Behind the scenes settings

//maxFPS=80;

initObjects();

//Setup gamewindow

gameWindow =new JFrame("SnakeSoccer v"+version);

JPanel panel = (JPanel)gameWindow.getContentPane();

setBounds(0,0,WIDTH,HEIGHT);

panel.setPreferredSize(new Dimension(WIDTH,HEIGHT));

panel.setLayout(null);

panel.setBackground(Color.white);

panel.add(this);

gameWindow.setResizable(false);

gameWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

gameWindow.pack();

//makes the buffer work

createBufferStrategy(2);

strategy = this.getBufferStrategy();

//sets up all listeners

addMouseListener(this);

addMouseMotionListener(this);

addKeyListener(this);

this.requestFocus();

gameWindow.setVisible(true);

}

publicvoid initObjects(){

}

publicvoid run(){

tm=System.currentTimeMillis();

while(!isFinished){

if(!isPaused){

g=strategy.getDrawGraphics();

switch(stage){

case 1://Draw Title Screen

drawTitleScreen(g);

stage=2;//This must be taken out once KeyListener works

break;

case 2://Main Game loop

checkWorld();

updateWorld();

drawWorld(g);

break;

}

strategy.show();

}

if(debug)

if(System.currentTimeMillis()-tm>1000)

drawFPS(g);

}

System.exit(0);

}

Basically, you should be able to tell what's going on. I can limit the FPS by putting an if statement in the beginning of 'case 2' by making it look like this:

case 2://Main Game loop

if(fps<maxFPS)

checkWorld();

updateWorld();

drawWorld(g);

break;

basically, in the drawWorld method it does if(debug)fps++;

Then in the drawFPS it resets the FPS and all that jazz.

Anyways, that's the game loop and everything. It does it's thing, but I noticed weird FPS output. Anywhere from 30 all the way up to 3k+ when I didn't limit it. It also is extremely laggy on my PC (good specs, shouldn't be a problem) whether it's capped or uncapped. Any advice would be awesome.

Also, ball collision... check it:

Ball class is basically this:

int x,y,size;

x,y are the top left points of the ball, and the size is the diameter. I'm trying to have it bounce of two moving objects and all the walls. The obvious thing for this is:

if(ball.x><0) ball.invertX(); //inverts the movement of the ball along the X axis. Does not affect the velocity.

or something to that nature. But I guess the real question is what happens if the velocity would land it on the other side of the wall. IE: it's at 5,5 and it moves 8 up and 8 over every time. So it would appear slightly outside the screen. How would I solve this? Sorry it's kinda choppy, but any help would be awesome. I'm programming as we speak, so I will be checking every 5min. My AIM is SAOniKami if you guys wanna chat.

Let me know if you need anymore info. Thanks.

[5588 byte] By [Sangea] at [2007-11-27 6:05:48]
# 1
Also a note I forgot to add:Those methods are doing nothing. The update and check worlds are blank, and the draw world only draws one, red rectangle.
Sangea at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 2

Wow, ok... so I think I figured out the lag for now.

I tried adding this line of code in and it seemed to work just fine:

try{Thread.sleep(1000/maxFPS);}catch(Exception e){}

Should I stick with this way of delaying my loop? Any suggestions would be appreciated.

Sangea at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 3

Thats generally not a very good solution because all of your code seems to be running within one thread and you are freezing all execution of your program for an entire second.

That is hardly a reliable solution.

You should move your public void run code from your Canvas class into a seperate ActionListener object and then add that ActionListener to a javax.swing.Timer object. I find that the Swing Timer works really well on smaller applications and it runs the code within its actionPerformed method once every set delay, in your case likely 1000 milliseconds.

The best advantage to this is that your Timer object runs on a seperate thread of execution from the rest of your application, so animation and action on your screen does not prevent users from providing input or doing something else while there is still something going on in the screen.

maple_shafta at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 4
What do you mean I'm delaying it for a second? I'm actually pausing it for 1000/80 mil. sec.So like under 15 mil. sec pauses each loop. Do you really think that's a bad solution? O.o It seems like the ActionEvent thing would lag a bit.
Sangea at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 5

Your method is fine. I've been using it for many years and it's always served its purpose.

The Timer seems like a good idea, but don't use it. It introduces some things that are troublesome for animation, such as multiple paint event collapsing. It's too much hassle to deal with with no advantage.

I don't understand what you're doing with your ball class...

It seems to me like a VelocityX and a VelocityY fields are pretty important to what you're doing, and yet you don't have those.....

CuppoJavaa at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 6
you should use Thread.currentThread().sleep(1000/fps); That way it won't lag everything.
RAIN_MANa at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 7

for ball-wall collision: If it hits a vertical wall coming from the right, you shoud not only invert the x-velocity but you you should also invert the location over the wall so it doesn't get stuck.

I don't know what all the variables are called so replace what you can

say your wall is at 600.

//ball hits wall before the left side gets past 600

int rightWall = 600-size

//mirrors location over rightWall

ballLocationX = (rightWall*2)-ballLocationX;

ballVelocityX *= -1;

RAIN_MANa at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...
# 8

Ok, so a few questions:

1. With the sleeper stuff, why should I use my current thread? My application starts like this:

public class Runner{

public static void main(String[] args){

SnakeSoccer app = new SnakeSoccer();

app.run();

}

}

I actually never reference a thread, so it should be all on one thread. Is this bad? When you mentioned that other sleep method it just got me thinking.

Also, about the collisions: I'm not quite sure what you're saying. Right now I have this in my ball class:

public class Ball extends GameObject{

//Data Fields

private int x,y,vY,vX,radius;

private boolean isVisible,isXMoveable,isYMoveable;

private Color ballColor;

private Image ballImage;

Ball(){

x=50;

y=50;

vX=3;

vY=3;

radius=5;

ballImage = new ImageIcon("images/ballPic.gif").getImage();

isXMoveable=true;

isYMoveable=true;

}

Ball(int x,int y,int vX,int vY,int size,Color c){

this.x=x;

this.y=y;

this.vX=vX;

this.vY=vY;

this.radius=radius;

ballColor=c;

isXMoveable=true;

isYMoveable=true;

}

Ball(int x,int y,int vX,int vY,int size,Image i){

this.x=x;

this.y=y;

this.vX=vX;

this.vY=vY;

this.radius=radius;

ballImage=i;

isXMoveable=true;

isYMoveable=true;

}

public int getX(){ return x; }

public int getY(){ return y; }

public int getVX(){ return vY; }

public int getVY(){ return vY; }

public int getRadius(){ return radius; }

public boolean isVisible(){ return isVisible; }

public boolean isXMoveable(){ return isXMoveable; }

public boolean isYMoveable(){ return isYMoveable; }

public void setX(int n){ x=n; }

public void setY(int n){ y=n; }

public void setVX(int n){ vX=n; }

public void setVY(int n){ vY=n; }

public void setVisible(boolean b){ isVisible=b; }

public void setXMoveable(boolean b){ isXMoveable=b; }

public void setYMoveable(boolean b){ isYMoveable=b; }

public void inverseX(){ vX*=-1; }

public void inverseY(){ vY*=-1; }

public void tick(){

if(isXMoveable)

x+=vX;

if(isYMoveable)

y+=vY;

}

public void draw(Graphics g){

if(ballImage==null){

g.setColor(ballColor);

g.fillOval(x-radius,y-radius,radius*2,radius*2);

}

else

g.drawImage(ballImage,x-radius,y-radius,null);

}

}

Basically, vX and vY are how many pixels it moves everytime it's updated. Then I just call invertX or invertY to just times it by -1. Unfortunately, this is a very simple collision engine, but it seems to serve it's purpose.

How I detect them is something like this:

//check for wall collisions

if(ballX-radius-1<=0) //left wall

ball.inverseX();

else if(ballX+radius+1>=numCols*gridSize) //right wall

ball.inverseX();

if(ballY-radius-1<=0) //top wall

ball.inverseY();

else if(ballY+radius+1>=(numRows-10)*gridSize) //bottom wall

ball.inverseY();

gridSize is the size of a grid in my program. While, there are no 'grids', I just use that to scale the program. IE: If I change the gridSize from 10 to 20, the window will be twice as big, and everything else will work fine also.

Anyways, let me know if you see anything wrong with that.

Sangea at 2007-7-12 16:52:30 > top of Java-index,Other Topics,Java Game Development...