1

I am trying to broaden by OOP skills by trying to program a 2D graphical game. Using Java's swing utilities.

Now what I have so far is: 4 general classes, an abstract class, an interface and a KeyListener class. (Don't worry it's a very small game at the moment).

Of the 4 general classes, the main class sets up two other classes as objects within it. These two objects are my graphics and my gamestate. Gamestate in turn sets up the last remaining object (player) within it.

The problem I have is that when I initially got it all working so the player could move (via keyPressed) the way input is read from the keyboard meant the player would jerk forward slightly, then run in a continuous motion. This is exactly how if you hold down a letter key on your keyboard a single letter comes up before a string of letters begin to form.

So I thought: "Oh it's so obvious. I should try and tackle this with booleans so that when a key goes down I have 'boolean right = true'. And I'll have some code somewhere going off in a loop with conditional statements for the moving of the player".

This is where I am stuck. Because I cannot figure out how to do get into this loop without 'jamming up' my program. In attempts I have run my program and been treated to nothing. The program hangs because it's in the loop and hasn't brought up the swing window yet. I have a feeling the answer is thread related (implements runnable), but I am in such new territory with this that I want 'a right and good' way to do it.

So I suppose this is a very open ended question to a variety of answers. How would you (have you) tackle this kind of problem?

--- EDIT*

Here are all the source files as requested. https://www.dropbox.com/sh/f4diy7qtzh4xkem/AABUkM415PrRK1hu35TVkBo2a

General classes: Main, Window, GameState, Robot. Interfaces: Movement Abstracts: GameVisualiser Listeners: ArrowPress

Forgive some of the commenting.

Ozal
  • 21
  • 4
  • 1
    It would be easier for us to answer if you post the realted part of your code. – padawan May 30 '14 at 16:44
  • 1
    Your idea of keeping track of whether a key is down or not with a boolean is a good idea and is often used in games using Swing. It's hard though to give advice on how to tackle it without knowing your architecture related to how you update your game's state. Do you have a game loop, where at different stages you do the following three things? : 1. update animations/positions based on how much time has elapsed since the last update, 2. update state based on last received user input (this is where you check your booleans), and 3. when you draw. – NESPowerGlove May 30 '14 at 17:11
  • A related game using `javax.swing.Timer` is cited [here](http://stackoverflow.com/a/3072979/230513). – trashgod May 30 '14 at 17:18
  • @NESPowerGlove I have a loop 'at the top' of my design. From the class that creates the graphic object and the gamestate object. Should I add to this loop and class so that it can do what I want? Won't that lead to the loop getting very large and very bad interdependency? – Ozal May 30 '14 at 17:31
  • It's hard to say without knowing how you update your state. It sounds like you might have a classic game loop, if you don't that's okay. Can you provide more details? How do you go about updating your game's state, like positions and time spent on current animation and such? How is your drawing being done, is it just a custom JComponent with paintComponent overridden which draws whatever your game state object depicts, or are you using a BufferStrategy in a loop? – NESPowerGlove May 30 '14 at 17:41
  • @NESPowerGlove I have added the source to the question, if you wish to poke around. The GameState implements an interface which the Graphic class can access, through extension of an abstract class. So when the game is loaded and some key input is detected on the Graphic Object then the KeyListener tells the Graphic object to use certain methods in the GameState object to manipulate the player's position in code, and thus on screen. I have an overridden paintcom in the Graphic object that gets information through the interfaces through to GameState. I'm curious as to what the BufferStrategy is? – Ozal May 30 '14 at 17:50
  • I don't have time to peak around the source code right now, but I'm guessing you have a loop somewhere, or a Timer, which calls repaint and updates your state (tick based or time based). A timer being called repeatedly is essentially also a loop. So in this loop, you also should look at your isWhateverKeyDown boolean, and change state based on that (for example, the player sprite's x velocity would now be 0 plus 1 if right key down and minus 1 if left key down). After you changed the velocities your updating of positions should take those into account and your sprite should move correctly. – NESPowerGlove May 30 '14 at 18:02
  • @NESPowerGlove Sorry, yes I do have that kind of loop. I shall try your idea when I get the chance. Thank you. – Ozal May 30 '14 at 18:27

2 Answers2

0

I would suggest using threads, which allows you to have two things running at the same time (in your case drawing the game and handling those inputs). If you make the player position public, you should be able to create a thread that handles the input and writes in the position and have the main thread (the one that displays the game) read that position. All the info you should need is in the oracle docs page.

Minja
  • 1
  • 1
0

Well you didn't go into detail what kind of game you're making.

Regardless, its easy to guess what your problem is. You are only advancing your games state in direct response to some kind of input event (you mentioned KeyListener). That kind of purely input event driven architecture works fine for games that only do things in response to the users input (e.g. simple card or board games).

But it seems you want to advance your game state at a point where there is no user input (e.g. between a KeyDown and an KeyUp event). In that case you will need what is commonly called a game loop, where the game is actually working continously updating the game state (usually at fixed intervals in time).

You have two options to do that:

a.) Using multiple threads, which has a steep learning curve for beginners, but is very flexible.

b.) Generate an event artificially at a fixed rate to advance your game state (this will also use threads under the hood, but you needn't deal with the details):

Take a look at class java.swing.Timer. You create a Timer instance, that triggers at regular intervals (lets say every 32 milliseconds, which is roughly 30 times per second). The timer generates an event (you attach a listener to the timer to get notified of the event) at regular intervals. You now move all the game state changing into that action event. This transforms your game from input event driven into a tick event driven game, giving you an opportunity to advance game state at each tick as needed.

In your KeyListener, you would simply update the flags for "moves in direction", the actual movement would be done in the tick event from the timer.

The reason you get jerky movement right now is probably you're relying on the KeyTyped event, which is generated artificially by swing - one event the moment the key is pressed, then some delay, then finally after that initial delay the event is fired with the key repeat rate (set in the system preferences) until the key is released. Thats not really suitable for a game, you are better of processing the KeyPressed and KeyReleased events, those reflect what the user is really doing on the keyboard.

Approach a.) with threads essentially does the same thing, with more freedom and everything under your control - but many more pitfalls to be aware of, such as concurrency and race conditions.

Durandal
  • 19,919
  • 4
  • 36
  • 70