How to use Thread.sleep in a basic RPG game - java

I've been working on this really basic Java RPG game, and when I tried using Thread.sleep for my monster to move slower, it seems to affect the player as well, in other words, the movement of the player had slow down when the monster appears, but turns back to normal when I move to another part of the map where the monster is not there
Here's the code for the monster's movement
int wolfRandNum;
if (isKilled() == false){
wolfRandNum = (int) (Math.random()*4);
if (wolfRandNum == 1){ // up
System.out.println("up");
if (playerRow -1 <= 0){
setCurrentEnemySprite(3);
} else {
moveUp();
playerRow--;
}
} else if (wolfRandNum == 2){ // down
System.out.println("down");
if (playerRow +1 >= 8){
setCurrentEnemySprite(0);
} else {
moveDown();
playerRow++;
}
} else if (wolfRandNum == 3){ // left
System.out.println("left");
if (playerColumn -1 <= 0){
setCurrentEnemySprite(1);
} else {
moveLeft();
playerColumn--;
}
} else{ // right
System.out.println("right");
if (playerColumn + 1 >= 9){
setCurrentEnemySprite(2);
} else {
moveRight();
playerColumn++;
}
}
}
The code above is in a method called update, which is from an enemy class.
Here's the where I call the method:
public void paintComponent(Graphics g) {
super.paintComponent(g); //required to ensure the panel is correctly redrawn
map.draw(g);
player.draw(g);
for (Character character : characterList) {
character.draw(g);
}
for (Enemy enemy : enemyList){
enemy.draw(g);
try {
enemy.update();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (Item item : bagList) {
item.draw(g);
}
repaint();
}
Is there anyway to use thread.sleep without affecting the player's movement? If not, what other methods can I use to make the monster move slower but not the player?
I'm not really sure how to fix this problem, any advise would help a lot! Thank you :)

This is a event-driven Swing GUI, and so the answer to the question:
How to use Thread.sleep(...)
is that you don't.
You're coding this as if it were a linear console program, and this design won't work for event-driven non-linear programs. Calling Thread.sleep on the Swing event thread and especially in any painting method is a guarantee to put your entire GUI to sleep so that it becomes totally unresponsive. The proper solution is to create a non-GUI Model class to go with your GUI (your "View"), and to change how the view responds based on the state of the Model, i.e., the state of its key fields.
Also, if your game is being run in "real time", then you will need a game loop to drive your game. This can be done easily via a Swing Timer, although it does not provide absolute precision. If greater precision is required, then use the Swing Timer, but don't assume that each time slice is accurate, and instead measure each delta time and base your physics on the measured slice, not the assumed slice. Other ways to create a game loop include use of a background thread with a while loop and Thread.sleep within this thread.

All you are slowing down is the rendering (drawing) of your monster. As all drawing is done on the UI thread, this will, as you have rightly noticed, have a huge performance impact on your entire application. As a general rule, you should never call a blocking operation such as sleep in the UI thread.
Given you only have two characters, what I would consider trying is creating two threads, one for your character and one for your monster. You will do what you need to do in each of these threads, and then call repaint() when you need to redraw. If you want to slow down the monster, for example, you can call sleep in the monster thread.

Related

JAVA GAME loop?

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.

Properly implementing a delay in a game

This is a follow up to a previous question I had. I have a Battleships game with two boards. When the user clicks on the computer board an action occurs, along these lines:
public void mouseClicked(MouseEvent e)
// Get coordinates of mouse click
if (//Set contains cell) {
/add Cell to set of attacked cells
//Determine if set contains attacked cell.
// If yes, hit, if no, miss.
checkForWinner();
The checkForWinner method determines if the game has been won yet. If it hasn't it calls a nextTurn method which changes the current turn. If the currentTurn is set to Computer, a ComputerMove() method is automatically called.
When that method finishes, it again checksforWinner, changes turn and waits for the user to click on the grid to start the cycle again.
Ideally, I'd like to have sound effects, or at the very least a pause between moves. However, no matter how I use Thread.sleep, or TimerTask, or anything else, I can't get it to function correctly.
If I use a simple Thread.sleep(500) in the CheckforWinner method, or in the ComputerMove method, all that happens is the human's go is delayed for the set amount of time. As soon as his move is executed the computer's move is completed immediately.
I know very little about threads but I assume this is because all the initiation of the bouncing back and forth between methods begins with a method in the mouse listener.
Given the set up of my system, is there a way to implement a delay without radically changing things?
Edit: May as well include the classes:
public void checkForWinner() {
if (human.isDefeated())
JOptionPane.showMessageDialog(null, computer.getName() + " wins!");
else if (computer.isDefeated())
JOptionPane.showMessageDialog(null, human.getName() + " wins!");
else
nextTurn();
}
public void nextTurn() {
if (currentTurn == computer) {
currentTurn = human;
} else {
currentTurn = computer;
computerMove();
}
}
public void computerMove() {
if (UI.currentDifficulty == battleships.UI.difficulty.EASY)
computerEasyMove();
else
computerHardMove();
}
public void computerEasyMove() {
// Bunch of code to pick a square and determine if its a hit or not.
checkForWinner();
}
Ideally, I'd like to have sound effects, or at the very least a pause between moves. However, no matter how I use Thread.sleep, or TimerTask, or anything else, I can't get it to function correctly.
You should be using a Swing Timer. Something like:
Timer timer = new Timer(1000, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
currentTurn = computer;
computerMove();
}
});
timer.setRepeats(false);
timer.start();

Java Game Keeps Freezing When I Start A Thread?

I'm making a above mode 2D Zombie Shooter, and I'm having some problems with a thread. here's the deal. I had the character shoot a bullet every time i pressed space. the problem was that if you held space, it would shoot one, then pause, and then shoot a lot of bullets. there were a bunch of ways to fix this, but i want this way because it leaves room for future changes to shoot speed. here is the code for the thread that is causing the problems:
package threads;
import Game.GameCore;
public class Shoot extends GameCore implements Runnable {
/**
* WHEN I START THIS THREAD, THE ENTIRE GAME FREEZES, AND I DO NOT KNOW
* WHY... NEED TO FIX. IT DOES NOT FIX THE PROBLEM TO TAKE OUT THE "SHOOT"
* OR THE "SLEEP"...
*/
public void run() {
while (shooting && gameRunning) { // shooting is made true when space is
// pressed, and set false when space
// is released. gameRunning is true
// if the game is running, which it
// is. removing either of these
// doesnt work either.
player.shoot(); // player comes from the GameCore class, and
// represents the player entity. if i remove this,
// nothing changes.
try {
Thread.sleep(bulletShootSpeedMillis); // bulletShootSpeedMillis
// is equal to 1000, but
// makes no difference
// to change
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
so here is the dang problem. the comments kinda point them out, but ill list them. if i remove the obvious things, such as player.shoot(); or Thread.sleep(bulletShootSpeedMillis); or even one of the things in the while loop, nothing changes. the issue is that when i initiallize the thread, with
else if (key == Integer.parseInt(commands[6])) {
shooting = true;
new Thread(new Shoot()).run();
}
the entire game just freezes. nothing happens at all. the moment i start the thread with space, my game freezes, and i cannot figure out why!!! the previous version with:
else if (key == Integer.parseInt(commands[6])) {
player.shoot();
}
it works just fine. Please help! Thanks in advance! :)
EDIT: thanks for the quick answer. needless to say, major learning experience with simple mistakes XD
Ayyyy!
new Thread(new Shoot()).run(); // ***** !!!!
You don't start a Thread by calling its run() method, since all that does is call the code in the same thread as the calling code. You start a new Thread by calling its start() method.

Panning on GUI map Java

This is my first post so if any other information is needed please let me know.
I'm making a game in a Java GUI and just have two hopefully quick questions about which. I can currently paint a map to the screen and pan around the map with the following code:
private class MoveMap implements MouseMotionListener{
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if(e.getX() > swidth-30){
if(xmod+(columns*30) > swidth){
xmod-=30;
repaint();
}
}
else if(e.getX() < 30){
if(xmod < 0){
xmod+=30;
repaint();
}
}
else if(e.getY() > sheight-30){
if(ymod+(rows*30) > sheight){
ymod-=30;
repaint();
}
}
else if(e.getY() < 30){
if(ymod < 0){
ymod+=30;
repaint();
}
}
else{
}
}
}
The only problem is the mouse must continually move at the edge of the screen to continually pan. My question is if there's a way to have the mouse at the edge of the screen and continually pan while updating the graphics? My second question would be if this could be applied to characters moving as well? I thought maybe a thread would be a possible solution but am not familiar with using them. Thank you!
I can think of two ways to achieve this.
You could...
Start a javax.swing.Timer that would update the x/y position as required and repaint the screen when ever the mouse entered within a given distance of the edge of the screen. You would, obviously stop the timer as the mouse moved back out ;)
You could...
Use a background Thread to monitor the mouse position and when it enters the "trigger" zone, would update the x/y values and trigger a repaint, making sure you re-sync the calls to the EDT ;)

How to reduce lag in my java 2d platformer?

I am making a 2d platformer in Swing java, and I am wondering how to reduce the lag I get from it. I mean, it doesnt lag too bad but it is noticable that it slows down sometimes. I have a Swing timer ticking at 12 milliseconds, a cycle function, and a paint function.
public void cycle() {
if (guy.getJumpState() == false) {
if (canExecuteMovement(0, 4)) {
onGround = false;
if (guy.getY() > 300) {
// if you are in the middle, move the platforms.
for (int i = 0; i < platformCount; i++) {
platform[i].setY(platform[i].getY() - 4);
}
} else {
// or just move the guy if not.
guy.moveY(4);
}
} else {
onGround = true;
}
} else {
if (canExecuteMovement(0, -8)) {
if (guy.getY() < 300) {
// if you are in the middle, move the platforms.
for (int i = 0; i < platformCount; i++) {
platform[i].setY(platform[i].getY() + 8);
}
} else {
// or just move the guy if not.
guy.moveY(-8);
}
jumpCount++;
if (jumpCount >= 15) {
jumpCount = 0;
guy.setJumpState(false);
}
} else {
jumpCount = 0;
guy.setJumpState(false);
}
}
if (guy.getDirection() == "left") {
if (canExecuteMovement(-3, 0)) {
if (guy.getX() < 450) {
// if you are in the middle, move the platforms.
for (int i = 0; i < platformCount; i++) {
platform[i].setX(platform[i].getX() + 3);
}
} else {
// or just move the guy if not.
guy.moveX(-3);
}
}
} else if (guy.getDirection() == "right") {
if (canExecuteMovement(3, 0)) {
if (guy.getX() > 450) {
// if you are in the middle, move the platforms.
for (int i = 0; i < platformCount; i++) {
platform[i].setX(platform[i].getX() - 3);
}
} else {
// or just move the guy if not.
guy.moveX(3);
}
}
}
}
public void paint(Graphics g) {
super.paint(g); // something important
Graphics2D g2d = (Graphics2D) g;
// draw platforms
for (int i = 0; i < platformCount; i++) {
if (platform[i].getX() > -50 && platform[i].getX() < 950 && platform[i].getY() > -50 && platform[i].getY() < 650) {
g2d.drawImage(platform[i].getImage(), platform[i].getX(), platform[i].getY(), this);
}
}
// draw guy
g2d.drawImage(guy.getImage(), guy.getX(), guy.getY(), this);
// destroy unneeded processes
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
What can I do to optimize this and cause less lag? When I make a thread for the cycle function itself, the platforms sometimes seperate for a split second. I assume because since the thread is asynchronous, half of it is done while the paint function goes on.
Some loose thoughts (it's been years since I did some animation in Swing), and you didn't posted some compilable code.
Have you tried do paintComponent() --- paint does a lot of other stuff. And then maybe you need to add repaint() to tick function. Every time I reloaded paint it enden in a mess.
Also try increasing tick time --- youll waste less time repaiting.
Also I assume you are doing ticks by Timers.
I have no idea why you dispose graphics object
Also try just dropping sync (Ive done animations that work on many oeses without it) Toolkit.getDefaultToolkit().sync()
If it doesn't help use profiler to find a bottleneck. Visual VM is quite nice. Also Visual VM is part of the jdk for some time --- just go into bin folder and launch jvisualvm.
EDIT: (thread issues)
Some people suggested using threads --- which I diasgree. If you want do some work outside EDT please use SwingWorker
I assume you are not calling paint() but just call repeaint(). If you do call paint() (whatever black magic you also make to make it work) please just call repaint() that will schedule repaing on appropriate time.
First of all, this bit here is a problem:
// destroy unneeded processes
Toolkit.getDefaultToolkit().sync();
g.dispose();
In general, disposing a resource you did not create is probably a bad idea. In this specific case, the Graphics passed into paint() is probably used by all other components in the hierarchy, so this could cause really odd results.
Calling Toolkit.sync() here is I think your attempt to eliminate the tearing you were seeing when moving things in the background. But all that it does is to flush any pending draw instructions. That has no effect here because you are probably drawing to a back-buffered Swing component that will be drawn fully later.
The correct way to eliminate tearing is to perform any updates on the event thread, so that you are not changing the screen data while drawing it. One simple way to implement this would be to have your timer just call repaint(), and have the paint() method call cycle() before doing anything.
For dealing with lag, one solution might be to allow a variable frame rate. Instead of moving everything a fixed distance each frame, calculate the time since the last frame and move everything accordingly.
I would create your variables outside the method so that it is not being created every time you call that method. The best way to program games is to re-use things instead of destroying and creating because destroying & creating cost a lot of computing power.
Graphics2D g2d = (Graphics2D) g; <---declare it outside your method.
And also try to find redundant conditionals. I saw one where you say (if direction right then ..., else if direction left ...); just say (if direction right then ... else ...). Conditionals do not cost much but when you're calling that conditional 1000 times a second I think it adds up. (idk though, but I do it just in case and for making things fluid)
Where you say setjumpstate(false) it's redundant because no matter what, it is executed - just move it outside the conditional.

Categories