多重碰撞和得分保持

时间:2016-08-24 22:14:01

标签: java libgdx

我做了一个蛇游戏,当蛇和食物发生碰撞时,应该在分数上加1。相反,一旦蛇吃了食物,它会增加多个点。苹果附有多个固定装置(这可能是检测到多个碰撞的原因)。我有什么方法可以确保得分只上升一分吗?一些想法会有所帮助。

我尝试使用布尔值来确保在重新定位食物之前没有注册碰撞但是没有解决问题。

代码:(一些不相关的代码被遗漏了,所以我不会压倒人,例如我有一个vector2列表,用于对象的多边形形状的顶点。顶点创建多个灯具。)

Apple.java:

public class Apple {

    private Sprite img;
    private float width, x, y;
    private Body body;

    private Vector2[][] vertices;
    public boolean isRelocating;
    private Vector2 previousPosition;

    //constructor
    public Apple(float x, float y, float width, World world) {
        this.x = x;
        this.y = y;
        this.width = width;
        isRelocating = false;
        //intialize previous number to a mechncially imposible number
        previousPosition = new Vector2(-100, -100);

        img = new Sprite(new Texture(Gdx.files.internal("Emoji/Red Apple.png")));
        img.setSize(width, width * 0.9416f);
        img.setPosition(x, y);

        //set up the physics body
        BodyDef def = new BodyDef();
        def.type = BodyDef.BodyType.DynamicBody; //keep it dynamic so collisions can be collected
        def.position.set(x, y);
        body = world.createBody(def);

        loadVertices();
        //scale vertices accroding to the width
        for (int i = 0; i < vertices.length; i++) {
            for (int j = 0; j < vertices[i].length; j++) {
                vertices[i][j].scl(width);
            }
        }

        //attach multiple fixtures to the body
        FixtureDef fixtureDef = new FixtureDef();
        PolygonShape shape = new PolygonShape();
        fixtureDef.isSensor = true;
        shape.set(vertices[0]);

    }

    public void update(float dt) {
        img.setPosition(x, y);
        body.setTransform(x, y, body.getAngle());
    }

    public void draw(SpriteBatch batch) {
        batch.begin();
        img.setAlpha(0.1f);
        img.draw(batch);
        batch.end();
    }

    public void changePosition(float newX, float newY) {
        x = newX;
        y = newY;
        body.setTransform(x,y,body.getAngle());
        isRelocating = false;
    }

    public float getWidth(){
        return img.getWidth();
    }

    public float getHeight(){
        return img.getHeight();
    }

    public Vector2 getPosition(){
        return new Vector2(x,y);
    }

    public Vector2 getPreviousPosition(){
        return previousPosition;
    }

    public void setPreviousPosition(Vector2 value){
        previousPosition = value;
    }

}

Snake.java:

public class Snake {

    private ArrayList<Segment> snake;
    private float speed;
    private World worldRef;
    private float width;

    public Snake(float x, float y, float width, float speed, World world) {
        snake = new ArrayList<Segment>();

        this.speed = speed;
        worldRef = world;

        //add the head
        snake.add(new Segment(width, x, y, true, Segment.Direction.UP, speed, world));

    }

    public void draw(SpriteBatch batch){
        for (int i = 0; i < snake.size(); i ++ ){
            snake.get(i).draw(batch);
        }
    }

    public void update(float dt){
        for (int i = 0; i < snake.size(); i ++){
            snake.get(i).update(dt);
        }
    }


    public void changeDirection(Segment.Direction direction){
        //change the direction of the head, and the rest will follow
        snake.get(0).setDirection(direction);
    }

    public Rectangle[] getTakeArea(){
        Rectangle[] rects = new Rectangle[snake.size()];
        for (int i = 0; i < rects.length; i ++){
            rects[i] = snake.get(i).getArea();
        }
        return  rects;
    }

    public float getWidth(){
        return width;
    }



}

Segment.java:

public class Segment {

    //direction enum
    public enum Direction {
        UP,
        DOWN,
        LEFT,
        RIGHT;
    }

    private Sprite img;
    private float width, x, y;

    private Body body;
    private float speed;
    private Direction direction;
    private boolean isHead;

    private Vector2[] vertices1;
    private Vector2[] vertices2;
    private Vector2[] vertices3;
    private Vector2[] vertices4;

    //constructor
    public Segment(float width, float x, float y, boolean isHead, Direction
            direction, float speed, World world) {
        this.width = width;
        this.x = x;
        this.y = y;
        this.direction = direction;
        this.speed = speed;
        this.isHead = isHead;

        if (isHead)
            img = new Sprite(new Texture(Gdx.files.internal("Emoji/Tears of Joy.png")));
        else
            img = new Sprite(new Texture(Gdx.files.internal("Emoji/Smiling Face with Mouth Open" +
                    ".png")));
        img.setSize(width, width);
        img.setPosition(x, y);

        //load up the physcis
        BodyDef bodyDef = new BodyDef();
        bodyDef.position.set(x, y);
        bodyDef.type = BodyDef.BodyType.DynamicBody;
        body = world.createBody(bodyDef);

        //load up fixtures
        loadVertices();
        for (int i = 0; i < vertices1.length; i++) {
            vertices1[i].scl(width);
            vertices2[i].scl(width);
            vertices3[i].scl(width);
            vertices4[i].scl(width);
        }

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.friction = 0;
        fixtureDef.restitution = 1;
        PolygonShape shape1 = new PolygonShape();

        shape1.set(vertices1);
        fixtureDef.shape = shape1;
        body.createFixture(fixtureDef);


        shape1.dispose();

        //add userData to all the fixtures
        for (int i = 0; i < body.getFixtureList().size; i++) {
            body.getFixtureList().get(i).setUserData(new UserData("segment"));
        }
    }


    public void update(float dt) {
        //update the position based on the speed
        switch (direction) {
            case UP:
                body.setLinearVelocity(0, speed);
                break;
            case DOWN:
                body.setLinearVelocity(0, -speed);
                break;
            case RIGHT:
                body.setLinearVelocity(speed, 0);
                break;
            case LEFT:
                body.setLinearVelocity(-speed, 0);
                break;
        }
        //make sure that the segment stays in side the camara
        if (x > (Launcher.WIDTH/SnakeMain.PPM))
            body.setTransform(x - (Launcher.WIDTH/SnakeMain.PPM) - width,y, body.getAngle());


        x = body.getPosition().x;
        y = body.getPosition().y;
        //have to adjust the sprite if it is head
        if (isHead) {
            img.setPosition(x - (width * 0.03f), y - (width * 0.024f));
        } else {
            img.setPosition(x, y);
        }
        img.setRotation((float) Math.toDegrees(body.getAngle()));
    }

    public void draw(SpriteBatch batch) {
        batch.begin();
        img.setAlpha(0.1f);
        img.draw(batch);
        batch.end();
    }

    public Direction getDirection() {
        return direction;
    }

    public Rectangle getArea(){
        return new Rectangle(x,y,width,width);
    }


    public void setDirection(Direction newDirection) {
        direction = newDirection;
    }
}

SnakeMain.java:

public class SnakeMain implements Screen {
    private Launcher mainRef;

    private OrthographicCamera camera;
    private FitViewport viewport;

    private World world;
    private Box2DDebugRenderer debugRenderer;
    public static final float PPM = 100;

    private Snake snake;
    private Apple apple;

    private Stage HUD;
    private Table hubTable;
    private Label lblScore;

    private int score = 0;

    //constructor
    public SnakeMain(Launcher main) {
        mainRef = main;

        camera = new OrthographicCamera();
        viewport = new FitViewport(Launcher.WIDTH / PPM, Launcher.HEIGHT / PPM, camera);
        viewport.apply();

        world = new World(new Vector2(0, 0), true);
        debugRenderer = new Box2DDebugRenderer();

        snake = new Snake((Launcher.WIDTH / 2) / PPM, (Launcher.HEIGHT / 2) / PPM, 200 / PPM, 400
                / PPM, world);
        apple = new Apple((Launcher.WIDTH / 2) / PPM, (Launcher.HEIGHT / 2 - 300) / PPM, 200 / PPM,
                world);

        world.setContactListener(new CollisionDetector(this));
        Gdx.input.setInputProcessor(new GestureDetector(new TouchListener(snake)));

        HUD = new Stage();
        HUD.setViewport(new FitViewport(Launcher.WIDTH /3, Launcher.HEIGHT/3, new OrthographicCamera
                ()));
        hubTable = new Table();
        String strScore = "Score: " + score;
        lblScore = new Label(strScore, mainRef.getSkin(), "small38");
        hubTable.add(lblScore);
        hubTable.top();
        hubTable.padTop(10);
        hubTable.setFillParent(true);
        HUD.addActor(hubTable);


    }

    @Override
    public void show() {

    }

    public void update(float delta) {
        world.step(1 / 30f, 6, 2);
        snake.update(delta);
        apple.update(delta);
        lblScore.act(delta);
        HUD.act();
    }

    @Override
    public void render(float delta) {
        update(delta);
        debugRenderer.render(world, camera.combined);
        mainRef.batch.setProjectionMatrix(camera.combined);
        snake.draw(mainRef.batch);
        apple.draw(mainRef.batch);
        HUD.draw();
    }

    public Apple getApple(){
        return apple;
    }

    //handles things when the snake eats the food
    public void foodEaten() {
        score ++;
        String strScore = "Score: " + score;
        lblScore.setText(strScore);

        //relocate the food to a new location
        boolean isValid = false;
        float newX = -1;
        float newY = -1;
        Rectangle rect = new Rectangle();
        while (!isValid) {
            newX = (float) Math.random() * (Launcher.WIDTH - apple.getWidth() * PPM);
            newY = (float) Math.random() * (Launcher.HEIGHT - apple.getHeight() * PPM);
            rect.set(newX, newY, apple.getWidth(), apple.getHeight());

            isValid = true;
            //check to make sure that the apple will not be in the same position as the snake
            for (int i = 0; i < snake.getTakeArea().length; i++) {
                if (rect.overlaps(snake.getTakeArea()[i])) {
                    isValid = false;
                }
            }
        }
        apple.changePosition(newX/PPM, newY/PPM);
        Gdx.app.log("SnakeMain.java", "Done relocating the apple");

    }

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height, true);
        HUD.getViewport().update(width,height,true);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {

    }
}

CollisionDetector.java:

public class CollisionDetector implements ContactListener {

    private SnakeMain mainRef;

    //constructor
    public CollisionDetector(SnakeMain main) {
        mainRef = main;
    }


    @Override
    public void beginContact(Contact contact) {
        try {
            UserData userData1 = (UserData) contact.getFixtureA().getUserData();
            UserData userData2 = (UserData) contact.getFixtureB().getUserData();

            //if there is a collision between an apple and a segment
            if ((userData1.getId() == "apple" && userData2.getId() == "segment")
                    || (userData1.getId() == "segment" && userData2.getId() == "apple")) {
                if (!mainRef.getApple().isRelocating) {
                    Gdx.app.log("Apple eaten", "About to reset Apple");
                    Gdx.app.log("Apple eaten", "State of apple: " + mainRef.getApple()
                            .isRelocating);
                    mainRef.getApple().isRelocating = true;
                    mainRef.foodEaten();
                }



            }
        } catch (Exception e) {
            Gdx.app.log("Error!", e.getMessage());
        }
    }

    @Override
    public void postSolve(Contact contact, ContactImpulse impulse) {

    }

    @Override
    public void endContact(Contact contact) {

    }

    @Override
    public void preSolve(Contact contact, Manifold oldManifold) {

    }
}

1 个答案:

答案 0 :(得分:0)

考虑在Apple吃掉苹果后立即添加一个hasBeenEaten布尔值。然后,当检测到碰撞时(可能是再次),在调用foodEaten()函数之前检查hasBeenEaten的状态。

public void beginContact(Contact contact) {
    try {
        UserData userData1 = (UserData) contact.getFixtureA().getUserData();
        UserData userData2 = (UserData) contact.getFixtureB().getUserData();

        //if there is a collision between an apple and a segment
        if ((userData1.getId() == "apple" && userData2.getId() == "segment")
                || (userData1.getId() == "segment" && userData2.getId() == "apple")) {
            if (!mainRef.getApple().hasBeenEaten) {
                mainRef.getApple().isRelocating = true;
                mainRef.getApple().hasBeenEaten = true;
                mainRef.foodEaten();
            }
        }
    } catch (Exception e) {
        Gdx.app.log("Error!", e.getMessage());
    }
}