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

2017/2/24

serious lagging

tmargaret tmargaret

2017/2/24

#
Hello everyone, I want to ask a general question and if it's necessary I could be more specific by posting code etc. As I'm building my game, I'm getting an out of memory message more and more often. So far, my character after few seconds is moving really slowly. I have plenty of classes and lots of codelines and I don't know where to start searching from! Is there some general rules I should follow? for example where to look first? What could possibly is causing this huge lagging etc. thank you
danpost danpost

2017/2/24

#
Usually, that kind of lagging is due to too many actors in the world. When it starts to lag, pause the scenario and right click on the world and select the 'numberOfObjects' method call to see how many you have. If the number is much larger than expected, then look through your code to places you use the 'new' keyword. Look for them especially in your Actor subclasses and within loop structures. Oftentimes, beginners fall in the trap of adding objects of a class from within their own class when they should be added them from the world.
tmargaret tmargaret

2017/2/26

#
So, I followed your advice and I found the problem. I have this HiddenSprite() class, which draws a rectangle over one Actor character, so as to achieve a better collision, or in other words, a collision under circumstances.
import greenfoot.*; 
import java.awt.Color; 
import java.util.*;

public class HiddenSprite extends Actor {  
    GreenfootImage body;  
    int offsetX;  
    int offsetY;  
    Actor host;    
    
    public HiddenSprite(Actor a, int w, int h, int dx, int dy, boolean visible) {    
        host = a;   
        offsetX = dx;    
        offsetY = dy;    
        body = new GreenfootImage(w, h);    
        if( visible ) {      
            // Transparency values range from 0 (invisible) to 255 (opaque) 
            body.setColor(Color.RED);
            body.fill();
            body.setTransparency(200);          
        }    
        setImage(body);  
    }    
    
    public void act() {    
        if( host.getWorld() != null ) {      
            setLocation(host.getX()+offsetX, host.getY()+offsetY);    
        } else {      
            getWorld().removeObject(this);    
        }  
    }    
    
    public List getHitBoxIntersections() {    
        return getIntersectingObjects(Actor.class);  
    } 
}
The problem is that I call this HiddenSprite(), in the act() class of every actor like this:
   public void act() 
    {
        addHiddenSprite();
        elderDialog();  
    }
    
        protected void addHiddenSprite() {   
  //this line creates the HidderSprite object, in every cycle?!!
        hs = new HiddenSprite(this, getImage().getWidth() + getImage().getWidth()/2 , 40, 10, 5, true);  
        getWorld().addObject(hs, getX(), getY()); 
    }
    
     public void elderDialog(){
        
        if( hs.getWorld() != null ) {   
            List<Actor> things = hs.getHitBoxIntersections();    
            if( things.size() > 1 ) {      
                int infront = 0;      
                for(int i=0; i < things.size(); i++ ) {       
                    Actor a = things.get(i);        
                    if(a instanceof HiddenSprite)        
                    continue;        
                    if( a instanceof Robot) {  
                        counter--;
                        if (counter<0 && !isActive){
                            helloText = new TextPanel("welcomeMsg");
                            getWorld().addObject(helloText, getWorld().getWidth()/2, getWorld().getHeight()/2);
                            isActive = true;
                        }
                        if (Greenfoot.isKeyDown("enter") && count_enter == 0 && counter<0){
                            counter = 20;
                            getWorld().removeObject(helloText);
                            taskText = new TextPanel("taskText");
                            getWorld().addObject(taskText, getWorld().getWidth()/2, getWorld().getHeight()/2);
                            count_enter = 1;
                        }
                        if (Greenfoot.isKeyDown("enter") && count_enter == 1 && counter <0){
                            counter = 30;
                            getWorld().removeObject(taskText);
                            taskText2 = new TextPanel("taskText2");
                            getWorld().addObject(taskText2, getWorld().getWidth()/2, getWorld().getHeight()/2);
                            count_enter = 2;
                        }
                        if (Greenfoot.isKeyDown("enter") && count_enter == 2 && counter <0){
                            counter = 30;
                            getWorld().removeObject(taskText2);
                            taskText3 = new TextPanel("taskText3");
                            getWorld().addObject(taskText3, getWorld().getWidth()/2, getWorld().getHeight()/2);
                            count_enter = 3;
                        }
                        if (Greenfoot.isKeyDown("enter") && count_enter == 3 && counter <0){
                            counter = 30;
                            getWorld().removeObject(taskText3);
                            taskText4 = new TextPanel("taskText4");
                            getWorld().addObject(taskText4, getWorld().getWidth()/2, getWorld().getHeight()/2);
                            count_enter = 4;
                        }
                        if (Greenfoot.isKeyDown("enter") && count_enter == 4 && counter <0){
                            counter = 30;
                            getWorld().removeObject(taskText4);
                            taskText5 = new TextPanel("taskText5");
                            getWorld().addObject(taskText5, getWorld().getWidth()/2, getWorld().getHeight()/2);
                            count_enter = 5;
                        }
                    }      
                   }
                }
            }
        }
}
Should I use an if-statement to allow the object to be created only once, or is there another, better way?
Super_Hippo Super_Hippo

2017/2/26

#
Try to only add it once like this:
protected void addedToWorld(World w)
{
    addHiddenSprite();
}
Remove the call to the 'addHiddenSprite' method from the act method (= remove line 3).
tmargaret tmargaret

2017/2/26

#
Thanks a lot! That really helped. I have another question as well. I have an Actor enemy and I want him to blink his eyes every couple of seconds, in other words to change between 2 images. Is it better to do this by using 2 counting variables or I should count the cycles using timer etc?
danpost danpost

2017/2/26

#
You can use just one counter. Start it at a value of how many cycles from the start of one image to the next start of the same image (maybe 200). Have the image change at some point before it reaches zero (maybe 20) and back when it reaches zero, when the counter is reset.
Nosson1459 Nosson1459

2017/2/27

#
tmargaret wrote...
I have an Actor enemy and I want him to blink his eyes every couple of seconds,...?
If you want it every couple of seconds then you can do:
// outside all methods
private int timer = Greenfoot.getRandomNumber(100) + 200;

// code for changing the image (in act or method called in act method)
timer--;
if (timer == 30)
{
    setImage(new GreenfootImage("file name for closed eyes"));
}
else if (timer == 0)
{
    setImage(new GreenfootImage("file name for opened eyes"));
    timer = Greenfoot.getRandomNumber(100) + 200;
}
I haven't done testing with the act cycles per minute so it could be that what danpost suggested is better but I just thought that it looks like too small of a number.
tmargaret tmargaret

2017/2/27

#
So I used dapost's suggestion. I had to use 3 if's so as to keep the eyes closed a little longer. If you have any better solution let me know!
public void blink(){
        eyes_counter--;
        System.out.println(eyes_counter);
        if (eyes_counter > 10){
            setImage(knight); 
        }
        if (eyes_counter < 10){
            setImage(knight_eyes);
            if (eyes_counter == 0){
                eyes_counter = 150;
            }
        }
    }
thanks
danpost danpost

2017/2/27

#
With your code (which is fine, by the way), you have the image changing when 'eyes_counter' is 149 and 9; this can be simplified by changing at 150 (or 0) and 10. I prefer to increment my counters from zero to avoid having to set a default value to the counters, like with the following, which changes at 140 and 150 (or 0)::
public void blink()
{
    if (++eyes_counter == 150){
        eyes_counter = 0;
        setImage(knight);
    }
    else if (eyes_counter == 140){
        setImage(knight_eyes);
    }
}
Nosson1459 Nosson1459

2017/2/28

#
tmargaret wrote...
So I used dapost's suggestion....
We had the same idea just I used a random number so the amount of time it takes for the blink will be different every time.
tmargaret tmargaret

2017/2/28

#
Great, thanks both of you!
You need to login to post a reply.