I'm coding a turn-based RPG battle simulator (text based) in Java.
I'm doing this as an exercise/project to learn OOP design. I've coded something similar in C, but just porting that code over to java would, of course, be rather silly. I'm going to be taking this extremely slow, focusing on getting each element right and learning as much as I can from it, rather than trying to progress as quick as possible. (I've been programming for about 3 months)
With the above in mind, I'm currently focusing on just:
- Display input prompt
- Get input
- Calculate results
- Display results
So, without any further ado, rip my terrible code to pieces :)
public class Demo
{
public static void main(String[] args){
Combatant syd = new Combatant("Syd",5,3); //name,strength,magic
Combatant goblin = new Combatant("Goblin",5,1);
Battle encounter = new Battle(syd, goblin);
}
}
package packs.rpg;
public class Combatant{
// instance variables //
private final String name;
private int maxHealth;
private int health;
private int strength;
private int magic;
BattleAction battleAction;
// constructor(s) //
public Combatant(String name, int strength, int magic){
this.name = name;
maxHealth = 10;
this.health = maxHealth;
this.strength = strength;
this.magic = magic;
}
// methods //
protected void takeTurn(BattleAction chosenAction, Combatant target){
if(health > 0){
setBattleAction(chosenAction); //strategy pattern
}
else{
setBattleAction(new FaintedAction());
}
performAction(target);
}
private void performAction(Combatant target){
battleAction.execute(this, target);
};
protected void decreaseHealth(int amount){
if(health - amount < 0){health = 0;}
else{health -= amount;}
}
protected void increaseHealth(int amount){
if(health + amount > maxHealth){health = maxHealth;}
else{health += amount;}
}
// accessors / mutators //
public String getName(){
return name;
}
public int getHealth(){
return health;
}
public int getStrength(){
return strength;
}
public int getMagic(){
return magic;
}
public void setBattleAction(BattleAction chosenAction){
battleAction = chosenAction;
}
}
package packs.rpg;
public interface BattleAction{
public void execute(Combatant user, Combatant target);
public String toString();
}
class AttackAction implements BattleAction{
String outcomeText;
public void execute(Combatant user, Combatant target){
int damage = BattleHelper.getRng(user.getStrength())+1; //get randomized damage based on user strength
target.decreaseHealth(damage);
outcomeText = (user.getName() + " hits for " + damage + "\n" + target.getName() + "'s health is now " + target.getHealth() + "\n\n");
}
public String toString(){
return outcomeText; //return the result of the attack (the gnarly string above)
};
}
class HealAction implements BattleAction{
public void execute(Combatant user, Combatant target){
int amount = BattleHelper.getRng(user.getMagic()+1);
user.increaseHealth(amount);
}
public String toString(){
return "placeholder text for heal";
};
}
class FaintedAction implements BattleAction{
String outcomeText;
public void execute(Combatant user, Combatant target){
outcomeText = (user.getName() + " fainted...");
}
public String toString(){
return outcomeText;
};
}
package packs.rpg;
import java.util.*;
public class Battle{
private Combatant player;
private Combatant enemy;
private BattleAction playerAction;
public Battle(Combatant thePlayer, Combatant theEnemy){
player = thePlayer;
enemy = theEnemy;
fight();
}
private void fight(){
while(player.getHealth() > 0 && enemy.getHealth() > 0){
playerAction = BattleHelper.getBattleAction(player); //poll for input to get choie of action
player.takeTurn(playerAction, enemy); //pass the enemy encase decision was to attack
BattleHelper.displayTurnOutcome(player.battleAction.toString()); //toString method returns result of chosen action
}
}
}
package packs.rpg;
import java.util.*;
class BattleHelper{
static Random rng = new Random();
static Scanner in = new Scanner(System.in);
public static BattleAction getBattleAction(Combatant user){
System.out.printf("%s's turn\n",user.getName());
System.out.println("Select an action");
System.out.println("1. Attack | 2. Heal");
int i;
do{
i = in.nextInt();
}
while(i != 1 && i != 2);
if(i == 1){
return new AttackAction();
}
else{
return new HealAction();
}
}
public static void displayTurnOutcome(String outcomeText){
System.out.printf("%s",outcomeText);
};
public static int getRng(int range)
{
return rng.nextInt(range);
}
}
I'd love to hear how you'd personally accomplish coding the above (simplified down to my level...) the more approaches I have to compare the better. The only pattern I've looked at in depth thus far is the strategy pattern, and I'm having to stop myself from trying to work it into every situation. Handling I/O without bolting/coupling it directly to the logic is proving difficult for me to get my head around. It's so tempting to just put printf statements right after the event has happened in the method that processed it, but from what I've read, that's a big no-no.
I don't have internet at home (posting from the library) so if I don't reply for 24 hours, that's why. Any questions about how the code works, of course just ask (I hope the formatting/structure is easy enough to follow).
BattleHelper
class is incomplete. \$\endgroup\$