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

2015/6/20

Help with optimizing my EnemySpawner and Animation Class

miningmanna miningmanna

2015/6/20

#
I really need help with my Classes. I recently i uploaded pixel invaders, but the performance is bad. I´d like to optimize the Animation Class and EnemySpawner. I think they are the source of lagg. My Animation Class:
import greenfoot.*;
import java.util.List;
import java.util.ArrayList;

public class Animation
{
    private static List<Animation> animations = new ArrayList();
    private static List<String> names = new ArrayList();
    
    private Content owner;
    private int frames;
    private int curFrame = 1;
    private List<GreenfootImage> images = new ArrayList();
    private List<Integer> frame = new ArrayList();
    
    public Animation(int frames)
    {
        this.frames = frames;
        add(this, Integer.toString(animations.size()+1));
    }
    
    public Animation(int frames, String name)
    {
        this.frames = frames;
        add(this, name);
    }
    
    public void addImage(GreenfootImage image, int actionFrame)
    {
        images.add(image);
        frame.add(actionFrame);
    }
    
    public void nextFrame()
    {
        int size = images.size();
        for(int i = 0; i<size; i++)
        {
            if(curFrame == frame.get(i))
            {
                owner.setImage(images.get(i));
            }
        }
        curFrame++;
        if(curFrame == frames)
        {
            curFrame = 1;
        }
    }
    
    public void reset()
    {
        curFrame = 0;
    }
    
    public static void add(Animation a, String name)
    {
        animations.add(a);
        names.add(name);
    }
    
    public static void createAnimation(int frames)
    {
        Animation a = new Animation(frames);
    }
    
    public static void createAnimation(int frames, String name)
    {
        Animation a = new Animation(frames, name);
    }
    
    public static Animation getAnimation(String name)
    {
        int size = names.size();
        for(int i = 0; i<size; i++)
        {
            if(names.get(i) == name)
            {
                return animations.get(i);
            }
        }
        return null;
    }
    
    public static Animation setAnimation(Content owner, String name)
    {
        Animation a = getAnimation(name);
        a.setOwner(owner);
        return a;
    }
    
    public static Animation cloneAnimation(String name)
    {
        Animation toClone = getAnimation(name);
        Animation a = new Animation(toClone.getFrames());
        a.setImages(toClone.getImages());
        a.setFrameList(toClone.getFrameList());
        return a;
    }
    
    public List<Integer> getFrameList()
    {
        return frame;
    }
    
    public List<GreenfootImage> getImages()
    {
        return images;
    }
    
    public int getFrames()
    {
        return frames;
    }
        
    public void setOwner(Content owner)
    {
        this.owner = owner;
    }
    
    public void setImages(List images)
    {
        this.images = images;
    }
    
    public void setFrameList(List<Integer> frame)
    {
        this.frame = frame;
    }
    
    public int getCurFrame()
    {
        return curFrame;
    }
}
My EnemySpawner Class:
import greenfoot.*;
import java.util.List;
import java.util.ArrayList;

public class EnemySpawner  
{
    private Game world;
    private List<Enemy> enemys = new ArrayList();
    private Counter c;
    private int enemysPrMin = 10;
    private int enemysTickDelay;
    private List<Integer> moreEnemysScores = new ArrayList();
    private List<Integer> moreEnemysAmount = new ArrayList();
    private int frame;
    
    public EnemySpawner(Game world)
    {
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        enemys.add(new Enemy());
        this.world = world;
        c = world.getCounter();
        enemysTickDelay = 3720/enemysPrMin;
    }
    
    public void act()
    {
        Enemy e = null;
        for(int i = 0; i<enemys.size() && e == null; i++)
        {
            if(enemys.get(i).reset == true)
            {
                e = enemys.get(i);
            }
        }
        for(int i = 0; i<moreEnemysScores.size() && c.getCount() != moreEnemysScores.get(i); i++)
        {
            if(c.getCount() == moreEnemysScores.get(i))
            {
                enemysPrMin += moreEnemysAmount.get(i);
                enemysTickDelay = 3720/enemysPrMin;
                moreEnemysScores.remove(i);
                moreEnemysAmount.remove(i);
            }
        }
        if(frame % enemysTickDelay == 0)
        {
            world.addObject(e, 910, 20+Greenfoot.getRandomNumber(560));
        }
        frame++;
        if(frame == 600)
        {
            frame = 1;
        }
    }
    
    public void addEnemysAt(int score, int amount)
    {
        moreEnemysScores.add(score);
        moreEnemysAmount.add(amount);
    }
}
danpost danpost

2015/6/20

#
First, each element of your 'animations' List should probably be in their respective classes. Have the Animation class deal with only a single set of images (the active set for the actor). That would simplify the Animation class code and allow the class of the actor to control what animation to use when (by just changing the image set). Second, since the number of images in each animation is fixed (the number of images for any animation does not change), an Array would be a better choice for the images (rather than an ArrayList), and I do not see the sense in having the 'frame' List<Integer> (I may be missing something here; but, I kind of doubt it). The block of code in your EnemySpawner class from lines 52 through 57 above will never execute. The 'if' condition (line 51) will always be opposite the loop condition (line 49). So if the condition was true to process the loop, the if condition check will be false. If the loop condition was false, the if condition check will not be processed (the loop is discontinued).
miningmanna miningmanna

2015/6/21

#
To the List<Integer> frame i have to say it only contains the frame, that the image in the list images (with the same index as the actFrame), should act at that frame. (what i understand) Its smarter to do this:
int[] frame;

public Animation(int frames)
{
    frame = new int[frames];
}
than adding only the frame number of the frame that should change the image
danpost danpost

2015/6/21

#
It would be better just to use 'frames.size()' if 'frames' was a List object or 'frames.length' if 'frames' was an array. There is no need to add duplicate fields (fields that hold the same data as fields that already exist; in this case, in either the List class or the Array class).
miningmanna miningmanna

2015/6/21

#
ahh ok i see thanks (by the way i thought it would use more cpu if you call the method for every loop)
danpost danpost

2015/6/21

#
You should be able to see immediately from the use of your 'for' loops that your way would be more cpu intensive. These method calls, on the other hand, are quick and simple (just returning values that are already saved in fields -- no counting required).
You need to login to post a reply.