Looking for an algorithm to switch lights in traffic light - java

Given a greenLightDuration and a yellowLightDuration, I need to switch lights (including red Light) based on duration. This all happens inside a run method for the traffic light. The reason for the run method is because it is used when running the entire simulation (trafficLight is an Agent).
//Run method for agents in Model
public void run(double duration) {
if (disposed)
throw new IllegalStateException();
for (int i=0; i<duration; i++) {
time++;
for (Agent a : agents.toArray(new Agent[0])) {
a.run(time);
}
super.setChanged();
super.notifyObservers();
}
}
In Light I have the run method...
public void run(double runTime){
double check_time = runtime - time;
if(check_time >= yellowLightDuration&& color == Color.RED){
color = Color.GREEN;
time = runtime;
}else if(check_time >= greenLightDuration&& color == Color.GREEN){
color = Color.RED;
time = runtime;
}
...but it was just something silly I did to get the lights switching from red/green and obviously does not work for yellow or is not proportionate to green/yellow light duration(I don't think).
For color I use
Color.RED, Color.YELLOW, Color.GREEN from java.awt.Color.
public void run(double runtime){
if(this.color == Color.GREEN){
if(time%greenLightDuration==0){
color = Color.YELLOW;
}
}
if(this.color == Color.YELLOW){
if(time%yellowLightDuration == 0){
color = Color.RED;
}
}
else
color = Color.GREEN;
}
Tried this but the three colors are blinking furiously. I set green to 200 and yellow to 40.

Since this is a cycle, you want to get the current phase of the cycle using the modulus operator. Something like: double phase = (runTime - startTime) % (greenDuration + yellowDuration + redDuration). You can take the modulus of a floating-point number in Java.

the three colors are blinking furiously.
The first/main cause of this is the simulator/model, and not necessarily the traffic light (though your traffic light my still be a problem). The issue is that your current model for time is just some sketchy for-loop, which will run however fast it runs... and it clearly runs a lot faster than your eyes would like.
What you can do is attempt to control the time in your simulation, using Thread.sleep() to delay the program momentarily. The following version will run an iteration roughly once per millisecond...
//Run method for agents in Model
public void run(double duration) {
if (disposed)
throw new IllegalStateException();
for (int i=0; i<duration; i++) {
time++;
try{ Thread.sleep(1); } //wait 1ms
catch(Exception e){} //just resume after interruption
for (Agent a : agents.toArray(new Agent[0])) {
a.run(time);
}
super.setChanged();
super.notifyObservers();
}
}
Now a duration of 300 for green lights takes roughly 0.3 seconds, which is brisk but not unobservable.

Related

LibGdx - How can I not load my textures every single frame?

I am kinda new to Java and LibGdx but for my school project I need to Animate a Player-Sprite.
For only one Animation per Player everything went fine with the Methode I made for this but now I also need a Walking, Idling and Fighting Animation. I managed to get the Animations to switch but the Problem is now, that only one Frame of each Animation gets Displayed. After some research I know that I need to stop updating my Textures every frame but I cant get to know how to do so.
So far Ive tried a simple timer before updating but this just looks weird.
Here is my Code:
public Player(){
img3 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img1 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_run_anim_strip_6.png");
img2 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_sword_attack_anim_strip_4.png");
animation();
changeCharacter();
}
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
img3 = img2;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
img3 = img1;
tileWidth = 16;
amount = 3;
}else{
img3 = img;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(img3, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
Timer.schedule(new Timer.Task() {
#Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
}
Both Methodes "animation" and "changeCharacter" are called in render().
I know there are simpler solutions for this in LibGdx but the rest of my code is based on this and I basically would have to rewrite the entire Project...
If you need any other classes just ask. I'm probably asking a very easy thing but I dont know what to do with this.
You need to rename first.
img3 looks like it serves the purpose of being the pointer to the currentTextureSet. so when you initialise in Player() you might want to rename img3 to currentTextureSet and then, instead of the duplicate load of herochar_idle_anim_strip_4.png, set
currentTextureSet = img;
after
(you may also want to rename img, img1, img2 to idleTextureSet, runTextureSet and swordAttackTextureSet).
That aside,
definitely get rid of Timer.schedule which you are calling from render will run in a background thread you don't want that.
Looking at the asset pack here https://o-lobster.itch.io/platformmetroidvania-pixel-art-asset-pack?download if this is the same one, the images should be selected left to right i.e. x should be incremented not y. However, it looks like you increment y...
sprite.setRegion(regions[0][frame]); and the incorrect array access is swallowed because in a background timer task and the only textureRegion you can access is [0][0] i.e. you just see a single frame.
So dump this
Timer.schedule(new Timer.Task() {
#Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
and replace with
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[frame][0]);
*EDIT
So this means that your frame updates with every render, which is too fast. So the -easy fragile way- (not the best which would be deltaTime please read this excellent article https://gafferongames.com/post/fix_your_timestep/ ). The easy way, not the best in the case there is no time left, would be to declare
long renderCallCount =0;
put the above where frame is declared, then in your render method
renderCallCount++; //One more render call
if (renderCallCount % 60 == 0) { //Should I update frame?
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
So whenever renderCallCount is divisible by 60 using the mod operator https://www.edureka.co/blog/mod-method-in-java/ , which would be once a second if your refresh rate is 60hz, then your frame is incremented. To switch frames twice a second change 60 to 30.
This assumes your monitor is ONLY going to run at 60hz. I think your application probably depends on the timing on the refresh rate for position updates so you may want to update that in the future based on some thinking from the article. On a monitor with a faster frame rate everything will speed up (consistently).
I just put some stuff in the right order and it now works! I dont really get why the number after the mod operator needs to be so small but otherwise it just doesnt look right. Also I know that you shouldnt create the Spritebatch in render() but when I do it in the constructor the Program just crashesbecause of the missing Spritebatch??? But thanks for the help :) Here is the working code for anyone whos interested in this:
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT) && InfoGame.cl.isGrounded() && current > Enemy.lastDmg + Enemy.dmgCool){
currentTextureSet = attackTexture;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
currentTextureSet = runTexture;
tileWidth = 16;
amount = 3;
}else{
currentTextureSet = idleTexture;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(currentTextureSet, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
sprite.setOrigin(8,8);
if (renderCallCount % 6 == 0) {
frame++;
if (frame > amount) {
frame = 0;
}
}
sprite.setRegion(regions[0][frame]);
}

Java game lag, too many if statement?

I'm working on a game in java, based on the Atari game adventure. I got the basic KeyListener part working fine, but then I added another if statement, using another class, to test if if the player was going to hit a wall, and stopping movement if that was the case. The method I used also used if statements, and when I ran the code, it had MAJOR lag. I tried a while loop first, but that made it lag even worse. Anyway to make this not lag so much? It doesn't seem that complex a program to run, and I still have to add yet another if statement to make be able to move into another room, so I have to do something to massively cut down on the lag.
Here is the class:
class Player extends JPanel implements KeyListener{
private char c = 'e';
int x = 400;
int y = 400;
int mapX = 0;
int mapY = 0;
public Player() {
this.setPreferredSize(new Dimension(800, 500));
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Environment Layout = new Environment();
Layout.drawRoom(mapX,mapY,g);
g.fillRect(x , y , 20, 20);
}
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) {
c = e.getKeyChar();
repaint();
Environment Layout = new Environment();
if(Layout.isWall(x,y,c)){}
else{
if (c == 'a'){
x = x - 3;
}
else if (c == 'w'){
y = y - 3;
}
else if (c == 's'){
y = y + 3;
}
else if (c == 'd'){
x = x + 3;
}
}
}
public static void main(String[] s) throws IOException{
JFrame f = new JFrame();
f.getContentPane().add(new Player());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
The draw room method I used in this was just to put the background of the room into place.
Here is the isWall method from the Environment class:
public boolean isWall(int moveX, int moveY, char let){
BufferedImage room = null;
try {
room = ImageIO.read(new File(xNum + "," + yNum + ".png"));
}
catch (IOException e) {
}
int[][] walls = convertImage(room);
boolean blocked = false;
if(let == 'w') {
if(walls[moveY-8][moveX] == -3584){blocked = true;}
}
else if(let == 's') {
if(walls[moveY+20][moveX] == -3584){blocked = true;}
}
else if(let == 'a') {
if(walls[moveY][moveX-5] == -3584){blocked = true;}
}
else if(let == 'd') {
if(walls[moveY][moveX+20] == -3584){blocked = true;}
}
return blocked;
}
the convertImage method just converts the image of the room into an int array, for the value of the colors. -3584 is the color of the walls. It's possible this is what's lagging it, but this seemed like the best way for each room to have the walls done automatically.
I also tried a timer, but either I did that wrong, or it just didn't help.
I can give more of my code if that's needed, but help with this would be much appreciated. I'm relatively new to this kind of stuff, so it's likely I'm missing something big. Thanks.
The lag here is almost certainly not from the if statements. Those are really fast. I think the bigger issue is in isWall. Notice that any time you want to check for whether a wall is present, you
Open a file,
read the file contents,
convert the file contents from an image to a grid of pixels, and
read exactly one pixel.
Reading files from disk is extremely slow compared to looking at values in memory. For example, a regular magnetic hard drive works at around 7200 RPM, so the seek time is measured in milliseconds. On the other hand, your processor can do about a billion operations per second, so other operations take nanoseconds. That means that a disk read is roughly a million times slower than other operations, which is almost certainly where you're getting the lag from!
To fix this, consider rewriting your isWall code so that you only read the file and do the conversion once and, having done that, then just look up the part of the image you need. This converts doing tons of (glacially slow) file reads to one single (slow but inevitable) file read followed by tons of fast memory reads.
You appear to be moving your walls further than you are moving your player.
Is it possible that your player object is getting stuck in a wall there by producing "blocked = true" continuously?
Your character gets +- 3 in every direction, however your walls seem inconsistent and range from 8 up to 20 down to 5 left to 20 right.
This is an extension to #templatetypedef's answer.
Instead of loading the image files upon calling the isWall method, you might want to consider caching all of the walls on game start.
So I am thinking;
have a HashMap data structure keyed by <String, Integer>. Where String is your coordinates. E.g. coordinate string = "100,238"
parse all the .png image files in the directories and store the coordinates as key and the value can just be any dummy value like 1 or 2.
Then when isWall() is invoked. Given the X and Y coordinate, build the coordinate string as mentioned in point 1 and check if the key exists. If it does then we know it is a piece of wall else not.
This should drastically reduce the I/O disk contention.
In future, if you would like to extend the solution to incorporate APIs like isTreasureChest() or isMonster(). It can be extended by building a immutable class call "Room" or "Tile" to represent the object. Then modify the HashMap to take in <String, Room>.

Swing, Java and multithreading, and coloring buttons

Yes, this is homework. Yes, I am completely stuck.
Here is the gist. I have created a JFrame. There are 3 panels (top, middle, bottom). In the bottom panel are 3 buttons called: Red, Green, and Blue. In the top Panel are 3 text fields that give us the number of times we have clicked the respective button. The max we are allowed is 10 for each button. In the middle Panel is an 8 x 8 grid of Jbuttons numbered from 0 to 63. So far, so good.
Every time we click a button, a thread starts. No thread ever dies When a thread starts, a number from 0 to 63 is randomly chosen. The JButton corresponding to that number is painted the color that was clicked on. So if the red button was clicked, we should see a box with a white background turn red. But then the color of that JButton starts to fade until it becomes white. The process should take about 8 seconds.
Threads that you create should not have access to any Swing components. Rather, one has to maintain a data structure and update by threads according to their cycle of execution. On the other hand, periodically invoke repaint() methods from main thread to invite Swing Event Dispatcher thread to eventually visit the content of the data structure and display the GUI components accordingly.
........ I have gotten all the objects created and displayed. You can't click more than 10 times on a button. Here is where I am:
I have two arrays: one is an array of strings with size 64. They represent the buttons. I also have an array of ints. This is so that I know the order by which the threads were created. I have created the threads as a button is clicked, and I have started them. Here is my run method for the threads:
public void run() {
Random num = new Random(new Date().getTime());
while (true) {
Thread j = Thread.currentThread();
int randInt = num.nextInt(64);
synchronized (lock) {
if ((array[randInt].compareTo("red") == 0
|| array[randInt].compareTo("blue")
== 0 || array[randInt].compareTo("green") == 0))
{
randInt = num.nextInt(64);
}
for (int k = 0; k < 10; k++) {
if (threadarray[k] == -1) {
threadarray[k] = randInt;
break;
}
}
}
}
}
Even though we haven't covered it, I have tried to use a Timer object that immediately goes off right outside of the lock section. This takes me to the actionPerformed method. I have added all the appropriate registration.
public void actionPerformed(ActionEvent arg0) {
for (int i = 0; i < threadarray.length; i++) {
int num = threadarray[i];
if (num != -1) {
System.out.println(num);
String s = array[num];
System.out.println(s + "is ");
if (s.compareTo("red") == 0) {
button[num].setOpaque(true);
button[num].setBackground(Color.red);
while (button[num].getBackground() != Color.white) {
System.out.println("not white yet");
int g = button[num].getBackground().getGreen();
int b = button[num].getBackground().getBlue();
if (255 - (g + 1) >= 0) {
Color c = new Color(255, g + 1, b + 1, 1);
button[num].setOpaque(true);
button[num].setBackground(c);
System.out.println(c + " " + " c is");
} else {
button[num].setBackground(Color.white);
}
}
}
System.out.println(i + " i is " + button[num].getBackground()); //just some debugging info
threadarray[i] = -1; //clear the thread array
array[num] = "0"; //clear the string array
}
}
}
The actionPerformed method is handled by the Event Dispatch Thread. (Note the code immediately above is for the red threads only. The idea is to fade the color by inclemently increasing the green and blue colors till it becomes white.
Problems: no button ever changes color when I click the red button on bottom (yes, appropriate registration has been done.) I also have no idea how to control the timing with a multitude of threads going. Am I even going down the right road here?
Without giving away too much, this example illustrates a way to deal with color and buttons that ignore setBackground(). Examples here and here demonstrate how to fade the color. As both rely on a javax.swing.Timer thread, neither is a solution, but the techniques may prove useful.

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.

Why is my java made pacMan clone sometimes laggy?

I'm working on a pacman clone in java using eclipse and sometimes it appears laggy more specifically the movement of pacman/ghosts is slow, sometimes its fine. Once it has happened while I was running it so it wasn't after I added code and it doesn't seem to be after any specific event in game. I can't find any trigger or produce the lag on purpose
The resource manager shows the same cpu usage(only around 50%)/memory usage . Aswell the FPS seems to be around 200 consistently through lag and during the periods where it is working well.
Does anyone know what this could be?
Is there any information I left out that could be of use?
edit - I am basing movement on a timer is that bad? I will post the movement relevant code below is there a good way of posting the whole code on here?
Timer movement = new Timer(20, new ActionListener()//500 is time in milliseconds between
//calls to actionPerformed as far as I know.
{
public void actionPerformed(ActionEvent arg0)
{
if(movingUp == true)
{
moveUp();
}
else if(movingDown == true)
{
moveDown();
}
else if(movingRight == true)
{
moveRight();
}
else if(movingLeft == true)
{
moveLeft();
}
}
});
public void moveUp()
{
yPos -= 1;
this.rect.y -= 1;
}
public void setDirUp()
{
movingUp = true;
movingDown = false;
movingRight = false;
movingLeft = false;
}
in the main class in public void keyPressed:
if(keyCode == KeyEvent.VK_W)
{
if(pacMan.isUpHittingWall == false)
{
pacMan.setDirUp();
pacMan.isDownHittingWall = false;
pacMan.isRightHittingWall = false;
pacMan.isLeftHittingWall = false;
}
}
edit 2 -Thanks for the help guys. I have the movement using System time now and it seems to have fixed the issue because I implemented it only for pacman at first and the ghosts were still slow. Now there is an issue where moving right and down are much slower than moving left or up The only difference I see is that right and down are both adding and left and up are subtracting. What can I do about this?
The updated code is below.
//updated movement code
public void moveUp(long timePassed)
{
yPos -= vy * timePassed;
this.rect.y -= vy * timePassed;
}
public void moveDown(long timePassed)
{
yPos += vy * timePassed;
this.rect.y += vy * timePassed;
}
public void moveRight(long timePassed)
{
xPos += vx * timePassed;
this.rect.x += vx * timePassed;
}
public void moveLeft(long timePassed)
{
xPos -= vx * timePassed;
this.rect.x -= vx * timePassed;
}
//I passed timePassed through a globalInputObject because my input is handled in public //void keyPressed(KeyEvent e) and I didnt know how else to get timePassed in to the //movement method
//Here is the code in gameLoop()
globalInputObject.isPacManMovingUp(timePassed);
globalInputObject.isPacManMovingDown(timePassed);
globalInputObject.isPacManMovingRight(timePassed);
globalInputObject.isPacManMovingLeft(timePassed);
//This is inside the GlobalInputObject
public void isPacManMovingUp(long timePassed)
{
if(pacMan.movingUp == true)
{
pacMan.moveUp(timePassed);
}
}
public void isPacManMovingDown(long timePassed)
{
if(pacMan.movingDown == true)
{
pacMan.moveDown(timePassed);
}
}
public void isPacManMovingRight(long timePassed)
{
if(pacMan.movingRight == true)
{
pacMan.moveRight(timePassed);
}
}
public void isPacManMovingLeft(long timePassed)
{
if(pacMan.movingLeft == true)
{
pacMan.moveLeft(timePassed);
}
}
Rather than always moving the pacman by a constant distance (1 pixel, it appears) each time the timer runs, you should:
Set the timer to run as fast as possible (e.g. once every millisecond or less). Edit: if you set it too fast, the game may end up actually running slower, you'll have to experiment.
Calculate how much time has passed between each frame using the system clock and move the pacman by an amount proportional to that.
Doing the above will mean that if the system is "laggy," it will simply show fewer frames per second, rather than actually moving everything slower.
As I feared, you're basing the distance moved on the time chunk from the Timer. You shouldn't do this as all timers can be variable and unreliable, especially with small time chunks. Better to base movement on difference in system time. So yes, use a Timer or something to run your "game loop", but know the sprite's position and velocity using doubles, and calculate the distance to move based on velocity vector (math vector not Java Vector) * difference in system time. That way if the timer is delayed by say garbage collection, making the time chunk larger, the distance moved will be correspondingly greater and will look smoother.
You should look into creating a proper "main loop" or "game loop" as some call it. Take a look at the game structure part of this wikipedia article.. Basically those input events are happening\invoked from a separate thread than the main thread and they are directly modifying geometry of in game objects. Instead consider something like this for a main loop:
loop:
process collision detection
process animation (alters geometry of game objects)
process input (more on this later)
any other game specific logic
render screen
your process input could be something like this
if (globalInputObject.movingUp==true) {
hero.y -= 10;
}
if (globalInputObject.movingDown==true) {
hero.y += 10;
}
if (globalInputObject.movingLeft==true) {
hero.x -= 10;
}
if (globalInputObject.movingRight==true) {
hero.x += 10;
}
and your input handler would look something like this:
public void actionPerformed(ActionEvent evt) {
if (evt.button==UP_BUTTON) {
globalInputObject.movingUp=true;
}
if (evt.button==DOWN_BUTTON) {
globalInputObject.movingDown=true;
}
if (evt.button==LEFT_BUTTON) {
globalInputObject.movingLeft=true;
}
if (evt.button==RIGHT_BUTTON) {
globalInputObject.movingRight=true;
}
}
Basically the processing that you're doing in your "extra" threads (input thread) is minimal and therefore doesn't interfere with your main thread. Also, this method has the benefied of easily supporting multiple directions simultaneously (ie: UP+RIGHT = diagonal).
Only super high end games have more than a single thread (if they even need it at all). Dealing with synchronisation in a game is not good for performance.

Categories