I've done quite a bit of digging and can't seem to find the answer I'm looking for, I may be asking the question wrong because I'm pretty nooby.
Anyway I'm trying to build a simple Pokemon style game for practice and I can't seem to get the opponent or player hit points to change during the combat event..
I have it so you select 1. to attack with the following code:
if(select == 1){
System.out.println("You strike at the raccoon!");
System.out.println("You deal " + play1.atk + " damage!");
Math.subtract(raccoon1.hp, play1.atk);
the Math.subtract class is just
public static int subtract(int x, int y){
return (x-y);
}
Where it pulls raccoon1.hp from an object I built from an 'Opponent' class that just has:
public class Opponent {
public int hp = 5;
public int def = 0;
public int atk = 1;
}
The player is set up the same way.
I'm sure I'm just missing and/or doing something dumb but any help to a new programmer would be greatly appreciated.
Thanks!
Racoon1.hp = Math.subtract(raccoon1.hp, play1.atk)
You have to set the returned value equal to raccoon.hp, or else there's no point in returning a value.
This is a question of proper object-oriented programming. Instead of thinking about it in terms of variables, think about it in terms of methods. Don't try to manipulate the variable directly, try to manipulate it through operations done by the class.
In your case...
if(select == 1){
System.out.println("You strike at the raccoon!");
System.out.println("You deal " + play1.atk + " damage!");
//reduce the health by the current attack value of the player
racoon.reduceHealth(play1.getAttackValue());
In your Pokemon class, or whatever you named the class that you instantiate an instance of when creating a new Pokemon, create a method like this...
public void reduceHealth(int attackValue){
this.hp = this.hp - attackValue;
}
In your Player class, or whatever you named that class that you instantiate an instance of when creating a new Player, create a method like this...
public int getAttackValue(){
return this.atk;
}
This way, operations done on your objects are done so by its own class, not other classes. When getting information, create methods that return the information you want. When manipulating a variable of an object, use methods of the object to do the manipulation.
I suggestions you todo somethings like that
public class Opponent {
public int hp = 5;
public int def = 0;
public int atk = 1;
public void attack(Opponent target){
target.hp -= atk;
}
}
After you can simply do
Opponent player = new Opponent ();
Opponent badGuy = new Opponent ();
player.attack(badGuy);
Related
I know everyone gets skeptical whenever people put homework on here but I've run out of options and could really use some direction. I have a project where I have to create a deck of cards and allow the user to pick the size of the hand and then fill that hand with random cards and display that to the user. I've found plenty of answers using ArrayLists but mine requires an array and I've tried everything I know and my code is either completely wrong or throws a bunch of errors.
So here are the problems I have:
1) The addCard method in the Hand class can be used to add one Card object at a time to the hand array until it is full. It should increment the cardsInHand counter each time a Card object is added to the Hand as long as there is room for the Card to fit into the Hand.
Here is the code for the Hand class:
public class Hand
{
private int handSize; //Holds the size of the hand
private int cardsInHand; //Holds the number of cards allowed in the hand
private Card[] hand; //Array of card objects
public Hand()
{
this.handSize = 5;
this.cardsInHand = 0;
this.hand = new Card[52];
}//end Default Constructor
public Hand(int handSize)
{
this.handSize = handSize;
}//end Parameterized Constructor
public Hand(Hand handIn)
{
this.handSize = handIn.handSize;
this.cardsInHand = handIn.cardsInHand;
this.hand = handIn.hand;
}//end Copy Constructor
public void addCard(Card card)
{
hand[card]; //--> throws a type mismatch exception (change card param to an int)
}//end addCard()
public int getHandSize()
{
return handSize;
}
public void setHandSize(int handSize)
{
this.handSize = handSize;
}
public int getCardsInHand()
{
return cardsInHand;
}
public void setCardsInHand(int cardsInHand)
{
this.cardsInHand = cardsInHand;
}
public Card[] getHand()
{
return hand;
}
public void setHand(Card[] hand)
{
this.hand = hand;
}
public String toString()
{
String msg = "";
return msg;
}//end toString()
}//end class
My addCard method is just all janky and I could really use some help trying to fill it so my program works. Any help or even a pointing in the right direction would be appreciated!
My addCard method is just all janky and I could really use some help trying to fill it so my program works. Any help or even a pointing in the right direction would be appreciated
Sometimes the best thing to do is stop, turn the screen off, get a pen and piece of paper and just nut it out without any code. Try to understand the problem and get the logic straight in your head.
Basically, you have a series of buckets into which you can put a Card. Before you can put a Card in a bucket, you need to know if you have any free buckets available.
If there are, you need to add the Card to the next available bucket (which should be pointed to by cardsInHand) and increment cardsInHand
Your error is because you're trying reference a "bucket" using a Card, but you can only reference a "bucket" by an index (number) so...
hand[card];
should be more like...
hand[cardsInHand] = card;
but only after you've determined if there is a free "bucket" available, and you should increment cardsInHand AFTER this statement
I'd also be worried about your constructors
public Hand(int handSize)
{
this.handSize = handSize;
}//end Parameterized Constructor
isn't initialising hand, so that's going to be null. A better solution might be to use existing constructors where possible to build a common "initialisation" path
public Hand() {
this(5);
}//end Default Constructor
public Hand(int handSize) {
this.handSize = handSize;
this.cardsInHand = cardsInHand;
this.hand = new Card[handSize];
}//end Parameterized Constructor
Also
public Hand(Hand handIn)
{
this.handSize = handIn.handSize;
this.cardsInHand = handIn.cardsInHand;
this.hand = handIn.hand;
}//end Copy Constructor
is worrying, as it's possible for some external class to make a change to handIn's hand and that change will be reflected by this instance as well (as they are pointing to the same array).
A "copy" constructor should be making a "copy" of the data. Realistically, this should probably be a "deep" copy, so any changes to Card don't mess with the Hand as well, but I'll start with a simple "shallow" copy to get you started
public Hand(Hand handIn) {
this.handSize = handIn.handSize;
this.cardsInHand = 0;
this.hand = new Card[this.handSize];
// Yes, I know there is a better way to do this, but
// I want the OP to learn something
for (int index = 0; index < handIn.hand.length; index++) {
Card card = handIn.hand[index];
if (card != null) {
hand[cardsInHand] = card;
cardsInHand++;
}
}
}//end Copy Constructor
#MadProgrammer already give better answer, I only want to chime a little. Knowing the OP project assignment using Java I want to comment a little about the Hand class design.
The task clearly said that user can pick hand with custom size, then the user will add card into the hand until the hand is full. Thus, I would propose the Hand class design like below.
public class Hand {
private int size; // Hold the amount of card can be hold by hand.
private int counter; // Count how many card added.
private Card[] cards; // The card on hand.
public Hand(int size) {
this.counter = 0;
this.size = size;
this.cards = new Card[size];
}
public void addCard(Card card) {
if (this.counter > this.size) {
throw new IllegalStateArgument("The hand is full of card!");
}
this.cards[this.counter] = card;
this.counter++;
}
public String show() {
StringBuilder result = new StringBuilder("The card on hand is: \n");
for (int i=0; i<this.size; i++) {
result.append(this.cards[i].toString()).append("\n");
}
return result.toString();
}
}
In my opinion the Hand class more easy to understand and achieve the goals of the Hand purpose from the task. However, just use this as reference and write code that you understand well.
I made these 2 objects:
Fighter Lucas = new Fighter(Statistics.punchStrength,
Statistics.movementSpeed, Statistics.reflex);
Opponent Simon = new Opponent(Statistics.punchStrength2,
Statistics.movementSpeed2, Statistics.reflex2);
I want to make them "fight" by comparing their random variables, but I have no idea how to do this.
Make one class fighter and then 2 instances Fighter and Opponent ... I don't understand why you make 2 classes which are doing same job.
You Fighter class should have a method attack(Opponent)
class Figher{
// ..
public void attack(Opponent opponent){
int opponentMaxDamage = calculateHitpointsBy(opponent);
int damageByOpponent = opponent.defend(this, opponentMaxDamage);
this.lifePoints-=damageByOpponent;
}
public boolean isAlive(){
return 0< this.lifePoints;
}
// ..
}
and your Opponent class should have a method defend(Fighter)
class Opponent{
// ..
public void defend(Figher fighter, int maxAttackDamage){
int myDamage = reduceDamage(fighter,int maxAttackDamage);
int attackerDamage = calculateAttackerDamage(fighter);
this.lifePoints-=myDamage ;
}
public boolean isAlive(){
return 0< this.lifePoints;
}
// ..
}
This gives you the possibility to add more complex calculations for the life points later. Eg.: the actual damage an attacker can do to the opponent may depend on the equipment she wears. The same may be true for the damage the opponent receives.
The method isAlive() could be extracted to a common base class...
You use it this way:
Fighter Lucas = new Fighter(Statistics.punchStrength, Statistics.movementSpeed, Statistics.reflex);
Opponent Simon = new Opponent(Statistics.punchStrength2, Statistics.movementSpeed2, Statistics.reflex2);
// fight
while(Lucas.isAlive()&&Simon.isAlive())
Lucas.attack(Simon);
// report winner
if(Lucas.isAlive())
System.out.println("winner is Lucas");
if(Simon.isAlive())
System.out.println("winner is Simon");
Use getter and setter methods in both of the classes i.e Fighter and Opponent
Then
Your Fighter class looks like this
class Fighter{
private int punchStrength, movementSpeed, reflex;
public int getPunchStrength() {
return punchStrength;
}
public void setPunchStrength(int punchStrength) {
this.punchStrength = punchStrength;
}
public int getMovementSpeed() {
return movementSpeed;
}
public void setMovementSpeed(int movementSpeed) {
this.movementSpeed = movementSpeed;
}
public int getReflex() {
return reflex;
}
public void setReflex(int reflex) {
this.reflex = reflex;
}
public Fighter(int punchStrength, int movementSpeed, int reflex) {
this.punchStrength = punchStrength;
this.movementSpeed = movementSpeed;
this.reflex = reflex;
}
}
Your Opponent class look like this
class Opponent{
private int punchStrength, movementSpeed, reflex;
public int getPunchStrength() {
return punchStrength;
}
public void setPunchStrength(int punchStrength) {
this.punchStrength = punchStrength;
}
public int getMovementSpeed() {
return movementSpeed;
}
public void setMovementSpeed(int movementSpeed) {
this.movementSpeed = movementSpeed;
}
public int getReflex() {
return reflex;
}
public void setReflex(int reflex) {
this.reflex = reflex;
}
public Opponent(int punchStrength, int movementSpeed, int reflex) {
this.punchStrength = punchStrength;
this.movementSpeed = movementSpeed;
this.reflex = reflex;
}
}
Now in your main class :
Fighter Lucas = new Fighter (Statistics.punchStrength,
Statistics.movementSpeed, Statistics.reflex);
Opponent Simon = new Opponent (Statistics.punchStrength2,
Statistics.movementSpeed2, Statistics.reflex2);
int avgFighter = ((Lucas.getpunchStrength())+(Lucas.getmovementSpeed())+(Lucas.getreflex()))/3;
int avgOpponent = ((Opponent .getpunchStrength())+(Opponent .getmovementSpeed())+(Opponent .getreflex()))/3;
if(avgFighter > avgOpponent )
System.out.println("Fighter wins");
else if(avgFighter == avgOpponent)
System.out.println("Draw");
else
System.out.println("Fighter looses");
Short version
Make one class - Fighter - which has fight(Fighter otherFighter) method. In that method, resolve the fight, so that the fight() logic and Fighter implementation does not leak outside the class. For an example, see below.
Long version
What I would do is abandon idea of having Opponent and Fighter classes if they're doing the same thing and have the same fields. Instead, why not have one Fighter class? The way I understand, the only difference between your objects is that they have different values - and that does not necessarily mean that you need to belong to different classes. Hence, unless Fighter can fight some other entities that have vastly different properties, one class should be enough. Besides, you can always extend the class if you need more fields or/and methods that behave slightly differently.
Now, determining who would win the fight is a rather interesting problem because you can do it in many ways, some more maintainable than others. On the one hand, you could calculate the outcome outside the classes. However, I do not think that this is the best approach. First of all, this means you need to know quite a lot about the Fighter, and how the fights work. Imagine if someone else worked with your code and wanted to resolve a fight. Would he/she be able to do it easily, or would he/she have to consult with you?
In my opinion, the logic should not leak to the outside, as this will make your code harder to maintain in the long run. E.g., what if attributes change? What if you want to resolve fights in multiple places of your code? Are you going to create a class whose sole purpose is to resolve a fight? Seems a bit strange. Or, worse yet, are you going to copy-paste the code? If so, what will you do if you need to change the logic of an outcome? Are you sure you can adjust all code you've copy-pasted? These are the questions you should be actively thinking about.
What I immediately think when I see a class named Fighter is that the entity represented, well, fights. Wouldn't it be nice if it could resolve the fights itself? Wouldn't it be logical place to put the code? Hence, my solution would be something like this:
public class Fighter {
private int speed;
private int reflex;
private int strength;
public Fighter(int speed, int reflex, int strength) {
this.speed = speed;
this.reflex = reflex;
this.strength = strength;
}
public String fight(Fighter otherFighter) {
int thisSum = speed + reflex + strength;
int thatSum = otherFighter.speed + otherFighter.reflex + otherFighter.strength;
int outcome = thisSum - thatSum;
if (outcome == 0) {
return "Draw";
} else if (outcome > 0) {
return "First fighter won";
} else {
return "Second fighter won";
}
}
}
Notice the fight() method. You pass another Fighter instance into it and without any effort the fight is resolved. The only caveat is that you need a way to figure out to determine which attributes are 'higher' and calculate the overall outcome. There are many ways to do it, of course. I used ints for clarity and ease of use. But you could use anything you like, or implement any logic you want. In any case, now you can resolve the fight with one method call. Hence, the whole code outside the class looks something like this:
public class Main {
public static void main(String[] args) {
Fighter fighter = new Fighter(1, 2, 3);
Fighter opponent = new Fighter(4, 2, 1);
System.out.println(fighter.fight(opponent));
}
}
Naturally, fight() could be extended to contain much more complex logic. Or it could be changed to accept some common base class of opponents, monsters, or fighters, which would allow you not only to fight Fighter's, but also other entities, too. Nevertheless, one thing I would try to achieve is to have as little logic about the fight as possible outside the Fighter class, so as to not have to change code in multiple places if I change my mind about how the fights work.
By the way, I have not used getters and setters, but it would probably be a good idea if getting an attribute involves some kind of logic.
public class Boss{
public void Attack1(){
int randomspace = (int )(Math.random() * 3 + 1);
System.out.println("Attacking space " + randomspace);
if(space == randomspace){
//Something right here to kill the player
}
}
}
But space is in a different class called Player
public class Player {
int space = 1;
}
I thought about making a separate space variable and change them at the same time, but how would the Boss class know when to increment/decrement at the same time as the Player class. it would be easier to just keep it in the one class for simplicity.
EDIT: I figured it out. public class Boss extends Player{ and that fixed my problem
Use parameters. (and lowercase your methods)
A boss will attack a space.
public void attack(int space){
if(space == randomspace){
//Something right here to kill the player
}
If you need the Player, then you should really be using some abstract class, say Unit, then use Hero to be the main piece.
Then you can have
public void attack(Unit unit){
if(unit.getSpace() == randomspace){
//Something right here to kill the player
}
And ideally unit.getSpace() could also come from some Board class that holds all information about the Unit types
Then, your logic elsewhere says boss.attack(player) or boss.attack(player.getSpace())
My current program is a simple game.. I am trying to make it to help figure out how to properly use OOP. But every time I get a little bit into a new program I run into the same problem:
I make an instance to use in my game. This instance could be anything - the main hero, a monster, whatever. Everything is going good, the instance is exactly what I want it to be. Maybe I manipulate it a little bit.
I then try to use a different class, I guess I create an instance of a different class, in an attempt to further manipulate the original instance. Maybe I originally created my hero and changed his stats, and now at this point I am trying to have my hero say something based on the stats that were chosen.
This point is always where I hit a roadblock. I can't seem to do what I want to do here - I can't use that original instance I made because It was just an instance and I don't know how to manipulate it(or even if I am supposed to) from within a new class.
So.. it's a fundamental design problem/lack of understanding of OOP.
But I feel like I have a decent grasp on how to actually program stuff.. I keep reading and reading and getting advice but I can't seem to get past this barrier.
I know people on this site don't seem to like posts like this but maybe someone here can Identify with what it is I am not grasping.
Here is an example of what I am talking about, the game I am trying to make right now.
package pkgnew.stupid.game;
import java.util.Scanner;
/**
*
* #author whyguy2
*/
public class Hero {
public static int heroattack = 1;
public static int herospeed = 1;
public static int heroarmorpen = 1;
public static int heroarmor = 1;
public static int herohealth = 5;
public static String inputstat;
public static int herothepoints = 0;
Hero(int points){
spendpoint(points);
}
public void attack(){
}
public void die(){
System.exit(0);
}
public void winbattle(){
System.out.println("You win the battle and have one new point to spend!");
spendpoint(1);
new NewEncounter();
}
public void levelup(){
System.out.println("You have leveled up and receive 5 new points to spend");
spendpoint(5);
new NewEncounter();
}
public void spendpoint(int points){
for(int x=0; x<points; x++){
System.out.println("Available Points: " + points);
System.out.println("Available Attributes:");
System.out.println("attack: " + heroattack);
System.out.println("speed: " + herospeed);
System.out.println("armorpen: " + heroarmorpen);
System.out.println("armor: " + heroarmor);
System.out.println("health: " + herohealth);
System.out.println(points);
System.out.println(x);
Scanner keyboard = new Scanner( System.in );
inputstat = keyboard.next( );
if(inputstat.equals("attack")){
heroattack = heroattack + 1;
}
else if(inputstat.equals("speed")){
herospeed = herospeed + 1;
}
else if(inputstat.equals("armorpen")){
heroarmorpen = heroarmorpen + 1;
}
else if(inputstat.equals("armor")){
heroarmor = heroarmor + 1;
}
else if(inputstat.equals("health")){
herohealth = herohealth + 5;
}
else{
System.out.println("Please pick one of the stats");
x = x-1;
}
}
}
}
public class StartGame {
StartGame(){ //runs through output for a new game
System.out.println("Welcome to the game");
System.out.println("Pick your hero's starting stats");
Hero thishero = new Hero(10); //spends your points
System.out.println("Let's Begin!/n/n");
new NewEncounter(); //goes into the encounter loops
}
}
at this point I I try to program an encounter in the NewEncounter class, but that isn't possible because I can't use that instance of my hero that I created. and I am pretty sure that my design is bad in the first place, I think I have read that you should be trying to use static variables as little as possible in the first place. I am still reading trying to grasp this but I have read a lot and I feel like nothing is helping me. I actually think a more "hands on" large scale project/tutorial might help me, but I don't know one. Anyways thanks for any help and sorry for the long/blog-like post.
The standard way to use an instance of one class within another is to either store a reference to it or to pass it into the method that stores or uses it.
For example:
class Encounter {
private final Hero mainHero;
private final List<Hero> participants;
public Encounter(Hero mainHero) {
this.mainHero = mainHero;
participants = new ArrayList<>();
}
public void addParticipant(Hero hero) {
participants.add(hero);
}
}
Allows:
Encounter encounter = new Encounter(hero);
or:
encounter.addParticipant(hero);
These can then be used within the class. For example:
class Encounter {
public void moveAllParticipants() {
participants.forEach(Hero::move);
}
}
I notice you have used a lot of public static class variables. This is unusual and there are few good reasons to use them. One is to define constants. If that's your intent then I suggest you use the following standard form:
private static final int HERO_ATTACK = 1;
If you intend for these to be instance variables (i.e. different for each hero) then they should not be static nor public.
This is the sort of area that is well covered in the various Java tutorials. I suggest working through one of them and coming back here if you have further issues.
The error i am having here is a infinite or near infinite loop in my method calls and class's creating other class's constructors. What my program is trying to do is semi-randomly generate survey results based off actual statistics. I would highly appreciate not only some insight in whats going wrong here. But some advice and pointers on how to prevent this from happening and ways to analyze the error messages by myself. I get how some of the work but like i stated below i am new to programming im a freshman in college so programming is new to me. Thanks in advance and sorry for my previous post, thought i would take the time to give you guys an appropriate one.
Im new to programming this is my 2nd project ive done on my own so im sorry if its not the best.
This is my Test class:
public Tester()
{
randomGenerator = new Random();
probability = new Probability();
stats = new Statistics();
double chance = randomGenerator.nextDouble();
double gender = probability.getProbabilityOfMale();
if(chance > gender)
{
male = false;
stats.incrementFemale();
}else{
male = true;
stats.incrementMale();
}
age = randomGenerator.nextInt(49)+16;
int range = stats.getNumberOfQuestion();
for(int i=0;i<range;i++)
{
probabilities = probability.probOfAnswer(i);
answers = probability.getAnswers(i);
chance = randomGenerator.nextDouble();
int size = probabilities.size();
for(int j=0;j<size;j++)
{
double qTemp = chance - probabilities.get(j);
if(qTemp <= 0.0)
{
Answer aTemp = answers.get(j);
aTemp.incrementCounter();
answers.set(j,aTemp);
}
}
}
}
Statistics class:
public ArrayList<Answer> getAnswers(int index)
{
temp = survey.getAnswers(index);
return temp;
}
public int getMale()
{
return male;
}
public int getFemale()
{
return female;
}
public int getNumberOfQuestion()
{
return numberOfQuestion;
}
public void incrementNumberOfQuestion()
{
numberOfQuestion++;
}
public void incrementMale()
{
male++;
}
public void incrementFemale()
{
female++;
}
and probability class:
public Probability()
{
stats = new Statistics();
probOfAnswer = new ArrayList<Double>(0);
}
public ArrayList<Double> probOfAnswer(int index)
{
temp = stats.getAnswers(index);
int size = temp.size();
for(int i=0;i<size;i++)
{
aTemp = temp.get(i);
for(int j=0;j<size;j++)
{
Answer aTemp = temp.get(j);
sum += (double)aTemp.getCounter();
}
double number = (double)aTemp.getCounter();
probOfAnswer.add(number/sum);
sum = 0;
}
return probOfAnswer;
}
public ArrayList<Answer> getAnswers(int index)
{
temp = stats.getAnswers(index);
return temp;
}
public ArrayList<Double> getProbofAnswer()
{
return probOfAnswer;
}
public void probabilityOfMale()
{
double male = (double)stats.getMale();
double female = (double)stats.getFemale();
probabilityOfMale = male / (male + female);
}
public double getProbabilityOfMale()
{
return probabilityOfMale;
}
These are the only real important parts where the loop exsists the rest of the code is not needed to be uploaded.
Im having difficulty uploading my error message on this site its not accepting it as code in the code insert, then it wont let me submit the message afterwards so im going to upload the code elseware and link it.
http://forum.overdosed.net/index.php/topic/56608-this-is-unimportant/
But i dont know how long that forum will let me keep that post there ><
at Question.<init>(Question.java:17)
at Survey.addQuestion(Survey.java:23)
at Statistics.<init>(Statistics.java:52)
at Question.<init>(Question.java:17)
at Survey.addQuestion(Survey.java:23)
at Statistics.<init>(Statistics.java:52)
at Probability.<init>(Probability.java:19)
You need to check why Question is creating Statistics object and again Statistics is trying to create Question object leading to infinite recursion. As the line numbers are given you can take a look at corresponding lines.
Judging by the stack trace, the problem lies in three parts which you haven't shown us - the Question and Statistics constructors and the Survey.addQuestion method:
From the stack trace:
at Survey.addQuestion(Survey.java:23)
at Statistics.<init>(Statistics.java:52)
at Question.<init>(Question.java:17)
at Survey.addQuestion(Survey.java:23)
at Statistics.<init>(Statistics.java:52)
at Question.<init>(Question.java:17)
So your Question constructor is calling the Statistics constructor. But the Statistics constructor is then calling Survey.addQuestion, which is in turn calling the Question constructor.
It feels to me like there's much more construction going on than is really useful. Why would a Statistics constructor need to add anything to a survey? I wouldn't expect a Statistics class to even know about surveys and questions.
It's entirely possible that a lot of this can be fixed by passing a reference to an existing object to the constructors - so the Probability constructor may be better taking a Statistics reference in its constructor and using that for its stats field than creating a new Statistics object itself. It's hard to say without knowing what these classes are really meant to represent though... which may be part of the problem. Do you have a firm grasp of what the responsibility of each class is? Think about that carefully before making any code changes.
We don't have the relevant source code, but the error message says what's wrong:
Tester creates a Probability
Probability constructor creates a Statistics
Statistics constructor calls Survey.addQuestion()
addQuestion() creates a Question
Question creates a Statistics (goto 3 and loop infinitely)
I think you should probably pass objects around rather than creating them each time.