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

2015/6/6

Actor collision help

1
2
3
Gingervitis Gingervitis

2015/6/6

#
I am having some trouble with the code below in the dealEnemyDamage() method in the MrBoom class and the aquireTarget() method in the EnemyDamageField class... When a MrBoom actor makes contact with the EnemyDamageField actor, it is supposed to subtract 1 from the health bar (hb in the code) and then remove the EnemyDamageField actor from the world. Currently, all I am getting is this error java.lang.IllegalStateException: Actor not in world. An attempt was made to use the actor's location while it is not in the world. Either it has not yet been inserted, or it has been removed. or null pointer exceptions... if more code is needed I am happy to upload my project for a short time.
import greenfoot.*;
import java.util.List;
/**
 * Write a description of class MrBoom here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class MrBoom extends Ally
{
    private GreenfootImage [] imgs;
    int i=1;
    boolean isAttacked = false;
    Round round;
    HealthBar hb;
    public MrBoom(Round rnd)
    {
        round = rnd;//round instance field
        imgs = new GreenfootImage[16];//array of images
        for(int i=1;i<16;i++)
            imgs[i]= new GreenfootImage("MrBoom_"+i+".png");//sets each picture to a new position in the array
        hb = new HealthBar("","hp",100,100);
        hb.setBarWidth(25);
        hb.setBarHeight(5);
    }

    /**
     * Act - do whatever the Ally wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        health();  
        despawn();
        dealEnemyDamage();
        if(getWorld()!=null)
            isAttacking();
        if(isAttacking())
        {
            i++;//counter used for determining which image is being used
            setImage(imgs[i%16]);
            if(i==imgs.length-1)
                i=0;            
            damage();
        }

    }

    public int getDamage()
    {
        EnemyDamageField enemy = (EnemyDamageField)(getOneObjectAtOffset(0, 0, EnemyDamageField.class));
        int damage = enemy.power();
        return damage;
    }

    public void dealEnemyDamage()
    {      
        isAttacked=true;
        
        if(getOneObjectAtOffset(100, 100, EnemyDamageField.class)!=null)
        {
            hb.subtract(1);              
        }
        if(canSee(EnemyDamageField.class))
        {
            eat(EnemyDamageField.class);
        }   
    }

    public void despawn()
    {
        if(hb.getValue()==0)  
        {
            getWorld().removeObject(hb);
            getWorld().removeObject(this);
        }
    }

    public void health()
    {
        getWorld().addObject(hb, getX(), getY()-30);
        hb.setLocation(getX(), getY()-50);
    }

    /**
     * Checks if Ally has made contact with the enemy
     *     if true- stop moving and fight
     *     if false- move until true
     */
    public boolean isAttacking()
    {

        if(getWorld()!=null)
        {
            List players = getObjectsAtOffset(0, 0, Enemy.class);
            List players2 = getObjectsAtOffset(0,0, EnemyCastle.class);   
            Actor enemyCastle = (Actor) (getWorld().getObjects(EnemyCastle.class).get(0));
            if (! players.isEmpty()&& getOneObjectAtOffset(50, 50, Enemy.class)!=null||isTouching(Enemy.class)&&!players.isEmpty()) {
                Actor player = (Actor) players.get(0);
                if (player.getX()-50>getX()) 
                    move(1);
                else
                    move(0);
                    dealEnemyDamage();
                return true;
            }
            else if(getX()>=enemyCastle.getX()-175)
            {
                move(0);
                return true;
            }
            else {
                move(1);
                setImage(imgs[1]);
                return false;
            }   
        }
        return false;
    }

    /**
     * creates a new DamageField at certain parts of the image
     */
    public void damage()
    {   if(i>8)//checks if image is i or greater
        {
            for(int w=getImage().getWidth()/3;w<getImage().getWidth()-10;w+=120)//width
            {
                for(int h=0; h<getImage().getHeight()/3;h+=+150)//height
                {
                    if(getImage().getColorAt(w, h)!=null)//checks the pixels (getColor not needed)
                    {
                        getWorld().addObject(new DamageField(round,MrBoom.class), getX()+w, getY()+h);//add new DamageField
                    }
                }
            }
        }
    }
}
import greenfoot.*;

/**
 * Write a description of class EnemyDamageField here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class EnemyDamageField extends Animal
{
    
    Class damageType;
    Round round;
    int damagePower=2;
    int life= Greenfoot.getRandomNumber(1)+5;
    int speed = (Greenfoot.getRandomNumber(6)+3)*(1);
    Class[] clss = {MrBoom.class};

    /**
     * Round rnd- allows DamageField to know which round it is
     * damage is calculated by round
     * Actor actr-gets the Actor DamageField was created by
     * damage is calculated by Actor type
     */
    public EnemyDamageField(Round rnd,Class obj)
    {
        damageType=obj;
        round=rnd;
    }

    /**
     * Act - do whatever the DamageField wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        aquireTarget();
        // if(canSee(EnemyDamageField.class)&&getWorld()!=null )
          //  eat(EnemyDamageField.class);
        if(life<=0||atWorldEdge()&&getWorld()!=null||speed<=0)  
           getWorld().removeObject(this);
        move(-1);
        speed--;    
        life--;
    } 
    public int power()
    {
        if(damageType.equals(Skeletor.class))
            damagePower = 1;
        return damagePower;
    }

    public void aquireTarget()
    {        
        for(int i=0;i<clss.length;i++)
        {
            Ally  ally = (MrBoom)(getOneObjectAtOffset(0, 0, Ally.class)) ;
            Castle castle = (Castle)(getOneObjectAtOffset(0, 0, Castle.class));
            if(ally!=null)
            {
                turnTowards(ally.getX(), ally.getY());
                getWorld().removeObject(this);
            }
            else if(castle!=null&&ally!=null)
            {
                turnTowards(ally.getX(), ally.getY());
                getWorld().removeObject(this);
            }
            else if(castle!=null)
            {
                turnTowards(castle.getX(), castle.getY());  
                castle.getHealthBar().subtract(power());
                getWorld().removeObject(this);
            }
        }
    } 
}
Super_Hippo Super_Hippo

2015/6/6

#
Line 55 in the EnemyDamageField class starts a for loop. In every iteration you do the same though. It is not that you check intersecting with each MrBoom object. So if you find a MrBoom or Castle object at the same cell as the EnemyDamageField, you remove this EnemyDamageField object. Then the next iteration starts and it will fail because the object isn't in the world anymore -> it can't check collision -> nullpointer exception. So remove lines 55, 56 and 75. Two other things in the method: 1. If you find an Ally object (which is not a MrBoom object), it will get an error too. To prevent that to happen, change the (MrBoom) in line 57 to (Ally). The if-block starting at 64 will never be executed. It is executed when castle and ally are both not null, but if ally isn't null, the if-block before that is executed. You are using the turnTowards method but immediately after that, you remove the object so the turning won't be visible. What is the reason for that?
danpost danpost

2015/6/6

#
In the MrBoom class, the act method calls 'despawn' which could remove the actor from the world; after which the 'dealEnemyDamage' method is called, requiring the actor be in the world for 'getOneObjectAtOffset' to function. The act method must be exited if 'despawn' removes the actor. Insert between the two calls in the 'act' method the following line:
if (getWorld() == null) return;
Gingervitis Gingervitis

2015/6/6

#
Thank you super_hippo that has fixed the errors from occurring but my MrBoom still does not take damage. And in response to your question above about removing the object after the turnTowards method, I had put that there when I was having a different problem and never removed it because nothing changed, but I have removed it now.
Gingervitis Gingervitis

2015/6/6

#
Danpost I have inserted your code to my program and there has been no change...
danpost danpost

2015/6/6

#
Gingervitis wrote...
Danpost I have inserted your code to my program and there has been no change...
That is because no damage is being taken yet. In the 'dealEnemyDamage' method, you have two separate 'if' blocks. One does damage when an EnemyDamageField is located to the lower-right of the actor, when the field is intersecting (getX()+100, getY()+100); the other removes the field when the images of the two intersect at all. It is most probable that the second one removes the field before the field gets to that particular offset location. If you want the damage to take place at the same time the field is removed, move the code to decrement the damage to the second 'if' block and remove the first one.
Gingervitis Gingervitis

2015/6/6

#
Danpost wrote...
If you want the damage to take place at the same time the field is removed, move the code to decrement the damage to the second 'if' block and remove the first one.
The reason there are two separate if blocks in that method is because the second one never gets called in the first place. Earlier I had placed a boolean variable inside the second if block and set it to true but it never became true, indicating that it would never be called.
danpost danpost

2015/6/6

#
Verify the following with 'true' or 'false': (1) there is no class that extends the MrBoom class (2) there is no code that moves the MrBoom object when it is not attacking (3) the DamageField class extends the EnemyDamageField class (4) the EnemyDamageField objects only remain in the world for a very short time (max 6 act cycles); which means it can move only 6 cells, presumably to the left, before being removed from the world Please also explain, in detail, what the 'damage' method of the 'MrBoom' class is supposed to be doing (be clear as to what images are being used; what their sizes are; etc.)
danpost danpost

2015/6/6

#
Other issues may include, but are not necessarily limited to: * calling 'dealEnemyDamage' from within the 'isAttacking' method and directly from the 'act' method * calling 'isAttacking' twice in the 'act' method (one if the actor is still in the world and another time immediately after that as the condition in the following 'if' statement)
Gingervitis Gingervitis

2015/6/6

#
1. true 2. false, it moves when not attacked or is not attacking and does not move when attacked or attacking 3. false, two separate classes 4. unsure The damage method creates an EnemyDamageField at certain parts of the image. Since my actors will be animated and the image is constantly changing, I had no other ideas to make enemies take damage at parts of the image, such as an explosion, so I made it so a different actor (DamageField &EnemyDamageField) which will be placed at those certain parts of the images. I hope that makes sense
Gingervitis Gingervitis

2015/6/6

#
The set of MrBoom images are 72x82 pixels The EnemyDamageField 6x6 pixels and is supposed to spawn at the left side of another class 'Skeletor' and those dimensions are 150x150 but that size may be adjusted in the future.
danpost danpost

2015/6/6

#
1. good 2. I see how you did that within the 'isAttacking' method, now, however cumbersome 3. gotcha 4. troublesome; trace what happens (follow the 'life' field from what its possible start values are through several act cycles); btw, the 'speed' value should be traced also, as it will only allow up to 9 act cycles As far as the 'damage' method, I still would like to know the range in size of the possible images used for the MrBoom object.
Gingervitis Gingervitis

2015/6/6

#
Danpost wrote...
As far as the 'damage' method, I still would like to know the range in size of the possible images used for the MrBoom object.
Please explain what you mean by 'range of possible sizes'? Every image of the MrBoom object is the same size.
danpost danpost

2015/6/6

#
Gingervitis wrote...
Please explain what you mean by 'range of possible sizes'? Every image of the MrBoom object is the same size.
Then it is that size that I wish to be informed of.
Gingervitis Gingervitis

2015/6/6

#
Gingervitis wrote...
The set of MrBoom images are 72x82 pixels The EnemyDamageField 6x6 pixels and is supposed to spawn at the left side of another class 'Skeletor' and those dimensions are 150x150 but that size may be adjusted in the future.
There are more replies on the next page.
1
2
3