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

2013/8/18

Collision Detection Transparency?

DuctTapeTardis DuctTapeTardis

2013/8/18

#
Do any of you know a good way to make collisions only happen on non-transparent pixels of an Actor? If two actors collide, I want to check and see if the actors are touching VISUALLY, and not if one is in the other's rectangle. Could you give me an example in code please? It would be very helpful.
Some people have coded that themselves actually. Here's an example, Game/Maniac did this for his sprite sheet slicer (make sure to give him credit!): http://www.greenfoot.org/scenarios/8502
DuctTapeTardis DuctTapeTardis

2013/8/18

#
Thank you! I will check that out.
DuctTapeTardis DuctTapeTardis

2013/8/18

#
His method actually didn't work. Can I get a different method? Thanks.
It didn't? Did you make a subclass of the actor class he had (or put his method into your actor subclass)?
danpost danpost

2013/8/19

#
I coded the following in the post window and have not tested it. However, it should be real close to what you need.
// getting the intersecting actor and calling the method
Actor intersector = getOneIntersectingObject(null);
boolean visuallyIntersecting = isVisuallyIntersecting(intersector);

// the method, using 'A' for 'this' and 'B' for 'actor'
private boolean isVisuallyIntersecting(Actor actor)
{
    // get width and height of images
    int wA = getImage().getWidth();
    int hA = getImage().getHeight();
    int wB = actor.getImage().getWidth();
    int hB = actor.getImage().getHeight();
    // get world coordinates of origin point (0, 0) of images
    int xAw = getX()-wA/2;
    int yAw = getY()-hA/2;
    int xBw = actor.getX()-wB/2;
    int yBw = actor.getY()-hB/2;
    // determine (x, y) on each image to begin checking from
    // and dimensions of area to check
    int xA = 0, yA = 0, xB = 0, yB = 0; // initialize start coord fields
    int w = 0, h = 0; // initialize scan dimension fields
    // determine values for fields just initialized
    if (xAw > xBw)
    {
        xB = xAw-xBw;
        if (xAw+wA > xBw+wB) w = wB-xB; else w = wA;
    }
    else
    {
        xA = xBw-xAw;
        if (xBw+wB > xAw+wA) w = wA-xA; else w = wB;
    }
    if (yAw > yBw)
    {
        yB = yAw-yBw;
        if (yAw+hA > yBw+hB) h = hB-yB; else h = hA;
    }
    else
    {
        yA = yBw-yAw;
        if (yBw+hB > yAw+hA) h = hA-yA; else h = hB;
    }
    // perform checking
    Color trans = new Color(0, 0, 0, 0);
    for (int x=0; x<w; x++) for (int y=0; y<h; y++)
    {
        if (!trans.equals(getImage().getColorAt(xA+x, yA+y) &&
            !trans.equals(actor.getImage().getColorAt(xB+x, yB+y)) return true;
    }
    return false;
}
DuctTapeTardis DuctTapeTardis

2013/8/19

#
Thank you danpost. With a little tweaking, your code worked perfectly. Is there a way to upvote posts? And FlyingRabidUnicornPig, I put the method in my actor subclass, but it just wasn't working. Oh well, problem still solved. Thanks for your help.
danpost danpost

2013/8/19

#
Please explain how you tweaked it and post the code you ended up with. Also: what exactly do you mean by 'upvote posts'?
DuctTapeTardis DuctTapeTardis

2013/8/19

#
 public void enemyCollision()
    {
        if (getWorld() != null)
        {
            Enemies collision = (Enemies)getOneIntersectingObject(Enemies.class);  
            if (collision != null)
            {
                boolean visuallyIntersecting = isVisuallyIntersecting(collision);  
                if (visuallyIntersecting)
                {
                    
                }
            }
        }
    }

private boolean isVisuallyIntersecting(Actor actor)  
    {  
        // get width and height of images  
        int wA = getImage().getWidth();  
        int hA = getImage().getHeight();  
        int wB = actor.getImage().getWidth();  
        int hB = actor.getImage().getHeight();  
        // get world coordinates of origin point (0, 0) of images  
        int xAw = getX()-wA/2;  
        int yAw = getY()-hA/2;  
        int xBw = actor.getX()-wB/2;  
        int yBw = actor.getY()-hB/2;  
        // determine (x, y) on each image to begin checking from  
        // and dimensions of area to check  
        int xA = 0, yA = 0, xB = 0, yB = 0; // initialize start coord fields  
        int w = 0, h = 0; // initialize scan dimension fields  
        // determine values for fields just initialized  
        if (xAw > xBw)  
        {  
            xB = xAw-xBw;  
            if (xAw+wA > xBw+wB) w = wB-xB; else w = wA;  
        }  
        else  
        {  
            xA = xBw-xAw;  
            if (xBw+wB > xAw+wA) w = wA-xA; else w = wB;  
        }  
        if (yAw > yBw)  
        {  
            yB = yAw-yBw;  
            if (yAw+hA > yBw+hB) h = hB-yB; else h = hA;  
        }  
        else  
        {  
            yA = yBw-yAw;  
            if (yBw+hB > yAw+hA) h = hA-yA; else h = hB;  
        }  
        // perform checking  
        java.awt.Color trans = new java.awt.Color(0, 0, 0, 0);  
        for (int x=0; x<w; x++) for (int y=0; y<h; y++)  
            {  
                if (!trans.equals(getImage().getColorAt(xA+x, yA+y)) &&  
                    !trans.equals(actor.getImage().getColorAt(xB+x, yB+y))) 
                    return true;
        }  
        return false;  
    }  
I just fixed a few errors and changed the getOneIntersectingObject(null) to getOneIntersectingObject(Enemies.class) And forget about the upvote thing. I have an answer.
danpost danpost

2013/8/19

#
I was concerned when you said you tweaked it that the code I posted was error-filled. However, looking at what you changed, it was just line 55 (your code post) requiring the Color class which could have been imported. Glad to be of some help and that you got it fixed.
Busch2207 Busch2207

2013/8/19

#
This first method recognizes the rotation of the Actors:
public boolean touch(Actor A)
    {
        double d_Hypot=Math.hypot(getImage().getWidth(),getImage().getHeight());
        GreenfootImage i=new GreenfootImage((int)d_Hypot,(int)d_Hypot);
        i.drawImage(getImage(),i.getWidth()/2-getImage().getWidth()/2,i.getHeight()/2-getImage().getHeight()/2);
        i.rotate(getRotation());
        int w=i.getWidth(),h=i.getHeight(),x=getX(),y=getY();

        GreenfootImage Ai = A.getImage();
        d_Hypot=Math.hypot(Ai.getWidth(),Ai.getHeight());
        GreenfootImage
        i2=new GreenfootImage((int)d_Hypot,(int)d_Hypot);
        i2.drawImage(Ai,i2.getWidth()/2-Ai.getWidth()/2,i2.getHeight()/2-Ai.getHeight()/2);
        i2.rotate(A.getRotation());
        Ai=i2;

        i2 = new GreenfootImage(w,h);
        int Aw=Ai.getWidth(),Ah=Ai.getHeight(),Ax=A.getX(),Ay=A.getY();
        i2.drawImage(Ai,Ax-x-(Aw/2-w/2),Ay-y-(Ah/2-h/2));
        for(int yi = 0; yi<h ; yi++)
            for(int xi = 0; xi<w ; xi++)
                if(i2.getColorAt(xi,yi).getAlpha()>0 && i.getColorAt(xi,yi).getAlpha()>0)
                {
                    return true;
        }
        return false;
    }
This one ignores the rotation of the Actors (and so it's much faster, of course):
public boolean touch(Actor A)
    {
        GreenfootImage i=getImage();
        int w=i.getWidth(),h=i.getHeight(),x=getX(),y=getY();

        GreenfootImage Ai = A.getImage(),
        i2 = new GreenfootImage(w,h);
        int Aw=Ai.getWidth(),Ah=Ai.getHeight(),Ax=A.getX(),Ay=A.getY();
        i2.drawImage(Ai,Ax-x-(Aw/2-w/2),Ay-y-(Ah/2-h/2));
        boolean b = true;
        for(int yi = 0; yi<h && b; yi++)
            for(int xi = 0; xi<w && b; xi++)
                if(i2.getColorAt(xi,yi).getAlpha()>0 && i.getColorAt(xi,yi).getAlpha()>0)
                    b=false;
        return !b;
    }
I'm using this methods in many of my games! :)
You need to login to post a reply.