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

2016/11/24

Problems with making a Object find itself in an Arraylist

Tritos Tritos

2016/11/24

#
Hey, I am currently working on a small sidescrolling Jump 'n' Run Game and have just added a horizontally scrolling "camera". However recently I have run into some problems with this "camera" The whole project already got a bit out of hand and complicated (atleast in my opinion). Therefore I will try to keep everything as simple as possible. To make the camera work I created a Arraylist, to wich all the Actors are added with there corresponding X- and Y-coordinates. A method checks in every frame for every Object if they are in the camera or not. If they are not they will be removed. If they are in the camera they will be removed and replaced at the position that is in the Arraylist Therefore I have to change the X- and Y-coordinates if I have (for example) a moving Actor. I already did that for my main player. However I only was able to because I made sure that he is in position "0" in this list before hand. Now I want to add some basic enemies that walk in a constant speed, so their position in the Arraylist needs to be changed too. So I need to find out in what position in the list they are. However the way a friend of mine showed me does not work.
int index = getWorld().getObjects(WorldActor.class).get(0).getIndexOfObject(this);
( WorldActor is the Object the world is created in and contains the list. getIndexOfObject() is a method in WorldActor
public int getIndexOfObject (Object o)
    {
        return obj.indexOf(o);
    }
obj is the name of the Arraylist ) In this case the game crashes, because it thinks index is -1.... Every single idea is much appreciated. Tritos
danpost danpost

2016/11/24

#
It would be best just to unbound your world to allow actors to remain "in" the world while not currently within the window of the world. This not only makes your code a lot easier, but also creates a smooth transition between in and out of view. Please review the constructors within the World class API documentation for details.
Tritos Tritos

2016/11/24

#
Hey danpost, thanks for your quick response. I like your idea. However I would really like to stay with my basic concept, because I came up with it myself and it kind of works (atleast it has been working). I dont really want to write code right now that I would never have come up with myself. Also I thought that it couldnt be to hard to check what position in a list a object is (maybe I am wrong about that?). If you can imagine some way of getting my code to work or can just give me a small tip I would be very happy Thanks again Tritos
danpost danpost

2016/11/24

#
No code is much better than any code you can create; especially when the code you are creating will probably hog CPU time and cause your project to lag.
Tritos Tritos

2016/11/24

#
Well okay then, I will try it out. Thanks for the support ;)
danpost danpost

2016/11/24

#
Btw, you might want to check out my Scrolling Tutorial scenario.
Tritos Tritos

2016/11/24

#
I already did a while back, but I thought the Supper world was a bit overcomplicated... I have one quick question that might be a bit offtopic. If I want to know how many Objects exist in the World how do I do that. I started with
getWorld().getObjects()
but I dont know any further...
danpost danpost

2016/11/24

#
You could try:
int objectCount = getWorld().getObjects().size();
But, you could also just do this:
int objectCount = getWorld().numberOfObjects();
danpost danpost

2016/11/24

#
Tritos wrote...
I already did a while back, but I thought the Supper world was a bit overcomplicated
The 'Supper' (or 'Super") world? there is no such world in the tutorial. Or, maybe there is a bit of a misunderstanding here. I think you are referring to my Scrolling SuperWorld scenario, which was done years ago. Though not written badly, it is a bit much. Through time, I have refined the scrolling class to what I think to be in the most basic terms and the easiest to use. I really think you should check it out.
Tritos Tritos

2016/11/24

#
Oh, ok yeah, I was referring to the Scrolling SuperWorld. Sorry for that I sadly cant open the other scenario, because neither Chrome, IE, or Edge allow me to. They all just say.
Your browser is ignoring the <APPLET> tag
danpost danpost

2016/11/24

#
Alright, well the Scrolling class has this code:
import greenfoot.*;
/**
 * CLASS: Scroller extend Object
 * AUTHOR: danpost (greenfoot.org username)
 * DATE: November 11, 2016
 * 
 * DESCRIPTION:  This is a support class for a scrolling world.  It contains two constructors;
 * one for unlimited scrolling and one for limited scrolling.  Both constructors have an 'image'
 * parameter.  Because image manipulation can hog up CPU time, it is important to remember that
 * it is better not to have a scrolling background image (having an Actor for the background is
 * probably worse than having the background scroll).  For unlimited scrolling using a background
 * image, the smaller that background image to be tiled, the better.  Making the viewport (the
 * size of the world that is visible) smaller can help in CPU expense, also.  Scrolling worlds
 * should be unbounded, allowing actors to move beyond the visible area.  Ensuring that actors
 * are removed from the world if no longer needed when out of view will help to prevent lag,
 * as well.  
 * 
 * It is the responsibility of the World object that creates a Scroller object to determine when
 * to scroll and by how much.
 */
public class Scroller
{
    private World world; // view window world
    private GreenfootImage scrollImage; // scrolling image
    private boolean limited;
    private int scrolledX, scrolledY;
        
    /**
     * This constructor is for an unlimited scrolling world;
     * If 'image' is null, the background will not change; else the given image is wrapped
     * 
     * @param viewWorld the world that scrolling will be performed on
     * @param image the background image that will be tiled, if needed, and wrap with scrolling
     */
    public Scroller(World viewWorld, GreenfootImage image)
    {
        world = viewWorld;
        scrollImage = image;
        scroll(0, 0); // sets initial background image
    }
    
    /**
     * This constructor is for a limited scrolling world;
     * If 'image' is smaller than the given total scrolling area, it will be tiled
     * If 'image' is null, the background will not change
     * 
     * @param viewWorld the world that scrolling will be performed on
     * @param image the background image that will be tiled, if needed, to fill the scrolling area
     * @param wide the width of the visible area encompassed through scrolling;
     * the given value must be at least equal to the width of 'viewWorld' and
     * is given in world cells (not in pixels)
     * @param high the height of the visible area encompassed through scrolling;
     * the given value must be at least equal to the height of 'viewWorld' and
     * is given in world cells (not in pixels)
     */
    public Scroller(World viewWorld, GreenfootImage image, int wide, int high)
    {
        limited = true;
        world = viewWorld;
        if (image != null)
        {
            // create an image as large as scrolling area; tiled, if needeed
            scrollImage = new GreenfootImage(wide*world.getCellSize(), high*world.getCellSize());
            for (int x=0; x<wide*world.getCellSize(); x+= image.getWidth())
                for (int y=0; y<high*world.getCellSize(); y+=image.getHeight())
                    scrollImage.drawImage(image, x, y);
            // set initial background image
            scroll(0, 0);
        }
    }
    
    /**
     * performs scrolling on 'world' by the given distances along the horizontal and vertical;
     * if 'limited' is false, requested distances are actual scrolling distances;
     * if 'limited' is true, the distances may be adjusted due to the limits of scrolling
     *
     * @param dsx the requested distance to shift everything horizontally
     * @param dsy the requested distance to shift everything vertically
     */
    public void scroll(int dsx, int dsy)
    {
        if (scrollImage != null)
        {
            if (limited)
            {
                // calculate limits of scrolling
                int maxX = scrollImage.getWidth()/world.getCellSize()-world.getWidth();
                int maxY = scrollImage.getHeight()/world.getCellSize()-world.getHeight();
                // apply limits to distances to scroll
                if (scrolledX+dsx < 0) dsx = -scrolledX;
                if (scrolledX+dsx >= maxX) dsx = maxX-scrolledX;
                if (scrolledY+dsy < 0) dsy = -scrolledY;
                if (scrolledY+dsy >= maxY) dsy = maxY-scrolledY;
                // update scroll positions
                scrolledX += dsx;
                scrolledY += dsy;
                // adjust background image
                world.getBackground().drawImage
                (   
                    scrollImage,
                    -scrolledX*world.getCellSize(),
                    -scrolledY*world.getCellSize()
                );
            }
            else
            {
                // update scroll positions
                scrolledX += dsx;
                scrolledY += dsy;
                // create working variables of scroll positions
                int imageX = scrolledX*world.getCellSize();
                int imageY = scrolledY*world.getCellSize();
                // find a similar positive value for scroll positions
                while (imageX < 0) imageX += 100*scrollImage.getWidth();
                while (imageY < 0) imageY += 100*scrollImage.getHeight();
                // get new starting positions for drawing 'scrollImage'
                imageX = imageX%scrollImage.getWidth();
                imageY = imageY%scrollImage.getHeight();
                // create image of appropriate size and tile fill 'scrollImage' onto it
                GreenfootImage hold = new GreenfootImage(scrollImage);
                hold.drawImage(scrollImage, -imageX, -imageY);
                if (imageX > 0) hold.drawImage(scrollImage, scrollImage.getWidth()-imageX, -imageY);
                if (imageY > 0) hold.drawImage(scrollImage, -imageX, scrollImage.getHeight()-imageY);
                if (imageX > 0 && imageY > 0)
                    hold.drawImage(scrollImage, scrollImage.getWidth()-imageX, scrollImage.getHeight()-imageY);
                // set image to background of 'world'
                world.setBackground(hold);
            }
        }
        // adjust position of all actors (that can move with 'setLocation')
        for (Object obj : world.getObjects(null))
        {
            Actor actor = (Actor) obj;
            actor.setLocation(actor.getX()-dsx, actor.getY()-dsy);
        }
    }
    
    /**
     * getter method for the current total scrolled distance horizontally
     *
     * @return the current total offset of horizontal scrolling
     */
    public int getScrolledX()
    {
        return scrolledX;
    }
    
    /**
     * getter method for the current total scrolled distance vertically
     *
     * @return the current total offset of vertical scrolling
     */
    public int getScrolledY()
    {
        return scrolledY;
    }
}
Notice that it has only three methods and two constructors. The world that scrolls should have the following in it:
// instance reference field for Scroller object
private Scroller scroller;

// create Scroller object in world constructor
scroller = new Scroller(this, new GreenfootImage("background.jpg"), 600, 400); // for example

// in act method
scroll(); // to call following method added to world class

// the 'scroll' method
private void scroll()
{
    // determine amount to scroll (dsx, dsy)
    scroller.scroll(dsx, dsy); // have scroller scroll world
}
That is pretty much it.
danpost danpost

2016/11/24

#
Oh -- I also wanted to mention what to do with objects you do not want to be moved when scrolling. Add the following line to any class that creates those objects (usually counters, timers, buttons, maps, text messages or other types of gui components):
public void setLocation(int x, int y) { }
Tritos Tritos

2016/11/24

#
Thanks for your help. I really appreciate it. However I now have exactly the problem I was trying to avoid. I am adding code into my programm that i didnt write and do not fully understand... It doesnt work and I do not how to fix it because of the reasons mentioned. That is why I wanted to stay with my own concept. It might not be perfect and most likely not efficient at all, but I wrote it myself and most importantly I do understand every single word I wrote. Please do not take this personally you're doing great work and are very helpful. However for beginners its often better to take the easy way instead of the right one. It is getting late for me I am going to sleep now. I will keep trying around with the code tomorrow. I might get back to you then.
danpost danpost

2016/11/25

#
If you really wanted to go your route, then maybe adding x and y fields to the actor subclasses would help. Set their values at the end of the act method (as well as in the 'addedToWorld' method, which is needed for those actors that do not move or anything). Then, you only need a list of actors (without the cooresponding coordinates because the actors already have them stored). With this, the actors do not need to know where exactly in the list they are located.
// in Actor subclasses
public int x, y;

protected void addedToWorld(World world)
{
    x = getX();
    y = getY();
}

// the end of the act method (if there is one)
    x = getX();
    y = getY();
}
Now, when scrolling, you can check the x and y to see if actor is in view or not, adjust the x and y values and remove and add the actors from the world as needed, except for the fact that you would have to go through all the possible classes to see what type each actor is before you can access their x and y values. Instead of the above, maybe it would help to have an interim class between Actor and the particular subclasses -- call it ScrollActor -- to keep track of the x and y values (without needing to do anything to all the other classes except change what class they extend to this one):
import greenfoot.*;

public class ScrollActor extends Actor
{
    public int x;
    public int y;

    protected void addedToWorld(World world)
    {
        x = getX();
        y = getY();
    }

    public void setLocation(int xLoc, int yLoc)
    {
        super.setLocation(xLoc, yLoc);
        x = getX();
        y = getY();
    }

    public void move(int dist)
    {
        super.move(dist);
        x = getX();
        y = getY();
    }
}
Then, your list only need consist of ScrollActor objects and the x and y values will be easily accessible.
danpost danpost

2016/12/23

#
I had to correct some code in my Scroller class. The revised class code is as follows:
import greenfoot.*;
/**
 * CLASS: Scroller (extends Object)
 * AUTHOR: danpost (greenfoot.org username)
 * DATE: November 11, 2016
 * MODIFIED: December 22, 2016 (fixed 'scroll' method for limited no-image scrolling)
 * MODIFIED: February 21, 2017 (fixed scroll offsets for unlimited no-image scrolling)
 * 
 * DESCRIPTION:  This is a support class for a scrolling world.  It contains two constructors;
 * one for unlimited scrolling and one for limited scrolling.  Both constructors have an 'image'
 * parameter.  Because image manipulation can hog up CPU time, it is important to remember that
 * it is better not to have a scrolling background image (having an Actor for the background is
 * probably worse than having the background scroll).  For unlimited scrolling using a background
 * image, the smaller that background image to be tiled, the better.  Making the viewport (the
 * size of the world that is visible) smaller can help in CPU expense, also.  Scrolling worlds
 * should be unbounded, allowing actors to move beyond the visible area.  Ensuring that actors
 * are removed from the world if no longer needed when out of view will help to prevent lag,
 * as well.  
 * 
 * It is the responsibility of the World object that creates a Scroller object to determine when
 * to scroll and by how much.
 */
public class Scroller
{
    private World world; // view window world
    private GreenfootImage scrollImage; // scrolling image
    private boolean limited; // flag to indicate whether scrolling is limited or not
    private int scrolledX, scrolledY; // current scrolled distances
    private int wide, high; // if limited, dimensions of scrolling area else of image to wrap
  
    /**
     * This constructor is for an unlimited scrolling world;
     * If 'image' is null, the background will not change; else the given image is wrapped
     * 
     * @param viewWorld the world that scrolling will be performed on
     * @param image the background image that will be tiled, if needed, and wrap with scrolling
     */
    public Scroller(World viewWorld, GreenfootImage image)
    {
        world = viewWorld;
        scrollImage = image;
        if (image != null)
        {
            wide = image.getWidth();
            high = image.getHeight();
        }
        scroll(0, 0); // sets initial background image
    }
  
    /**
     * This constructor is for a limited scrolling world;
     * If 'image' is smaller than the given total scrolling area, it will be tiled
     * If 'image' is null, the background will not change
     * 
     * @param viewWorld the world that scrolling will be performed on
     * @param image the background image that will be tiled, if needed, to fill the scrolling area
     * @param wide the width of the visible area encompassed through scrolling;
     * the given value must be at least equal to the width of 'viewWorld' and
     * is given in world cells (not in pixels)
     * @param high the height of the visible area encompassed through scrolling;
     * the given value must be at least equal to the height of 'viewWorld' and
     * is given in world cells (not in pixels)
     */
    public Scroller(World viewWorld, GreenfootImage image, int wide, int high)
    {
        this.wide = wide;
        this.high = high;
        limited = true;
        world = viewWorld;
        if (image != null)
        {
            // create an image as large as scrolling area; tiled, if needeed
            scrollImage = new GreenfootImage(wide*world.getCellSize(), high*world.getCellSize());
            for (int x=0; x<wide*world.getCellSize(); x+= image.getWidth())
                for (int y=0; y<high*world.getCellSize(); y+=image.getHeight())
                    scrollImage.drawImage(image, x, y);
            // set initial background image
            scroll(0, 0);
        }
    }
  
    /**
     * performs scrolling on 'world' by the given distances along the horizontal and vertical;
     * if 'limited' is false, requested distances are actual scrolling distances;
     * if 'limited' is true, the distances may be adjusted due to the limits of scrolling
     *
     * @param dsx the requested distance to shift everything horizontally
     * @param dsy the requested distance to shift everything vertically
     */
    public void scroll(int dsx, int dsy)
    {
        // adjust scroll amounts and scroll background image
        if (limited)
        {
            // calculate limits of scrolling
            int maxX = wide-world.getWidth();
            int maxY = high-world.getHeight();
            // apply limits to distances to scroll
            if (scrolledX+dsx < 0) dsx = -scrolledX;
            if (scrolledX+dsx >= maxX) dsx = maxX-scrolledX;
            if (scrolledY+dsy < 0) dsy = -scrolledY;
            if (scrolledY+dsy >= maxY) dsy = maxY-scrolledY;
            // update scroll positions
            scrolledX += dsx;
            scrolledY += dsy;
            // scroll background image
            if (scrollImage != null)
            {
                world.getBackground().drawImage
                (   
                    scrollImage,
                    -scrolledX*world.getCellSize(),
                    -scrolledY*world.getCellSize()
                );
            }
        }
        else // unlimited image wrapping
        {
            // update scroll positions
            scrolledX += dsx;
            scrolledY += dsy;
            // scroll background image
            if (scrollImage != null)
            {
                // create working variables of scroll positions
                int imageX = scrolledX*world.getCellSize();
                int imageY = scrolledY*world.getCellSize();
                // get near-zero starting positions for drawing 'scrollImage'
                imageX = imageX%wide;
                imageY = imageY%high;
                // adjust negative values as needed
                if (imageX < 0) imageX += wide;
                if (imageY < 0) imageY += high;
                // create image of appropriate size and tile fill 'scrollImage' onto it
                GreenfootImage hold = new GreenfootImage(scrollImage);
                hold.drawImage(scrollImage, -imageX, -imageY);
                if (imageX > 0) hold.drawImage(scrollImage, wide-imageX, -imageY);
                if (imageY > 0) hold.drawImage(scrollImage, -imageX, high-imageY);
                if (imageX > 0 && imageY > 0)
                    hold.drawImage(scrollImage, wide-imageX, high-imageY);
                // set image to background of 'world'
                world.setBackground(hold);
            }
        }
        // adjust position of all actors (that can move with 'setLocation')
        for (Object obj : world.getObjects(null))
        {
            Actor actor = (Actor) obj;
            actor.setLocation(actor.getX()-dsx, actor.getY()-dsy);
        }
    }
  
    /**
     * getter method for the current total scrolled distance horizontally
     *
     * @return the current total offset of horizontal scrolling
     */
    public int getScrolledX()
    {
        return scrolledX;
    }
  
    /**
     * getter method for the current total scrolled distance vertically
     *
     * @return the current total offset of vertical scrolling
     */
    public int getScrolledY()
    {
        return scrolledY;
    }
}
You need to login to post a reply.