This site requires JavaScript, please enable it in your browser!
Greenfoot back
darkmist002
darkmist002 wrote ...

2013/7/1

need help for calling a method

1
2
darkmist002 darkmist002

2013/7/1

#
i want this method to be called by another so that it can check the health of one of the classes i put in there. i was going to just use the parent class, but couldn't figure out how to do it, so i tried doing it in another class and have it call a method from one of the classes based on a switch statement, but i can't remember how to input the switch so it will go to a certain class depending on which the particular unit is calling the method. here's the code calling the method:
private void attack()
    {
        List<enemies> e = getObjectsInRange(5, enemies.class);//change radius to variable for when
                                                            //upgrading to up radius.
         
        if(! e.isEmpty())
        {
            /** attack first enemy.
             * if(clock)
             * {
              *     e(0).health - attack;
              *}
              *
            **/
            //int index = e.indexOf(enemies.class);
            enemies temp = e.get(0);  
            double hp = temp.getHealth();
            if(clock())
            {
                hp -= attack;
            }
        
            if(hp <= 0)
            {
                ((tdpath)getWorld()).removeObject(temp);
                // minerals+= whatever the value is for the monster.
            }
        }
    }
and the code i'm trying to call is this one now:
public class spawnHp extends Actor
{
    /**
     * Act - do whatever the spawnHp wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    private Boss b;
    private minion1 m1;
    private minion2 m2;
    private minion3 m3;
    private minion4 m4;
    private enemies E;
    public spawnHp(Boss B, minion1 M1, minion2 M2, minion3 M3, minion4 M4)
    {
        b = B;
        m1 = M1;
        m2 = M2;
        m3 = M3;
        m4 = M4;
    }
    public void act() 
    {
        // Add your action code here.
    }    
    
    public double getHealth()
    {
        E = this.class;
       switch (E)
       {
            case (b)://Boss.class):
            {
               return Boss.getHealth();
                break;
            }
            case(m1)://minion1.class):
            {
                return minion1.getHealth();
                break;
            }
            case(m2)://minion2.class):
            {
                return minion2.getHealth();
                break;
            }
            case(m3)://minion3.class):
            {
                return minion3.getHealth();
                break;
            }
            case(m4)://minion4.class):
            {
                return minion4.getHealth();
                break;
            }
        return 0;
       }
    }
}
want it to call that code based on the unit the tower sees, and then get the health of that unit so it can lower the health of that unit when it attacks.
danpost danpost

2013/7/1

#
Are you getting an error message (incompatible types -- maybe; or, cannot find method 'getHealth()')?
darkmist002 darkmist002

2013/7/1

#
was getting both of those. i changed it around a little, and don't get errors now, but the tower still doesn't attack a unit when it gets within range: tower code:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List;
/**
 * Write a description of class fasttower here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class fasttower extends tower
{
    /**
     * Act - do whatever the fasttower wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    //att lv 1/2/3          1/2/4/8
    //att spd lv 1/2/3      1/.75/.5/.35
    //price                 5
    //upgrade price         10
    
    private int attack = 1;
    private long attspd = 1000; //milliseconds
    private int range = 5;
    private int lvl = 1;
    private long count = 0;
    private long aTime = 0;
    private int wave = 1; //have wave class come in as well
    private minion1 m1;
    private Object unit;
    
    public fasttower(minion1 M1)
    {
        m1 = M1;
    }
    
    public fasttower()
    {
        
    }
    public void act() 
    {
        // Add your action code here.
        //use getObjectsInRange() method for actors to make a radius for towers
        update();
        attack();
    }   
    
    private void attack()
    {
        List<enemies> e = getObjectsInRange(5, enemies.class);//change radius to variable for when
                                                            //upgrading to up radius.
         
        if(! e.isEmpty())
        {
            /** attack first enemy.
             * if(clock)
             * {
              *     e(0).health - attack;
              *}
              *
            **/
            //int index = e.indexOf(enemies.class);
            enemies temp = e.get(0);  
            double hp = temp.getHealth();
            unit = temp.getClass();
            
            if(clock())
            {
                hp -= attack;
                if(unit.equals(m1))
                {
                    m1.decHealth();
                }
                //temp.getClass().decHealth();
            }
        
            if(hp <= 0)
            {
                ((tdpath)getWorld()).removeObject(temp);
                // minerals+= whatever the value is for the monster.
            }
        }
    }
    private void update()
    {
        /**if have minerals and click on tower, upgrade to next lv
         * will have to add a minerals class and have it seen in every class.
          *if(minerals == 10 && clickontower && (lv <= 4))
          *{
          *     lvl++;
          *     attack += (attack*lvl);
          *     attspd = attspd - 200;
          *     range += (range*lvl);
          *}
          **/
        
    }
    
    //says when to attack based on milliseconds (1000 = 1 sec, so every second for this tower unless
    //it's upgraded)
    private boolean clock()
    {
        long time = System.currentTimeMillis();
        
        if(count!=0)
        {
            long temp = time - count;
            aTime = temp;
        }
        count = time;
        
        if(aTime >= 1000 && lvl == 1)
        {
            aTime = 0;
            return true;
        }
        
        if(aTime >= (1000 -(lvl*100)) && lvl > 1)
        {
            aTime = 0;
            return true;
        }
        return false;
    }

}
parent class of the spawned units:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class enemies here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class enemies extends Actor
{
    /**
     * Act - do whatever the enemies wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    private int wave = 1; //get from wave class
    private double health;
   // private spawnHp hp;
        private Boss b;
        private minion1 m1;
        private minion2 m2;
        private minion3 m3;
        private minion4 m4;
//     public enemies(Boss B, minion1 M1, minion2 M2, minion3 M3, minion4 M4)
//     {
//         b = B;
//         m1 = M1;
//         m2 = M2;
//         m3 = M3;
//         m4 = M4;
//     }
    
    public void act() 
    {
        // Add your action code here.
       
    }    
    
     public double getHealth()
     {
        if(this.getClass().equals(Boss.class))// == Boss.class)
        {
             return health = b.getHealth(); //* (lvl *1.5);
        }
        if(this.getClass().equals(minion1.class))// == minion1.class)
        {
             return health = m1.getHealth();// * (lvl *1.5);
        }
        if(this.getClass().equals(minion2.class))// == minion2.class)
        {
             return health = m2.getHealth();// * (lvl *1.5);
        } 
        if(this.getClass().equals(minion3.class))// == minion3.class)
        {
             return health = m3.getHealth();// * (lvl *1.5);
        }
        if(this.getClass().equals(minion4.class))// == minion4.class)
        {
             return health = m4.getHealth();// * (lvl *1.5);
        }
               
        return health;//hp.getHealth();
     }

}
code for the spawned unit i was testing the code on to see if it would attack/remove it:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.awt.Color;
/**
 * Write a description of class minion1 here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class minion1 extends enemies
{
    /**
     * Act - do whatever the minion1 wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    int x = 0;
    int y = 0;
    public int health = 1;    
    public void act() 
    {
        // Add your action code here.
        /**the following code is used for the object to check the color at the cell, and if it's the one you want, in this case blue, 
             * it will change it's own coordinates to match the color, basically used to make a path for the object to follow in this case.
             */    
            move();
            checkHealth();
            
            
    }    
    
    private void move()
    {
        if(getWorld().getColorAt(getX()+1, getY()).getRed() < 10 && getWorld().getColorAt(getX()+1, getY()).getGreen() < 10 && x !=-1)      
            {      
                setLocation(getX() + 1,getY());    
                
                x = 1;
                y = 0;
            }      
            else if(getWorld().getColorAt(getX()-1, getY()).getRed() < 10 && getWorld().getColorAt(getX()-1, getY()).getGreen() < 10 && x !=1)      
            {      
                setLocation(getX()-1, getY());      
                
                x = -1;
                y = 0;
            } 
           
            else if(getWorld().getColorAt(getX(), getY()+1).getRed() < 10 && getWorld().getColorAt(getX(), getY()+1).getGreen() < 10 && y != -1)      
            {      
                setLocation(getX(), getY()+1);      
                x = 0;
                y = 1;
            }
            else if(getWorld().getColorAt(getX(), getY()-1).getRed() < 10 && getWorld().getColorAt(getX(), getY()-1).getGreen() < 10 && y !=1)      
            {      
                setLocation(getX(), getY()-1);   
                x = 0;
                y = -1;
            }
    }
    
    private void checkHealth()
    {
        if (health <= 0)
        {
            //minerals += 1;
            ((tdpath)getWorld()).removeObject(this);
        }
    }
    
    public double getHealth()
    {
        return health;
    }
    
    public void decHealth()
    {
        health--;
    }
    
    public void setHealth(int hp)
    {
        health = hp;
    }
}
danpost danpost

2013/7/1

#
Why do you have instance fields holding the boss and four minions in the enemy class? Each enemy (the boss and each minion) will have each of these fields all set with independent values. I do not think that is what you were trying to achieve. You should probably keep references to these actors in your world class, if at all. The biggest problem I see is you have all your methods (getHealth, decHealth, setHealth(int)... -- well, EVERYTHING!, including the instance fields) in your child classes (Boss, minion1, minoin2, etc), where all the code should be in the enemies class (this will also make it not matter which enemy is being attacked). The following is more what the enemies class should look like:
import greenfoot.*;
import java.awt.Color;

public class enemies extends Actor
{
    public int health;
    
    public void act() 
    {
            move();
            checkHealth();
    }    
    
    private void move()
    {
        int x = 0;
        int y = 0;
        if(getWorld().getColorAt(getX()+1, getY()).getRed() < 10 && getWorld().getColorAt(getX()+1, getY()).getGreen() < 10 && x !=-1)      
        {      
            x = 1;
            y = 0;
        }      
        else if(getWorld().getColorAt(getX()-1, getY()).getRed() < 10 && getWorld().getColorAt(getX()-1, getY()).getGreen() < 10 && x !=1)      
        {      
            x = -1;
        } 
        else if(getWorld().getColorAt(getX(), getY()+1).getRed() < 10 && getWorld().getColorAt(getX(), getY()+1).getGreen() < 10 && y != -1)      
        {      
            y = 1;
        }
        else if(getWorld().getColorAt(getX(), getY()-1).getRed() < 10 && getWorld().getColorAt(getX(), getY()-1).getGreen() < 10 && y !=1)      
        {      
            y = -1;
        }
        setLocation(getX()+x, getY()+y);
    }
    
    private void checkHealth()
    {
        if (health <= 0)
        {
            getWorld().removeObject(this);
        }
    }
    
    public int getHealth()
    {
        return health;
    }
    
    public void decHealth()
    {
        health--;
    }
    
    public void setHealth(int hp)
    {
        health = hp;
    }
}
And your Boss and minion classes should hardly have any code at all (as yet, at least). Here is what the minion1 class code should look like (and the other enemies sub-classes should be similar):
import greenfoot.*;

public class minion1 extends enemies
{
    public minion1()
    {
        health = 1;
    }
}
The 'wave' field should be an instance field of your sub-class of World. All you should need to do in the 'attack' method of the tower class is apply the damage (the enemies actor will remove itself if health is depleted). Also, not sure why you are using 'double' for health ('int' should work fine):
private void attack()
{
    if (clock() && !getObjectsInRange(5, enemies.class).isEmpty())
    {
        enemies e = (enemies)getObjectsInRange(5, enemies.class).get(0);
        enemies.decHealth();
    }
}
Line 5 and 6 can be combined to one statement as follows:
((enemies)getObjectsInRange(5, enemies.class).get(0)).decHealth();
darkmist002 darkmist002

2013/7/1

#
main reason i stuck the move method in there and then stuck others in those classes is because they don't move unless i have the coding in them. i can try putting the other coding in the parent class tho. tried putting that coding into the enemies class and the attack part of the tower, but it still doesn't lower their health when they go right next to a tower.
darkmist002 darkmist002

2013/7/1

#
ok, when i stick it on the path, it works for one of the minions, the one with 1 health, but any with more than one don't even get their health lowered. Edit: might have fixed it (some leak through without getting attacked, some get attacked, and some get removed from 0 health like they are supposed too). i think it has to do with the range and time between attacks. i want it to attack like once every second, but i'm not sure how to get the speed of the spawns faster/slower. plus i don't know how to show the range of the tower so i can see what goes in it, and where they have to be placed, plus how to make the range be seen by the player.
danpost danpost

2013/7/1

#
In the ones that do not move, put in the following act method:
public void act()
{
    checkHealth();
}
To increase the range of attack, increase the 'int' argument in the 'getObjectsInRange' method call. As far as time, I would use 'act cycles' instead of the system clock to regulate the attacks. First one thing, it is easier to implement; and for another, it makes it more consistent in the timing between it and other actions.
import greenfoot.*;

public class fasttower extends tower
{
    public fasttower()
    {
        // declare the following fields in the tower class
        range = 5; // adjust this to change the range of attack
        attspd = 60; // adjust this to change to rate of attack
        attTimer = 0;
    }
}

// with the tower class as follows
import greenfoot.*;

public class tower extends Actor
{
    public int range;
    public int attspd;
    public int attTimer;

    public tower()
    {
    }

    public void act() 
    {
        attack();
    }   
    
    private void attack()
    {
        if (canAttack() && !getObjectsInRange(range, enemies.class).isEmpty())
        {
            enemies e = (enemies)getObjectsInRange(range, enemies.class).get(0);
            enemies.decHealth();
            attTimer = attspd;
        }
    }

    private boolean canAttack()
    {
        if (attTimer > 0)
        {
            attTimer--;
        }
        return attTimer > 0;
    }
}
darkmist002 darkmist002

2013/7/2

#
tried entering in what you said, and it's not attacking at all now. before when i had the clock part it would attack some of the time, but now it doesn't attack at all. http://www.greenfoot.org/scenarios/8919
darkmist002 darkmist002

2013/7/2

#
also can't figure out why the addMinerals method doesn't work. gives a nullpointer error when i enable it in the enemies class (i have a set number of minerals for each enemy in their constructors). it'll remove em fine when i disable that line, so i know it has to do with that one, but can't figure out why it won't use the values from each separate unit.
darkmist002 darkmist002

2013/7/2

#
ok, got the canAttack to work, had to change the return statement to return attTimer == 0. thanks for that. can you help me with the minerals question i have above? that and getting the tower to 'fire' an object at the unit that it attacks. right now the object it's suppose to be firing just sits on top of the tower. here's the link to the scenario i made so far of it, although i don't have the buttons working yet so you'll have to open it in greenfoot to get access to the towers: http://www.greenfoot.org/scenarios/8919
danpost danpost

2013/7/2

#
Good catch on the return timer in the canAttack method. As far as firing the attack objects: first, you should not be sub-classing tower with the attack objects (they are not towers); second, you should probably pass the enemies object found to attack across to the new attack object so it can either use its location at the time you create the attack object to move toward or continuously use its location to track to it.
danpost danpost

2013/7/2

#
For the minerals problem: the only 'enemies' object that will have a set M value is the first one created (the one created in the world constructor that passes a value to the object created). All the rest are created without setting that value and therefore the value is retained as 'null' (hence, the NullPointerException). Fortunately, there is a real easy fix for this. You can have (not the objects of the class, but) the class itself hold the set value by adding the 'static' keyword in its definition in the 'enemies' class:
public static minerals M;
darkmist002 darkmist002

2013/7/3

#
the main reason i had the attack object sub classed to the tower was because it would give me an error when the tower tried to fire it if it wasn't subclassed under the tower, although today i can't seem to reproduce the error for now, so i'll re class it under a class for towerAttacks, and set up the coding in that one. wanted to get all the attacking from the tower fixed and the minerals system fixed before i moved the attacks to the attack objects. how do you get the attack objects to move toward the units they are attacking (so that once i put the code in for attacks, it'll take off their health when hit by the object, then the object will be removed). i get how i'll put the attack coding in there, since it will be just like how i did it in the tower part, but i can't figure out how to get it to move directly toward the object that is moving. and i tried changing it to static, and/or adding a value directly into the enemies class and just using that value, but it still gives me this error: java.lang.NullPointerException at enemies.checkHealth(enemies.java:58) at enemies.decHealth(enemies.java:46) at tower.attack(tower.java:61) at fasttower.act(fasttower.java:49) at greenfoot.core.Simulation.actActor(Simulation.java:507) at greenfoot.core.Simulation.runOneLoop(Simulation.java:470) at greenfoot.core.Simulation.runContent(Simulation.java:204) at greenfoot.core.Simulation.run(Simulation.java:194) sorry if I'm asking a lot of questions about this, still trying to figure it all out since i'm doing it by myself. decided to make a game for my internship and since i am by myself i have a lot to learn. (i do plan to put all the forum post links i used for help in the credits once i'm finished.)
darkmist002 darkmist002

2013/7/3

#
ok, figured out the minerals problem. it wouldn't let me use the methods from one class to another, even when i had an instance of it for the enemies class, but when i add a method to the world class and have it use the world's class method to use the minerals method, it works.
danpost danpost

2013/7/4

#
You can solve both issues (the movement to follow the enemies objects and the attacks applying the damages) by passing the actor found in the attack method to the towerAttack object. Then you can use its (the actor that was passed) continuous location to track it down and it will also be there to apply damage to it.
There are more replies on the next page.
1
2