Simple side-scrolling JFrame game lag, other questions haven't helped? - java

At the moment I'm trying to make a simple videogame in Java, just for fun. But there seems to be lag, and I'm not sure why it's happening. I'll give the lowdown:
The way it draws is using JFrame, and the actual drawing happens in the ImagePanel class. In ImagePanel, this is how I draw. It includes some things about debugging to show FPS and a timer to show length of run, but I'm not sure if that's important. It goes through multiple ArrayLists to show all the objects on the JFrame.
//Painting
public void paintComponent(Graphics g)
{
//Paint the background with its upper left corner at the upper left corner of the panel
g.drawImage(background, 0, 0, null);
//Paint each image in the foreground where it should go
for(MovingImage img : backgrounds)
{
g.drawImage(img.getImage(), (int)(img.getX()), (int)(img.getY()), null);
}
for(MovingImage img : foreground)
{
g.drawImage(img.getImage(), (int)(img.getX()), (int)(img.getY()), null);
}
if(g instanceof Graphics2D)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.scale(2, 2);
g2.setColor(Color.WHITE);
String milSpace;
if(timer%100 < 10)
milSpace = "0";
else
milSpace = "";
String secSpace;
if(timer/100 < 10)
secSpace = "0";
else
secSpace = "";
g2.drawString(secSpace + timer/100 + ":" + milSpace + timer%100, 10, 20);
//Debug
if(debug)
{
long currentTime = System.currentTimeMillis();
if (currentTime > nextSecond)
{
nextSecond += 1000;
frameInLastSecond = framesInCurrentSecond;
framesInCurrentSecond = 0;
}
framesInCurrentSecond++;
//g2.drawString("LagMS:" + (-frameRate - 10) + " FPS:" + frameInLastSecond, 20, 40); <-includes "lag"
g2.drawString("FPS:" + frameInLastSecond, 20, 40);
}
}
}
//Replaces the list of foreground images with the one given, and repaints the panel
public void updateImages(ArrayList<MovingImage> newForeground, ArrayList<MovingImage> newBackgrounds)
{
foreground = newForeground;
backgrounds = newBackgrounds;
//time checking
long time = System.currentTimeMillis();
lastTime = time;
repaint(); //This repaints stuff... you don't need to know how it works
}
Inside the primary class I made that includes a tick system, which causes it to be painted in the first place.
public void tick()
{
long lastTime = System.currentTimeMillis();
int place = 0;
boolean go = true;
while(go)
{
long time = System.currentTimeMillis(); //The current time
if(time - 10 > lastTime) //Update every .01 seconds, or 1 TICK (if time - 10 > lastTime)
{
lastTime = time;
//Reset the last time
place++;
imagePanel.incTime();
for(MovingImage object : movingObjects)
{
if(object instanceof Building)
{
object.incrementPosition(); //Augment position by velocity
if(place%500 == 0)//If 5 seconds have passed...
{
((Building) object).speedUp();//make it go a little faster!
}
}
if(object instanceof Player)
{
if(jumpKeyOn)
((Player) object).jump();//Initiate jump class assuming key is pressed
object.incrementPosition();
((Player) object).constrainPlayerToObjects(movingObjects, yMax);
if(object.getY()>yMax + 1000)
{
go = false;
}
}
}
//Repaint all the things in their new positions, possibly faster
for(MovingImage bg : backgrounds)
{
bg.incrementPosition();
if(place%500 == 0)
bg.setVelocity(bg.getXvel() - 0.1, 0);
}
/*
* Acceleration
*/
//Removes buildings once left screen
int i = 0;
while(i < movingObjects.size())
{
if(movingObjects.get(i) instanceof Building)
{
if(movingObjects.get(i).getX() + movingObjects.get(i).getImage().getWidth(null) < 0)
movingObjects.remove(i);
else
i++;
}
else
i++;
}
imagePanel.updateImages(movingObjects, backgrounds);
}
}
gameOver();
}
It's an endless loop that essentially runs the program. I used multiple ArrayLists in order to put different layers down. What am I doing that's causing it to lag? I'm still fairly new, but I'll answer any questions about the code or provide more details. I couldn't find any other questions that helped.
EDIT: There are some odd things I should mention. Occasionally it runs at nearly the full FPS, but most of the time not. I also noticed that when I ran another java program at the same time, it ran at nearly full speed.
EDIT 2: Should I include the entire primary class code and ImagePanel?

Related

Why wont my image move when the y value of it is increasing?

I'm currently having an issue where the image won't move when the y-value of the image is increasing. I wanted the image to move vertically so I made a method that controls the speed of the image, The parameter is the ActionEvent and the y-value for the player. The y-value increases as I printed out the value, but the image won't move. I've even added the timer which didn't make the image move at all. No error in the output whatsoever.
public void speedPerformed(ActionEvent e, Rectangle movingPlayer){
int speed = 15;
// help deals with gravity
ticks++;
// if the remainder of zero is given from tick
//then the object will feel heavier
if (ticks % 2 == 0 && yMotion < 15) {
yMotion += 3;
}
movingPlayer.y += yMotion;
}
#Override
public void actionPerformed(ActionEvent e) {
action.speedPerformed(e,movingPlayer);
gameInterface.getRenderer().repaint();
}
public void repaint(Graphics g) {
g.drawImage(Renderer.renderer.getImage(),movingPlayer.x,movingPlayer.y,100,100, null);
}
public RepaintConfiguration(GameInterface gameInterface) {
this.gameInterface = gameInterface;
lasers = new Lasers();
action = new Actions();
movingPlayer = new Rectangle(0, 550, 100, 100);
timer = new Timer(20,this);
timer.start();
}
let me know if you want to take a look at any of my codes that I haven't included here.
You code is wrong: you are updating the local variable y.
You should update directly the movingPlayer:
public void speedPerformed(ActionEvent e){
int speed = 15;
// help deals with gravity
ticks++;
// the y value of the moving player
// if the remainder of zero is given from tick
//then the object will feel heavier
if (ticks % 2 == 0 && yMotion < 15) {
yMotion += 3;
}
movingPlayer.y += yMotion;
}

How do I make circular hitboxes that change?

Im new to programming and I'm making a aim trainer game where you hit different circles and have to hit one before it changes to the next circle. I having some trouble though. I can't figure out how to make a hitbox for the circles that change for each circle and how to increase the score.
The code is in open processing in pjs.
class Timer {
int time;
int duration;
Timer() {
duration = 100;
reset();
}
void reset() {
time = millis() + duration;
}
boolean alarm() {
if ( millis() > time ) {
time = millis() + duration;
return true;
}
return false;
}
}
float x,y,s; //size and position of circles
color c; //colour of circles
int score = 0; //score
int miss = 0; //misses
Timer timer = new Timer();
void setup() {
size(700, 500);
timer.duration = 2000; //changes the circle every 2 seconds
missed =+ 1;
newEllipse(); // Make initial circle.
}
void draw() {
background(100);
fill(c);
text("SCORE: " + str(score),620,20);
text("MISSED: " + str(miss),20,20);
ellipse(x, y, s, s);
if( timer.alarm() ){
newEllipse();
}
}
void mousePressed(){
if( overEllipse() ){
score =+1;
newEllipse();
}
}
boolean overEllipse(){
if(mouseX > x && mouseX < x+s && mouseY > y && mouseY < y + s);
}
void newEllipse() {
s = random(5,min(50,50));
x = random(0, width - s);
y = random(0, height - s);
c = color( random(255), random(255), random(255) );
timer.reset();
}
Once I tried your code I realized that you were going for something very simple, so no need for OOP today. I fixed and commented your code so you can tweak it and test stuff:
float s; //size of circles
PVector targetPosition; // position of target
color c; //colour of circles
int score = 0; //score
int miss = 0; //misses
Timer timer = new Timer();
void setup() {
size(700, 500);
timer.duration = 2000; //changes the circle every 2 seconds
newEllipse(); // Make initial circle.
}
void draw() {
background(100);
fill(255); // easier to read if you don't change the color all the time
text("SCORE: " + str(score), 620, 20);
text("MISSED: " + str(miss), 20, 20);
fill(c);
ellipse(targetPosition.x, targetPosition.y, s, s);
if ( timer.alarm() ) {
miss += 1; // added a 'miss' when the user isn't able to click the target in due time
newEllipse();
}
}
// notice that I switched this method for 'mouseClicked' instead of 'mousePressed'
// the difference is that this works on a simple click, and run once per click instead of continuously
void mouseClicked() {
if (overEllipse()) {
score += 1;
newEllipse();
} else { // added a 'miss' when the user clicks at random
miss += 1;
}
}
boolean overEllipse() {
// these 3 lines are giving you feedback so you know how close to the target you were
PVector mousePosition = new PVector(mouseX, mouseY);
println(mousePosition.dist(targetPosition) + " / " + s/2);
// you only need the next line if you don't care about the feedback
return mousePosition.dist(targetPosition) < s/2;
}
void newEllipse() {
s = random(10, 50); // I removed the `min(50,50)` because the minimum number between 50 and 50 is... 50. Maybe you were going for something else, but like this it was not needed
targetPosition = new PVector(random(s/2, width - s/2), random(s/2, height - s/2));
c = color( random(255), random(255), random(255) );
timer.reset();
}
class Timer {
int time;
int duration;
Timer() {
duration = 100;
reset();
}
void reset() {
time = millis() + duration;
}
boolean alarm() {
if ( millis() > time ) {
time = millis() + duration;
return true;
}
return false;
}
}
The main problem here was that the method overEllipse made no sense, so I set it on fire and rewrote it using a PVector instead of straight coordinates. I did it mostly because it's easier than to use math to determine if we're clicking inside the target later (the PVector class will straight up do it for you, it's an awesome tool, take a look at how I tweaked the overEllipse method and how it's easy with this tool!). I also added some feedback as console println so you can know how close you clicked from the target.
I'll be around of there's something you'd like me to explain. Have fun!

Bouncing rectangle (Graphics g)

I'm playing around with graphics in Java. At the moment I have a rectangle that moves from left to right. I want it to start moving left once it hits the right side of the Canvas and left when it hits the right side, i have included a game loop as this will eventually turn into my first very basic game. Thanks.
P.S - I followed some tutorials for different parts of this code hence why it might be a bit messy, I'm working on it :)
Main Class:
public class Game extends JFrame implements Runnable {
private Canvas canvas = new Canvas();
private RenderHandler renderer;
private boolean running = true;
public static int WIDTH = 1200, HEIGHT = WIDTH / 12*9;
public static int moveX =WIDTH/2;
public Game() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
setLocationRelativeTo(null);
setLocationRelativeTo(null);
add(canvas);
setVisible(true);
canvas.createBufferStrategy(3);
renderer = new RenderHandler(getWidth(), getHeight());
}
public void update() {
}
public void render() {
BufferStrategy bufferStrategy = canvas.getBufferStrategy();
Graphics graphics = bufferStrategy.getDrawGraphics();
super.paint(graphics);
renderer.render(graphics);
graphics.dispose();
bufferStrategy.show();
}
public void run() {
BufferStrategy bufferStrategy = canvas.getBufferStrategy();
int FRAMES = 0;
int TICKS = 0;
long lastTime = System.nanoTime();
double unprocessed = 0;
double nsPerSecs = 1000000000 /60.0;
long Timer = System.currentTimeMillis();
while(running) {
long now = System.nanoTime();
unprocessed += (now - lastTime) / nsPerSecs;
lastTime = now;
if(unprocessed >= 1) {
TICKS ++;
update();
unprocessed -= 1;
}
try
{
Thread.sleep(3);
}catch (InterruptedException e) {
e.printStackTrace();
}
FRAMES++;
render();
if(System.currentTimeMillis() - Timer > 1000) {
System.out.println("Ticks: " + TICKS + " FPS: " + FRAMES);
TICKS = 0;
FRAMES = 0;
Timer += 1000;
}
}
}
public static void main(String[] args) {
Game game = new Game();
Thread gameThread = new Thread(game);
gameThread.start();
}
}
Class drawing the graphics:
public class RenderHandler {
public RenderHandler(int width, int height) {
}
public void render(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, Game.WIDTH, Game.HEIGHT);
g.setColor(Color.RED);
g.fillRect(Game.moveX, Game.HEIGHT/2, 50, 50);
if (Game.moveX >= Game.WIDTH) {
Game.moveX ++;
} else if (Game.moveX <= 0) {
Game.moveX --;
}else { Game.moveX++;
}
}
}
If you know how to draw on the screen and how stuffs work, I would think that this is more about getting the logic down.
This code slice I so brutally tore from your question is right next to where the rendering takes place (a problem because I view it as rather unorganized; I would recommend game logic and rendering to take place in two different functions). It basically says that it will move right if it is beyond the right of the screen, if not, it will move left if it is beyond the left of the screen, and finally, if not, it will just move left.
if (Game.moveX >= Game.WIDTH) {
Game.moveX ++;
} else if (Game.moveX <= 0) {
Game.moveX --;
}else { Game.moveX++;
}
If you want it to bounce, you will have to use a boolean to keep track of its moving state, or, if you want more versatility, use a pair of floats or doubles (floats are typically used in Java game design) to keep track of its position, and another for its velocity. I'm in a tight squeeze right now, I will return.
Add this to render handler instead of the current if statement in render
bool rol = true; // initialize this outside the method
If(Game.movex + 50 >= Game.width)
rol = false;
Else if(Game.movex <= 0)
rol = true;
If(rol)
Game.movex++;
Else
Game.movex--;
You need to store current moving direction somewhere, so add this to Game class:
public static int deltaX = 1;
And replace condition in render() with
if (Game.moveX >= Game.WIDTH-50) {
Game.deltaX =-1;
} else if (Game.moveX <= 0) {
Game.deltaX =1;
}
Game.moveX += Game.deltaX;

Jittery movement with Graphics2D and double buffer

I´m having some problems with a small game I´m developing. although I´m using double buffer and was able to get rid of flickering, the movement still looks somewhat jittery and not fluid.
I know it can be caused by increasing the movement in big steps and/or low framerate, but I still have the same problem using increments of 1 and 50+ fps. It´s somewhat difficult to explain, but the sprites move strangely (correctly, but not in a fluid motion)
I would appreciate if someone could point me in the right direction.
public class Gameplay extends javax.swing.JPanel {
GUI gui;
Canvas canvas = new Canvas();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage bi;
BufferStrategy buffer;
public Gameplay(GUI gui) {
this.gui = gui;
initComponents();
}
// Used to start the gameplay. Called by GUI
public void start() {
new RefreshScreen().start();
}
// ==============================================================================================
// DOUBLE BUFFER AND PAINTING ===================================================================
// ==============================================================================================
Date date = new Date(); // time
int lastSecond = 0; // seconds controll - for FPS calculation
int fpsCount = 0; // Count frames rendered
int showFps = 0; // The total FPS text that will appear on screen
int MAX_FPS = 30; // targeted Max FPS
int MIN_FPS = 24; // targeted Min FPS
int sleepTimeBetweenRefresh = 20; // Delay before new refresh
Color fpsColor = Color.yellow; // color of the FPS information on screen
String fpsInfo = ""; // Aditional info on FPS (increasing, decreasing, etc)
class RefreshScreen extends Thread {
public void run() {
Graphics graphics = null;
Graphics2D bufferGraphics = null;
add(canvas, BorderLayout.CENTER);
canvas.setIgnoreRepaint(true);
canvas.setVisible(true);
canvas.setSize(gui.getWidth(), gui.getHeight());
canvas.createBufferStrategy(2);
buffer = canvas.getBufferStrategy();
bi = gc.createCompatibleImage(gui.getWidth(), gui.getHeight());
bufferGraphics = bi.createGraphics();
while (true) {
try {
//FrameRate count
date = null;
date = new Date();
if (lastSecond != date.getSeconds()) {
lastSecond = date.getSeconds();
showFps = fpsCount;
fpsCount = 0;
if (showFps > MAX_FPS) {
sleepTimeBetweenRefresh++;
fpsInfo = "(--)";
fpsColor = Color.blue;
}
if ((showFps < MIN_FPS) && (sleepTimeBetweenRefresh > 5)) {
sleepTimeBetweenRefresh--;
fpsInfo = "(++)";
}
if (showFps < MIN_FPS) {
fpsColor = Color.red;
}
if ((showFps > MIN_FPS) && (showFps <= MAX_FPS)) {
fpsColor = Color.green;
fpsInfo = "(ok)";
}
}
fpsCount++;
//Clear canvas =============================
bufferGraphics.setColor(Color.black);
bufferGraphics.clearRect(0, 0, gui.getWidth(), gui.getHeight());
//FPS =============================
bufferGraphics.setColor(fpsColor);
bufferGraphics.drawString("FPS: " + showFps, 3, 15);
bufferGraphics.setColor(Color.black);
//SPRITES =============================
try {
for (int count = 0; count < Sprites.getSprites().size(); count++) {
bufferGraphics.drawImage(Sprites.getSprite(count).getImage(), Sprites.getSprite(count).getX(), Sprites.getSprite(count).getY(), null);
}
} catch (Exception e) { }
//HERO =============================
try {
bufferGraphics.drawImage(Sprites.getHero().getImage(), Sprites.getHero().getX(), Sprites.getHero().getY(), null);
} catch (Exception e) { }
// PAINT BUFFER =================================
try {
graphics = buffer.getDrawGraphics();
graphics.drawImage(bi, 0, 0, null);
if (!buffer.contentsLost()) {
buffer.show();
}
} catch (Exception e) { }
// SLEEP =================================
sleep(sleepTimeBetweenRefresh);
} catch (Exception e) { }
}//while
}//run
}//inner class
I would also like to point out that the X and Y of the sprite are being handled so that it doesn´t go right and then down - for instance - when it is supposed to go diagonally. I don´t suppose that´s the problem anyways since the problems occurs even on a straight line.
You might try timing how long it takes to draw everything then subtracting that from your sleep time.
long beforeTime = System.currentTimeMillis();
// do all drawing
sleepTimeBetweenRefresh -= System.currentTimeMillis() - beforeTime;
if(sleepTimeBetweenRefresh < 0) sleepTimeBetweenRefresh = 0;
This helps ensure that your thread is firing every 50ms (or whatever sleepTimeBetweenRefresh is). Say you want it to fire ever 50ms, your drawing takes 10ms. Without the code above after the code ran one time you would actually be painting 60ms after the last paint because you painted for 10 and slept for 50. By subtracting the time it took to paint the components you can keep your FPS stable.

Movement speed varies?

Hey guys on my 2D game the movement speed varies.. I was making my game on my Desktop and it ran fine but then I went on my laptop and the Player moved slower then the Desktop.
Here is my current game loop:
public void gameLoop() throws IOException {
isRunning = true;
while(isRunning == true) {
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
//main game loop
//updates everything and draws
//main componenets
//e.g. Player
// clear the screen
g2d.setColor(Color.lightGray);
g2d.fillRect(0,0,640,496);
//drawing
player.paint(g2d);//paint player
map.paint(g2d);//paint each wall in wall list
g2d.dispose();
strategy.show();
//update
try { player.updateMovement(); } catch (Exception e) {};
try { Thread.sleep(4); } catch (Exception e) {};
}
}
Here is my player.updateMovement() method:
public void updateMovement() {
if(!down || !up) {
ny = 0;
}
if(!left || !right) {
nx = 0;
}
if(left) {
nx = -1;
}
if(right) {
nx = 1;
}
if(up) {
ny = -1;
}
if(down) {
ny = 1;
}
if ((nx != 0) || (ny != 0)) {
x += nx;
y += ny;
}
}
How can I fix this issue?
You could have a fixed-rate drawing loop: every iteration should last the same, and if there is some time left, sleep that amount of time. For instance, if we fix a period of 41.6 ms (which is 24 fps), and a certain iteration lasts 20 ms, then you should sleep 41.6 - 20 = 21.6 ms that pass.
If your code is too heavy to run in that time on a low end PC, then you can increase the period so that every machine can cope with it.
By the way, you could also optimize your code.
You can find more information on gaming.stackexange.com

Categories