Uwzględnienie wszystkich płytek w grze na kolizje

0

Cześć piszę sobie grę i mam taki problem, bo gracz reaguje mi tylko na 1 płytę z trzech rodzajów (w sensie po jednej z trzech) na całej mapie. Tym czasem tych płytek na które powinien zareagować jest dużo więcej. Czy widzicie mój błąd i macie pomysł jak rozwiązać ten problem? Poniżej wrzucam potrzebne klasy do analizy.
Klasa Tile:

import java.awt.*;
import java.awt.image.BufferedImage;

public class Tile {

    private Rectangle rectangle = null;
    private BufferedImage bufferedImage;
    private boolean collision;

    public Tile(boolean hasCollision) {
        this.collision = hasCollision;
        if (hasCollision) {
            this.rectangle = new Rectangle();
        }
    }

    public void setParameters(int x, int y, int width, int height) {
        rectangle.x = x;
        rectangle.y = y;
        rectangle.width = width;
        rectangle.height = height;
    }

    public Rectangle getRectangle() {
        return rectangle;
    }

    public BufferedImage getBufferedImage() {
        return bufferedImage;
    }

    public void setBufferedImage(BufferedImage bufferedImage) {
        this.bufferedImage = bufferedImage;
    }

    public boolean isCollision() {
        return collision;
    }

    public void draw(Graphics2D g2d) {
        g2d.setColor(Color.RED);
        g2d.drawOval(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
    }
}

Klasa TileManager:

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class TileManager {

    //Jedna płytka powinna mieć wymiary 40x40
    //Dla szerokości 800 powinno być 20 płytek
    //Dla długości 600 powinno być 15 płytek

    private static final int SPEED = 2;
    private static final int MAX_WORLD_COLUMNS = 50;
    private static final int MAX_WORLD_ROWS = 50;
    private static final int TILE_SIZE = 40;

    private static final Tile[] tiles = new Tile[6];
    private static final ProportionCalculator pc = new ProportionCalculator();
    private static final int[][] mapTileNumbers = new int[MAX_WORLD_COLUMNS][MAX_WORLD_ROWS];

    private final String path;

    private int x;
    private int y;
    private int speedY;
    private int speedX;

    private boolean up;
    private boolean down;
    private boolean left;
    private boolean right;

    public TileManager(String path) {
        this.path = path;
        getTileImage();
        loadMap(path);
    }

    private void loadMap(String path) {
        try {
            InputStream inputStream = getClass().getResourceAsStream(path);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            int col = 0;
            int row = 0;
            while (col < MAX_WORLD_COLUMNS && row < MAX_WORLD_ROWS) {
                String line = bufferedReader.readLine();
                while (col < MAX_WORLD_COLUMNS) {
                    String[] numbers = line.split(" ");
                    int number = Integer.parseInt(numbers[col]);
                    mapTileNumbers[col][row] = number;
                    col++;
                }
                if (col == MAX_WORLD_COLUMNS) {
                    col = 0;
                    row++;
                }
            }
            bufferedReader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void getTileImage() {
        try {
            tiles[0] = new Tile(false);
            tiles[0].setBufferedImage(ImageIO.read(getClass().getResourceAsStream("/tiles/grass.png")));

            tiles[1] = new Tile(true);
            tiles[1].setBufferedImage(ImageIO.read(getClass().getResourceAsStream("/tiles/wall.png")));

            tiles[2] = new Tile(true);
            tiles[2].setBufferedImage(ImageIO.read(getClass().getResourceAsStream("/tiles/water.png")));

            tiles[3] = new Tile(false);
            tiles[3].setBufferedImage(ImageIO.read(getClass().getResourceAsStream("/tiles/earth.png")));

            tiles[4] = new Tile(true);
            tiles[4].setBufferedImage(ImageIO.read(getClass().getResourceAsStream("/tiles/tree.png")));;

            tiles[5] = new Tile(false);
            tiles[5].setBufferedImage(ImageIO.read(getClass().getResourceAsStream("/tiles/sand.png")));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void onKeyPressed(KeyEvent key) {
        if (up) {
            if (key.getKeyCode() == KeyEvent.VK_UP) {
                speedY = SPEED;
            }
        } else {
            speedY = 0;
        }

        if (down) {
            if (key.getKeyCode() == KeyEvent.VK_DOWN) {
                speedY = -SPEED;
            }
        } else {
            speedY = 0;
        }
        if (left) {
            if (key.getKeyCode() == KeyEvent.VK_LEFT) {
                speedX = SPEED;
            }
        } else {
            speedX = 0;
        }
        if (right) {
            if (key.getKeyCode() == KeyEvent.VK_RIGHT) {
                speedX = -SPEED;
            }
        } else {
            speedX = 0;
        }

    }

    public void onKeyReleased(KeyEvent key) {
        if (key.getKeyCode() == KeyEvent.VK_UP) {
            speedY = 0;
        }
        if (key.getKeyCode() == KeyEvent.VK_DOWN) {
            speedY = 0;
        }

        if (key.getKeyCode() == KeyEvent.VK_LEFT) {
            speedX = 0;
        }
        if (key.getKeyCode() == KeyEvent.VK_RIGHT) {
            speedX = 0;
        }
    }

    public void update(Player player) {
        xMove(player);
        yMove(player);
    }

    private void xMove(Player player) {
        left = true;
        right = true;

        //Collision X
        if (speedX < 0) {
            for (int i = 0; i < tiles.length; i++) {
                if (tiles[i].isCollision()) {
                    if (player.getEntityCollisionLeft().getRectangle().intersects(tiles[i].getRectangle())) {
                        left = false;
                    }
                }
            }
        } else if (speedX > 0) {
            for (int i = 0; i < tiles.length; i++) {
                if (tiles[i].isCollision()) {
                    if (player.getEntityCollisionRight().getRectangle().intersects(tiles[i].getRectangle())) {
                        right = false;
                    }
                }
            }
        }

        if (speedX < 0 && left) {
            x += speedX;
        } else if (speedX > 0 && right) {
            x += speedX;
        }
    }

    private void yMove(Player player) {
        up = true;
        down = true;

        //Collision Y
        if (speedY < 0) {
            for (int i = 0; i < tiles.length; i++) {
                if (tiles[i].isCollision()) {
                    if (player.getEntityCollisionUp().getRectangle().intersects(tiles[i].getRectangle())) {
                        up = false;
                    }
                }
            }
        } else if (speedY > 0) {
            for (int i = 0; i < tiles.length; i++) {
                if (tiles[i].isCollision()) {
                    if (player.getEntityCollisionDown().getRectangle().intersects(tiles[i].getRectangle())) {
                        down = false;
                    }
                }
            }
        }

        if (speedY < 0 && up) {
            y += speedY;
        } else if (speedY > 0 && down) {
            y += speedY;
        }
    }

    public void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        int col = 0;
        int row = 0;
        int x = 0;
        int y = 0;
        while (col < MAX_WORLD_COLUMNS && row < MAX_WORLD_ROWS) {
            int tileNumber = mapTileNumbers[col][row];

            g2d.drawImage(
                    tiles[tileNumber].getBufferedImage(),
                    x + this.x,
                    y + this.y,
                    pc.getCalculatedImageWidth(TILE_SIZE),
                    pc.getCalculatedImageHeight(TILE_SIZE),
                    null);

            if (tiles[tileNumber].isCollision()) {
                tiles[tileNumber].setParameters(
                        x + this.x,
                        y + this.y,
                        pc.getCalculatedImageWidth(TILE_SIZE),
                        pc.getCalculatedImageHeight(TILE_SIZE));
                tiles[tileNumber].draw(g2d);
            }

            col++;
            x += pc.getCalculatedImageWidth(TILE_SIZE);
            if (col == MAX_WORLD_COLUMNS) {
                col = 0;
                x = 0;
                row++;
                y += pc.getCalculatedImageHeight(TILE_SIZE);
            }
        }
    }
}

Klasa EntityCollision:

import java.awt.*;

public class EntityCollision {

    private final String direction;
    private Rectangle rectangle;

    public EntityCollision(int xPos, int yPos, int width, int height, String direction) {
        this.direction = direction;
        this.rectangle = new Rectangle(xPos, yPos, width, height);
    }

    public Rectangle getRectangle() {
        return rectangle;
    }

    public void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        if (direction.equals("up")) {
            g2d.setColor(Color.RED);
        }
        if (direction.equals("down")) {
            g2d.setColor(Color.YELLOW);
        }
        if (direction.equals("left")) {
            g2d.setColor(Color.BLUE);
        }
        if (direction.equals("right")) {
            g2d.setColor(Color.CYAN);
        }
        g2d.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
    }
}

Dodaje też zrzuty ekranu z zaznaczonym kafelkami na których następuje blokada gracza.1.png2.png3.png

3

Nie dziwię ci się, że się pogubiłeś we własnym kodzie. Jak chcesz w tym grzebać zamiast zaorać i napisać bardziej logiczną i czytelną wersję to dopisz sobie jakieś logowanie na konsolę co się dzieje w programie - jakie warunki są sprawdzane albo odpal to krok po kroku w debugerze po ustawieniu breakpointu tam gdzie powinnien się zacząć wykonywać kod sprawdzający.

0

trochę nie rozumiem tego designu.
oczekiwałbym (przynajmniej ja bym tak zrobił), że jeśli masz zmienną-mapę (tu nazwana mapTileNumbers), to ona będzie używana do sprawdzania kolizji.

Tymczasem tutaj coś dziwnego się zadziało, bo masz 6 elementową tablicę kafli tiles, która reprezentuje różne rodzaje kafli jak rozumiem, razem z grafikami. I to jest okej, gdzieś to trzeba trzymać. Ale problem jest, że zdaje się używasz tej tablicy kafli do dynamicznego ustawiania parametrów typu aktualne współrzędne:

  while (col < MAX_WORLD_COLUMNS && row < MAX_WORLD_ROWS) {
            int tileNumber = mapTileNumbers[col][row];
            // ...
            if (tiles[tileNumber].isCollision()) {
                tiles[tileNumber].setParameters(
                        x + this.x,
                        y + this.y,
                        pc.getCalculatedImageWidth(TILE_SIZE),
                        pc.getCalculatedImageHeight(TILE_SIZE));
                tiles[tileNumber].draw(g2d);
            }

a później w metodzie xMove przejeżdżasz przez te 6 kafli i sprawdasz te kolizje?

               if (tiles[i].isCollision()) {
                    if (player.getEntityCollisionLeft().getRectangle().intersects(tiles[i].getRectangle())) {
                        left = false;
                    }
                }

Nie jestem pewien, gdzie jest dokładnie bug, ale jakbym miał przypuszczać, to może być tak, że nadpisujesz. Jeśli np. masz na dwóch polach 2 drzewa, to zapiszesz w kaflu drzewo, ale potem pojawi się drugie drzewo i nadpiszesz (o ile dobrze rozumiem, co robisz i jak to działa).

To należałoby przepisać i lepiej rozdzielić odpowiedzialności. Jeśli masz mapę, to w zasadzie masz już współrzędne x, y.

Przy czym niepotrzebnie konwertujesz to na piksele:

x += pc.getCalculatedImageWidth(TILE_SIZE);

Do renderingu spoko, ale wykrywać kolizje możesz używając współrzędnych kaflowych. Wtedy nie musisz przeliczać na piksele, tylko poruszasz się po polach, jedno pole w górę/dół/lewo/prawo. I możesz sobie dodać/odjąć 1 do x czy y i masz już indeks tablicy mapTileNumbers[col][row], pod którą możesz sobie sprawdzić, co tam dokładnie jest.

0
Satanistyczny Awatar napisał(a):

Nie dziwię ci się, że się pogubiłeś we własnym kodzie. Jak chcesz w tym grzebać zamiast zaorać i napisać bardziej logiczną i czytelną wersję to dopisz sobie jakieś logowanie na konsolę co się dzieje w programie - jakie warunki są sprawdzane albo odpal to krok po kroku w debugerze po ustawieniu breakpointu tam gdzie powinnien się zacząć wykonywać kod sprawdzający.

Wskazanie debugera jest podstawowe. Ważniejsza umiejetnosc niż powiększanie ilości linii miernego kodu.

Kod jest brzydki, w jakiejś archaicznej wersji javy. Tutorial starszy od ciebie od jakiegoś Kriszana ?
a) stringi do określenia kierunku ruchu - pachnie jak rok 2000 - gdy to idealny obszar na enum
b) pętle po integerowym indeksie, tego sie dziś bardzo mało stosuje
c) kod prawo-lewo czy góra-dół łatwo by sie dal zrobić JEDEN ale sprametryzowany kierunkiem.
d) nieczyste / kłamliwe nazwy metod, np private void getTileImage()

Nie wnikam w kod, jest męczący, znalazło by się uwag jeszcze z dziesiec.
W tym sensiesie zgadzam z @Satanistyczny Awatar ale może pomęcz się, jeśli ten projekt zaraz zabijesz.
Debugera sie ucz, i zmień kurs javy na coś nowszego

0

Ogólnie powinieneś wrzucić cały kod do analizy, bo w głowie nikt tego nie sprawdza tylko łatwiej jest sobie lokalnie odpalić i przedebugować.

Jako, że widzę teoretycznie jaki jest błąd bo ty sprawdzasz czy teraz jest kolizja i przesuwasz, ale po przesunięciu jest dopiero kolizja, powinieneś do danego położenia dodać + speed, teraz masz nowe położenie i sprawdzasz czy na nowym nie ma kolizji jak jest to potem nie dodajesz tego tej zmiennej speed.

Musisz jakby jeden ruch do przodu być przed, jak masz x = 10, to jak idziesz w prawo np. jedna kafelka to 5x, to przy x = 10 nie sprawdzasz czy te 10 ma kolizję z kimś tylko dodajesz 10 + 5 i sprawdzasz czy to ma kolizje jak ma to nie dodajesz do x + 5, a jak nie ma to dodajesz jeden ruch do przodu musisz przewidywać.

Wystarczy, że do położenia gracza dodasz ten + speed i dopiero wtedy sprawdzisz czy jest kolizja, to powinno naprawić problem, jeśli jest to nie przesuwasz się, jesli nie ma to tak, mógłby być jedynie problem jeśli speed by był na tyle duży, że pominąłby kilka kafelek coś jak quantum teleportation elektronu, ale jeśli można jedynie tylko jedną kafelkę w każdym kierunku się poruszać to nie będzie takiego błędu.

2
Satanistyczny Awatar napisał(a):

Nie dziwię ci się, że się pogubiłeś we własnym kodzie. Jak chcesz w tym grzebać zamiast zaorać i napisać bardziej logiczną i czytelną wersję to dopisz sobie jakieś logowanie na konsolę co się dzieje w programie - jakie warunki są sprawdzane albo odpal to krok po kroku w debugerze po ustawieniu breakpointu tam gdzie powinnien się zacząć wykonywać kod sprawdzający.

Zaorałem napisałem od nowa i już działa. :)

0

I jak to teraz wygląda?

0
LukeJL napisał(a):

I jak to teraz wygląda?

W sensie kod? Zrobiłęm Interface Tile, zrobiłem 6 Klas, które implementują ten interface, potem napisałem wzorzec Factory, po wczytaniu mapy zwraca mi odpowiednią cyfrę z mapy i w zależności jaka jest cyfra to Factory zwraca mi odpowiedni obiekt, który jest dodawany do listy Tile. Z listy w pętli rysuje mi odpowiedni kafelek w odpowiednim miejscu. A implementacja metod xMove(Player palyer), yMove(Player player), onKeyPressedKeyEvent key), onKeyReleased(KeyEvent key) jest praktycznie bez zmian z wyjątkiem warunku w pętli, że zamiast tablicy jest lista, i ten fragment (dla x też):

        if (speedY < 0 && up) {
            y += speedY;
        } else if (speedY > 0 && down) {
            y += speedY;
        }

jest teraz w pętli i odpowiednio zmodyfikowany pod listę.

0
Ukulelemelelele napisał(a):

W sensie kod? Zrobiłęm Interface Tile, zrobiłem 6 Klas, które implementują ten interface,

Po co ci klasa do każdej płytki?

0
LukeJL napisał(a):

Po co ci klasa do każdej płytki?

Innego pomysłu nie miałem, a każda płytka musi mieć w sobie obiekt Rectangle i stałą boolean COLLISION.

Całość wygląda tak:

public class TileManager {

    private static final ProportionCalculator pc = new ProportionCalculator();
    private static final Factory factory = new Factory();
    private static final List<Tile> tiles = new ArrayList<>();
    private static final int SPEED = 2;
    private static final int MAX_WORLD_COLUMNS = 50;
    private static final int MAX_WORLD_ROWS = 50;
    private static final int TILE_SIZE = 40;

    private int[][] mapTileNumbers = new int[MAX_WORLD_COLUMNS][MAX_WORLD_ROWS];

    private final String path;

    private int x;
    private int y;
    private int speedY;
    private int speedX;

    private boolean up;
    private boolean down;
    private boolean left;
    private boolean right;

    public TileManager(String path) {
        this.path = path;
        loadMap(path);
        createTiles();
    }

    private void loadMap(String path) {
        try {
            InputStream inputStream = getClass().getResourceAsStream(path);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            int col = 0;
            int row = 0;
            while (col < MAX_WORLD_COLUMNS && row < MAX_WORLD_ROWS) {
                String line = bufferedReader.readLine();
                while (col < MAX_WORLD_COLUMNS) {
                    String[] numbers = line.split(" ");
                    int number = Integer.parseInt(numbers[col]);
                    mapTileNumbers[col][row] = number;
                    col++;
                }
                if (col == MAX_WORLD_COLUMNS) {
                    col = 0;
                    row++;
                }
            }
            bufferedReader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void onKeyPressed(KeyEvent key) {
        if (up) {
            if (key.getKeyCode() == KeyEvent.VK_UP) {
                speedY = SPEED;
            }
        } else {
            speedY = 0;
        }

        if (down) {
            if (key.getKeyCode() == KeyEvent.VK_DOWN) {
                speedY = -SPEED;
            }
        } else {
            speedY = 0;
        }
        if (left) {
            if (key.getKeyCode() == KeyEvent.VK_LEFT) {
                speedX = SPEED;
            }
        } else {
            speedX = 0;
        }
        if (right) {
            if (key.getKeyCode() == KeyEvent.VK_RIGHT) {
                speedX = -SPEED;
            }
        } else {
            speedX = 0;
        }
    }

    public void onKeyReleased(KeyEvent key) {
        if (key.getKeyCode() == KeyEvent.VK_UP) {
            speedY = 0;
        }
        if (key.getKeyCode() == KeyEvent.VK_DOWN) {
            speedY = 0;
        }

        if (key.getKeyCode() == KeyEvent.VK_LEFT) {
            speedX = 0;
        }
        if (key.getKeyCode() == KeyEvent.VK_RIGHT) {
            speedX = 0;
        }
    }

    public void update(Player player) {
        xMove(player);
        yMove(player);
    }

    private void xMove(Player player) {
        left = true;
        right = true;

        //Collision X
        if (speedX < 0) {
            for (int i = 0; i < tiles.size(); i++) {
                if (tiles.get(i).isCollision()) {
                    if (player.getEntityCollisionLeft().getRectangle().intersects(tiles.get(i).getRectangle())) {
                        left = false;
                        break;
                    }
                }
            }
        } else if (speedX > 0) {
            for (int i = 0; i < tiles.size(); i++) {
                if (tiles.get(i).isCollision()) {
                    if (player.getEntityCollisionRight().getRectangle().intersects(tiles.get(i).getRectangle())) {
                        right = false;
                        break;
                    }
                }
            }
        }

        for (int i = 0; i < tiles.size(); i++) {
            if (speedX < 0 && left) {
                tiles.get(i).getRectangle().x += speedX;
            } else if (speedX > 0 && right) {
                tiles.get(i).getRectangle().x += speedX;
            }
        }
    }

    private void yMove(Player player) {
        up = true;
        down = true;

        //Collision Y
        if (speedY < 0) {
            for (int i = 0; i < tiles.size(); i++) {
                if (tiles.get(i).isCollision()) {
                    if (player.getEntityCollisionUp().getRectangle().intersects(tiles.get(i).getRectangle())) {
                        up = false;
                        break;
                    }
                }
            }
        } else if (speedY > 0) {
            for (int i = 0; i < tiles.size(); i++) {
                if (tiles.get(i).isCollision()) {
                    if (player.getEntityCollisionDown().getRectangle().intersects(tiles.get(i).getRectangle())) {
                        down = false;
                        break;
                    }
                }
            }
        }

        for (int i = 0; i < tiles.size(); i++) {
            if (speedY < 0 && up) {
                tiles.get(i).getRectangle().y += speedY;
            } else if (speedY > 0 && down) {
                tiles.get(i).getRectangle().y += speedY;
            }
        }
    }

    private void createTiles() {
        int col = 0;
        int row = 0;
        int x = 0;
        int y = 0;
        while (col < MAX_WORLD_COLUMNS && row < MAX_WORLD_ROWS) {
            int tileNumber = mapTileNumbers[col][row];
            tiles.add(factory.getTile(
                    tileNumber,
                    x,
                    y,
                    pc.getCalculatedImageWidth(TILE_SIZE),
                    pc.getCalculatedImageHeight(TILE_SIZE)));

            col++;
            x += pc.getCalculatedImageWidth(TILE_SIZE);
            if (col == MAX_WORLD_COLUMNS) {
                col = 0;
                x = 0;
                row++;
                y += pc.getCalculatedImageHeight(TILE_SIZE);
            }
        }
    }

    public void draw(Graphics2D g2d) {
        for (Tile tile : tiles) {
            tile.draw(g2d);
        }
    }
}
public class Factory {

    private static final int GRASS = 0;
    private static final int WALL = 1;
    private static final int WATER = 2;
    private static final int EARTH = 3;
    private static final int TREE = 4;
    private static final int SAND = 5;


    public Tile getTile(int number, int xPos, int yPos, int width, int height) {
        switch (number) {
            case GRASS:
                return new Grass(xPos, yPos, width, height);
            case WALL:
                return new Wall(xPos, yPos, width, height);
            case WATER:
                return new Water(xPos, yPos, width, height);
            case EARTH:
                return new Earth(xPos, yPos, width, height);
            case TREE:
                return new Tree(xPos, yPos, width, height);
            case SAND:
                return new Sand(xPos, yPos, width, height);
            default:
                return null;
        }
    }
}
public class Earth implements Tile {

    private Rectangle rectangle;
    private BufferedImage image;

    private boolean collision;

    private int horizontalSpeed;
    private int verticalSpeed;

    public Earth(int xPos, int yPos, int width, int height) {
        this.rectangle = new Rectangle(xPos, yPos, width, height);
        collision = false;
        loadImage();
    }

    @Override
    public void loadImage() {
        try {
            image = ImageIO.read(getClass().getResourceAsStream("/tiles/earth.png"));
        } catch (IOException e){
            e.printStackTrace();
        }
    }

    @Override
    public void setHorizontalSpeed(int horizontalSpeed) {
        this.horizontalSpeed = horizontalSpeed;
    }

    @Override
    public void setVerticalSpeed(int verticalSpeed) {
        this.verticalSpeed = verticalSpeed;
    }

    @Override
    public void xMove() {
        rectangle.x += horizontalSpeed;
    }

    @Override
    public void yMove() {
        rectangle.y += verticalSpeed;
    }

    @Override
    public Rectangle getRectangle() {
        return rectangle;
    }

    @Override
    public boolean isCollision() {
        return collision;
    }

    @Override
    public void draw(Graphics2D g2d) {
        g2d.drawImage(image, rectangle.x, rectangle.y, rectangle.width, rectangle.height, null);
    }
}
public interface Tile {

    void setHorizontalSpeed(int horizontalSpeed);
    void setVerticalSpeed(int horizontalSpeed);
    void xMove();
    void yMove();
    void loadImage();
    Rectangle getRectangle();
    boolean isCollision();
    void draw(Graphics2D g2d);
}
0
Ukulelemelelele napisał(a):
        if (speedY < 0 && up) {
            y += speedY;
        } else if (speedY > 0 && down) {
            y += speedY;
        }

Nie wchodząc w szczegóły, nie możesz połączyć tych warunków? Widzę że bardzo nie lubisz łączyć warunków, a można by napisać tak:

        if ((speedY < 0 && up) || (speedY > 0 && down)) {
            y += speedY;
        }

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