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

2015/5/6

Multiple enemies in multiple worlds error

StuDent463212 StuDent463212

2015/5/6

#
I'm making a game, and I've tried to find a solution to this problem but I can't find anything. So, I'm trying to have different types of enemies in different worlds, but when I kill an enemy in the first world, being that it has the code to remove the other enemies in the other worlds, I get the 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. I know what the problem is, I just don't know how to fix it/make it work
davmac davmac

2015/5/6

#
Please see this, especially point #3. This may also help.
StuDent463212 StuDent463212

2015/5/6

#
I can't really be specific because for some reason it's hard to explain. I have 3 types of enemies, 3 different actor classes I want to use one type in my first world class, and another one in my second world class, and the last in my third world class. When the player class throws the sword class and it hits the enemy, the error comes up saying that the other enemy actor classes are not in the world Here is the sword class that is causing the problem, like I said I don't know what code I'd need to add to make it so that the sword class only kills the first enemy actor class in the first world, and doesn't interfere with the other enemy actor classes import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) public class Sword extends Actor { public void act() { move(5); killSlime(); killOktopus(); killSkeleton(); } public void killSlime() { Actor slime = getOneIntersectingObject(Slime.class); if (slime != null) { World myWorld = getWorld(); myWorld.removeObject(slime); Grass grass = (Grass)myWorld; Score score = grass.getScore(); score.addScore(10); myWorld.removeObject(this); return; } else if (atWorldEdge()) { getWorld().removeObject(this); } } public void killOktopus() { Actor oktopus = getOneIntersectingObject(Oktopus.class); if (oktopus != null) { World myWorld = getWorld(); myWorld.removeObject(oktopus); Desert desert = (Desert)myWorld; Score score = desert.getScore(); score.addScore(10); myWorld.removeObject(this); return; } else if (atWorldEdge()) { getWorld().removeObject(this); } } public void killSkeleton() { Actor skeleton = getOneIntersectingObject(Skeleton.class); if (skeleton != null) { World myWorld = getWorld(); myWorld.removeObject(skeleton); Cave cave = (Cave)myWorld; Score score = cave.getScore(); score.addScore(10); myWorld.removeObject(this); return; } else if (atWorldEdge()) { getWorld().removeObject(this); } } public boolean atWorldEdge() { if(getX() < 5 || getX() > getWorld().getWidth() - 5) return true; if(getY() < 5 || getY() > getWorld().getHeight() - 5) return true; else return false; } } Sorry I can't be more specific, but it's hard to explain in more detail when it's kind of simple, but can be confused with other things
Super_Hippo Super_Hippo

2015/5/6

#
The error message doesn't say that the other enemy objects aren't in the world, it says that the sword isn't in the world. You remove it when it touches a Slime, after that it isn't in the world anymore, so the 'getOneIntersectingObject' causes the error. There are different ways to make it work: 1. Add this line at the beginning of the 'kill...' methods:
if (getWorld()==null) return;
2. Only execute one method:
public void act() 
{
    move(5);
    World w = getWorld();
    if (w instanceof Grass) killSlime();
    else if (w instanceof Desert) killOktopus();
    else if (w instanceof Cave) killSkeleton();
}
3. Let the three enemies extend one class, for example class Enemy. Then you can check for an object of the Enemy class instead of having three methods, one for each type of enemy. Do not check for being at the world edge three times. It has nothing to do with killing an enemy, so it shouldn't be in those methods.
danpost danpost

2015/5/6

#
There are two major problems with the code given. One is that if 'killSlime' or 'killOktopus' removes 'this' from the world, the following method call will fail when executing 'getOneIntersectingObject' on another class type. You cannot check for an intersecting object with an actor ('this') that is not in a world. The other is that all three of the method calls to 'killSlime', 'killOktopus' and 'killSkeleton' are casting the world returned by 'getWorld' to different types without regard to which type it may be. That is, if 'this' is in a Grass world, you will not be able to cast it as a Desert type world -- a ClassCastException error will occur. You must determine which type world it is before casting (use 'instanceof'). To solves these issues, change your act method to this:
public void act() 
{
    move(5);
    if (getWorld() instanceof Grass) killSlime();
    if (getWorld() instanceof Desert) killOktopus();
    if (getWorld() instanceof Cave) killSkeleton();
}
Issue one is avoided because only one of the three calls will be executed.
davmac davmac

2015/5/6

#
danpost wrote...
The other is that all three of the method calls to 'killSlime', 'killOktopus' and 'killSkeleton' are casting the world returned by 'getWorld' to different types without regard to which type it may be.
I'm guessing that each of those world types holds only the one type of object (Slime, Oktopus or Skeleton) so this is not actually a problem - because the cast of the world is only done once a collision with an object of the appropriate type had been detected. I.e. if getOneIntersectingObject(Slime.class) returns non-null, then the world must be an instance of Grass.
You need to login to post a reply.