Alright, i'm making a small game, and I need to limit my FPS, because, when I play on my really fast computer, I have around 850 FPS, and the game will go like, REALLY fast, and when I switch to my older computer, it goes alot slower, so I will need to limit my FPS to get this right. How do I limit my FPS?
My main game loop:
public void startGame(){
initialize();
while(true){
drawScreen();
drawBuffer();
plyMove();
//FPS counter
now=System.currentTimeMillis();
framesCount++;
if(now-framesTimer>1000){
framesTimer=now;
framesCountAvg=framesCount;
framesCount=0;
}
try{
Thread.sleep(14);
}catch(Exception ex){}
}
}
How I draw the screen, and draw all of the other things, players, the ball, etc.
The game is a pong remake, btw.
public void drawBuffer(){
Graphics2D g = buffer.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0,600,500);
g.setColor(Color.GREEN);
g.fillRect(ply1.getX(),ply1.getY(),ply1.getWidth(),ply1.getHeight());
g.setColor(Color.RED);
g.fillRect(ply2.getX(),ply2.getY(),ply2.getWidth(),ply2.getHeight());
g.setColor(Color.WHITE);
g.fillOval(ball1.getX(),ball1.getY(),ball1.getWidth(),ball1.getHeight());
g.drawString("" + framesCountAvg,10,10);
}
public void drawScreen(){
Graphics2D g = (Graphics2D)this.getGraphics();
g.drawImage(buffer,0,0,this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
It sounds like your display it tied to your game engine. Make sure the two are disconnected. You want the game playing at the same speed no matter what the framerate is. If your fast computer repaints the screen faster that is ok if the engine is causing the game to play at a constant speed.
Rather than limiting your FPS, make it so that the game doesn't go really fast when the fps is high.
Presumably you have code that does certain things each frame e.g. moves the character forward if a button is pressed. What you want to do instead is move the character forward an amount dependent on the amount of time that has passed since the previous frame.
As aforementioned you need to separate your display loop from your update loop somewhere at the core of you game there is probably something like this
while (1)
{
drawscene();
update();
}
and in update you are advancing the time by a fixed amount e.g 0.17 sec. If you drawing at exactly 60fps then the animations are running in realtime, at 850fps everything would be sped by a factor 14 (0.17*850) to prevent this you should make your update time dependent. e.g.
elapsed = 0;
while (1)
{
start = time();
update(elapsed);
drawscene();
sleep(sleeptime);
end = time();
elapsed = end - start;
}
A description of what I meant in my comment. Inside your method plyMove(); I suspect there is something like
plyMove() {
ply1.x += amountX;
ply1.y += amountY;
}
Instead make the movement depending on the time elapsed
plyMove(double timeElapsed) {
ply1.x += amountX * timeElapsed;
ply1.y += amountY * timeElapsed;
}
where you calculate timeElapsed from the time difference inside your main loop and scale it accordingly to get a decent movement.
double timePrev = System.currentTimeMillis();
while(true) {
double timeNow = System.currentTimeMillis();
double elapsed = timeNow - timePrev;
drawScreen();
drawBuffer();
plyMove(0.001 * elapsed);
timePrev = timeNow;
}
If you really want a fixed timeframe game you could do this:
float timer = 0;
float prevTime= System.currentTimeMillis();
while(true)
{
draw();
float currentTime = System.currentTimeMillis();
timer += currentTime - prevTime;
while (timer > UPDATE_TIME) // To make sure that it still works properly when drawing takes too long
{
timer -= UPDATE_TIME;
update();
}
}
Where UPDATE_TIME is at what interval you want to update at in milliseconds.
One way would be using
try {
Thread.sleep(20);
} catch(InterruptedException e) {}
at the end of the main loop. Adjust the number to your needs.
Related
i've made a java aplication that displays the current time as a digital clock, and i would like to make the file automatically run after the mouse isn't moved for 10 minutes.Does anyone have any ideas?
P.S. I'm new to StackOverflow and to coding as well at that, so forgive me if this is actualy a stupid question.
As per your comment, Java doesn't make .exe files. You would need to place your jar file into a special executable wrapper to accomplish that. Launch4j can do that for you.
You would want to run your application as a Service. This SO Thread can shed some additional light on that subject.
In your application:
Set your clock component so that it is non-visible. Create a TimerTask to monitor the System Mouse pointer location (x, y). Utilize the MouseInfo Class within the TimerTask's run() method to track the Mouse Pointer location. Keep track of the time from the mouse last movement. If 10 minutes has elapsed with no mouse movement then display your clock (make it visible). If you like, when the mouse is moved again make the clock non-visible again. Your code in relation to this might look something like this:
First declare and initialize four (4) Class Member Variables:
int mouseX = 0;
int mouseY = 0;
long timeOfLastMovement = 0L;
TimerTask mouseMonitorTask;
Somewhere in your Class copy/paste this method. Make the required changes as you see fit:
private void startMouseMonitoring() {
mouseMonitorTask = new TimerTask() {
#Override
public void run() {
PointerInfo info = MouseInfo.getPointerInfo();
Point pointerLocation = info.getLocation();
long currentTime = java.lang.System.currentTimeMillis();
//System.out.format("Mouse Location - X: %d, Y: %d\n", pointerLocation.x, pointerLocation.y);
float elapsedTime = (((currentTime - timeOfLastMovement) / 1000F) / 60);
if (pointerLocation.x == mouseX && pointerLocation.y == mouseY) {
// Check if 10 minutes has elapsed with no mouse movement
if (elapsedTime >= 10.0f) {
/* Make Clock Visible if it isn't already
or whatever else you want to do. */
if (clockIsNonVisible) {
// clock.setVisible(true);
}
}
}
else {
mouseX = pointerLocation.x;
mouseY = pointerLocation.y;
timeOfLastMovement = currentTime;
// Make clock non-visible if you like.
if (clockIsVisible) {
// clock.setVisible(false);
}
}
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
cancel();
e.printStackTrace();
}
}
};
Timer monitorTimer = new Timer("Timer");
long delay = 1000L; // Start Delay: 1 second
long period = 1000L; // Cycle every: 1 second
monitorTimer.scheduleAtFixedRate(mouseMonitorTask, delay, period);
}
Call the startMouseMonitoring() method and the ball is rolling. I'm sure you'll figure out the rest.
If you want to cancel the TimerTask and Mouse Monitoring then you can call the TimerTask#cancel() method:
mouseMonitorTask.cancel();
Sorry, I couldn't word my title properly but I will explain my problem with more clarity here.
I am using libgdx.
When I want to move a Texture so that it covers the same distance with all FPS I will do this:
//...define Player class with x property up here.
Player player = new Player();
int SPEED = 100
public void render() {
player.x += SPEED * Gdx.graphics.getDeltaTime();
}
Now I want to know how to do this to have the same affect on a body in box2d. Here is an example(the render method of a class that extends ApplicationAdapter):
public void render() {
//clear screen, ... do other stuff up here.
playerBody.applyForce(new Vector2(0.5f / PIXEL_PER_METER, 0.0f), playerBody.getWorldCenter(), true);
//PIXEL_PER_METER -> applied to scale everything down
//update all bodies
world.step(1/60f, 6, 2);
}
This applies a force on the playerBody so that it's acceleration increases. How do I make shore, just like with my first example, that how fast the body is travelling stays constant across at 30fps, 10fps, 60fps, etc. I know the timeStep parameter of the world.step is the amount of time to simulate but this value shouldn't vary.
Thankyou in advance.
You can update all bodies with delta (not 1/60 fixed delta)
world.step(Gdx.graphics.getDeltaTime(), 6, 2);
EDIT:
As #Tenfour04 mentioned, in order to prevent high delta values (causes huge jumps), we mostly set a cap for delta.
world.step(Math.min(Gdx.graphics.getDeltaTime(), 0.15f), 6, 2);
I wouldn't use a variable timestep - this is the approach I've used:
private float time = 0;
private final float timestep = 1 / 60f;
public void updateMethod(float delta) {
for(time += delta; time >= timestep; time -= timestep)
world.step(timestep, 6, 2);
}
Basically a variable-ish timestep, but uniformly updating.
If you run your game at very low FPS, or if you force it to with the application configuration (e.g. for testing) this will keep updating at roughly the same speed as a normal 60 FPS instance.
Take a look at Fix your timestep!
I have a problem with my java game. I’m beginner, but i have to write it as a school project.
Game is called „Birthday Cake” there is 7 candles on the cake and randomly one of it is showing for let say 30s and during this time u have to click on it to get point, if u don’t click on it during this time next candle will show. Game end when 10 candle shows.
I made for loop and i tried to make it work for sooo long that I’m dying from frustration
my for loop works but it is so fast that i use Thread.sleep(1000), i tried lots of solutions it looks ok. BUT when i start my game nothing is happening and after few seconds all 7 candles shows and quickly disappear. I think I’m doing something wrong, but i have no idea what.
if(Dane.start){
int liczbaLosowa = 0;
for(int i=0; i<10 ;i++){
liczbaLosowa = (int)(Math.random()*7);
this.wspX= wspX_p[liczbaLosowa];
this.wspY= wspY_p[liczbaLosowa];
g2d.drawImage(plomienImg, wspX, wspY,null);
Toolkit.getDefaultToolkit().sync();
try {
Thread.sleep(1000);
} catch (Exception ex) { }
//repaint();
}
Dane.start=false;
}
this loop is inside JPanel paintComponent...
Never,
Never,
NEVER
call Thread.sleep(...) inside of paintComponent ever. Please understand that this method largely determines the perceived responsiveness of your program and anything that slows it down or freezes it will severely slow down and freeze your GUI. In fact you should never call Thread.sleep inside the code of most Swing programs (all that runs on the Swing event thread) but doing so in paintComponent is an even worse sin. The solution is to use a Swing Timer, and put code that you want to be called repeatedly at regular intervals inside of the Timer's ActionListener's actionPerformed code. Within this method, change the value held by fields within your class, for instance wspX and wspY, call repaint(), and then use those fields inside of paintComponent to determine what gets painted where.
Thread.sleep() is a bad call which can lead into many problems. i was told to never use it. instead i will show you the way i do my game loops. it might not be the perfect game loop but it is good.
i recommand implemets runnable and putting your loop in your run method.
public void run(){
init(); //initialisation of images, sound..etc. will be executed once only
int fps = 60 //number of update per second.
double tickPerSecond = 1000000000/fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
while(running){
now = System.nanoTime();
delta += (now - lastTime)/tickPerSecond;
lastTime = now;
if(delta >= 1){
tick();
render();
delta--;
}
}
}
private void init(){
//initialisation image, sound, loading world, generate maps....etc
}
private void tick(){
//tick player, world, entities..etc
}
private void render(){
//render graphics.
}
also dont forget to create start and stop method for the thread. you can change the fps to what number you would like, no need to go higher than 60.
I'm almost done with my project to make a very simple game. The point of the game is to count how many times the user touches the screen and compare it to the number of times an object popped up on the screen to be touched. It's considered a win if number of touches = number of objects. All of this is to happen in 10 seconds, and I have no idea where to start on how to time the game? (It's supposed to be a veryyy very simple game just to learn how to use libgdx)
As of now, there's a start screen that the user touches to start and then the game starts where objects pop up to be touched. The problem is that it's basically an endless game right now... Here's how I make an object "randomly pop up":
if (Gdx.input.isTouched()) {
touchCount++;
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
visual.x = MathUtils.random(10, 700);
visual.y = MathUtils.random(100, 400);
}
Do I have to put some built in timer function in this part of the code? And how to I go about tracking the touches to compare with the number of objects that popped up?
Thanks, any advice would be very appreciated!
System.currentTimeMillis() gives you current time in milliseconds
For example you can do something like this
private long time;
public void show(){
//...
time = System.currentTimeMillis();
}
public void draw(){
//...
if(System.currentTimeMillis()>time+10000){
System.out.println("after 10 seconds");
}
}
You may use old fashioned java way either:
Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
// Pause your game or just close it...
Gdx.app.exit();
}
}, 10000L);
Of course it's better to use synchronous timer approach, but for fast debuging or prototyping needs its sometimes more convenient.
Use the delta value inside your render() method.
render(float delta){
// ......
if (yeni_oyun_mesaji_var_MI)// a boolean value to increment my time value only it is needed.
oyun_uyari_zamani_tutucu += delta;
if (oyun_uyari_zamani_tutucu > oyun_uyari_zaman_siniri) {// after some time (**oyun_uyari_zaman_siniri**) do what you need
oyun_uyari_zamani_tutucu = 0f;
oyun_durum_mesaji_str = "";
yeni_oyun_mesaji_var_MI = false;
Gdx.app.log(TAG, "Uyarı Kapatıldı!");
}
}
In the ApplicationAdapter class, I override the render() method and draws my game from there.
I also have an own method: update() inside the render method which is where I want to update everything.
The render() method is as I know called ~60 times a second.
I dont want my update method to be dependent on how many times the render method is called.
I want the render method to render as much as the device can handle below 60 FPS.
I also want the update method to get called at a fixed rate: 60 times a second.
I´ve tried to call my update method 60 times a second in my render method like this:
double beforeMillis;
double FPS=4; //test
double millisPassed=0;
int x=0;
#Override
public void render () {
beforeMillis=System.currentTimeMillis();
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(tex, x, 10);
batch.end();
millisPassed+=(System.currentTimeMillis()-beforeMillis);
if(millisPassed>=1000/FPS){
update();
millisPassed=0;
}
}
...but it updates like once every four seconds.
Any good way of doing this? Thanks in advance!
The code you posted won't compare accurate time, because it ignores all the time spent doing things between batch.end() and the next call to render(), some of which occurs in the libgdx backend. And if you update after drawing in the render method, you will always have at least one visual frame of lag.
A basic implementation of a fixed timestep update in libgdx would be like this:
static final double DT = 1/60.0;
static final int MAX_UPDATES_PER_FRAME = 3; //for preventing spiral of death
private long currentTimeMillis;
public void create() {
currentTimeMillis = System.currentTimeMillis();
}
public void render() {
long newTimeMillis = System.currentTimeMillis();
float frameTimeSeconds = (newTimeMillis - currentTimeMillis) / 1000f;
currentTimeMillis = newTimeMillis;
int updateCount = 0;
while (frameTimeSeconds > 0f && updateCount <= MAX_UPDATES_PER_FRAME) {
float deltaTimeSeconds = Math.min(frameTimeSeconds, DT);
update(deltaTimeSeconds);
frameTimeSeconds -= deltaTimeSeconds;
++updateCount;
}
draw();
}
This does result in update occurring more than 60 times a second, because it gets updated with the "leftovers" to keep the visuals current (no stuttering). The update(float delta) method must be designed to use a variable delta time.
You can do a truly fixed update as described here in the last two sections, but that has the disadvantage of visual stuttering or needing to implement a one-frame delay and interpolating ahead.