Pomysły na strategię komputera (gra ping pong)

0

Cześć, jestem w trakcie pisania gr, a właściwie już mam ze 3/4 napisane, brakuje jedynie strategi dla komputera. Myślałem nad tym, żeby zrobić tak, że gdy piłka wpada na połowę komputera (połowa stołu należąca do komputera jest podzielona na trzy prostokąty), to paletka przesuwa się na "prostokąt" w którym obecnie piłka się znajduję i tak lata z góry na dół w odpowiednim przedziale, aż piłka nie wpadnie na pole kolejnego prostokąta, wtedy paletka znowu zmienia pozycję i lata z górny na dół na wysokości tego następnego prostokąta. Tylko gdy starałem się tak zrobić, to paletka kierowała się na ten prostokąt, ale tylko wtedy gdy miała zgodny kierunek tzn. gdy piłka wpadała w górny prostokąt, a paletka akurat kierowała się też do góry (czyli w stronę y = 0 ramy) to wszystko było ok, natomiast gdy piłka wpadała w górny prostokąt, a paletka kierowała się do dołu, no to paletka zaczynała głupieć... Inny pomysł jaki mi przyszedł do głowy, to żeby paletka kopiowała ruch piłki Też zrobiłem, że kopiowała natomiast wtedy paletka wylatywała poza grę i nie udawało mi się jej zatrzymać na y = 0 ani na enemy.y = GamePanel.HEIGHT - PADDLE_HEIGHT. Macie jakieś pomysły innych strategii, albo jak rozwiązać problem tych dwóch? :)

Poniżej wrzucam klasy i zrzut ekranu rozgrywki:
Piłka:

import java.awt.*;
import java.util.Random;

public class Ball extends Rectangle {

    private static final Random random = new Random();
    public static int xVelocity;
    public static int yVelocity;
    public int initialSpeed = 2;

    public Ball(int xPosition, int yPosition, int xSize, int ySize) {
        super(xPosition, yPosition, xSize, ySize);
        initBall();
    }

    public void initBall() {
        int randomXDirection = random.nextInt(2);
        int randomYDirection = random.nextInt(2);
        if (randomXDirection == 0) {
            randomXDirection--;
        }
        setXDirection(randomXDirection * initialSpeed);

        if (randomYDirection == 0) {
            randomYDirection--;
        }
        setYDirection(randomYDirection * initialSpeed);
    }

    public void setXDirection(int randomXDirection) {
        xVelocity = randomXDirection;
    }

    public void setYDirection(int randomYDirection) {
        yVelocity = randomYDirection;
    }

    public void move() {
        x += xVelocity;
        y += yVelocity;
    }

    public void draw(Graphics g) {
        g.setColor(new Color(241, 144, 39));
        g.fillOval(x, y, width, height);
    }
}

Rozgrywka (tutaj kombinuje ze strategią komputera):


import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Random;

public class Skirmish extends GameState {

    private static final int PADDLE_WIDTH = 25;
    private static final int PADDLE_HEIGHT = 100;
    private static final int BALL_DIAMETER = 20;
    private static final int MAX_POINTS = 11;
    private int randomEnemyMistake;
    private final File backgroundFile = new File("src/main/resources/static/pongTable.jpg");
    private static final Random random = new Random();
    private BufferedImage backgroundImage;
    private Paddle player;
    private Enemy enemy;
    private Ball ball;
    private Scores scores = new Scores(GamePanel.WIDTH, GamePanel.HEIGHT);
    public Skirmish(GameStateManager gameStateManager) {
        this.gameStateManager = gameStateManager;
    }

    public void newPaddles() {
        randomEnemyMistake = random.nextInt(DificultyMenu.dificultyPercent) + 1;
        player = new Paddle(0, (GamePanel.HEIGHT / 2) - PADDLE_HEIGHT / 2, PADDLE_WIDTH, PADDLE_HEIGHT);
        enemy = new Enemy(GamePanel.WIDTH - PADDLE_WIDTH, (GamePanel.HEIGHT / 2) - PADDLE_HEIGHT / 2, PADDLE_WIDTH, PADDLE_HEIGHT);
    }

    public void newBall() {
        ball = new Ball((GamePanel.WIDTH / 2) - (BALL_DIAMETER / 2), random.nextInt(GamePanel.HEIGHT - BALL_DIAMETER - 2) + 1, BALL_DIAMETER, BALL_DIAMETER);
    }

    public boolean isMistake(int mistakeSize) {
        int size = DificultyMenu.dificultyPercent / 5;
        if (mistakeSize <= size) {
            return true;
        } else {
            return false;
        }
    }

    public void enemyStrategy() {
        if (isMistake(randomEnemyMistake)) {
            //Algorytm, który robi błąd

        } else {
            //Algorytm, który nie robi błędu

            if (ball.x >= GamePanel.WIDTH - (GamePanel.WIDTH / 2) && ball.y >= 320) {
                System.out.println("Pilka w dolnym kwadracie " + ball.x + "/" + ball.y);
                //Paletka ma latać po Y w przedziale od 320 do 380

            } else if (ball.x >= GamePanel.WIDTH - (GamePanel.WIDTH / 2) && (ball.y < 320 && ball.y >= 160)) {
                System.out.println("Pilka w srodkowym kwadracie " + ball.x + "/" + ball.y);
                //Paletka ma latać po Y w przedziale od 160 do 319

            } else if (ball.x >= GamePanel.WIDTH - (GamePanel.WIDTH / 2) && (ball.y < 160 && ball.y >= 0)) {
                System.out.println("Pilka w gornym kwadracie " + ball.x + "/" + ball.y);
                //Paletka ma latać po Y w przedziale od 0 do 159

            } else if (ball.x <= GamePanel.WIDTH / 2){
                enemy.y += enemy.yVelocity;
                if (enemy.y <= 0) {
                    enemy.setYDirection(-enemy.yVelocity);
                }
                if (enemy.y >= GamePanel.HEIGHT - PADDLE_HEIGHT) {
                    enemy.setYDirection(-enemy.yVelocity);
                }
            }
        }
    }

    @Override
    public void init() {
        newPaddles();
        newBall();
        try {
            backgroundImage = ImageIO.read(backgroundFile);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public void checkBallPaddleCollision() {
        if (ball.intersects(player)) {
            ball.xVelocity = Math.abs(ball.xVelocity);
            ball.setXDirection(ball.xVelocity);
            ball.setYDirection(ball.yVelocity);
        }

        if (ball.intersects(enemy)) {
            ball.xVelocity = Math.abs(ball.xVelocity);
            ball.setXDirection(-ball.xVelocity);
            ball.setYDirection(ball.yVelocity);
        }
    }

    public void checkBallCollisionWithFrame() {
        if (ball.y <= 0) {
            ball.setYDirection(-ball.yVelocity);
        }

        if (ball.y >= GamePanel.HEIGHT - BALL_DIAMETER) {
            ball.setYDirection(-ball.yVelocity);
        }
    }

    public void checkPaddleCollisionWithFrame() {

        if (player.y <= 0) {
            player.y = 0;
        }

        if (player.y >= (GamePanel.HEIGHT - PADDLE_HEIGHT)) {
            player.y = GamePanel.HEIGHT - PADDLE_HEIGHT;
        }
    }

    public void givePlayerPoint() {
        if (ball.x + BALL_DIAMETER < 0) {
            newBall();
            newPaddles();
            scores.scorePlayer2++;
            if (scores.scorePlayer2 == MAX_POINTS) {
                checkSetWinner();
                scores.scorePlayer1 = 0;
                scores.scorePlayer2 = 0;
            }
        }

        if (ball.x > GamePanel.WIDTH) {
            newBall();
            newPaddles();
            scores.scorePlayer1++;
            if (scores.scorePlayer1 == MAX_POINTS) {
                checkSetWinner();
                scores.scorePlayer1 = 0;
                scores.scorePlayer2 = 0;
            }
        }
    }

    public void checkSetWinner() {
        if (scores.scorePlayer1 == MAX_POINTS) {
            Scores.player1Scores.add(scores.scorePlayer1);
            Scores.player2Scores.add(scores.scorePlayer2);
            Scores.setWinPlayer1++;
        }

        if (scores.scorePlayer2 == MAX_POINTS) {
            Scores.player1Scores.add(scores.scorePlayer1);
            Scores.player2Scores.add(scores.scorePlayer2);
            Scores.setWinPlayer2++;
        }
    }

    public void checkwhoWinSkirmish() {
        if (Scores.setWinPlayer1 == 2 && Scores.setWinPlayer2 == 0) {
            gameStateManager.setStates(GameStateManager.STATISTICS);
        } else if (Scores.setWinPlayer2 == 2 && Scores.setWinPlayer1 == 0) {
            gameStateManager.setStates(GameStateManager.STATISTICS);
        } else if (Scores.setWinPlayer1 == 2 && Scores.setWinPlayer2 == 1) {
            gameStateManager.setStates(GameStateManager.STATISTICS);
        } else if (Scores.setWinPlayer2 == 2 && Scores.setWinPlayer1 == 1) {
            gameStateManager.setStates(GameStateManager.STATISTICS);
        }
    }

    @Override
    public void update() {
        player.move();
        ball.move();
        enemyStrategy();
        checkBallCollisionWithFrame();
        checkPaddleCollisionWithFrame();
        checkBallPaddleCollision();
        givePlayerPoint();
        checkSetWinner();
        checkwhoWinSkirmish();
    }

    @Override
    public void draw(Graphics2D g) {
        g.drawImage(backgroundImage, 0, 0, null);
        player.draw(g);
        enemy.draw(g);
        ball.draw(g);
        scores.draw(g);
    }

    @Override
    public void keyPressed(KeyEvent key) {
        player.movePaddle(key);
    }

    @Override
    public void keyReleased(KeyEvent key) {
        player.stopPaddle(key);
    }
}

Przeciwnik:


import java.awt.*;
import java.util.Random;

public class Enemy extends Rectangle {

    private static final Random random = new Random();
    int yVelocity;
    private int PADDLE_HEIGHT;
    private static final int speed = 3;

    public Enemy(int xPosition, int yPosition, int PADDLE_WIDTH, int PADDLE_HEIGHT) {
        super(xPosition, yPosition, PADDLE_WIDTH, PADDLE_HEIGHT);
        this.PADDLE_HEIGHT = PADDLE_HEIGHT;
        initEnemy();
    }

    public void initEnemy() {
        int randomYDirection = random.nextInt(2);
        if (randomYDirection == 0) {
            randomYDirection--;
        }
        setYDirection(randomYDirection * speed);
    }

    public void setYDirection(int randomYDirection) {
        yVelocity = randomYDirection;
    }

    public void draw(Graphics g) {
        g.setColor(Color.RED);
        g.fillRect(x, y ,width, height);
    }
}

Zrzut.jpg

2
Ukulelemelelele napisał(a):

Inny pomysł jaki mi przyszedł do głowy, to żeby paletka kopiowała ruch piłki Też zrobiłem, że kopiowała natomiast wtedy paletka wylatywała poza grę i nie udawało mi się jej zatrzymać na y = 0 ani na enemy.y = GamePanel.HEIGHT - PADDLE_HEIGHT. Macie jakieś pomysły innych strategii, albo jak rozwiązać problem tych dwóch? :)

Gracz ma checkPaddleCollisionWithFrame(). Paletka wroga też powinna korzystać z takiej metody, żeby nie wylatywała poza stół.

Wróg i gracz mogliby dziedziczyć z jednej klasy, zawierającej wspólne metody, takie jak ta.
Tak w ogóle to Twoje AI najlepiej jakby odwoływało się do tych samych metod, co sterowanie gracza ;)


Jeśli chodzi o inne strategie, to możesz sobie w momencie odbicia obliczyć gdzie poleci piłeczka. Paletka wroga losowo albo przesunie się, żeby odbić, albo przesunie się gdzieś indziej, żeby przegrać.


@Adam Boduch #gamedev !

0

@Spine: Dzięki za sugestię, na razie zrobiłem, że y paletki śledzi y piłki, piłka jest odbijana na środku paletki, i jak piłka osiąga y = 0, albo y = GamePane.HEIGHT - BALL_DIAMETER to dorysowuję mi paletkę na górze lub na dole co daje złudzenie jak by się zatrzymywała, ale nie jestem zadowolony z tak prymitywnego rozwiązania, będę kombinował, żeby to jednak ta paletka co się rusza się zatrzymywała na krawędziach.

Edit: już ogarnięte (czasem nad taką pierdołą się zawieszam, że to wstyd...). :D

public void enemyStrategy() {
        if (isMistake(randomEnemyMistake)) {
            //Algorytm, który robi błąd
            enemy.y += enemy.yVelocity;
            if (enemy.y <= 0) {
                enemy.setYDirection(-enemy.yVelocity);
            }
            if (enemy.y >= GamePanel.HEIGHT - PADDLE_HEIGHT) {
                enemy.setYDirection(-enemy.yVelocity);
            }
        } else {
            //Algorytm, który nie robi błędu

            if (ball.y <= PADDLE_HEIGHT / 2 - BALL_DIAMETER / 2 || ball.y >= GamePanel.HEIGHT - PADDLE_HEIGHT / 2 - BALL_DIAMETER / 2) {
                enemy.setYDirection(0);
            } else {
                enemy.y = ball.y - (PADDLE_HEIGHT / 2) + (BALL_DIAMETER / 2);
            }
        }
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1