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

2021/4/25

Not landing correctly (platformer)

CreatorMoon CreatorMoon

2021/4/25

#
I'm currently trying to recreate the rhythmic platformer game Geometry Dash in Greenfoot (if you are unfamiliar with the game, here is how it is supposed to work: I haven't coded in the spikes yet, as I am having a few issues with the blocks. Whenever I land on a block, my character goes about halfway into the block instead of landing on the top of it like it's supposed to. My player code:
import greenfoot.*;
public class Cube extends Actor
{
    int direction = 5;
    int vSpeed = 0;
    int acceleration = 1;
    int jumpStrength = -5;
    public void act()
    {
        checkKeys();
        checkFall();
        jump();
        setLocation(getX()+direction,getY());
    }
    public void checkKeys()
    {
        if(Greenfoot.isKeyDown("space"))
        {
            jump();
        }
    }
    public void jump()  
    {
        if (Greenfoot.isKeyDown("space") && onBlock())
        {
            vSpeed = jumpStrength;  
            fall();  
        }
        if (Greenfoot.isKeyDown("space") && onGround())
        {
            vSpeed = jumpStrength;  
            fall();  
        }
    }
    public void fall()  
    {
        setLocation(getX(), getY()+vSpeed);  
        vSpeed = vSpeed + acceleration;  
    }
    public boolean onBlock()  
    {
        Actor blockUnder = getOneObjectAtOffset (0, getImage().getHeight()/2, Block.class);
        return blockUnder != null;
    }
    public boolean onGround()  
    {
        Actor groundUnder = getOneObjectAtOffset (0, getImage().getHeight()/2, Ground.class);
        return groundUnder != null;
    }
    public void checkFall()  
    {
        if (onBlock())
        {
            vSpeed = 0;  
        }
        else if (onGround())
        {
            vSpeed = 0;
        }
        else
        {
            fall();
        }
    }
}
As can be seen, I have already coded landing on the ground, and it works perfectly fine, so I am a bit confused as to why the blocks aren't working. Any help would be highly appreciated. (P.S. both my character and the blocks have a file size of 30x30. The ground, which works, has a file size of 150x150)
danpost danpost

2021/4/26

#
This issue is from landing at a different level from where jump was started. From ground to ground (or on block to on block), if properly placed on object before jump, it will end up properly placed after jump. However, when changing levels (ground to block or vice versa), it may not end up well. Therefore, when landing, you must properly set it "on" the object using setLocation (where is determined by actor image sizes and "ground" location). You will probably need to do this at the end of the fall method (if touching ground along with if touching block).
CreatorMoon CreatorMoon

2021/4/27

#
How would I go about doing that exactly? Different blocks are at different positions and so if I used one method and set the Y level to a singular value such as
setLocation(getX(),30);
it wouldn't work for all of the blocks.
danpost danpost

2021/4/27

#
danpost wrote...
where is determined by actor image sizes and "ground" location
CreatorMoon CreatorMoon

2021/4/27

#
I'm still really confused as to how I'd do that though.
RcCookie RcCookie

2021/4/28

#
// …
else if(onGround()) {
    vSpeed = 0;
    Actor block = getOne…
    setLocation(block.getX() + block.getImage().getHeight() / 2 + getImage().getHeight() / 2);
}
You’ll have to do the same thing for landing on ground now, too, since you’re not necessarily starting from ground height.
danpost danpost

2021/4/28

#
Landing on an actor, it would be like this:
setLocation(getX(), actor.getY()-actor.getImage().getHeight()/2-getImage().getHeight()/2);
RcCookie RcCookie

2021/4/28

#
Yeah sorry I’m stupid
CreatorMoon CreatorMoon

2021/4/29

#
That works - thank you both! One more thing though, there's a bit of clipping through the block for a few frames before it corrects itself, is there any way I could avoid that? If not that's fine.
danpost danpost

2021/4/29

#
CreatorMoon wrote...
That works - thank you both! One more thing though, there's a bit of clipping through the block for a few frames before it corrects itself, is there any way I could avoid that? If not that's fine.
Show updated codes.
CreatorMoon CreatorMoon

2021/4/29

#
import greenfoot.*;
public class Cube extends Actor
{
    int direction = 6;
    int vSpeed = 0;
    int acceleration = 1;
    int jumpStrength = -11;
    public void act()
    {
        checkKeys();
        checkFall();
        jump();
        die();
        setLocation(getX()+direction,getY());
    }
    public void die()
    {
        if (isTouching(Spike.class))
        {
            Greenfoot.stop();
        }
    }
    public void checkKeys()
    {
        if(Greenfoot.isKeyDown("space"))
        {
            jump();
        }
    }
    public void jump()
    {
        if (Greenfoot.isKeyDown("space") && onBlock())
        {
            vSpeed = jumpStrength;
            fall();
        }
        if (Greenfoot.isKeyDown("space") && onGround())
        {
            vSpeed = jumpStrength;
            fall();
        }
    }
    public void fall()
    {
        setLocation(getX(), getY()+vSpeed);
        vSpeed = vSpeed + acceleration;
        turn(4);
    }
    public boolean onBlock()
    {
        Actor block = getOneObjectAtOffset (0, getImage().getHeight()/2, Block.class);
        return block != null;
    }
    public boolean onGround()
    {
        Actor ground = getOneObjectAtOffset (0, getImage().getHeight()/2, Ground.class);
        return ground != null;
    }
    public void checkFall()
    {
        if (onBlock())
        {
            vSpeed = 0;
            setRotation(0);
            Actor block = getOneObjectAtOffset (0, getImage().getHeight()/2, Block.class);
            setLocation(getX(), block.getY()-block.getImage().getHeight()/2-getImage().getHeight()/2);
        }
        else if (onGround())
        {
            vSpeed = 0;
            setRotation(0);
            Actor ground = getOneObjectAtOffset (0, getImage().getHeight()/2, Ground.class);
            setLocation(getX(), ground.getY()-ground.getImage().getHeight()/2-getImage().getHeight()/2);
        }
        else
        {
            fall();
        }
    }
}
(I've just started working on everything else, ignore the die void)
danpost danpost

2021/4/29

#
One problem is that you check for ground before you fall. Better would be to fall (or move vertically) first, then check for obstacles and adjust position on collision. That way, you always end off any obstacles at the end of the act cycle. You might want to check out my Jump and Run Demo w/Moving Platform scenario.
CreatorMoon CreatorMoon

2021/5/1

#
danpost wrote...
Better would be to fall (or move vertically) first, then check for obstacles and adjust position on collision.
I can't figure out how to do this, and I'm not really understanding the scenario.
danpost danpost

2021/5/1

#
CreatorMoon wrote...
I'm not really understanding the scenario.
Vague. After moving vertically:
Actor obj = getOneIntersectingObject(null);
if (obj != null) && (obj instanceof Ground) || obj instanceof Block))
{
    // needed values
    int myHeight = getImage().getHeight();
    int objHeight = obj.getImage().getHeight();
    int objY = obj.getY();
    int dy = (int)Math.signum(vSpeed);
    
    // to do
    setLocation(getX(), objY-dy*(objHeight+myHeight+2)/2); // adjust vertical position
    vSpeed = 0; // kill fall speed
    if (dy > 0) onGround = true; // if landing, then on surface
}
CreatorMoon CreatorMoon

2021/5/6

#
After adjusting a few things (and removing the "+2" after myHeight in line 11) your method worked perfectly! Thanks danpost and RcCookie :D I'm having an issue with another part of the game, but I'll make a separate discussion for it.
You need to login to post a reply.