1

I am having this odd issue, and I am not sure what is causing it. Some times the issue isn't even there. From what I am guessing, is that this is a Java memory issue or some sort of threading issue.

I have a Ship and the ship shoots Bullets If I hold down the Space key the ship shoots the bullets. I have the bullets set to fire off every 200 milliseconds. Some times they shoot fine and move at the same speed! Other times, they shoot they move at different speeds. What could cause this?

package JGame.Actions;

import JGame.GameObject.GameObject;
import javax.swing.AbstractAction;

public class MoveAction extends Action implements Runnable{

    protected GameObject obj;
    protected int endX = 0, endY = 0;
    protected int moveAmount = 0;
    protected Thread thread;

    public void moveToY(GameObject obj, int y, int amount, AbstractAction complete){
        this.obj = obj;
        this.endY = y;
        this.moveAmount = amount;
        this.complete = complete;
        thread = new Thread(this);
        thread.start();
    }

    public void run(){
        try{
            boolean run = true;
            while(run){
                int objY = obj.getY();
                if(objY > this.endY){
                    obj.setY(obj.getY() - 1);
                }else if(objY < this.endY){
                    obj.setY(obj.getY() + 1);
                }else{
                    run = false;
                    this.actionComplete();
                }
                thread.sleep(moveAmount);
            }
        }catch(Exception e){
        }
    }
}

Action Complete:

package JGame.Actions;

import javax.swing.AbstractAction;

public class Action {
    protected boolean actionComplete = false;
    protected AbstractAction complete;

    public void actionComplete(){
        complete.actionPerformed(null);
    }
}

In my code I call moveToY it is a very simple call but sometime the Bullets move at different speeds (wrong), and others they move at the same speed (right). I don't know if it would help to mention that as the bullets move sometimes they slow down for a second or two then speed back up to the correct speed.

Edit: Main Thread

The following is my main thread with the paintComponent

@Override
public void run(){
    try{
        while(true){
            // Check for key press events
            Iterator actions = KeyboardMap.map.entrySet().iterator();
            while(actions.hasNext()){
                Map.Entry ap = (Map.Entry)actions.next();
                Mapping mp = (Mapping)ap.getValue();
                if(mp.pressed){
                    mp.run();
                }
            }

            // Check for click mouse events
            Iterator actions2 = MouseMap.map.entrySet().iterator();
            while(actions2.hasNext()){
                Map.Entry ap = (Map.Entry)actions2.next();
                Mapping mp = (Mapping)ap.getValue();
                if(mp.pressed){
                    mp.run();
                }
            }

            for(GameObject go : gameObjects){
                if(!go.getLeaveScreen()){
                    int goWidth = go.getWidth();
                    int goHeight = go.getHeight();
                    int goX = go.getX();
                    int goY = go.getY();
                    int gameWidth = Game.width;
                    int gameHeight = Game.height;
                    if(goX + goWidth >= gameWidth){
                        go.setX(gameWidth - goWidth);
                    }
                    if(goX <= 0){
                        go.setX(0);
                    }
                    if(goY + goHeight >= gameHeight){
                        go.setY(gameHeight - goHeight);
                    }
                    if(goY <= 0){
                        go.setY(0);
                    }
                }
            }
            this.repaint();
            Thread.sleep(roomSpeed);
        }
    }catch(Exception e){
    }
}

public void paintComponent(Graphics g){
    try{
        g.drawImage(bg, 0, 0, this);
        for(int i = 0; i < gameObjects.size(); i++){
            GameObject go = gameObjects.get(i);
            g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
        }
    }catch(Exception e){
    }
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
  • 1
    +1 to JBNizet, I'd suggest remodelling your game loop to update entity movements etc so that you wont have to do this via other threads thus a single thread will handle the movement etc of all entities on screen. see this fixed time step game loop example: http://stackoverflow.com/questions/13999506/threads-with-key-bindings/14001011#14001011 – David Kroukamp Dec 25 '12 at 19:01
  • 1
    Exactly. One loop to rule them all. – JB Nizet Dec 25 '12 at 20:40

3 Answers3

5

Well, I guess you have a large number of concurrent threads running (one by moving bullet), and you expect each thread to wake up after exactly moveAmount milliseconds. You can't have such a guarantee, because the thread scheduler allows each thread to run for some time one at a time, and you might thus have glitches.

Another problem is that you seem to execute modification on Swing components out of the event dispatch thread, which is clearly forbidden by Swing's threading policy.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I don't think I do any modify Swing exponents, where am I doing that? – Get Off My Lawn Dec 26 '12 at 15:26
  • `this.actionComplete()` calls `actionPerformed()` on a Swing `AsbtractAction`, which I imagine, changes something in the GUI. Also, you don't show how the GUI is repainted at each iteration of the loop, but I guess you're repainting somehow, else what would be the point of this loop? – JB Nizet Dec 26 '12 at 15:30
  • I added more code, What I am feeling I am misunderstading is that I shouldn't use threads with Swing, but don't I need a main game thread? And if so, shouldn't it modify the objects in the window as someone plays their game? – Get Off My Lawn Dec 26 '12 at 15:56
  • Read the link I gave you, and the tutorial pointed by the link. Each time you want to access Swing components (or their model) from your game thread, you must use `SwingUtilities.invoke[Later|AndWait]()`. `repaint()` may be called from any thread, though. – JB Nizet Dec 26 '12 at 20:07
1

The most important thing to change in your code is don't model time with Thread.sleep. Use a Swing Timer, which you'll schedule to execute every moveAmount milliseconds and, as a bonus, the code is executed on the Event Dispatch Thread with no effort on your part.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Depending on what GameObject is, i.e if it is a JComponent EDT will apply, if not i.e OP uses extended Rectangle/Shape class than Swing timer would not be necessary as changing the co-ordinates of the Shape/Rectangle wont modify any Swing UI components – David Kroukamp Dec 25 '12 at 19:03
  • Whether EDT is required or not, this is still the way to go for all other reasons. – Marko Topolnik Dec 25 '12 at 19:23
  • If no Swing components are being manipulated than I would disagree. I think executing unnecessary code (that which does not modify a Swing component) in EDT is incorrect a [`TimerTask`](http://docs.oracle.com/javase/1.4.2/docs/api/java/util/TimerTask.html) should than be used well IMO – David Kroukamp Dec 25 '12 at 19:43
  • You aren't taking into account that with that approach there's a whole new resource to manage---and waste, if the computation involved presents no real burden on the EDT. – Marko Topolnik Dec 25 '12 at 19:50
0

Inform yourself about the usage of multiple threads and how the processing structure of a game is made correctly. The most important info for your case: You should only use ONE thread to process/move all your bullets and then render them.

Thomas
  • 650
  • 9
  • 9