I'm making a small game in java for school purposes.
Now I want to count the number of players, code I have:
Player player1;
player1 = new Player();
player1.name = "Name1";
player1.score = 0;
player1.lives = 100.0;
Player player2;
player2 = new Player();
player2.name = "Name2";
player2.score = 0;
player2.lives = 50.0;
In the players use a static variable count that increments in the player constructor.
private static int playerCount = 0;
//constructor
Player(){
playerCount++;
}
Put all the players in a list:
List<Player> allPlayers = new ArrayList<Player>();
Player player;
player = new Player();
player.name = "Name1";
player.score = 0;
player.lives = 100.0;
allPlayers.add(player);
player = new Player();
player.name = "Name2";
player.score = 0;
player.lives = 50.0;
allPlayers.add(player);
allPlayers.size(); //Number of players
player = allPlayers.get(0); //Player 1
player = allPlayers.get(1); //Player 2
The best way to go about it is to use a container class, something that's a descendent of java.util.Collections.
When a player is added, he is added to the collection. When the player drops out of the game, he is removed from the collection. As a result, to determine the number of players at any moment in time, one only need to count the members of the collection (which is already implemented if you use a java.util pre-implemented Collection).
Even then, there are two techniques. One of these are flawed, and I'll demonstrate the flawed technique first (which is not much better than the static counter example others have provided).
private static HashSet<Player> players = new HashSet<Player>();
public Player() {
players.add(this);
}
public static int getPlayerCount() {
return players.size();
}
This leads to an interesting problem. The Player count will never go down, as even if Player classes are dereferenced, the counting collection holds a reference preventing garbage collection. This leads to the java version of a "garbage leak", but don't confuse it with the C/C++ "garbage leak" which is more nefarious.
The second technique arises from fixing the problems in the first. Basically, it doesn't rely upon construction to register, as destruction is an unsafe means of deregistering. Within a snippet of code you would have
HashSet<Player> players = new HashSet<Player>();
Player player = new Player("bob");
players.add(player);
... later on ...
players.remove(player);
or something equivalent. Basically the main idea is to have your current player list at the same level as the player creation. There are a million variants, depending on where the originating call comes from; however, the main idea is the same: explicit deregistering of the player, not directly tied to object life cycle.
Related
For my school examn I have to make a console-application game of Hangman in Java, in which a player should be able to play against another player or a computer (2 players). A player should however also be able to play against a computer/AI. On top of that computers should be able to play against a computer as well.
Given the above, I have defined HashMaps with the player's names as String indexes and respective objects as values, like so:
private HashMap<String, PlayerHuman> humans = new HashMap<>(2);
private HashMap<String, PlayerComputer> computers = new HashMap<>(2);
Since both 2 players and 2 computers can play against each other, both HashMaps have a capacity of 2. Now when creating the players, there should either be real names entered (e.g. "John", "Mary") or a simple "C" if a player is computer-controlled. I then run a check on wether the input given was a "C" or not, resulting in creating the respective class for that player, like so:
Scanner scanner = new Scanner(System.in);
System.out.println("First create the players for the game!");
//
System.out.println("Type the name of player 1 (type C for computer): ");
String playerName1 = scanner.nextLine();
System.out.println("Type the nam of player 2 (type C for computer): ");
String playerName2 = scanner.nextLine();
if (playerName1.equals("C")) {
PlayerComputer player1 = new PlayerComputer();
player1.setPlayerName(playerName1);
if (playerName2.equals("C")) {
playerName1 = "C1";
playerName2 = "C2";
PlayerComputer player2 = new PlayerComputer();
player1.setPlayerName(playerName1);
player2.setPlayerName(playerName2);
this.computers.put(playerName2, player2);
} else {
PlayerHuman player2 = new PlayerHuman();
player2.setPlayerName(playerName2);
this.humans.put(playerName2, player2);
}
this.computers.put(playerName1, player1);
} else {
PlayerHuman player1 = new PlayerHuman();
player1.setPlayerName(playerName1);
if (playerName2.equals("C")) {
PlayerComputer player2 = new PlayerComputer();
player2.setPlayerName(playerName2);
this.computers.put(playerName2, player2);
} else {
PlayerHuman player2 = new PlayerHuman();
player2.setPlayerName(playerName2);
this.humans.put(playerName2, player2);
}
this.humans.put(playerName1, player1);
}
String startingPlayer = raffle(playerName1, playerName2);
There is definitely an easier way to do this, I have just run completely stuck and do not see a way out anymore. I then have to randomly select either of 2 players to be the first to play. I do this in the following method "raffle".
private String raffle(String nameOne, String nameTwo) {
Random random = new Random();
String raffledName = random.nextBoolean() ? nameOne : nameTwo;
System.out.println(raffledName + " may begin!");
return raffledName;
}
After this is where I run stuck. I'm getting the expected result from the "raffle" method; one of two given player's names, however I'm lost on how to make the code know which array to retrieve the returned player from, as a computer could either be named "C", or "C1" and "C2" when both players are computer-controlled, to know which computer represents which player. How do I make my code take this into consideration when retrieving the player's respective instance?
Any suggestions on creating the players are welcome too, since I feel the above written code is dirty and too procedural.
Thanks in advance!
I would like to suggest that you define a super class "Player" that your two player types derive from.
abstract class Player {
private String name;
public void setPlayerName(String name) {
this.name = name;
}
public String getPlayerName() { return name; }
abstract public boolean isCPU();
...
}
class PlayerHuman extends Player {
public boolean isCPU() { return false; }
...
}
class PlayerComputer extends Player {
public boolean isCPU() { return true; }
...
}
HashMap<String, Player> players = ...
Or, you can just use an array for players:
Player[] players = new Player[2];
You don't have to refer to player by name, then, and you can shuffle the array to decide who goes first.
I am new on Java, but my problem can be language independent.
I have a Player class and in my game logic, i have a map stores created players.
I write a method -getNext()- that returns the next player to me and it works like a charm. But in the game, players that eliminated must not get in line. So I write a new method -getNextAlive()- should return next alive (!isLoser) player. If there isn't any loser player, getNextAlive() is working but if there is, program gets in while loop and looping infinitely. In while loop I switch to next player and sure that next is alive, but I think while(p.checkLose()) not affected in while changes and give this output forever:
player: allyozturk
I can't get why this happens in this way, what should I do for skipping all isLoser players and get the next alive one? (BTW, I use libgdx ArrayMap and my map is ordered because of order of next player is importont for my game)
in-game I use:
currPlayer = currPlayer.getNextAlive();
and here my Player.java is:
public class Player{
private static int counter;
public static int alives;
private int uniqueId;
private String name;
private boolean isLoser;
.
.
.
private Player getNext(){
int index = MyGdxGame.players.indexOfKey(uniqueId);
if(++index < MyGdxGame.players.size)
return MyGdxGame.players.getValueAt(index);
else
return MyGdxGame.players.getValueAt(0);
}
public Player getNextAlive(){
Player p = getNext();
while(p.checkLose()){
p = getNext();
MyGdxGame.logger.error("player: " + p.getName()); // just for testing purpose
}
return p;
}
}
And an addition question coming from some curiosity and some for doing the best: Is it totally appropriate that using a method returns Player in the Player class?
Replace p = getNext(); with p = p.getNext();
I have a method createGame on Server which create an instance of a game. What i want is to create another instance of the game for differents clients, but when i create another instance of the game, the first game created does not work anymore.
Here is the code:
private void createGame(){
gameThread.add(new GameThread(playerList, controllers.get(controllerNumber), controllers.get(controllerNumber)));
gameThread.get(gameNumber).start();
//just to shift the array of game
gameNumber++;
//shift the array of controller
controllerNumber++;
clientCounter = 0;
playerList.clear();
controllers.add(new ControllerServerSide());
}
Why I can't play two games at the same time, if each one is on a different thread?
EDIT:
GameThread
public class GameThread extends Thread{
private Settings settings;
private Game game;
private static int gamesActive = 0;
public GameThread(ArrayList<Player> playerList, Observer observer, ObservableInput controllerServer){
ArrayList<Player> newPlayerList = new ArrayList<>();
int size = playerList.size();
for(int i = 0; i < size; i++){
newPlayerList.add(playerList.remove(0));
}
settings = new Settings("src/main/java/it/polimi/ingsw/ps05/gamelogic/mappa.xml", newPlayerList);
game = new Game(settings, gamesActive++, observer, controllerServer);
game.init();
}
public void run(){
game.play();
}
}
From your code it isn't clear what are the members or what they do.. it's really hard to understand what your code does..
But I'll give it a shot:
Try and see if one of the new threads change the same objects as the old game thread.
Or - and I think that might be the problem - you clear the array/list of players and controllers - which both games use.. so the first game works fine but the second clean those list/arrays and destrying what's in there - so your first game stop working.. check it out.
private void createGame(){
gameThread.add(new GameThread(playerList, controllers.get(controllerNumber), controllers.get(controllerNumber)));
gameThread.get(gameNumber).start();
//just to shift the array of game
gameNumber++;
//shift the array of controller
controllerNumber++;
clientCounter = 0;
playerList.clear();
controllers.add(new ControllerServerSide());
I am creating a game in java. I am using an array of Armor's for equipment
The issue, is that whenever I change 1 variable in my array, the other objects are also affected. This looks like a pointer issue but, all of the objects have been initialized as separate and called as new.
private Armor[] equip = new Armor[3];
public Inventory()
{
for(int i = 0; i<3;i++)
equip[i] = new Armor();
equip[0] = new Armor("head","You don't have head equipment","head",0,10,0,0);
equip[1] = new Armor("tunic","A simple farmers tunic","chest",0,10,0,0);
equip[2] = new Armor("baggy pants","Basic pants woven from rough cloth","legs",0,10,0,0);
System.out.println(armorDes(0));
System.out.println(armorDes(1));
System.out.println(armorDes(2));
}
All of the print lines output
baggy pants
0 armor
10 evasion bonus
Basic pants woven from rough cloth
instead of their own stats.
This was tested with a debugger and all of the objects are declared to different locations in data. Is this a java issue are am I just stupid?
Code is unclear above
private Armor[] equip = new Armor[3];
public Inventory()
{
for(int i = 0; i<3;i++)
equip[i] = new Armor();// Why creating object using default constructor here? no use
equip[0] = new Armor("head","You don't have head equipment","head",0,10,0,0);
equip[1] = new Armor("tunic","A simple farmers tunic","chest",0,10,0,0);
equip[2] = new Armor("baggy pants","Basic pants woven from rough cloth","legs",0,10,0,0);
// Use toString() method in Armour class to see the values present in variables.
//Also be sure all variables are instance variables
System.out.println(equip[0]);
System.out.println(equip[1]);
System.out.println(equip[2]);
//System.out.println(armorDes(0));
//System.out.println(armorDes(1));
//System.out.println(armorDes(2));
}
So I'm fairly new with programming having done it for maybe just under a year at this point. I'm even more new with Java (I did C++ before). So I have variables like numberHealthPotions, health, attackDamage, and so on, in a class named Fighting. But then in my main class, there are points in the game in which the character picks up a weapon, picks up a potion, or is wounded. I just need a way to say in my main class he was wounded then change the value of the health of the character or whatever.
This is just a snipet of my code to give you an idea...
else if(inputHKitchen.equalsIgnoreCase ("examine")){
System.out.println("Examine what?");
examineWhat = in.nextLine();
if(examineWhat.equalsIgnoreCase("drawer")){
System.out.println("\tYou found a knife!");
attackDamage = 50;
System.out.println("\tYour attack damage has been increased!\n");
System.out.println(houseKitchen);
}
If your variable is static, then it might be
//note this variable must be public or protected
Player.HEALTH = 0;
if its not static, then
Player p = new Player();
p.HEALTH = 0;
I would write a series of public methods for the character that manage these various values.
For example, in the class YourCharacter:
private int attackDamage;
public void addDamage(int value)
{
attackDamage += value;
}
Then in your snippet:
if (examineWhat.equalsIgnoreCase("drawer")){
yourCharacter.addDamage(50);
}
Lots of good game-writing advice for Java can be found at java-gaming.org