Sign in to follow this  

2 player Java game

This topic is 4015 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I just started learning java and am starting my own game. I don't know how to make it 2 players though. When I execute the code, only 1 player can be moved at a time. How do I fix this? Here's the first part of my code(please point out any others mistakes I'm making if you see it): Edit: I reposted it to make it easier to see. Didn't know you could do that. [Edited by - Mossflower on December 11, 2006 11:20:22 PM]

Share this post


Link to post
Share on other sites
I'm not proficient in Java, so I can't answer your question, but I recommend that you edit or re-post your code using [source] tags so that it is readable. Also I'm not sure if the multiple statements on one line are intentional or are a formatting error, but I would fix those as well.

In other words, make your posted source as easy to read as possible; you'll be much more likely to get help that way.

Share this post


Link to post
Share on other sites
Like this?(this doesn't include the player class I made, if that's needed, I'll gladly post it):
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Rectangle2D;
/**LIBnation.java
*The Fighting Game
*@author David Finol
*@version 0.2 12/10/06
*/

public class LIBnation extends Applet implements KeyListener
{
private final int APPLET_WIDTH = 500;
private final int APPLET_HEIGHT = 375;
private int width, height;
private Image background, p1l1, p1l2, p1r1, p1r2, p1j, p1f, p1a;//still to add jr,fr, al1,
private Image backbuffer, p2l1, p2l2, p2r1, p2r2, p2j, p2f, p2a;//al2, ar1, ar2
private AudioClip music;//background, later coming sound effects with move and attack
private Player p1, p2;
private String name1 = "Mossflower", name2 = "Nyteshade";//causes character select
private String level = "LIBnation Homepage", healthsign1, healthsign2;//causes level select
private int p1width = 45, p1height = 30, p1atk = 2, p1def = 2, p1speed = 5, p1range = 100, health = 50;
private int p2width = 40, p2height = 40, p2atk = 3, p2def = 2, p2speed = 2, p2range = 100;//stats of players
private boolean gravity, offscreen, dissappear, teleport, team, com;//features and options
private boolean victory, spec1, spec2;//in-game events
Graphics2D Stringmaker;
Graphics backg;
Rectangle2D bounds, bounds2;
Font font = new Font("SansSerif", Font.BOLD+Font.ITALIC, 24);//for health and name output
FontRenderContext context;
/**Initializes the game by loading all necessary files
*/

public void init ()
{
setSize (APPLET_WIDTH, APPLET_HEIGHT);
setBackground (Color.black);
background = getImage (getDocumentBase(), level+".jpg");
music = getAudioClip (getDocumentBase(), level+".au");
backbuffer = createImage(APPLET_WIDTH, APPLET_HEIGHT);
backg = backbuffer.getGraphics();
backg.drawImage(background, 0, 0, this );
Stringmaker = (Graphics2D) backg; //helps with context
context = Stringmaker.getFontRenderContext(); //helps with drawP1&P2
addKeyListener(this);
}
/**Starts the game by drawing the screen and looping the music
*/

public void start ()
{
makeP1();
makeP2();
//the following lines prevent the character from mysteriously dissappearing the first time that you move them?
p1.jump();
drawP1(backg);
p1.fall();
drawP1(backg);
p1.attack(p2);
p1.attack(p2);
drawP1(backg);
p1.moveRight();
drawP1(backg);
p1.moveRight();
drawP1(backg);
p1.moveLeft();
drawP1(backg);
p1.moveLeft();
drawP1(backg);
p1.moveRight();
drawP1(backg);
p2.jump();
drawP2(backg);
p2.fall();
drawP2(backg);
p2.attack(p1);
p2.attack(p1);
drawP2(backg);
p2.moveLeft();
drawP2(backg);
p2.moveLeft();
drawP2(backg);
p2.moveRight();
drawP2(backg);
p2.moveRight();
drawP2(backg);
p2.moveLeft();
drawP2(backg);
backg.drawImage(background, 0, 0, this );
repaint();
music.loop();
}
/**Unused method
*@param typed the event that occurs when a character is typed
*/

public void keyTyped(KeyEvent typed){}
/**Contols character
*@param pressed the button that is pressed to move the character
*/

public void keyPressed(KeyEvent pressed)//try to find 2 player input
{
if(pressed.getKeyCode() == KeyEvent.VK_A)
p1.moveLeft();
if(pressed.getKeyCode() == KeyEvent.VK_W)
p1.jump();
if(pressed.getKeyCode() == KeyEvent.VK_D)
p1.moveRight();
if(pressed.getKeyCode() == KeyEvent.VK_S)
p1.fall();
if(pressed.getKeyCode() == KeyEvent.VK_CAPS_LOCK)
p1.attack(p2);
if(pressed.getKeyCode() == KeyEvent.VK_LEFT)
p2.moveLeft();
if(pressed.getKeyCode() == KeyEvent.VK_UP)
p2.jump();
if(pressed.getKeyCode() == KeyEvent.VK_RIGHT)
p2.moveRight();
if(pressed.getKeyCode() == KeyEvent.VK_DOWN)
p2.fall();
if(pressed.getKeyCode() == KeyEvent.VK_NUMPAD0)
p2.attack(p1);
backg.drawImage(background, 0, 0, this);
drawP1(backg);
drawP2(backg);
repaint();
}
/**Unused method
*@param released the event that occurs when a character is typed
*/

public void keyReleased(KeyEvent released){}
/**Method used by paint to prevent flickering
*@param screen the screen that the screen is drawn on
*/

public void update(Graphics screen)
{
screen.drawImage(backbuffer, 0, 0, this );
}
/**Draws the screen
*@param screen the screen that is drawn on
*/

public void paint (Graphics screen)
{
update (screen);
}
/**Draws the first player, his/her name, and its health
*@param c the screen that is drawn on
*/

public void drawP1 (Graphics c)
{
c.setFont(font);
c.setColor(Color.blue);
bounds = font.getStringBounds(name1, context); //to find where to put string
c.drawString (name1, 0, (int) bounds.getHeight());
healthsign1 = p1.getHealth();
bounds2 = font.getStringBounds(healthsign1, context);
c.drawString (healthsign1, 0, (int) bounds.getHeight()+ (int) bounds2.getHeight());
c.drawImage (p1.getSprite(), p1.getX(), p1.getY(), p1.getWidth(), p1.getHeight(), this);
}
/**Draws the second player, his/her name, and its health
*@param c the screen that is drawn on
*/

public void drawP2 (Graphics c)
{
c.setFont(font);
c.setColor(Color.blue);
bounds = font.getStringBounds(name2, context); //to find where to put strings
c.drawString (name2, APPLET_WIDTH- (int) bounds.getWidth(), (int) bounds.getHeight());
healthsign2 = p2.getHealth();
bounds2 = font.getStringBounds(healthsign2, context);
c.drawString (healthsign2, APPLET_WIDTH- (int) bounds2.getWidth(), (int) bounds.getHeight()+ (int) bounds2.getHeight());
c.drawImage (p2.getSprite(), p2.getX(), p2.getY(), p2.getWidth(), p2.getHeight(), this);
}
/**Downloads the necesary images for the first player and instantiates it
*/

public void makeP1()
{
p1l1 = getImage (getDocumentBase(), name1+"l1.png");
p1l2 = getImage (getDocumentBase(), name1+"l2.png");
p1r1 = getImage (getDocumentBase(), name1+"r1.png");
p1r2 = getImage (getDocumentBase(), name1+"r2.png");
p1j = getImage (getDocumentBase(), name1+"j.png");
p1f = getImage (getDocumentBase(), name1+"f.png");
p1a = getImage (getDocumentBase(), name1+"a.png");
p1 = new Player(p1l1, p1l2, p1r1, p1r2, p1j, p1f, p1a, p1width, p1height,
1, health, p1atk, p1def, p1speed, p1range);
healthsign1 = p1.getHealth();
}
/**Downloads the necessary images for the second player and instatiates it
*/

public void makeP2()
{
p2l1 = getImage (getDocumentBase(), name2+"l1.png");
p2l2 = getImage (getDocumentBase(), name2+"l2.png");
p2r1 = getImage (getDocumentBase(), name2+"r1.png");
p2r2 = getImage (getDocumentBase(), name2+"r2.png");
p2j = getImage (getDocumentBase(), name2+"j.png");
p2f = getImage (getDocumentBase(), name2+"f.png");
p2a = getImage (getDocumentBase(), name2+"a.png");
p2 = new Player(p2l1, p2l2, p2r1, p2r2, p2j, p2f, p2a, p2width, p2height,
2, health, p2atk, p2def, p2speed, p2range);
healthsign2 = p2.getHealth();
}
/**Plays out the commands of the level
*/

public void levelEffects()
{
//filld in later
}
/**Stops the music
*/

public void stop ()
{
music.stop();
}
}

Share this post


Link to post
Share on other sites
I move the input, but I get a "cannot find symbol class addKeyListener(Player)" error. Here's what I tried(the beginning of the player class):
import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
/**A player is used to show up on a screen, and interact with other player.
*/

public class Player implements KeyListener
{
private int width, height, X, Y, player, health, atk, defense, speed, range;
private Image sprite, right1, right2, left1, left2, jump, fall, attack, die;
private Player enemy;
private boolean dead;
/**Constructs a player with the images and stats specified
*@param l1 the image for beginning to move the player left
*@param l2 the image for ending to move the player left
*@param r1 the image for beginning to move the player right
*@param r2 the image for ending to move the player right
*@param j the image for making the player jump
*@param f the image for making the player fall
*@param a the image for making the player attack
*@param w the width size of the player
*@param h the height size of the player
*@param p the player character (player 1 or player 2)
*@param hp the health of the player
*@param at the atk stat of the player
*@param def the defense stat of the player
*@param s the movement speed stat of the player
*@param r the attack range stat of the player
*/

public Player(Image l1, Image l2, Image r1, Image r2, Image j, Image f, Image a,
int w, int h,int p, int hp, int at, int def, int s, int r, Player enemy)
{
left1 = l1;
left2 = l2;
right1 = r1;
right2 = r2;
jump = j;
fall = f;
attack = a;
defense = def;
width = w;
height = h;
player = p;
if(player == 1)
{
X = 0;
sprite = right1;
}
else
{
X = 500-width;
sprite = left1;
}
Y = 375-height;
health = hp;
atk = at;
speed = s;
range = r;
dead = false;
addkeyListener(this);
}
/**Unused method
*@param typed the event that occurs when a character is typed
*/

public void keyTyped(KeyEvent typed){}
/**Contols character
*@param pressed the button that is pressed to move the character
*/

public void keyPressed(KeyEvent pressed)
{
if(player == 1)
{
if(pressed.getKeyCode() == KeyEvent.VK_A)
moveLeft();
if(pressed.getKeyCode() == KeyEvent.VK_W)
jump();
if(pressed.getKeyCode() == KeyEvent.VK_D)
moveRight();
if(pressed.getKeyCode() == KeyEvent.VK_S)
fall();
if(pressed.getKeyCode() == KeyEvent.VK_CAPS_LOCK)
attack();
}
else
{
if(pressed.getKeyCode() == KeyEvent.VK_LEFT)
moveLeft();
if(pressed.getKeyCode() == KeyEvent.VK_UP)
jump();
if(pressed.getKeyCode() == KeyEvent.VK_RIGHT)
moveRight();
if(pressed.getKeyCode() == KeyEvent.VK_DOWN)
fall();
if(pressed.getKeyCode() == KeyEvent.VK_NUMPAD0)
attack();
}
}
/**Unused method
*@param released the event that occurs when a character is typed
*/

public void keyReleased(KeyEvent released){}




[Edited by - Mossflower on December 12, 2006 1:33:00 AM]

Share this post


Link to post
Share on other sites
OOPS, that's a stupid mistake. When I fixed it, I still got the eame error, so I did this:

public class Player extends Component implements KeyListener

Now that the movement is there, how can I get the characters to be drawn? Originally, I called the drawPX() method whenever one of the buttons was pressed, but that doesn't work now that they are in different classes. I tried making another method that would check to see if the character had been moved and then insert it the start method, but that causes the paint method never to be called.
So what can I do?

[Edited by - Mossflower on December 12, 2006 5:04:19 PM]

Share this post


Link to post
Share on other sites
By using a so-called game loop, in which you handle input, update game logic, and render the screen every cycle. That's actually the most common way to handle games.

Personally, I would keep input handling apart from the Player class. The input should message a Player object to move instead. This allows you to keep the input handling central, and it allows you to write AI code that can send the same messages to a Player, without any changes to the Player class.

Share this post


Link to post
Share on other sites
I agree with keeping the input handling away from the player class, but how would I be able to allow the two players to move at the same time? My previous code didn't work. And could you post an example of the game loop? SO I know what you're talking about.

Share this post


Link to post
Share on other sites
Err, yeah, I'm bein' an idiot; lol. I'm just so upside-down these days now that it's finals week (got two exams tomorrow; fun!). Yes, keep the input outside of the player class.

Last time I tried doing two-player input I think I ran into the same problem at one point. Not sure how I got by it. I'll look around through my old code and get back to ya. Just a hunch, but I believe I had to separate the input into two threads somehow, since each thread can handle only one key event at a time. Maybe... I'll check.

Share this post


Link to post
Share on other sites
You don't need to use two threads for multiple player input: the keyPressed method is called any time a key is pressed. All you need to do in that function is to check which key was pressed and move the associated player.

The game loop is just a while loop that runs as long as the game isn't over. In this case, you don't need to check for input, since that's event-driven. So, all that's left is an update part and the rendering part. This game loop should probably be placed in a game thread. Anyway, in pseudocode (along with some suggestions for the game's structure):


void run()
{
while(gameIsRunning)
{
update();
repaint();
}
}

void update()
{
// Handle anything that needs to be updated here, such as moving objects, etc.
}

void paint(Graphics g)
{
// Paint everything here. It may be usefull to provide all paintable game objects
// with a virtual draw(Graphics g) function or something similar, and
// derive them all from a single GameObject class, for example, and use
// a vector of GameObjects so repainting the screen is a simple for loop
// that runs through this vector and calls the draw function of each object.
// The same can be applied to the update function, by providing this GameObject
// class with an update() function, where each derived class fills in it's
// behaviour. For example, a character might do an idle animation now and then,
// which could be determined in it's update() function.
}


Share this post


Link to post
Share on other sites
The game loop sounds like a great idea, so I'll use that. But my problem is that the keyPressed method only checks one button at a time. The players will probably be pressing buttons at the same time quite often, but they won't be able to move at the same time.

Share this post


Link to post
Share on other sites
Instead of handline the input in the keyup and keydown events, create a container full of every possible key that Can be pressed. I don't know how to do arrays in java(or really anything in java), but it would be something like this:

Class Keyboard {
KeyboardArray
...
}

Class Player
...
public void keyPressed(KeyEvent pressed)
{
if(pressed.getKeyCode() == KeyEvent.VK_A)
KeyboardArray[KeyEvent.VK_A] = true
if(pressed.getKeyCode() == KeyEvent.VK_W)
KeyboardArray[KeyEvent.VK_W] = true
if(pressed.getKeyCode() == KeyEvent.VK_D)
KeyboardArray[KeyEvent.VK_D] = true
....
}
public void keyReleased(keyEvent released)
{
if(released.getKeyCode() == KeyEvent.VK_A)
KeyboardArray[KeyEvent.VK_A] = false
if(pressed.getKeyCode() == KeyEvent.VK_W)
KeyboardArray[KeyEvent.VK_W] = false
if(pressed.getKeyCode() == KeyEvent.VK_D)
KeyboardArray[KeyEvent.VK_D] = false
....
}
public void handleInput()
{
if(keyBoardArray[KeyEvent.VK_LEFT])
moveLeft();
COMMENT: What you Really want to do is have a speed variable and
COMMENT: Update it here
if(keyBoardArray[KeyEvent.VK_RIGHT)
moveRight();
COMMENT: What you Really want to do is have a speed variable and
COMMENT: Update it here
....
}



Hope this makes Some sense. I'm in a hurry and don't know java, but the principle is the same

Share this post


Link to post
Share on other sites
The previous poster is suggesting you use an array of bools to keep track of whether or not a key has been pressed. It will make your character movement smoother for example:


Public Class mainGameClass implements KeyListener
{
private boolean keyPressed[] = new boolean[256];


//...

public void keyPressed(KeyEvent pressed)
{
//set the key pressed to true
keyPressed[pressed.getKeyCode()] = true;
}
public void keyReleased(keyEvent released)
{
//set the key pressed to false
keyPressed[pressed.getKeyCode()] = false;
}

//...
//then later in your program you could respond to the input with something like this
public void run()
{
if(keyPressed[VK_A] == true)
p1.moveLeft();

//... etc etc
}
}



As for pressing multiple buttons at the same time I've run into this several times with java and I haven't figured out a solution :\. From what I can tell it usuall happens with the arrow keys as well as control, shift and space. You might want to try using letter keys only and see if that helps (although admitedly that probably wont make for the easiest control scheme, i just dont know a better way :\).

Share this post


Link to post
Share on other sites
It occurred to me last night that you'd want to set a movement flag rather than do movement in the keyPressed() function, indeed. Whether or not you use an array for this doesn't matter for now. Let's just say that, when the left button is pressed, you set player 1's moveLeft boolean to true, and when you release that button (I assume you can use the keyReleased() function for that) you set it to false.

In your player's update function, you check for this boolean, and move the character accordingly. That should do the trick.

Share this post


Link to post
Share on other sites
I think I understand what you're saying, but when I try it, the characters FLY across the screen. I think that the loop happens several times when I press it (even every quickly) and that's what causes it, but I don't really know about that. Here's what I tried:

//imports here
public class LIBnationGame extends JApplet implements Runnable
{
Thread GameRun;
//some variables are here, not needed for this
private boolean GameRunning
private boolean p1moveRight, p2moveLeft;
//more variables here
KeyListener Controller;
/**The control movements for a player
*/

class Controls implements KeyListener
{
/**Unused Method
*@param the key typed
*/

public void keyTyped (KeyEvent typed)
{
}
/**Controls the characters
*@param the key pressed
*/

public void keyPressed (KeyEvent pressed)
{
if(pressed.getKeyCode() == KeyEvent.VK_D)
p1moveRight = true;
if(pressed.getKeyCode() == KeyEvent.VK_L)
p2moveLeft = true;
}
/**Stops Character movement
*@param the key released
*/

public void keyReleased (KeyEvent released)
{
if(released.getKeyCode() == KeyEvent.VK_D)
p1moveRight = false;
if(released.getKeyCode() == KeyEvent.VK_L)
p2moveLeft = false;
}
}
/**Initializes the game by loading all necessary files
*/

public void init ()
{
setSize (APPLET_WIDTH, APPLET_HEIGHT);
background = getImage (getDocumentBase(), level+".jpg");
music = getAudioClip (getDocumentBase(), level+".au");
backbuffer = createImage(APPLET_WIDTH, APPLET_HEIGHT);
backg = backbuffer.getGraphics();
Stringmaker = (Graphics2D) backg; //helps with context
context = Stringmaker.getFontRenderContext(); //helps with drawP1&P2
backg.setFont (font);
Controller = new Controls();
GameRun = new Thread(this);
}
/**Starts the game by drawing the screen and looping the music
*/

public void start ()
{
GameRunning = true;
p1 = new Player(name1, p1width, p1height, 1, health, p1atk, p1def, p1speed, p1range);
p2 = new Player(name2, p2width, p2height, 2, health, p2atk, p2def, p2speed, p2range);
music.loop();
addKeyListener(Controller);
GameRun.start();
}
/**Runs a game loop to for the game to occur in
*/

public void run ()
{
while(GameRunning)
{
update();
repaint();
}
removeKeyListener(Controller);
}
/**Handles all the game logic and movements of the characters
*/

public void update ()
{
if(p1moveRight)
p1.moveRight();
if(p2moveLeft)
p2.moveLeft();
if(p1.isDead() && p2.isDead())
{
victory = "It's a Tie!";
GameRunning = false;
}
else if(p1.isDead())
{
victory = name2+" has won.";
GameRunning = false;
}
else if(p2.isDead())
{
victory = name1+" has won.";
GameRunning = false;
}
}
/**Draws the screen
*@param screen the screen that is drawn on
*/

public void paint (Graphics screen)
{
update (screen);
}
/**Method used by paint to prevent flickering
*@param screen the screen that the screen is drawn on
*/

public void update (Graphics screen)
{
backg.drawImage(background, 0, 0, this);
drawP1();
drawP2();
if(!GameRunning)
{
backg.setColor(Color.RED);
backg.drawString (victory, 187, 250);
}
screen.drawImage(backbuffer, 0, 0, this );
}
//Game continues but I don't think the problem is in there



[Edited by - Mossflower on December 14, 2006 9:50:21 PM]

Share this post


Link to post
Share on other sites
Make movement time-based rather than frame-based. Which means, you should multiply the movement with the frame time. You can get the frame time by storing the current time, and checking the current time against the time you stored in the previous cycle. This usually is a few milliseconds.

Dune, the old 2D RTS game, had this problem as well: movement was frame-based, so on a current system that would be insanely fast, but building times were time-based, so still normal. Very odd result. :)

Share this post


Link to post
Share on other sites

This topic is 4015 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this