Pomoc w tworzeniu klasy z istniejącego już kodu. Arkanoid

0

Witam,
Napisałem grę w Javie, jest to arkanoid, gra działa ale potrzebuję rozdzielić kod na dodatkową klasę (najlepiej klasę o nazwie "Player") i nie wiem jak się do tego zabrać.
Miałem nadzieję na przerzucenie sterowania paletką ale nie potrafię tego wykonać. Proszę o szybką pomoc z góry dziękuję.
Oto kod żródłowy:

package BrickBreaker;
import javax.swing.JFrame;

public class Main {

	public static void main(String[] args) {
		JFrame obj = new JFrame();
		Gameplay gamePlay = new Gameplay();
		obj.setBounds(10, 10, 700, 600);
		obj.setTitle("Brick Breaker");
		obj.setResizable(false);
		obj.setVisible(true);
		obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		obj.add(gamePlay);
	}

}

package BrickBreaker;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.Timer;
import javax.swing.JPanel;

public class Gameplay extends JPanel  implements KeyListener, ActionListener {
	private boolean play = false; 
	private int score = 0;
	
	private int totalBricks = 21;
	
	private Timer timer;
	private int delay = 6;
	
	private int playerX = 310;
	
	private int ballposX =  (int) (Math.random() * 500 ) ;
	private int ballposY = 350;
	private int ballXdir = -1;
	private int ballYdir = -2;
	
	private MapGenerator map;

	public Gameplay() {
		map = new MapGenerator( 3, 7);
		addKeyListener(this);
		setFocusable(true);
		setFocusTraversalKeysEnabled(false);
		timer = new Timer(delay, this);
		timer.start();
	}
		
		
	
	public void paint(Graphics g) {
		//tło
		g.setColor(Color.black);
		g.fillRect(1,1, 692, 592);
		
		//rysowanie mapy
		map.draw((Graphics2D)g);
		
		//ramka
		g.setColor(Color.yellow);
		g.fillRect(0, 0, 3, 592);
		g.fillRect(0, 0, 692, 3);
		g.fillRect(691, 0, 3, 592);
		
		
		//Score
		g.setColor(Color.white);
		g.setFont(new Font("serif", Font.BOLD, 25));
		g.drawString(""+score, 590, 30);
		
		//panel
		g.setColor(Color.green);
		g.fillRect(playerX, 550, 100, 8);
		
		
		//Kulka
		g.setColor(Color.yellow);
		g.fillOval(ballposX, ballposY, 20, 20);
		
		//warunek zwycięstwa
		if(totalBricks <= 0) {
			play = false;
			ballXdir = 0;
			ballYdir = 0;
			g.setColor(Color.RED);
			g.setFont(new Font("serif", Font.BOLD, 30));
			g.drawString("Zwycięstwo:", 260, 300);
			
			g.setFont(new Font("serif", Font.BOLD, 20));
			g.drawString("Wciśnij Enter aby zresetować", 230, 350);
		}
		
		//przegrana
		if(ballposY > 570) {
			play = false;
			ballXdir = 0;
			ballYdir = 0;
			g.setColor(Color.RED);
			g.setFont(new Font("serif", Font.BOLD, 30));
			g.drawString("Koniec gry", 280, 300);
			
			g.setFont(new Font("serif", Font.BOLD, 20));
			g.drawString("Wciśnij Enter aby zresetować", 230, 350);
		}
		
		g.dispose();
		
	}
	
	
	@Override
	public void actionPerformed(ActionEvent e) {
		timer.start();
		if(play) {
			if(new Rectangle(ballposX, ballposY, 20, 20).intersects(new Rectangle(playerX, 550, 100, 8))){
				ballYdir = -ballYdir;
			}
			
			A: for(int i = 0; i<map.map.length; i++) {
				for(int j = 0; j<map.map[0].length; j++) {
					if(map.map[i][j] > 0) {
						int brickX = j * map.brickWidth +80;
						int brickY = i * map.brickHeight + 50;
						int brickWidth = map.brickWidth;
						int brickHeight = map.brickHeight;
						
						Rectangle rect = new Rectangle(brickX, brickY, brickWidth, brickHeight);
						Rectangle ballRect = new Rectangle(ballposX, ballposY, 20, 20);
						Rectangle brickRect= rect;
						
						if(ballRect.intersects(brickRect)) {
							map.setBrickValue(0,  i,  j);
							totalBricks--;
							score += 5;
							
							if(ballposX +19 <=brickRect.x || ballposX +1 >= brickRect.x + brickRect.width) {
								ballXdir = -ballXdir;
							}
							else {
								ballYdir = -ballYdir;
							}
							
							break A;
						}
					}
				}
			}
			
			
			ballposX += ballXdir;
			ballposY += ballYdir;
			if (ballposX < 0) {
				ballXdir = -ballXdir;
			}
			if (ballposY < 0) {
				ballYdir = -ballYdir;
			}
			if (ballposX > 670) {
				ballXdir = -ballXdir;
			}
		}
		repaint();
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {

		
	}

	@Override
	public void keyReleased(KeyEvent arg0) {

		
	}

	@Override
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
			if(playerX > 600){
				playerX = 600;
			}
			else {
				moveRight();
			}
		}
		if(e.getKeyCode() == KeyEvent.VK_LEFT) {
			if(playerX < 10){
				playerX = 10;
			}
			else {
				moveLeft();
			}
		}
		if(e.getKeyCode() == KeyEvent.VK_ENTER) {
			if(!play) {
				play = true;
				ballposX = (int) (Math.random() * 500 ) ;
				ballposY = 350;
				ballXdir = -1;
				ballYdir = -2;
				playerX = 310;
				score = 0;
				totalBricks = 21;
				map= new MapGenerator(3, 7);
				
				repaint();
				
			}
		}
		
	}
	public void moveRight() {
		play = true;
		playerX+=20;
		
	}
	public void moveLeft() {
		play = true;
		playerX-=20;
	}
}
package BrickBreaker;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class MapGenerator {
	public int map[][];
	public int brickWidth;
	public int brickHeight;
	public MapGenerator(int row, int col) {
		map = new int[row][col];
		for(int i =0; i < map.length; i++){
			for (int j=0; j< map[0].length; j++) {
				map[i][j] = 1;
			}
		}
		brickWidth= 540/col;
		brickHeight = 150/row;
	}
	public void draw(Graphics2D g) {
		for(int i =0; i < map.length; i++){
			for (int j=0; j< map[0].length; j++) {
				if (map[i][j] > 0) {
					g.setColor(Color.lightGray);
					g.fillRect(j * brickWidth + 80, i * brickHeight +50, brickWidth, brickHeight);
					
					g.setStroke(new BasicStroke(3));
					g.setColor(Color.black);
					g.drawRect(j * brickWidth + 80, i * brickHeight +50, brickWidth, brickHeight);
				}
			}
		}
	}
	public void setBrickValue(int value, int row, int col) {
		map[row][col] = value;
	}
}
0

W twoim kodzie jest dużo powtórzeń i niepotrzebnego skomplikowania. Moim zdaniem powinieneś stworzyć obiekty takie jak Ball, Player, Brick.
Odpowiadając na twoje pytanie, to zastanów się za co ma być odpowiedzialny ten obiekt Player. jeśli tylko za ruszanie paletką to powinien mieć metody moveLeft() i moveRight() i zawierać pozycję. Powinieneś też wyciągnąć do stałych wszystkie magiczne liczby.

0
bames napisał(a):

W twoim kodzie jest dużo powtórzeń i niepotrzebnego skomplikowania. Moim zdaniem powinieneś stworzyć obiekty takie jak Ball, Player, Brick.
Odpowiadając na twoje pytanie, to zastanów się za co ma być odpowiedzialny ten obiekt Player. jeśli tylko za ruszanie paletką to powinien mieć metody moveLeft() i moveRight() i zawierać pozycję. Powinieneś też wyciągnąć do stałych wszystkie magiczne liczby.

Brzmi rozsądnie, tylko ja nie umiem programować... Tego kodu nie pisałem samemu, podążałem za instrukcjami...

1

Tak z grubsza to samo wydzielenie klasy Player mogło by tak wyglądać:

class Player {

  private static final int POSITION_Y = 550;
  private static final int WIDTH = 100;
  private static final int HEIGHT = 8;
  private static final int STEP = 20;
  private int position;

  Player(int position) {
    this.position = position;
  }

  void draw(Graphics graphics) {
    graphics.setColor(Color.green);
    graphics.fillRect(position, POSITION_Y, WIDTH, HEIGHT);
  }

  Rectangle rectangle() {
    return new Rectangle(position, POSITION_Y, WIDTH, HEIGHT);
  }

  void moveLeft() {
    if (position > 10) {
      position -= STEP;
    }
  }

  void moveRight() {
    if (position < 600) {
      position += STEP;
    }
  }

}

i wtedy

public class Gameplay extends JPanel implements KeyListener, ActionListener {

  private static final int PLAYER_START_POSITION = 310;
  private boolean play = false;
  private int score = 0;

  private int totalBricks = 21;

  private Timer timer;
  private int delay = 6;


  private Player player = new Player(PLAYER_START_POSITION);

  private int ballposX = (int) (Math.random() * 500);
  private int ballposY = 350;
  private int ballXdir = -1;
  private int ballYdir = -2;

  private MapGenerator map;

  public Gameplay() {
    map = new MapGenerator(3, 7);
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
    timer = new Timer(delay, this);
    timer.start();
  }

  public void paint(Graphics g) {
    //tło
    g.setColor(Color.black);
    g.fillRect(1, 1, 692, 592);

    //rysowanie mapy
    map.draw((Graphics2D) g);

    //ramka
    g.setColor(Color.yellow);
    g.fillRect(0, 0, 3, 592);
    g.fillRect(0, 0, 692, 3);
    g.fillRect(691, 0, 3, 592);

    //Score
    g.setColor(Color.white);
    g.setFont(new Font("serif", Font.BOLD, 25));
    g.drawString("" + score, 590, 30);

    //player
    player.draw(g);

    //Kulka
    g.setColor(Color.yellow);
    g.fillOval(ballposX, ballposY, 20, 20);

    //warunek zwycięstwa
    if (totalBricks <= 0) {
      play = false;
      ballXdir = 0;
      ballYdir = 0;
      g.setColor(Color.RED);
      g.setFont(new Font("serif", Font.BOLD, 30));
      g.drawString("Zwycięstwo:", 260, 300);

      g.setFont(new Font("serif", Font.BOLD, 20));
      g.drawString("Wciśnij Enter aby zresetować", 230, 350);
    }

    //przegrana
    if (ballposY > 570) {
      play = false;
      ballXdir = 0;
      ballYdir = 0;
      g.setColor(Color.RED);
      g.setFont(new Font("serif", Font.BOLD, 30));
      g.drawString("Koniec gry", 280, 300);

      g.setFont(new Font("serif", Font.BOLD, 20));
      g.drawString("Wciśnij Enter aby zresetować", 230, 350);
    }

    g.dispose();

  }

  @Override
  public void actionPerformed(ActionEvent e) {
    timer.start();
    if (play) {
      if (new Rectangle(ballposX, ballposY, 20, 20)
          .intersects(player.rectangle())) {
        ballYdir = -ballYdir;
      }

      A:
      for (int i = 0; i < map.map.length; i++) {
        for (int j = 0; j < map.map[0].length; j++) {
          if (map.map[i][j] > 0) {
            int brickX = j * map.brickWidth + 80;
            int brickY = i * map.brickHeight + 50;
            int brickWidth = map.brickWidth;
            int brickHeight = map.brickHeight;

            Rectangle rect = new Rectangle(brickX, brickY, brickWidth, brickHeight);
            Rectangle ballRect = new Rectangle(ballposX, ballposY, 20, 20);
            Rectangle brickRect = rect;

            if (ballRect.intersects(brickRect)) {
              map.setBrickValue(0, i, j);
              totalBricks--;
              score += 5;

              if (ballposX + 19 <= brickRect.x || ballposX + 1 >= brickRect.x + brickRect.width) {
                ballXdir = -ballXdir;
              } else {
                ballYdir = -ballYdir;
              }

              break A;
            }
          }
        }
      }

      ballposX += ballXdir;
      ballposY += ballYdir;
      if (ballposX < 0) {
        ballXdir = -ballXdir;
      }
      if (ballposY < 0) {
        ballYdir = -ballYdir;
      }
      if (ballposX > 670) {
        ballXdir = -ballXdir;
      }
    }
    repaint();

  }

  @Override
  public void keyTyped(KeyEvent arg0) {

  }

  @Override
  public void keyReleased(KeyEvent arg0) {

  }

  @Override
  public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
      play = true;
      player.moveRight();
    }
    if (e.getKeyCode() == KeyEvent.VK_LEFT) {
      play = true;
      player.moveLeft();
    }
    if (e.getKeyCode() == KeyEvent.VK_ENTER) {
      if (!play) {
        play = true;
        ballposX = (int) (Math.random() * 500);
        ballposY = 350;
        ballXdir = -1;
        ballYdir = -2;
        player = new Player(PLAYER_START_POSITION);
        score = 0;
        totalBricks = 21;
        map = new MapGenerator(3, 7);

        repaint();

      }
    }

  }
}
0

Dziękuję za odpowiedź. Skopiowałem kod ale pojawia się błąd przy włączaniu: Could not find or load main class org.hsqldb.util.CodeSwitcher

1

Masz coś źle w importach. Ja nigdzie nie mam takiej zależności.

0

Tak jeszcze podpowiem, że jeżeli robisz to dla siebie, to zacznij od podstaw. Chociaż to o co pytasz nie jest skomplikowane, to jest dla ciebie na początek trudne, niezrozumiałe, przez co możesz sie niepotrzebnie zniechecic.

0

Uczelnia nie pyta czy to jest zrozumiałe :( Nadal walczę z tym problemem inportów, sprawdzam i sprawdzam i nie mogę znaleźć błędu

1

A dobry projekt odpalasz? Bo to czego ci niby brakuje to jest w ogóle nie związane z tym projektem.

0

Ugh właśnie zauważyłem to okienko z główną klasą main dzięki wielkie. Na szczęście działa, już się bałem bo nawet poprzednia wersja nieedytowana mi nie działała.

0

Tutaj: https://gitlab.com/bames/arkanoid-refactor/tree/master/src/main/java/pl/kubie
możesz sobie zobaczyć jakby to wyglądało w troche bardziej ludzkiej wersji. Do dobrego kodu jeszcze daleko, ale to zdecydowanie krok w dobrą stronę.

0

Chciał bym jeszcze zapytać o klasę Player, którą napisałeś bames. Nie do końca wiem co się tam dzieje. Zmieniam wartości liczbowe w kodzie i nie widzę różnicy w programie. Przy nazwie tej klasy znajduje się jeszcze niebieski trójkąt i nie wiem co to oznacza. Proszę o proste wyjaśnienie.

class Player {
 
  private static final int POSITION_Y = 550;
  private static final int WIDTH = 100;
  private static final int HEIGHT = 8;
  private static final int STEP = 20;
  private int position;
 
  Player(int position) {
    this.position = position;
  }
 
  void draw(Graphics graphics) {
    graphics.setColor(Color.green);
    graphics.fillRect(position, POSITION_Y, WIDTH, HEIGHT);
  }
 
  Rectangle rectangle() {
    return new Rectangle(position, POSITION_Y, WIDTH, HEIGHT);
  }
 
  void moveLeft() {
    if (position > 10) {
      position -= STEP;
    }
  }
 
  void moveRight() {
    if (position < 600) {
      position += STEP;
    }
  }
 
}
0

Ale jakie wartości zmieniasz?

0

Te
private static final int POSITION_Y = 550;
private static final int WIDTH = 100;
private static final int HEIGHT = 8;
private static final int STEP = 20;

Przydały by się komentarze, bo nie będę wiedział jak odpowiedzieć na pytanie co to robi i po co to tu jest

1
private static final int POSITION_Y = 550; // Ustala pozycje na osi Y, tzn, żeby pionek gracza był na dole ekranu
private static final int WIDTH = 100; // Szerokość pionka
private static final int HEIGHT = 8; // Wysokość pionka
private static final int STEP = 20; // Krok, tzn. o tyle przesuwa się pionek przy jednym ruchu
0

Pionek znaczy ta paletka którą się kieruje? Zmieniam np wartość STEP z 20 na nawet 400 i po kliknięciu strzałki nie widzę różnicy o ile się przesunęło kiedy było ustawione 20.

0

Wklej swój aktualny kod z Gameplay

0
package BrickBreaker;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.Timer;
import javax.swing.JPanel;

public class Gameplay extends JPanel  implements KeyListener, ActionListener {
    private boolean play = false; 
    private int score = 0;

    private int totalBricks = 21;

    private Timer timer;
    private int delay = 6;

    private int playerX = 310;

    private int ballposX =  (int) (Math.random() * 500 ) ;
    private int ballposY = 350;
    private int ballXdir = -1;
    private int ballYdir = -2;

    private MapGenerator map;

    public Gameplay() {
        map = new MapGenerator( 3, 7);
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        timer = new Timer(delay, this);
        timer.start();
    }

    public void paint(Graphics g) {
        //tło
        g.setColor(Color.black);
        g.fillRect(1,1, 692, 592);

        //rysowanie mapy
        map.draw((Graphics2D)g);

        //ramka
        g.setColor(Color.yellow);
        g.fillRect(0, 0, 3, 592);
        g.fillRect(0, 0, 692, 3);
        g.fillRect(691, 0, 3, 592);

        //Score
        g.setColor(Color.white);
        g.setFont(new Font("serif", Font.BOLD, 25));
        g.drawString(""+score, 590, 30);

        //panel
        g.setColor(Color.green);
        g.fillRect(playerX, 550, 100, 8);

        //Kulka
        g.setColor(Color.yellow);
        g.fillOval(ballposX, ballposY, 20, 20);

        //warunek zwycięstwa
        if(totalBricks <= 0) {
            play = false;
            ballXdir = 0;
            ballYdir = 0;
            g.setColor(Color.RED);
            g.setFont(new Font("serif", Font.BOLD, 30));
            g.drawString("Zwycięstwo:", 260, 300);

            g.setFont(new Font("serif", Font.BOLD, 20));
            g.drawString("Wciśnij Enter aby zresetować", 230, 350);
        }

        //przegrana
        if(ballposY > 570) {
            play = false;
            ballXdir = 0;
            ballYdir = 0;
            g.setColor(Color.RED);
            g.setFont(new Font("serif", Font.BOLD, 30));
            g.drawString("Koniec gry", 280, 300);

            g.setFont(new Font("serif", Font.BOLD, 20));
            g.drawString("Wciśnij Enter aby zresetować", 230, 350);
        }

        g.dispose();

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        timer.start();
        if(play) {
            if(new Rectangle(ballposX, ballposY, 20, 20).intersects(new Rectangle(playerX, 550, 100, 8))){
                ballYdir = -ballYdir;
            }

            A: for(int i = 0; i<map.map.length; i++) {
                for(int j = 0; j<map.map[0].length; j++) {
                    if(map.map[i][j] > 0) {
                        int brickX = j * map.brickWidth +80;
                        int brickY = i * map.brickHeight + 50;
                        int brickWidth = map.brickWidth;
                        int brickHeight = map.brickHeight;

                        Rectangle rect = new Rectangle(brickX, brickY, brickWidth, brickHeight);
                        Rectangle ballRect = new Rectangle(ballposX, ballposY, 20, 20);
                        Rectangle brickRect= rect;

                        if(ballRect.intersects(brickRect)) {
                            map.setBrickValue(0,  i,  j);
                            totalBricks--;
                            score += 5;

                            if(ballposX +19 <=brickRect.x || ballposX +1 >= brickRect.x + brickRect.width) {
                                ballXdir = -ballXdir;
                            }
                            else {
                                ballYdir = -ballYdir;
                            }

                            break A;
                        }
                    }
                }
            }

            ballposX += ballXdir;
            ballposY += ballYdir;
            if (ballposX < 0) {
                ballXdir = -ballXdir;
            }
            if (ballposY < 0) {
                ballYdir = -ballYdir;
            }
            if (ballposX > 670) {
                ballXdir = -ballXdir;
            }
        }
        repaint();

    }

    @Override
    public void keyTyped(KeyEvent arg0) {

    }

    @Override
    public void keyReleased(KeyEvent arg0) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
            if(playerX > 600){
                playerX = 600;
            }
            else {
                moveRight();
            }
        }
        if(e.getKeyCode() == KeyEvent.VK_LEFT) {
            if(playerX < 10){
                playerX = 10;
            }
            else {
                moveLeft();
            }
        }
        if(e.getKeyCode() == KeyEvent.VK_ENTER) {
            if(!play) {
                play = true;
                ballposX = (int) (Math.random() * 500 ) ;
                ballposY = 350;
                ballXdir = -1;
                ballYdir = -2;
                playerX = 310;
                score = 0;
                totalBricks = 21;
                map= new MapGenerator(3, 7);

                repaint();

            }
        }

    }
    public void moveRight() {
        play = true;
        playerX+=20;

    }
    public void moveLeft() {
        play = true;
        playerX-=20;
    }
}
1

Nie zaktualizowałeś tej klasy i w ogóle nie korzystasz z klasy Player to jak zmienianie tamtych wartości ma coś dać? W poście gdzie ci wkleiłem Player'a jest też nowa wersja tej klasy, która z niego korzysta...

Możesz przy okazji zaobserwować jak zmienił/uprościł się kod.

0

Właśnie uderzam się w czoło bo nie to skopiowałem... Przepraszam za utrudnienia

0

Kurcze bames jesteś mistrz dzięki za cierpliwość. A wracając do tego niebieskiego trójkąta przy nazwie klasy i metodach. Czy jest to zależne od tego, że użyłeś tutaj samego "void" a nie np "private void"?

0

Z jakiego IDE korzystasz?

0

Jeśli chodzi o program w którym piszę jest to Eclipse

1

Z tego co mówisz wynika, że masz racje, tzn. Eclipse tak oznacza widoczność pakietową, ale możesz zrobić screena dla pewności i pokazać. Dawno nie korzystałem z Eclipse'a i nie pamiętam jak on to oznacza.

0

Zaznaczyłem w czerwonych kółkach element o który mi chodzi.

1

Na to wygląda. Możesz dopisać do tej klasy/metody public i zobaczyć co się zmieni.

0

Tak, gdy wpiszę "public void" trójkąt zmienia się na zieloną kropkę, nie wiedziałem czy aplikacja przez taką zmianę może przestać funkcjonować poprawnie ale wygląda na to, że nie ma to tutaj dużego wpływu. Jeszcze raz dziękuję.

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