2

I am finally setting out on my own instead of following courses online and trying to create something on my own, it's just a simple text based dungeon type of game.

However I know I'm messing up when I'm passing in the new values from one class to another class, the class where I try to set the values to pass to another

package com.company;

import java.util.Random;
import java.util.Scanner;



public class CharBuilder {
static public Random randNum = new Random();
static public Scanner sc = new Scanner(System.in);

 private String mCharacterName;
 private int mStrength = 6;
 private int mIntelligence = 6;
 private int mConstitution = 6;
 private int mDexterity = 6;
 private int mHitPoints = 40;
 private int mManaPoints = 40;
 private String mCharClass;
 private CharBuilder hero;




public CharBuilder(String charClass,int str, int intl, int con, int dex, int hp, int mp) {
    mCharClass = charClass;
    mStrength = str;
    mIntelligence = intl;
    mConstitution = con;
    mDexterity = dex;
    mHitPoints = hp;
    mManaPoints = mp;

}

public CharBuilder() {

}

public CharBuilder(String charClass) {
    mCharClass = charClass;

}



public void characterNameCreator() {

    System.out.println("Greetings, what is your name adventurer? ");
    mCharacterName = sc.nextLine();
    System.out.printf("I see, so your name is %s very well, very well \n", mCharacterName);
}

public void createHero() {
    hero = new  CharBuilder(mCharClass,mStrength,mIntelligence,mConstitution,mDexterity,mHitPoints,mManaPoints);


String acceptedAnswers = "warrior wizard thief";

    System.out.printf("%s would you say you are more of a warrior, wizard or more of the thievery type \n", mCharacterName);
    String classAnswer = sc.nextLine();
    boolean isAcceptableClass = classAnswer.contains(acceptedAnswers);
    do  {
        if (classAnswer.equalsIgnoreCase("warrior")) {
            mCharClass = "warrior";
            hero.setStr(mStrength + 3);
            hero.setIntelligence(mIntelligence - 1);
            hero.setmConstitution(mConstitution + 4);
            hero.setmDexterity(mDexterity + 1);
            hero.setHitPoints(mHitPoints + 20);
            hero.setManaPoints(mManaPoints - 10);
        } else if (classAnswer.equalsIgnoreCase("Wizard")) {
            mCharClass = "wizard";
            hero.setStr(mStrength -1);
            hero.setIntelligence(mIntelligence + 3);
            hero.setmConstitution(mConstitution + 2);
            hero.setmDexterity(mDexterity);
            hero.setHitPoints(mHitPoints - 10);
            hero.setManaPoints(mManaPoints + 30);
        } else if (classAnswer.equalsIgnoreCase("thief") || classAnswer.equalsIgnoreCase("thievery")) {
            mCharClass = "thief";
            hero.setStr(mStrength + 2);
            hero.setIntelligence(mIntelligence + 1);
            hero.setmConstitution(mConstitution + 1);
            hero.setmDexterity( mDexterity + 5);
            hero.setHitPoints(mHitPoints + 10);
            hero.setManaPoints(mManaPoints + 10);
        } else {
            System.out.println("I'm sorry, that is not an acceptable class, please pick warrior, wizard, or thief");
            createHero();
        }
    }while (isAcceptableClass);

}



public int getStrength() {
    return mStrength;
}
public  int getIntelligence() {
    return mIntelligence;
}
public int getConsitution() {
    return mConstitution;
}
public int getDex() {
    return mDexterity;
}
public int getHP() {
    return mHitPoints;
}
public int getMP() {
    return mManaPoints;
}
public CharBuilder getHero() {
    return hero;
}


public void setStr(int str) {
    mStrength = str;

}
public void setIntelligence(int intl) {
    mIntelligence = intl;
}
public void setmConstitution(int con) {
    mConstitution = con;
}
public void setmDexterity(int dex) {
    mDexterity = dex;
}
public void setHitPoints( int hitPoints) {
    mHitPoints = hitPoints;
}
public void setManaPoints( int manaPoints) {
    mManaPoints = manaPoints;
}
public void setmCharClass(String charClass) {
    mCharClass = charClass;
}







}

and the class where I'm trying to pass the variables into doesn't seem to be getting anything as it is giving me a nullPointerException so I know there's no value when I ask it go it, and I've included that class below,

package com.company;

import java.util.List;
import java.util.Random;
import java.util.Scanner;



public class Combat   {
    Scanner sc = CharBuilder.sc;
    Random randNum = CharBuilder.randNum;

    List<Enemy> enemyList = new Enemy().createList();
    Enemy enemy = enemyList.get(randNum.nextInt(enemyList.size()));
    CharBuilder character = new CharBuilder().getHero();
    int charStrength = character.getStrength();
    int charHp = character.getHP();
    int enemyHp = enemy.getHP();
    int enemyStr =enemy.getStr();
    String enemyName = enemy.getName();


    public void initiateCombat() {


        System.out.printf("A %s appears, it has %d hitpoints, and it's strength is %s \n", enemyName, enemyHp, enemyStr);
    }
    public void playersTurn() {
        System.out.println("It is your turn, your available actions are attack, or use a skill");
        String actionAnswer = sc.nextLine();
        if (actionAnswer.equalsIgnoreCase("attack")) {
            enemyHp -= charStrength;
            System.out.printf("You attack the enemy, doing %s damage, the enemy currently has %s hp left \n", charStrength,
                    enemyHp);

        }


        else {
            System.out.println("Sorry, please choose attack or skill ");
            playersTurn();
        }
    }
    public void enemyTurn() {
        charHp -= enemyStr;
        System.out.printf("It is the enemy's turn, it attacks doing %s damage, your current hp is %s \n", enemyStr, charHp);
    }
    public void combat() {
        while(enemyHp >= 0 && charHp >= 0) {
            initiateCombat();
            playersTurn();
            if (enemyHp <= 0) {
                System.out.println("You have defeated the enemy, congratulations");
                break;

            }
            enemyTurn();
        }
    }
}

any tips for a new guy on what I am doing wrong, and how I can get these values over? I know that I could just declare the hero static but is there a better way?

I'm getting NullPointerException in the first possible area where they try to pull data from the CharBuilder class. Which is

int charStrength = character.getStrength();
6
  • 2
    In which line you get NullPointerException? Commented May 6, 2015 at 2:20
  • Hey Sorry, I should have included that, when it first tries to pull value from the CharBuilder object. int charStrength = character.getStrength(); Commented May 6, 2015 at 2:23
  • @riser11 you should add this info to your post not here as a comment Commented May 6, 2015 at 2:25
  • You're right, I did that. Commented May 6, 2015 at 2:27
  • 2
    If you are creating these on your own, although off topic, there are a lot of obvious design issues that I suggest you fixing it: 1. Make the Builder just doing the building job, NOT asking for user input. 2. Take a look on Fluent Builder for a easy-to-use builder. 3. It is obviously not appropriate to have the Builder providing a Random. 4. I think it is more appropriate to manipulate the HP on the character/enemy, and you can give more meaningful methods to them, like, isDead(), receiveAttack(int) etc Commented May 6, 2015 at 2:36

4 Answers 4

1

You need to call createHero() on a CharBuilder before you call getHero() in your constructor.

Sign up to request clarification or add additional context in comments.

Comments

1

Your code should be,

    List<Enemy> enemyList = new Enemy().createList();
    Enemy enemy = enemyList.get(randNum.nextInt(enemyList.size()));
    CharBuilder cb = new CharBuilder();
    cb.createHero();
    CharBuilder character = cb.getHero();
    int charStrength = character.getStrength();
    int charHp = character.getHP();
    int enemyHp = enemy.getHP();
    int enemyStr =enemy.getStr();
    String enemyName = enemy.getName();

The reason for this is because you need to execute createHero() in order to initialize the hero object.

Further go more on this, you are initializing CharBuilder inside CharBuilder which is not a good practice when we think in terms of object orientation. One alternative is to use the singleton pattern here.

3 Comments

Hello, thanks for the help. Your answer made sense but when I tried it couldn't find the symbol when I tried to use the createHero(); on the cb instance. Could this be a simple fix?
@riser11 but I am curious to know whether you understand why you have this issue at the first place?
Yes, I think I do. Because there was no value passed into the constructor as far as the parameters I was trying to pull it wasn't finding anything when it tired to pull it. Like I said, this was my first program.
1

Lets see why you have NPE issue:

Take a look at here

public CharBuilder() {

}

The first constructor is a default constructor. It only initializes the bare minimum and lets users set the rest with getters and setters.

CharBuilder character = new CharBuilder().getHero();
some setters is missing here?
int charStrength = character.getStrength();

As you see in your code, you did not set anything to get it after wards

In addition, There are three common reasons to define a default constructor:

  1. To construct an object with default values.
  2. To initialize an object that doesn't need parameters in that initialization process.
  3. To redefine the scope of the constructor. Making the constructor private will prevent anyone but the class itself from constructing an object.

If you want to make sure that any instance created is always valid and any member variables are always initialized,then you would define the constructor which initializes all the required member variables.

In your case, you can use createHero function before getHero because createHero sets the values up.

Suggestion:

Plaese take a look at builder pattern for designing a better class

More Info About Builder Pattern

6 Comments

Thanks for the link, I'll read the article and try this tomorrow. Appreciate it.
I took out the default constructor and it's now passing in six for every stat value just to test, and it's still giving me the NPE.
Let me work on this for bit, and try to drive through it myself. If I'm still hitting my head against a desk tommorow I'll check and see when you're available. Thanks for offering to help, definately appreciated.
@riser11 it is k but at least can you say what kind of error you get?
Hello, sorry, it's still giving me the nullPointerException at the same part in the code int charStrength = character.getStrength();
|
1

As has already been pointed out, you are not calling createHero, which generates the instance of CharBuilder which getHero returns. Thus returning a null value.

The problem seems to steam from a misunderstanding of what a builder should do. A builder should take raw material and build something, it shouldn't return a copy of it self.

For example...

public class CharBuilder {

    static public Random randNum = new Random();

    private String mCharacterName;
    private int mStrength = 6;
    private int mIntelligence = 6;
    private int mConstitution = 6;
    private int mDexterity = 6;
    private int mHitPoints = 40;
    private int mManaPoints = 40;
    private String mCharClass;
    private String classType;

    public Character createHero() {
        // Valid the properties you have been given...

        if ("warrior".equalsIgnoreCase(classType)) {
            mCharClass = "warrior";
            mStrength = mStrength + 3;
            mIntelligence = mIntelligence - 1;
            mConstitution = mConstitution + 4;
            mDexterity = mDexterity + 1;
            mHitPoints = mHitPoints + 20;
            mManaPoints = mManaPoints - 10;
        } else if ("Wizard".equalsIgnoreCase(classType)) {
            mCharClass = "wizard";
            mStrength = (mStrength - 1);
            mIntelligence = (mIntelligence + 3);
            mConstitution = (mConstitution + 2);
            mDexterity = (mDexterity);
            mHitPoints = (mHitPoints - 10);
            mManaPoints = (mManaPoints + 30);
        } else if ("thief".equalsIgnoreCase(classType) || "thievery".equalsIgnoreCase(classType)) {
            mCharClass = "thief";
            mStrength = (mStrength + 2);
            mIntelligence = (mIntelligence + 1);
            mConstitution = (mConstitution + 1);
            mDexterity = (mDexterity + 5);
            mHitPoints = (mHitPoints + 10);
            mManaPoints = (mManaPoints + 10);
        } else {
            throw new UnsupportedOperationException("Unknown class");
        }

        return new DefaultCharacter(mCharacterName, mStrength, mIntelligence, mConstitution, mDexterity, mHitPoints, mManaPoints, mCharClass);
    }

    public CharBuilder setCharacterName(String mCharacterName) {
        this.mCharacterName = mCharacterName;
        return this;
    }

    public CharBuilder setStrength(int mStrength) {
        this.mStrength = mStrength;
        return this;
    }

    public CharBuilder setIntelligence(int mIntelligence) {
        this.mIntelligence = mIntelligence;
        return this;
    }

    public CharBuilder setConstitution(int mConstitution) {
        this.mConstitution = mConstitution;
        return this;
    }

    public CharBuilder setDexterity(int mDexterity) {
        this.mDexterity = mDexterity;
        return this;
    }

    public CharBuilder setHitPoints(int mHitPoints) {
        this.mHitPoints = mHitPoints;
        return this;
    }

    public CharBuilder setManaPoints(int mManaPoints) {
        this.mManaPoints = mManaPoints;
        return this;
    }

    public CharBuilder setCharClass(String mCharClass) {
        this.mCharClass = mCharClass;
        return this;
    }

    public CharBuilder setClassType(String classType) {
        this.classType = classType;
        return this;
    }

}

You can use method chaining to make it easier to call, for example

Character character = new CharBuilder().
                setCharClass("Wizard").
                setCharacterName("Bob").
                setConstitution(10).
                setDexterity(10).
                setHitPoints(10).
                setIntelligence(10).
                setManaPoints(10).
                setStrength(10).
                createHero();

The builder shouldn't be asking questions of the user, this information should already have been obtained and simply given to the builder. You should only call the methods which you need in order to build character, so many of the methods in the above example might be omitted in favor of default values

Character character = new CharBuilder().
                setCharClass("Wizard").
                setCharacterName("Bob").
                createHero();

The builder should validate the properties it has been given and throw an Exception if one or required properties are missing (like the name or class)

I, personally, like to work with interfaces, rather then implementations, it allows you to define the public contract that a object can have, for example...

public interface Character {
    public String getCharacterName();
    public int getStrength();
    public int getIntelligence();
    public int getConstitution();
    public int getDexterity();
    public int getHitPoints();
    public int getanaPoints();
    public String getCharClass();
}

Which can be wrapped in

public class DefaultCharacter implements Character {

    private final String mCharacterName;
    private final int mStrength;
    private final int mIntelligence;
    private final int mConstitution;
    private final int mDexterity;
    private final int mHitPoints;
    private final int mManaPoints;
    private final String mCharClass;

    public Character(String mCharacterName, int mStrength, int mIntelligence, int mConstitution, int mDexterity, int mHitPoints, int mManaPoints, String mCharClass) {
        this.mCharacterName = mCharacterName;
        this.mStrength = mStrength;
        this.mIntelligence = mIntelligence;
        this.mConstitution = mConstitution;
        this.mDexterity = mDexterity;
        this.mHitPoints = mHitPoints;
        this.mManaPoints = mManaPoints;
        this.mCharClass = mCharClass;
    }

    public String getCharacterName() {
        return mCharacterName;
    }

    public int getStrength() {
        return mStrength;
    }

    public int getIntelligence() {
        return mIntelligence;
    }

    public int getConstitution() {
        return mConstitution;
    }

    public int getDexterity() {
        return mDexterity;
    }

    public int getHitPoints() {
        return mHitPoints;
    }

    public int getManaPoints() {
        return mManaPoints;
    }

    public String getCharClass() {
        return mCharClass;
    }

}

Now, because the CharBuilder only says it will return a Character, you can change the physical implementation anyway you like

In this way, it's pretty hard to run into the problem you are having, because either the builder is going to return a valid Character or throw an Exception

Take a closer look at the Builder Pattern for more details

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.