简体   繁体   中英

Java 2D Platformer - Some Logic/Physics Quirks

I am making a Java 2d platformer, and am using threads, so far I have 4 classes:

Main.java -Handles the main JFrame

Board.java -Where most of the game logic is -Using thread that refreshes every 5 milliseconds -KeyListener

Guy.java -Where the instance of guy is made -Using ImageIcon, getting image of guy -other things like getBounds, getX/Y, etc. useful functions

Platform.java -Where a platform instance is initiated -Again, the useful functions

Now, on to what I have working:

I am able to move from platform to platform, and am able to jump. Here is my gravity code, to check need for gravity, and do it if needed

if(guy.getGravityState() == true) {
        //check need for gravity
        boolean colliding = false;
        for(int a = 0; a < platform.length; a++) {
            if(guy.getBounds().intersects(platform[a].getBounds())) {
                colliding = true;
                //guy.setY(platform[a].getY()-platform[a].getHeight()+3);
            }
        }

        //if needed, do gravity
        if(colliding == false) {
            guy.setYSpeed(3);
                            //move him down by positive y speed
        } else {
            guy.setYSpeed(0);
        }
}

Here is how the character moves:

if(guy.getXSpeed() > 0 && guy.getX() > 500) {
        for(int i = 0; i < platform.length; i++) {
            platform[i].setX(platform[i].getX() - guy.getXSpeed());
        }
    } else if (guy.getXSpeed() < 0 && guy.getX() < 300) {
        for(int i = 0; i < platform.length; i++) {
            platform[i].setX(platform[i].getX() - guy.getXSpeed());
        }
    } else {
        guy.moveX();
    }

    if(guy.getYSpeed() > 0 && guy.getY() > 350) {
        for(int i = 0; i < platform.length; i++) {
            platform[i].setY(platform[i].getY() - guy.getYSpeed());
        }
    } else if  (guy.getYSpeed() < 0 && guy.getY() < 250) {
        for(int i = 0; i < platform.length; i++) {
            platform[i].setY(platform[i].getY() - guy.getYSpeed());
        }
    } else {
        guy.moveY();
    }

Sorry for the lack of comments there, basically it checks if it needs to move the guy, or the platform. If it is close to the edges, it will move the platforms, it if isnt, the guy will be moved.

Now, jump code (not sure if relevant):

if(guy.getGravityState() == false) {
        d++;
        if(d == 35) {
            d = 0;
            guy.setGravityState(true);
        }
    }

The only way gravity can be turned off is with jump, so if the gravity is off, I used setYSpeed(-5); so the character would move up (negative number) now it moves up until d = 35, so 35 refreshes. after this point, the gravity is put back to normal.

So now I hope you stuck around, and can get on to my questions. Take a look on how the game looks at run time:

在此处输入图片说明

Now, when I move right, the character moves down, as wanted, but when I move left, he goes through the platform. How would I make it so it will not move if there is something stopping it? For example look here, the guy goes right through:

在此处输入图片说明

My second question is, it is relevant to the first one, when my character jumps, and hits a platform above him, I want it to go straight down, not through the platform.

Also, when I jump from something above and just to the left/right, he will sometimes even get stuck as so:

在此处输入图片说明

Those are all my questions for now, I very much appreciate if you even help me a little, I know this might be an overwhelming question but any help at all is appreciated. Thank you.

Looks like you're doing the collision check in your gravity function that stops the player falling through the ground, but there's no collision detection happening when processing the player's movement (either left/right or up from jumping). That's the issue with both of your problems.

When moving the player, you need to work out if his next movement will collide with anything. You should move the collision detection you have at the moment outside of your gravity function, and handle it in the player's movement function--actually, since the player will continuously be moved as long as his Y speed is set according to your implementation, you might not even need to have gravity running in a loop... Just set the player's Y speed to 3 whenever he isn't jumping.

I won't attempt to show you what I mean there because I can't see enough of your code to tell how jumping works, but hopefully this answer is enough to put you on the right track.

Note that this is just a rough guide, and you will have other considerations since you're moving platforms around, and may have to change this depending on how you're handling jumping etc.

This also isn't taking account for the fact that the guy might try to fall 3 pixels down, but the ground is 2 pixels away--in this case he would levitate 2 pixels above the block because canExecuteMove is always going to return false.

Hope this helps a little. :) If you get stuck you should have a read up on ways to handle simple collision detection. I haven't done much of this myself but I'm sure someone else might be able to link you to a useful tutorial.

EDIT: Whoops, this won't really fix your second problem with making the guy fall back down after bumping his head very nicely. With my suggestion below he'll stick to the bottom of ceiling until he's finished jumping, then start falling again. Clearly you need to make sure his jump finishes after he collides with a ceiling (causing him to start dropping again immediately) but the question is "where is the best place to do that?" I'm out of time so I'll leave that up to you or someone else!

private void move()
{
    //....your other code
    if(canExecuteMovement(guy.getBounds(), guy.getXSpeed(), 0))
    {
        guy.moveX();
    }

    if(canExecuteMovement(guy.getBounds(), 0, guy.getYSpeed())
    {
        guy.moveY();
    }
}


private boolean canExecuteMovement(Bounds currentBounds, int xChange, int yChange)
{
    int projectedX = currentBounds.getX() + xChange;
    int projectedY = currentBounds.getY() + yChange;
    Bounds projectedBounds = new Bounds(projectedX, projectedY);
    // ^ Making an assumption about Bounds constructor but you get the idea

    for(int i = 0; i < platform.length; i ++)
    {
            if(projectedBounds.intersects(platform[i].getBounds())
            {
                    return false;
            }
    }

    return true;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM