问题描述:

In my little text game I have an Item class that loads it's objects from a .txt file and then adds the object to an ArrayList of type Item. I'm trying to upgrade using an upgrade() method in the Item class. It works but if I have two of the same items in my inventory, since they reference the same item if I upgrade one, I upgrade all items of that type.

Is there a way to create a new Item (Bronze Helmet) that when created will be the same as the Bronze Helmet loaded from the text file, but when upgraded it doesn't change the original object in the static helmet ArrayList in Item.java.

openInventory() method from Player class:

public void openInventory(){

//newWindow();

int selection;

boolean upgraded = false;

backPack.printInventory(this);

println("[1] UseItem [2] Upgrade Item [3] Item Details");

selection = getInt();

if(selection == 1){

println("Type the number of the corresponding Item Slot you would like to use.");

int itemNum = (getInt() - 1);

Item itemSelection = backPack.itemSlot[itemNum].oi;

if(backPack.itemSlot[itemNum].stack.size() > 0){

itemSelection = backPack.itemSlot[itemNum].stack.get(0);

}

itemSelection.printStats();

this.useItem(itemSelection);

}

if(selection == 2){

int sInt;

Item scroll = new Item();

Item item = new Item();

while(upgraded == false){

println("Pick a scroll");

sInt = getInt();

if(backPack.itemSlot[sInt - 1].oi.type.equals("scroll")){

scroll = backPack.itemSlot[sInt - 1].oi;

}

else

println("Not a Scroll");

println("Pick which " + scroll.category + " to upgrade.");

sInt = getInt();

if(backPack.itemSlot[sInt - 1].oi.type.equals(scroll.category)){

item = backPack.itemSlot[sInt - 1].oi;

}

else

println("Wrong type of Item");

if(scroll.name != "None" && item.name != "None"){

backPack.itemSlot[sInt - 1].oi.upgrade(scroll);

upgraded = true;

}

}

}

if(selection == 3){

println("Pick item to display details.");

int i = getInt();

backPack.itemSlot[i - 1].oi.printStats();

}

}

Inventory after upgrading one of the 'Bronze Helmets'

—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

[1] Bronze Helmet [+1] [2] Bronze Helmet [+1] [3] Helmet Def Scroll [4] None [5] None

[6] None [7] None [8] None [9] None [10] None

—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

[Gold]: $50

—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

Item.java:

import static com.projects.aoa.Print.*;

import static com.projects.aoa.Input.*;

import java.util.*;

import java.io.*;

class Item {

//Item

String name, type, category, statUpgrade;

int remSlots, maxSlots, upgraded, probability, statIncrease;

int hp, mp, str, def, atk, dex, duration;

Area shopPurchased;

//Inventory

public boolean filled;

public int count, stackLimit;

public static List<Item> helmets = new ArrayList<Item>();

public static List<Item> potions = new ArrayList<Item>();

public static List<Item> swords = new ArrayList<Item>();

public static List<Item> scrolls = new ArrayList<Item>();

Item(){

name = "None";

maxSlots = 5;

remSlots = 5;

}

public String toString(){

return (name);

}

static void loadItems(){

try {

//System.out.println(System.getProperty("user.dir"));

FileInputStream fstream = new FileInputStream(System.getProperty("user.dir")

+ "/LoadFiles/" + "itemLoad.txt");

DataInputStream in = new DataInputStream(fstream);

BufferedReader br = new BufferedReader(new InputStreamReader(in));

String line, itemType = "none";

int counter = 0;

Item newItem = new Item();

while((line = br.readLine()) != null) {

if(line.length() == 0){

newItem.printStats();

if(itemType.equals("helmet")){

helmets.add(newItem);

}

if(itemType.equals("potion")){

potions.add(newItem);

}

if(itemType.equals("sword")){

swords.add(newItem);

}

if(itemType.equals("scroll")){

scrolls.add(newItem);

}

counter = -1;

}

if(line.equals("#"))

break;

switch(counter) {

case -1:

counter++;

break;

case 0:

itemType = line;

counter++;

break;

case 1:

if(itemType.equals("helmet")){

//tempName = line;

newItem = new Helmet(line);

newItem.type = itemType;

}

if(itemType.equals("potion")){

newItem = new Potion(line);

newItem.type = itemType;

}

if(itemType.equals("sword")){

newItem = new Sword(line);

newItem.type = itemType;

}

if(itemType.equals("scroll")){

newItem = new Scroll(line);

newItem.type = itemType;

counter = 9;

}

counter++;

break;

case 2:

newItem.hp = Integer.parseInt(line);

counter++;

break;

case 3:

newItem.mp = Integer.parseInt(line);

counter++;

break;

case 4:

newItem.def = Integer.parseInt(line);

counter++;

break;

case 5:

newItem.str = Integer.parseInt(line);

counter++;

break;

case 6:

newItem.atk = Integer.parseInt(line);

counter++;

break;

case 7:

newItem.dex = Integer.parseInt(line);

counter++;

break;

case 8:

newItem.stackLimit = Integer.parseInt(line);

counter++;

break;

case 9:

newItem.duration = Integer.parseInt(line);

counter++;

break;

case 10:

newItem.category = line;

counter++;

break;

case 11:

newItem.statUpgrade = line;

counter++;

break;

case 12:

newItem.statIncrease = Integer.parseInt(line);

counter++;

break;

case 13:

newItem.probability = Integer.parseInt(line);

counter++;

break;

}

}

in.close();

} catch (Exception e) {

e.printStackTrace();

}

}

void printStats(){

line();

println("[" + name + "]");

println("Type: " + type);

println("Stack Limit: " + stackLimit);

println("Duration: " + duration);

println("HP: " + hp);

println("MP: " + mp);

println("Def: " + def);

println("Str: " + str);

println("Atk: " + atk);

println("Dex: " + dex);

}

void upgrade(Item scroll){

Random rand = new Random();

int geti;

if(remSlots > 0){

if(this.type.equals(scroll.category)){

int prob = rand.nextInt(99);

println("Prob: " + prob);

if(prob < scroll.probability){

if(scroll.statUpgrade.equals("def")){

this.def += scroll.statIncrease;

this.upgraded++;

println("Upgraded: " + this.upgraded);

}

}

remSlots--;

println("Slots: " + this.remSlots + " / " + this.maxSlots);

}

}

else

println("No slots remaining.");

}

static Item getItem(String searchedName){

Item item = new Item();

for(int i = 0; i < potions.size(); i++){

if(potions.get(i).name.equals(searchedName)){

item = potions.get(i);

return item;

}

}

for(int i = 0; i < helmets.size(); i++){

if(helmets.get(i).name.equals(searchedName)){

item = helmets.get(i);

return item;

}

}

for(int i = 0; i < swords.size(); i++){

if(swords.get(i).name.equals(searchedName)){

item = swords.get(i);

return item;

}

}

for(int i = 0; i < scrolls.size(); i++){

if(scrolls.get(i).name.equals(searchedName)){

item = scrolls.get(i);

return item;

}

}

return item;

}

}

Inventory:

public class Inventory {

int useableSlots, slots = 50;

Itemslot[] itemSlot = new Itemslot[slots];

Inventory(int slots){

this.useableSlots = slots;

}

public void printInventory(Player playerOne){

newWindow(5);

int excess, lineTotal = 0, invSlotSize = 25, maxLineLength = 125;

String invItem, difference = "";

String inventoryTitle = "[" + playerOne.name + "'s BackPack]";

String invTitleIndent = "";

for(int i = 0; i < (maxLineLength - inventoryTitle.length()) / 2; i++){

invTitleIndent += " ";

}

println(invTitleIndent + inventoryTitle);

printMult("—", maxLineLength);

line();

for(int i = 0; i < useableSlots; i++){

if(lineTotal >= maxLineLength){

line();

lineTotal = 0;

line();

}

if(i < 9){

difference = " ";

}

else{

difference = "";

}

invItem = ("[" + (i + 1) + "] " + difference);

if(itemSlot[i].stack.size() > 0){

invItem += (itemSlot[i].stack.get(0).name + "(" + itemSlot[i].stack.size() + ")");

}

else {

invItem += itemSlot[i].oi.name;

if(itemSlot[i].oi.upgraded > 0){

invItem += " [+" + itemSlot[i].oi.upgraded + "]";

}

}

excess = (invSlotSize - invItem.length());

for(int v = 0; v < excess; v++){

invItem += " ";

}

//print(invItem.length());

print(invItem);

lineTotal += invItem.length();

}

line();

printMult("—", maxLineLength);

line();

String printGold = "[Gold]: $" + playerOne.gold;

String goldIndent = "";

for(int i = 0; i < (maxLineLength - printGold.length()) / 2; i++){

goldIndent += " ";

}

println(goldIndent + printGold);

printMult("—", maxLineLength);

line();

line(2);

}

void addItem(Item item){

for (int i = 0; i < useableSlots; i++){

if (itemSlot[i].occupied == false) {

itemSlot[i].oi = item;

itemSlot[i].occupied = true;

break;

}

}

}

ItemSlot:

public class Itemslot extends Item{

List<Item> stack = new ArrayList<Item>();

Item oi = new Item();

boolean occupied;

}

It could very likely just be me being stupid but any help on solving this, or what direction to take would be appreciated.

EDIT: Solved

added copy constructor to Item

Item(Item item){

this.name = item.name;

this.type = item.type;

this.category = item.category;

this.statUpgrade = item.statUpgrade;

this.remSlots = item.remSlots;

this.maxSlots = item.maxSlots;

this.upgraded = item.upgraded;

this.probability = item.probability;

this.statIncrease = item.statIncrease;

this.hp = item.hp;

this.mp = item.mp;

this.str = item.str;

this.def = item.def;

this.atk = item.atk;

this.dex = item.dex;

this.duration = item.duration;

}

changed addItem

void addItem(Item item){

Item newItem = new Item(item);

for (int i = 0; i < useableSlots; i++){

if (itemSlot[i].occupied == false) {

itemSlot[i].oi = newItem;

itemSlot[i].occupied = true;

break;

}

}

}

网友答案:

The recommended way for copying objects according to Effective Java 2 is provide a copy constructor

public Foo(Foo foo){
//.. copy all members
this.name=foo.name;
this.age=foo.age;

}

Note that the clone method is broken in Java, according to the same book.

I think that your approach is wrong, instead you can write your object to a data file using ObjectInputStream and ObjectOutputStream

public class Item implements java.io.Serializable{
  ....
}

{
  Item item=new Item();
  ObjectInputStream stream=new ObjectInputStream(fileStream);
  stream.write(item);
}
网友答案:

I did not read all the code however addItem looks fishy to me and is likely to cause your problem:

    void addItem(Item item){
    Item newItem = new Item();
    newItem = item;
    for (int i = 0; i < useableSlots; i++){
        if (itemSlot[i].occupied == false) {
            itemSlot[i].oi = newItem;
            itemSlot[i].occupied = true;
            break;
        }
    }
    }

What you probably want to do here is

   newItem = item.clone()

This is just a guess since I don't know how you actually call addItem.

http://en.wikipedia.org/wiki/Clone_(Java_method)

EDIT: I just saw you are calling addItem in loadItems. Either you do what Tom Ingram is suggesting or change the implementation of addItem. The effect should be the same.

EDIT 2: In case you are not planning on subclassing Item, this would be a quick solution:

 void addItem(){
 Item newItem = new Item();
 for (int i = 0; i < useableSlots; i++){
     if (itemSlot[i].occupied == false) {
         itemSlot[i].oi = newItem;
         itemSlot[i].occupied = true;
         break;
     }
 }
 }
网友答案:

instead of having two objects for the same item in the inventory bave one object and an counter. (the conter will tell you how many items the object represents)

网友答案:

Rather then

Item newItem = new Item();

for ... 
  helmets.add(newItem);

should it not be

for ...
  helmets.add(new Item());

or

for ...
  Item newItem = new Item();
  helmets.add(newItem);
相关阅读:
Top