Cannot find symbol in Java application - java

I am working on a simple text-based rpg battler program as an introduction to Java. I seem to have a decent understanding of the majority of code, but I have ran into a couple of issues.
The issues I am having are in the Project class.
In my switch statement I am trying to use the setSpells() and setArrows() methods and I am getting a "cannot find symbol" error message. I realize that this is probably due to something I have set up incorrectly in the sub-classes, but I am unsure what that is.
The second issue is in the print statement pulling the character name by use of c.getName(). The c part of that statement gives the same error message.
Is there something simple that I am misunderstanding in these situations? Any help resolving this would be appreciated. Thank you.
Here is my main project class file:
package project;
import java.util.Scanner;
public class Project {
public static void main(String[] args) {
System.out.println("Welcome to Lands of the Sun\n");
Scanner sc = new Scanner(System.in);
String choice = "y";
while (choice.equalsIgnoreCase("y"))
{
System.out.print("Please choose your class (wizard or elf): \n");
String classChoice = sc.next();
sc.nextLine();
System.out.print("Please choose a name for your " + classChoice + ": ");
String charName = sc.next();
sc.nextLine();
int healthVal = (int) (Math.random() * 10) + 1;
switch (classChoice) {
case "wizard":
{
Character c = new Wizard();
c.setName(charName);
c.setGold(25);
c.setHealth(healthVal);
c.setSpells(10);
break;
}
case "elf":
{
Character c = new Elf();
c.setName(charName);
c.setGold(25);
c.setHealth(healthVal);
c.setArrows(10);
break;
}
}
System.out.print(c.getName());
System.out.print("Continue? (y/n): ");
choice = sc.nextLine();
System.out.println();
}
}
}
Here is my Character class:
package project;
public abstract class Character {
private String name;
private int gold;
private int health;
public static int count = 0;
public Character()
{
name = "";
gold = 0;
health = 0;
}
public Character(String name, int gold, int health) {
this.name = name;
this.gold = gold;
this.health = health;
}
public void setName(String name)
{
this.name = name;
}
public String getName(){
return name;
}
public void setGold(int gold)
{
this.gold = gold;
}
public int getGold()
{
return gold;
}
public void setHealth(int health)
{
this.health = health;
}
public int getHealth()
{
return health;
}
#Override
public String toString()
{
return "Name: " + name + "\n" +
"Gold: " + gold + "\n" +
"Health: " + health + "\n";
}
public static int getCount()
{
return count;
}
public abstract String getDisplayText();
}
Here is my Wizard sub-class:
package project;
public class Wizard extends Character {
private int spells;
public Wizard()
{
super();
spells= 0;
count++;
}
public void setSpells(int spells)
{
this.spells= spells;
}
public int getSpells(){
return spells;
}
#Override
public String getDisplayText()
{
return super.toString() +
"Spells: " + spells+ "\n";
}
}
And finally my Elf sub-class:
package project;
public class Elf extends Character{
private int arrows;
public Elf()
{
super();
arrows = 0;
count++;
}
public void setArrows(int arrows)
{
this.arrows = arrows;
}
public int getArrows(){
return arrows;
}
#Override
public String getDisplayText()
{
return super.toString() +
"Arrows: " + arrows + "\n";
}
}

When you create one of your Characters...
Character c = new Elf();
You are downcasting the instance to "act" like Character, this is very useful feature in Object Oriented Programming, but is causing you issues in this case, as Character does not have the methods you are looking for.
Instead, start by assigning the class to a concrete version of the instance...
Elf elf = new Elf();
Apply the properties you need and then assign it to a Character reference...
Character c = null;
//...
switch (classChoice) {
//...
case "elf":
{
Elf elf = new Elf();
//...
c = elf;
}
}
c = elf;
for example...
Have a look at the section on Polymorphism for more details

Your issue is with these lines
Character c = new Wizard();
....
Character c = new Elf();
The character class itself doesn't have the setFireballs or SetArrows methods. You need to define the object as a wizard or elf in order to get access to said methods... EG:
Elf c = new Elf();
Wizard c = new Wizard();
etc

Character c = new Wizard();
Character has neither a setFireBalls method nor a setArrows method.

I have made the some changes to your code..
here is the final code.
package h;
import java.util.Scanner;
public class he {
public static void main(String[] args) {
System.out.println("Welcome to Lands of the Sun\n");
Character c = new Wizard();
Character e = new Elf();
Scanner sc = new Scanner(System.in);
String choice = "y";
while (choice.equalsIgnoreCase("y"))
{
System.out.print("Please choose your class (wizard or elf): \n");
String classChoice = sc.next();
sc.nextLine();
System.out.print("Please choose a name for your " + classChoice + ": ");
String charName = sc.next();
sc.nextLine();
int healthVal = (int) (Math.random() * 10) + 1;
switch (classChoice) {
case "wizard":
{
c.setName(charName);
c.setGold(25);
c.setHealth(healthVal);
c.setFireballs(10);
break;
}
case "elf":
{
;
e.setName(charName);
e.setGold(25);
e.setHealth(healthVal);
e.setArrows(10);
break;
}
}
System.out.print(c.getName());
System.out.print("Continue? (y/n): ");
choice = sc.nextLine();
System.out.println();
}
}
}
Wizard class
public class Wizard extends Character {
private int fireballs;
public Wizard()
{
super();
fireballs = 0;
count++;
}
public void setFireballs(int fireballs)
{
this.fireballs = fireballs;
}
public int getFireballs(){
return fireballs;
}
#Override
public String getDisplayText()
{
return super.toString() +
"Fireballs: " + fireballs + "\n";
}
#Override
public void setArrows(int i) {
}
}
Elf class
public class Elf extends Character {
private int arrows;
public Elf()
{
super();
arrows = 0;
count++;
}
public void setArrows(int arrows)
{
this.arrows = arrows;
}
public int getArrows(){
return arrows;
}
#Override
public String getDisplayText()
{
return super.toString() +
"Arrows: " + arrows + "\n";
}
#Override
public void setFireballs(int i){
}
}
abstract class Character
public abstract class Character {
private String name;
private int gold;
private int health;
public static int count = 0;
public Character() {
name = "";
gold = 0;
health = 0;
}
public Character(String name, int gold, int health) {
this.name = name;
this.gold = gold;
this.health = health;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setGold(int gold) {
this.gold = gold;
}
public void setHealth(int health) {
this.health = health;
}
public int getHealth() {
return health;
}
#Override
public String toString() {
return "Name: " + name + "\n" + "Gold: " + gold + "\n" + "Health: "
+ health + "\n";
}
public static int getCount() {
return count;
}
public abstract String getDisplayText();
public abstract void setFireballs(int i);
public abstract void setArrows(int i);
}
hope this helps...

Related

Creating an printing an object that stores strings and integers in java

I have the following problem. Five classes are interacting with each other. Two of theme are doing fine. But with the creating of an Object of one class (Ticket) in my main class Event (getting user input from another class (UserInput), an processing this in the costructor) i have now problem to display the results.
Main class Event with main methode
import java.util.ArrayList;
public class Event {
private static String artistName;
private static int artistSalary;
private Language language;
private static ArrayList<String> trackList;
private InputReader inputReader;
private Ticket ticket;
private int amountOfTicketCategories;
private static Object[] ticketList;
private static int index;
public Event() {
}
public Event(Artist artist, Ticket ticket) {
artistName = artist.getArtistName();
artistSalary = artist.getArtistSalary();
trackList = artist.getArrayList();
for (index = 0; index < amountOfTicketCategories; index++) {
ticketList[index] = ticket.getTicket();
ticketList[index].toString();
}
}
public void chooseWhatToDefine() {
language = new Language();
language.whatToSpecify();
}
public void setTicketPrice(String ticketCategory, int ticketPrice) {
}
public void displayArtist(String artistName, int artistSalary) {
language = new Language();
language.displayArtistAndSalary(artistName, artistSalary);
}
public void displayTracklist(ArrayList<String> trackList) {
language = new Language();
language.displayTrackList(trackList);
}
public void displayTickets(Object[] ticketList) {
language = new Language();
language.displayTicket(ticketList);
}
public static void main(String[] args) {
Event event1 = new Event(new Artist(), new Ticket());
event1.displayArtist(artistName, artistSalary);
event1.displayTracklist(trackList);
event1.displayTickets(ticketList);
}
}
Ticket class with constructor that initalize the class with the user input comming from the InputReader class, and creates an object of Strings and Integers.
import java.util.Arrays;
public class Ticket {
private static String ticketCategory;
private static int ticketAmount;
private static int ticketPrice;
private InputReader inputReader;
private int amountOfTicketCategories;
private int index;
private Ticket[] ticketList;
public Ticket(String ticketCategory,int ticketAmount,int ticketPrice) {
}
public Ticket() {
inputReader = new InputReader();
inputReader.specifyTicketCategories();
ticketList = new Ticket[amountOfTicketCategories];
for (index = 0; index < amountOfTicketCategories; index++) {
inputReader.specifyTicket(ticketCategory, ticketAmount, ticketPrice);
ticketList[index] = new Ticket(ticketCategory, ticketAmount, ticketPrice);
}
}
public String toString() {
return("TicketCategory: " + ticketCategory + "Amount of Tickets: " + ticketAmount + "Ticket Price: " +ticketPrice);
}
public Object getTicket() {
return ticketList[index];
}
public int getAmountOfTicketCategories() {
amountOfTicketCategories = inputReader.specifyTicketCategories();
return amountOfTicketCategories;
}
}
InptReader class that processes the user input:
import java.util.ArrayList;
import java.util.Scanner;
public class InputReader {
private Scanner sc;
private Language language;
private ArrayList <String> tracks;
public InputReader() {
tracks = new ArrayList<String>();
language = new Language();
sc = new Scanner(System.in);
}
public int specifyTicketCategories() {
language.defineAmountOfTicketCategories();
return sc.nextInt();
}
public void specifyTicket(String ticketCategory, int ticketAmount, int ticketPrice) {
language.specifyTicketCategory();
ticketCategory = sc.next();
language.specifyTicketAmount();
ticketAmount = sc.nextInt();
language.specifyTicketPrice();
ticketPrice = sc.nextInt();
}
public int amountOfTickets() {
return sc.nextInt();
}
public int ticketPrice() {
return sc.nextInt();
}
public String readName() {
language.specifyArtist();
return sc.nextLine();
}
public int readInteger() {
language.specifyArtistSalary();
return sc.nextInt();
}
public void addTitle() {
int anzahlSongs = 3;
int index = 0;
while (index < anzahlSongs) {
language.specifyTrackList();
tracks.add(sc.nextLine());
index++;
}
}
public ArrayList<String> getArray() {
return tracks;
}
}
Language class that consists of the language statements
import java.util.ArrayList;
public class Language {
public Language () {
}
public void whatToSpecify() {
System.out.println("What would you like to specify fist? For Artist press 1, for Ticket press 2");
}
public void specifyArtist() {
System.out.println("Who is the artist? ");
}
public void specifyArtistSalary() {
System.out.println("How much does the artist earn? ");
}
public void displayTicket(Object[] ticketList) {
System.out.println("Ticketlist: " + ticketList);
}
public void displayArtistAndSalary(String artistName, int artistSalary) {
System.out.println("Artist: " + artistName + " " + "Salary: " + artistSalary);
}
public void displayTrackList(ArrayList<String> trackList) {
System.out.println("Tracklist: " + trackList);
}
public void specifyTicketCategory() {
System.out.println("What is the ticket category? ");
}
public void specifyTicketAmount() {
System.out.println("What ist the amount of tickets? ");
}
public void specifyTicketPrice() {
System.out.println("What is the price for your ticket?");
}
public void specifyTrackList() {
System.out.println("Add title: ");
}
public void defineAmountOfTicketCategories() {
System.out.println("How many ticket categories you like to set up?");
}
public void line() {
System.out.println("***********************************");
}
}
Artist class that that has creates an instance of an artist in the main class (same idea as for ticket) but with other variables and parameters.
import java.util.ArrayList;
public class Artist {
private int artistSalary;
private String artistName;
private InputReader inputReader;
ArrayList <String> trackList;
public Artist() {
inputReader = new InputReader();
artistName = inputReader.readName();
artistSalary = inputReader.readInteger();
inputReader.addTitle();
trackList = inputReader.getArray();
trackList.remove(2);
}
public String getArtistName() {
return artistName;
}
public int getArtistSalary() {
return artistSalary;
}
public ArrayList<String> getArrayList(){
return trackList;
}
}
Output in the console:
Add title:
Hello
Add title:
Hello
How many ticket categories you like to set up?
5
Artist: David Salary: 5000
Tracklist: [, Hello]
Ticketlist: null
First of all, in the Ticket class's constructor, you use the other constructor (The one with the 3 arguments), which has an empty body.
ticketList[index] = new Ticket(ticketCategory, ticketAmount, ticketPrice);
public Ticket(String ticketCategory,int ticketAmount,int ticketPrice) {
//this is empty
}
That means you're creating an object with.. nothing in it (null variables).
Try this:
public Ticket(String ticketCategory,int ticketAmount,int ticketPrice) {
this.ticketCategory = ticketCategory;
this.ticketAmount = ticketAmount;
this.ticketPrice = ticketPrice;
}
Then, your getTicket method is wrong. You never define the "index" integer in your Ticket class.
public Object getTicket() {
return ticketList[index];
}
Where "index" is undefined.
The ticketList should not be in the Ticket class => each time you create a Ticket instance, it will probably not be the same as the previous one.

Exception in thread error when running Interface

I have written a code in which I have made an interface and a class that implements that interface. Now when I run the code, i give my self 2 options i.e. 1 to Enter string and 2 to quit. Now when i run the code, if i select 1, it lets me put in string, but after this when i press 0, it gives me error: Exception in thread "main" java.lang. Can some body please help me figure out what I am missing here. Below is the code:
import java.util.ArrayList;
import java.util.List;
public interface ITimsSaveable {
List<String> write(); // this will save the data;
void read (List<String> savedValues); //this will print the data
}
import java.util.ArrayList;
import java.util.List;
public class TimsPlayers implements ITimsSaveable {
private String name;
private int hitPoints;
private int strength;
private String weapon;
public TimsPlayers(String name, int hitPoints, int strength) {
this.name = name;
this.hitPoints = hitPoints;
this.strength = strength;
this.weapon = "Sword";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHitPoints() {
return hitPoints;
}
public void setHitPoints(int hitPoints) {
this.hitPoints = hitPoints;
}
public int getStrength() {
return strength;
}
public void setStrength(int strength) {
this.strength = strength;
}
public String getWeapon() {
return weapon;
}
public void setWeapon(String weapon) {
this.weapon = weapon;
}
//now go to generate > to string method
#Override
public String toString() {
return "TimsPlayers{" +
"name='" + name + '\'' +
", hitPoints=" + hitPoints +
", strength=" + strength +
", weapon='" + weapon + '\'' +
'}';
}
//now let us create stubs, i.e. the empty methods from interface
#Override
public List<String> write() {
List<String > values = new ArrayList<String >();
values.add(0,this.name);
values.add(1,""+this.hitPoints); //"" is quick trick to convert int to String
values.add(2,""+this.strength);
values.add(3,this.weapon);
return values;
}
#Override
public void read(List<String> savedValues) {
if ((savedValues != null) && (savedValues.size() > 0)) {
this.name = savedValues.get(0);
this.hitPoints = Integer.parseInt(savedValues.get(1));
this.strength = Integer.parseInt(savedValues.get(2));
this.weapon = savedValues.get(3);
}
// now let us go back to our main class
}
}
public class Main {
public static void main(String[] args) {
TimsPlayers tim = new TimsPlayers("Tim",10,15);
System.out.println(tim.toString());
saveObject(tim);
tim.setHitPoints(8);
System.out.println(tim);
tim.setWeapon("Stormbringer");
saveObject(tim);
loadObject(tim);
System.out.println(tim);
}
public static ArrayList<String> readValues() {
ArrayList<String> values = new ArrayList<String>();
Scanner scanner = new Scanner(System.in);
boolean quit = false;
int index = 0;
System.out.println("Choose\n" +
"1 to enter a string\n" +
"0 to quit");
while (!quit) {
System.out.print("Choose an option: ");
int choice = scanner.nextInt();
scanner.nextLine();
switch (choice) {
case 0:
quit = true;
break;
case 1:
System.out.print("Enter a string: ");
String stringInput = scanner.nextLine();
values.add(index, stringInput);
index++;
break;
}
}
return values;
}
public static void saveObject(ITimsSaveable objectToSave) { //ITims is the interface that is being implemented by the player
//class,so we can use ITims as object type
for (int i = 0; i < objectToSave.write().size(); i++) {
System.out.println("Saving " + objectToSave.write().get(i) + " to storage device");
}
}
public static void loadObject (ITimsSaveable objectToLoad) {
ArrayList<String > values = readValues();
objectToLoad.read(values);
}
}
Stacktrace:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:373)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at org.mm.sandbox.so.TimsPlayers.read(TimsPlayers.java:77)
at org.mm.sandbox.so.Main.loadObject(Main.java:62)
at org.mm.sandbox.so.Main.main(Main.java:17)
This method
#Override
public void read(List<String> savedValues) {
if ((savedValues != null) && (savedValues.size() > 0)) {
this.name = savedValues.get(0);
this.hitPoints = Integer.parseInt(savedValues.get(1));
this.strength = Integer.parseInt(savedValues.get(2));
this.weapon = savedValues.get(3);
}
// now let us go back to our main class
}
expects the savedValues to be completely filled, i.e. having 4 elements - name, HP, strength and weapon. You do savedValues.size() > 0 but that doesn't mean you didn't just input one of the required and then stopped and it still tries to access an element which does not exist - this.hitPoints = Integer.parseInt(savedValues.get(1));

array in object oriented programming

I'm a beginner in object-oriented programming and this is my first little project.I've heard that here everyone can help you in your code and this is my first time.Anyway, my problem why array doesn't store any value?
Here is the code:
public class Information {
private IT_Members[] member= new IT_Members[10];
private int counter = 0;
Information()
{
for ( int ctr=0;ctr<member.length;ctr++)
{
member[ctr] = new IT_Members ();
}
}
public void Add(IT_Members member)
{
if(counter<10)
{
this.member[counter].setName(member.getName());
this.member[counter].setDeparment(member.getDeparment());
this.member[counter].setPostion(member.getPostion());
this.member[counter].setID(member.getID()+counter);
counter++;
}
else
System.out.println("Add List Full");
}
public void Display()
{
if (counter!=0)
{
for (int ctr=0;ctr<10;ctr++){
System.out.println(this.member[ctr].getName()+
this.member[ctr].getDeparment()+
this.member[ctr].getPostion()+
this.member[ctr].getID());
}
}
else
System.out.println("No member yet!");
}
Here is the Main class:
import java.util.Scanner;
import java.util.Arrays;
public class Interface {
public static void main(String[]args)
{
Scanner in=new Scanner(System.in);
IT_Members input1 = new IT_Members();
Information input2 = new Information();
int x=1;
while(x!=0)
{
System.out.println(" \n[1] Add new student member. \n[2] View members.\nChoose now: ");
int choose = in.nextInt();
switch (choose){
case 1:
System.out.println("Name: ");
input1.setName(in.nextLine());
System.out.println("Deparment: ");
input1.setDeparment(in.nextLine());
System.out.println("Postion: ");
input1.setPostion(in.nextLine());
System.out.println("Student record has been added. ");
break;
case 2:
input2.Display();
break;
}
}
.........................................................................
public class IT_Members {
private String name,deparment,postion;
private int ID=1000;
private int Flag=0;
IT_Members (){
}
IT_Members (String name, String deparment , String postion ,int ID , int Flag){
this.name= name;
this.deparment=deparment;
this.postion=postion;
this.ID=ID;
this.Flag=Flag;
}
public String getName (){
return this.name;
}
public String getDeparment (){
return this.deparment;
}
public String getPostion (){
return this.postion;
}
public int getID (){
return this.ID;
}
public int getFlag (){
return this.Flag;
}
public void setName (String name){
this.name = name;
}
public void setDeparment (String Deparment){
this.deparment = deparment;
}
public void setPostion (String postion){
this.postion = postion;
}
public void setID (int ID){
this.ID = ID;
}
public void setFlag (int Flag){
this.Flag = Flag ;
}
public String toStu()
{
String str = "";
str = "\nName: " + this.name +
"\nDeparment: " + this.deparment +
"\nPostion: " + this.postion +
"\nID: " + this.ID;
return str;
}
}
Please, I'm stuck with this I appreciate any help.
Thanks.
You never call the Add function in the Information class. Therefore you never initialize any of the array elements you then want to display.
You need to add input2.Add(input1) before you print that is has been added.
You have to create every time a new Object and in the end you have to add in the list.
import java.util.Scanner;
import java.util.Arrays;
public class Interface {
public static void main(String[]args)
{
Scanner in=new Scanner(System.in);
Information input2 = new Information();
int x=1;
while(x!=0)
{
System.out.println(" \n[1] Add new student member. \n[2] View members.\nChoose now: ");
int choose = in.nextInt();
switch (choose){
case 1:
IT_Members input1 = new IT_Members();// this need to be here so that every time crete new object
System.out.println("Name: ");
input1.setName(in.nextLine());
System.out.println("Deparment: ");
input1.setDeparment(in.nextLine());
System.out.println("Postion: ");
input1.setPostion(in.nextLine());
input2.Add(input1); // that was missing
System.out.println("Student record has been added. ");
break;
case 2:
input2.Display();
break;
}
}

Java static/nonstatic method

I started working on my first java project, which is a basic RPG, and I have a question regarding the spells. I have an abstract class named Character, which is extended by some subclasses (like Fighter, Mage etc.). Only spellcasters can cast spells. Regarding Spells - I have a class named Spell that describes a spell (it's name, it's effect, mana etc.). All the spells are stored in SpellsList class that has a spellsList list (objects of class Spell). I have an Effect class (very plausible that it will become an interface) that has some effects like "damage" and "heal", but I don't make use of that for the meanwhile, I just want to test that what I have works.
My problem is that Mage's methods addToSpellBook and showSpellBook give a compiler error: java can't find symbol: method addToSepllBook, location: variable hero of type Game.Character. also for showSpellBook. Why and how to fix it ?
(The problem is probably in Mage/Spell/SpellsList class, and not Character which is long, so it's less intimidating :) )
public class Game {
public static void main(String[] args) throws IOException {
CharacterCreator heroCreator = new CharacterCreator();
CharacterCreator.showAllClasses();
Scanner sc = new Scanner(System.in);
int scan = sc.nextInt();
String chosenClass = CharacterCreator.getCharacterClass(scan);
Character hero = CharacterCreator.createCharacter(chosenClass);
try {
hero.displayCharacter();
}catch (Exception e){
System.out.println("Wrong input");
}
if (hero.getCharacterClass().equals("Mage")){
hero.addToSpellBook("Fireball");
hero.showSpellBook();
}
}
}
public class CharacterCreator {
public static Character createCharacter(String chosenClass) {
Character hero = null;
System.out.println("Choose Name:");
Scanner nameIn = new Scanner(System.in);
String name = nameIn.next();
switch (chosenClass) {
case "Fighter":
return new Fighter(name);
case "Rogue":
return new Rogue(name);
case "Mage":
return new Mage(name);
case "Cleric":
return new Cleric(name);
case "def":
System.out.println("Wrong input");
return null;
default:
return null;
}
}
public static void showAllClasses(){
System.out.println("Choose a character: ");
System.out.println("1. Fighter");
System.out.println("2. Rogue");
System.out.println("3. Mage");
System.out.println("4. Cleric");
}
public static String getCharacterClass(int scan){
String classIn;
switch (scan) {
case 1:
classIn = "Fighter";
break;
case 2:
classIn = "Rogue";
break;
case 3:
classIn = "Mage";
break;
case 4:
classIn = "Cleric";
break;
default:
System.out.println("Enter again");
classIn = "def";
}
return classIn;
}
}
abstract public class Character {
private String name;
private String characterClass;
private int level;
private int hp;
private int currentHp;
private int armorClass;
private long xp;
/*private int BAB; /*Base attack bonus*/
private int strength;
private int constitution;
private int dexterity;
private int intelligence;
private int wisdom;
private int charisma;
protected Character(String name){
setName(name);
setCharacterClass("Class");
setLevel(1);
setStrength(10);
setConstitution(10);
setDexterity(10);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
setHp(0);
setCurrentHp(getHp());
setArmorClass(10);
setXp(0);
}
void displayCharacter() throws IOException{
System.out.print("\n\n\n");
System.out.println("Name: " + getName());
System.out.println("Class: " + getCharacterClass());
System.out.println("Level: " + getLevel());
System.out.println("HP: " + getHp());
System.out.println("Current HP: " + getCurrentHp());
System.out.println("Armor Class: " + getArmorClass());
System.out.println("***************");
System.out.println("Attributes: ");
System.out.println("Strength: " + getStrength());
System.out.println("Constitution: " + getConstitution());
System.out.println("Dexterity: " + getDexterity());
System.out.println("Intelligence: " + getIntelligence());
System.out.println("Wisdom: " + getWisdom());
System.out.println("Charisma: " + getCharisma());
System.out.println("***************");
System.out.println("XP: " + getXp());
}
public int getModifier(int number){
int mod = (int)((number -10)/2);
return mod;
}
public String getName() { return name; }
public String getCharacterClass() { return characterClass; }
public int getLevel() { return level; }
public int getHp() { return hp; }
public int getCurrentHp() { return currentHp; }
public int getArmorClass() { return armorClass; }
public int getStrength(){ return strength; }
public int getConstitution(){ return constitution; }
public int getDexterity(){ return dexterity; }
public int getIntelligence(){ return intelligence; }
public int getWisdom(){ return wisdom; }
public int getCharisma(){ return charisma;}
public long getXp(){ return xp;}
protected void setName(String Name) { name = Name; }
protected void setCharacterClass(String characterClass) { this.characterClass = characterClass; }
protected void setLevel(int lvl){ level = lvl; }
protected void setHp(int hitPoints){ hp = hitPoints; }
protected void setCurrentHp(int curHp){ currentHp = curHp; }
protected void setArmorClass(int ac){ armorClass = ac; }
protected void setStrength(int str){ strength = str; }
protected void setConstitution(int con){ constitution = con; }
protected void setDexterity( int dex) { dexterity = dex; }
protected void setIntelligence(int intel){ intelligence = intel; }
protected void setWisdom(int wis){ wisdom = wis; }
protected void setCharisma(int cha){charisma = cha; }
protected void setXp(int XP){xp = XP; }
}
public class Mage extends Character {
private List<Spell> spellBook;
public Mage(String name){
super(name);
setName(name);
setCharacterClass("Mage");
setLevel(1);
setStrength(10);
setConstitution(10);
setDexterity(14);
setIntelligence(16);
setWisdom(14);
setCharisma(10);
setHp((int) (4 + getModifier(getConstitution())));
setCurrentHp(getHp());
setArmorClass(10 + getModifier(getDexterity()));
spellBook = null;
}
void addToSpellBook(String spellName){
Spell newSpell;
newSpell = SpellsList.getSpell(spellName);
spellBook.add(newSpell);
}
void showSpellBook(){
for (Iterator<Spell> iter = spellBook.iterator(); iter.hasNext(); ) {
Spell spell = iter.next();
if (spellBook.equals(spell.getSpellName())) {
System.out.println("Spell name: " + spell.getSpellName());
System.out.println("Spell effect: " + spell.getEffect());
}
}
}
}
public class Spell {
private String name;
private int spellLevel;
private String effect;
private int manaCost;
private int duration;
Spell(String name, int spellLevel, String effect, int manaCost, int duration){
this.name = name;
this.spellLevel = spellLevel;
this.effect = effect;
this.manaCost = manaCost;
this.duration= duration;
}
void castSpell(String spellName, Character hero, Character target){
try {
Spell spell = SpellsList.getSpell(spellName);
System.out.println("You casted: " + spellName);
System.out.println("Spell effect: " + spell.effect);
}
catch (Exception e){
System.out.println("No such spell");
}
}
String getSpellName(){ return name; }
int getSpellLevel() {return spellLevel; }
String getEffect(){ return effect; }
int getManaCost(){
return manaCost;
}
int getDuration() { return duration; }
}
public class SpellsList {
static List<Spell> spellsList = new ArrayList<Spell>();
static
{
spellsList.add(new Spell("Fireball", 3, "damage", 5,0 ));
spellsList.add(new Spell("Ice Storm", 4, "damage", 8, 0));
spellsList.add(new Spell("Heal", 2, "heal", 4, 0));
}
static Spell getSpell(String spellName) {
try {
for (Iterator<Spell> iter = spellsList.iterator(); iter.hasNext(); ) {
Spell spell = iter.next();
if (spellName.equals(spell.getSpellName())) {
return spell;
}
}
} catch (Exception e){
System.out.println(spellName + " haven't been found in spells-list");
return null;
}
return null;
}
}
hero is of type Character. You should cast it to Mage. or add addToSpellBook in Character class and override it in Mage class. Something like:
if(hero instanceof Mage)
((Mage) hero).addToSpellBook();
There is a difference between the type of variables when compiling and their class during execution. The problem is that your hero variable is not of type Mage but of type Character and only has access to methods available to any Character.
The compiler also doesn't notice your logic in attempting to make sure hero is an instance of Mage. To tell it you know you have Mage and want to use Mage methods you need to cast.
Your way of verifying is okay, but I would advise using theinstanceof keyword.
if(hero instanceof Mage) {
((Mage)hero).addToSpellBook("Fireball");
((Mage)hero).showSpellBook();
}
You call the methodes addToSpellBook and showSpellBook on the class Character, but you have no methodes with this names in your class Character.

Java OOD and code duplication

I started creating a basic roleplaying game, and now I work on the basics. I have a code duplication for creating new characters and for existed character, which is a very bad things. I'll explain my problem - At the beginning a player can choose a Character Class (like fighter) by calling using CharacterCreator. I have a Character class that describes all the information regarding the character. I also have an abstract class named CharacterClass that describes specific attributes and other stuff of character classes (like Fighter, not java class). CharacterClass has some subclasses (like Fighter, Mage etc.). The code works, but has a bad design.
How can I get rid of the code duplication of Character and CharacterClass? Should I change the design?
public class Game {
public static void main(String[] args) {
Character hero = CharacterCreator.CharacterCreator();
}
}
public class CharacterCreator {
public static Character CharacterCreator() {
System.out.println("Choose a character: ");
System.out.println("1. Fighter");
System.out.println("2. Rogue");
System.out.println("3. Mage");
System.out.println("4. Cleric");
Scanner sc = new Scanner(System.in);
int scan = sc.nextInt();
String choice = getCharacterClass(scan);
System.out.println("Choose Name:");
Scanner nameIn = new Scanner(System.in);
String name = nameIn.next();
CharacterClass chosenClass = null;
Character hero = null;
switch (choice){
case "Fighter":
chosenClass = new Fighter();
break;
case "Rogue":
chosenClass = new Rogue();
break;
case "Mage":
chosenClass = new Mage();
break;
case "Cleric":
chosenClass = new Cleric();
break;
}
try {
hero = new Character(name, chosenClass);
System.out.println("A hero has been created");
hero.displayCharacter();
} catch (Exception e){
System.out.println("There was a problem assigning a character class");
}
return hero;
}
public static String getCharacterClass(int scan){
String classIn;
switch (scan) {
case 1:
classIn = "Fighter";
break;
case 2:
classIn = "Rogue";
break;
case 3:
classIn = "Mage";
break;
case 4:
classIn = "Cleric";
break;
default:
System.out.println("Enter again");
classIn = "def";
}
return classIn;
}
}
public class Character {
private String name;
private String characterClass;
private int level;
private int hp;
private int currentHp;
private int armorClass;
private long xp;
/*private int BAB; /*Base attack bonus*/
private int strength;
private int constitution;
private int dexterity;
private int intelligence;
private int wisdom;
private int charisma;
Character(String name, CharacterClass chosenClass){
this.name = name;
this.characterClass = chosenClass.getCharacterClass();
level = chosenClass.getLevel() ;
hp = ( chosenClass.getHp() + getModifier( chosenClass.getConstitution() ) );
currentHp = hp;
setArmorClass(10 + getModifier( + chosenClass.getDexterity()));
strength = chosenClass.getStrength();
constitution = chosenClass.getConstitution();
dexterity = chosenClass.getDexterity();
intelligence = chosenClass.getIntelligence();
wisdom = chosenClass.getWisdom();
charisma = chosenClass.getCharisma();
xp = 0;
}
void displayCharacter() throws IOException {
System.out.print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
System.out.println("Name: " + getName());
System.out.println("Class: " + getCharacterClass());
System.out.println("Level: " + getLevel());
System.out.println("HP: " + getHp());
System.out.println("Armor Class: " + getArmorClass());
System.out.println("***************");
System.out.println("Attributes: ");
System.out.println("Strength: " + getStrength());
System.out.println("Constitution: " + getConstitution());
System.out.println("Dexterity: " + getDexterity());
System.out.println("Intelligence: " + getIntelligence());
System.out.println("Wisdom: " + getWisdom());
System.out.println("Charisma: " + getCharisma());
System.out.println("***************");
System.out.println("XP: " + getXp());
}
public int getModifier(int number){
int mod = (int)((number -10)/2);
return mod;
}
public String getName() { return name; }
public String getCharacterClass() { return characterClass; }
public int getLevel() { return level; }
public int getHp() { return hp; }
public int getCurrentHp() { return currentHp; }
public int getArmorClass() { return armorClass; }
public int getStrength(){ return strength; }
public int getConstitution(){ return constitution; }
public int getDexterity(){ return dexterity; }
public int getIntelligence(){ return intelligence; }
public int getWisdom(){ return wisdom; }
public int getCharisma(){ return charisma;}
public long getXp(){ return xp;}
protected void setLevel(int lvl){ level = lvl; }
protected void setHp(int hitPoints){ hp = hitPoints; }
protected void setCurrentHp(int curHp){ currentHp = curHp; }
protected void setArmorClass(int ac){ armorClass = ac; }
protected void setStrength(int str){ strength = str; }
protected void setConstitution(int con){ constitution = con; }
protected void setDexterity( int dex) { dexterity = dex; }
protected void setIntelligence(int intel){ intelligence = intel; }
protected void setWisdom(int wis){ wisdom = wis; }
protected void setCharisma(int cha){charisma = cha; }
}
abstract class CharacterClass {
private String characterClass;
private int level;
private int hp;
private int strength;
private int constitution;
private int dexterity;
private int intelligence;
private int wisdom;
private int charisma;
protected CharacterClass(){
setCharacterClass("Character Class");
setLevel(1);
setHp(10);
setStrength(10);
setConstitution(10);
setDexterity(10);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
}
public String getCharacterClass() { return characterClass; }
public int getLevel() { return level; }
public int getHp() { return hp; }
public int getStrength(){ return strength; }
public int getConstitution(){ return constitution; }
public int getDexterity(){ return dexterity; }
public int getIntelligence(){ return intelligence; }
public int getWisdom(){ return wisdom; }
public int getCharisma(){ return charisma; }
protected void setCharacterClass(String characterClass){ this.characterClass = characterClass; }
protected void setLevel(int lvl){ level = lvl; }
protected void setHp(int hitPoints){ hp = hitPoints; }
protected void setStrength(int str){ strength = str; }
protected void setConstitution(int con){ constitution = con; }
protected void setDexterity( int dex) { dexterity = dex; }
protected void setIntelligence(int intel){ intelligence = intel; }
protected void setWisdom(int wis){ wisdom = wis; }
protected void setCharisma(int cha){charisma = cha; }
}
class Fighter extends CharacterClass {
Fighter(){
setCharacterClass("Fighter");
setLevel(1);
setHp(10);
setStrength(14);
setConstitution(16);
setDexterity(14);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
}
}
suggestions:
CharacterCreator.CharacterCreator(). Method should be verb and describe action, i.e createCharacter
look ad design pattern Factory. Your Creator is 'Factory'. The method 'createCharacter' should take parameter characterType. That means, that getting info from System.in should be done in class who invoke that method.
Add enum for characterClass with mapping to numbers (look to inner map in enum).
Whilst this is not a direct solution to your problem, this should help you in the long run. When it comes to games, especially RPG genre, where you have lots of objects which seem to be similar yet different, inheritance isn't best foundation for design. On top of the example you have, one will also have problems when designing consumable items / weapons / gear / NPC, etc. This means you end up with having duplicate code in many classes simply because using abstract class would mean all subclasses have same behavior, but this is not true.
A better approach in this case is to avoid inheritance and use ECS. This means everything is a type of Entity. In order to add some "functionality" to an entity you would use Component types. For example, items don't have HP property, but say when dropped on the ground, they can be attacked and destroyed. Meaning we need to add a dynamic property to it. We can do that as follows:
entityItem.addComponent(new HPComponent(50));
This will allow other systems like Attack/Damage to "see" that the entity has HP component and can be attacked.
This is just a tiny example of ECS and there's lots more to it. I'd suggest reading more about it, as this will make game development design (for most games) significantly smoother.

Categories