You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Pong游戏球与Paddle/墙体多次碰撞滑行问题排查与解决

Pong游戏碰撞滑行问题的解决方法

我和同学开发Pong游戏时遇到一个问题:当球与墙体或玩家Paddle发生碰撞时,有时会出现多次碰撞的情况,导致球看起来像是在Paddle上滑行。我们最终通过在球碰撞物体(墙体或Paddle)后添加冷却机制解决了该异常滑行问题。

import greenfoot.*;
import java.awt.*;

/**
 * A Ball is a thing that bounces of walls and paddles (or at least i should).
 * 
 * @author The teachers 
 * @version 1
 */
public class Ball extends Actor
{
    private static final int BALL_SIZE = 50;
    private static final int BOUNCE_DEVIANCE_MAX = 5;
    private static final int STARTING_ANGLE_WIDTH = 90;
    private static final int DELAY_TIME = 200;

    private int speed;
    private boolean hasBouncedHorizontally;
    private boolean hasBouncedVertically;
    private int delay;
    private int touchCounter;

    /**
     * Contructs the ball and sets it in motion!
     */
    public Ball()
    {
        // createImage();
        init();
    }

    /**
     * Creates and sets an image of a black ball to this actor.
     */
    /*
    private void createImage()
    {
        GreenfootImage ballImage = new GreenfootImage(BALL_SIZE,BALL_SIZE);
        ballImage.setColor(Color.RED);
        ballImage.fillOval(0, 0, BALL_SIZE, BALL_SIZE);
        setImage(ballImage);
    }
    */

    /**
     * Act - do whatever the Ball wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        if (delay > 0)
        {
            delay--;
        }
        else
        {
            move(speed);
            checkBounceOffWalls();
            checkBounceOffCeiling();
            checkRestart();
            bounceOffPaddles();
        }
    }    

    /**
     * Returns true if the ball is touching one of the side walls.
     */
    private boolean isTouchingSides()
    {
        return getX() <= BALL_SIZE/2 || getX() >= getWorld().getWidth() - BALL_SIZE/2;
    }

    /**
     * Returns true if the ball is touching the ceiling.
     */
    private boolean isTouchingCeiling()
    {
        return (getY() <= BALL_SIZE/2);
    }

    /**
     * Returns true if the ball is touching the floor.
     */
    private boolean isTouchingFloor()
    { 
        return (getY() >= getWorld().getHeight() - BALL_SIZE/2);
    }

    /**
     * Check to see if the ball should bounce off one of the walls.
     * If touching one of the walls, the ball is bouncing off.
     */
    private void checkBounceOffWalls()
    {
        if (isTouchingSides())
        {
            if (! hasBouncedHorizontally)
            {
                revertHorizontally();
            }
        }
        else
        {
            hasBouncedHorizontally = false;
        }
    }

    /**
     * Check to see if the ball should bounce off the ceiling.
     * If touching the ceiling the ball is bouncing off.
     */
    private void checkBounceOffCeiling()
    {
        if (isTouchingCeiling())
        {
            if (! hasBouncedVertically)
            {
                revertVertically();
            }
        }
        // Removed for purpose of solving Task 3
        /*
        else
        {
            hasBouncedVertically = false;
        }
        */
    }

    /**
     * Check to see if the ball should be restarted.
     * If touching the floor the ball is restarted in initial position and speed.
     */
    private void checkRestart()
    {
        if (isTouchingFloor())
        {
            PingWorld theWorld = (PingWorld) getWorld();
            theWorld.resetGameLevel();
            init();
            setLocation(getWorld().getWidth() / 2, getWorld().getHeight() / 2);
        }
    }

    /**
     * Bounces the ball back from a vertical surface.
     */
    private void revertHorizontally()
    {
        int randomness = Greenfoot.getRandomNumber(BOUNCE_DEVIANCE_MAX)- BOUNCE_DEVIANCE_MAX / 2;
        setRotation((180 - getRotation()+ randomness + 360) % 360);
        Greenfoot.playSound("pewsoundeffect.mp3");
        hasBouncedHorizontally = true;
    }

    /**
     * Bounces the bal back from a horizontal surface.
     */
    private void revertVertically()
    {
        int randomness = Greenfoot.getRandomNumber(BOUNCE_DEVIANCE_MAX)- BOUNCE_DEVIANCE_MAX / 2;
        setRotation((360 - getRotation()+ randomness + 360) % 360);
        Greenfoot.playSound("pewsoundeffect.mp3");
        hasBouncedVertically = true;
    }
    
    // Checking for the paddles if they intersect with the ball, if touching, revert vertically.
    public void bounceOffPaddles() 
    {
        Actor paddle = getOneIntersectingObject(Paddle.class);
        Actor enemyPaddle = getOneIntersectingObject(EnemyPaddle.class);
        
        if (paddle != null) {
            revertVertically();
            hasBouncedVertically = false;
            speedIncreaser();
        }
        if (hasBouncedVertically == false && enemyPaddle != null) {
            revertVertically();
        }
    }
    
    // Increases speed
    public void speedIncreaser() {
        touchCounter++;
            if (touchCounter == 10) {
                speed++;
                PingWorld theWorld = (PingWorld) getWorld();
                theWorld.increaseGameLevel();
                touchCounter = 0;
            }
    }

    /**
     * Initialize the ball settings.
     */
    private void init()
    {
        speed = 2;
        delay = DELAY_TIME;
        hasBouncedHorizontally = false;
        hasBouncedVertically = false;
        setRotation(Greenfoot.getRandomNumber(STARTING_ANGLE_WIDTH)+STARTING_ANGLE_WIDTH/2);
    }
}

内容的提问来源于stack exchange,提问作者D R O P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 18:47:32