Napisałem grę, ale...

0

Napisałem w Javie Arkanoida. Ogólnie rzecz biorąc działa nieźle, ale... No właśnie - nie jest idealna :P Nie działa w pełni dobrze. Napiszę jakie mam problemy:

  1. Kulka nie odbija się prawidłowo od deski (paletki, którą się steruje) - kąt odbicia nie jest zawsze przewidywalny.
  2. Kulka nie odbija się prawidłowo od boków ekranu (czasami przelatuje przez nie - tak samo i przez deskę czasem).

Problem polega na tym, że współrzędne zapisuję w zmiennych double - i czasem piłka po zmianie kąta po kontakcie z przeszkodą - nie opuszcza w pełni przeszkody - co powoduje następną zmianę konta i tak w kółko, aż albo nie wyleci za ekran, albo wróci. Proszę o pomoc jak to załatwić. Nie będę sępem i podzielę się z Wami moim kodem :)

//Ark.java
import java.awt.Color;
import java.awt.Cursor;
import java.awt.DisplayMode;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Ark extends JFrame implements KeyListener
{
	
	private class ArkanoidPanel extends JPanel implements MouseMotionListener, MouseListener
	{
		private Cegielka ceg [][];
		private Deska des;
		private Kulka kul;
		private boolean start;
		
		public ArkanoidPanel(int xE, int yE)
		{
			ceg = zbudujCegielki(xE, yE);
			des = new Deska(xE, yE);
			kul = new Kulka(xE, yE, des);
			start = false;

			addMouseMotionListener(this);
			addMouseListener(this);
		}
		
		public Cegielka [][] getC()
		{
			return ceg;
		}
		
		public Deska getD()
		{
			return des;
		}
		
		public Kulka getK()
		{
			return kul;
		}
		
		public Cegielka [][] zbudujCegielki(int xE, int yE)
		{
			Cegielka [][] c = new Cegielka [10][20];
			double ax = 0.005 * xE;
			double ay = 0.04 * yE;
			
			for (int i = 0; i < 10; i++)
			{
				for (int j = 0; j < 20; j++)
				{
					c[i][j] = new Cegielka();
					c[i][j].setX((int)(ax));
					c[i][j].setY((int)(ay));
					c[i][j].setW((int)(0.04 * xE));
					c[i][j].setH((int)(0.02 * yE));
					
					ax += 0.05 * xE;
				}
				
				ay += 0.03 * yE;
				ax = 0.005 * xE;
			}
			
			return c;
		}
		
		public void wyswietlCegielki(Graphics g)
		{
			for (int i = 0; i < ceg.length; i ++)
				for (int j = 0; j < ceg[i].length; j++)
					ceg[i][j].wyswietlCegielke(g);
		}
		
		public void wyswietlDeske(Graphics g)
		{
			des.wyswietlDeske(g);
		}
		
		public void wyswietlKulke(Graphics g)
		{
			kul.wyswietlKulke(g);
		}
		
		public boolean czyZawiera(Kulka k, int x, int y)
		{
			if (((x - k.getX() - k.getR() / 2) * (x - k.getX() - k.getR() / 2)) + ((y - k.getY() - k.getR() / 2) * (y - k.getY() - k.getR() / 2)) <= (k.getR() / 2) * (k.getR() / 2))
				return true;
			
			return false;
		}
		
		public int yOdcinek(Odcinek o, int x)
		{
			return ((o.getY2() - o.getY1()) * (x - o.getX1()) / (o.getX2() - o.getX1()) + o.getY1());
		}
		
		public boolean kolizjaKulkaOdcinek(Kulka k, Odcinek o)
		{
			if (o.getX1() == o.getX2() && o.getY1() == o.getY2())
				return czyZawiera(k, o.getX1(), o.getY1());
			
			else if (o.getX1() == o.getX2())
			{
				for (int i = o.getY1(); i <= o.getY2(); i++)
					if (czyZawiera(k, o.getX1(), i))
						return true;
			}
			
			else if (o.getY1() == o.getY2())
			{
				for (int i = o.getX1(); i <= o.getX2(); i++)
					if (czyZawiera(k, i, o.getY1()))
						return true;
			}
			
			else
				for (int i = o.getX1(); i <= o.getX2(); i++)
					if (czyZawiera(k, i, yOdcinek(o, i)))
						return true;
			
			return false;
		}
		
		public int kolizjaKulkaCegielka(Kulka k, Cegielka c)
		{
			if (c.getS() == false)
				return -1;
			
			else
				for (int i = 0; i < 4; i++)
					if (kolizjaKulkaOdcinek(k, c.zwrocOdcinek(i)))
						return i;
			
			return -1;
		}
		
		public int kolizjaKulkaBanda(Kulka k)
		{
			if (k.getX() + k.getR() / 2 <= 0) 
				return 3;
			
			else if ((k.getX() + k.getR() / 2) > Toolkit.getDefaultToolkit().getScreenSize().width)
				return 1;
			
			else if ((k.getY() + k.getR() / 2) <= 0)
				return 0;
			
			else if ((k.getY() + k.getR() / 2) > Toolkit.getDefaultToolkit().getScreenSize().height)
				return 2;
			
			return -1;
		}
		
		public boolean kolizjaKulkaDeska(Kulka k, Deska d)
		{
			return kolizjaKulkaOdcinek(k, d.zwrocOdcinek());
		}
		
		public void przesunKulke()
		{
			kul.przesun();
			
			for (int i = 0; i < 10; i++)
				for (int j = 0; j < 20; j++)
				{
					int bok = -1;
					
					if ((bok = kolizjaKulkaCegielka(kul, ceg[i][j])) != -1)
					{
						ceg[i][j].setS(false);
						kul.zmienKatCegielka(bok);
					}
				}
			
			int bok = -1;
			
			if ((bok = kolizjaKulkaBanda(kul)) != -1)
				kul.zmienKatBanda(bok);
			
			if (kolizjaKulkaDeska(kul, des))
				kul.zmienKatDeska(des);
		}
		
		
		
		public void paintComponent(Graphics g)
		{
			super.paintComponent(g);
			g.setColor(Color.black);
			
			wyswietlCegielki(g);
			wyswietlDeske(g);
			wyswietlKulke(g);
			
			if (start)
				przesunKulke();
		}
		
		@Override
		public void mouseDragged(MouseEvent me) {
		}

		@Override
		public void mouseMoved(MouseEvent me) {
			des.setX(me.getX() - des.getW() / 2);
			
			if (!start)
				kul.setX(me.getX() - kul.getR() / 2);
		}

		@Override
		public void mouseClicked(MouseEvent me) {
			start = true;
		}

		@Override
		public void mouseEntered(MouseEvent me) {
		}

		@Override
		public void mouseExited(MouseEvent me) {
		}

		@Override
		public void mousePressed(MouseEvent me) {
		}

		@Override
		public void mouseReleased(MouseEvent me) {
		}
	}

	@Override
	public void keyPressed(KeyEvent ke) {
		if (ke.getKeyCode() == KeyEvent.VK_ESCAPE)
			System.exit(0);
	}

	@Override
	public void keyReleased(KeyEvent ke) {
	}

	@Override
	public void keyTyped(KeyEvent ke) {
	}

	public Ark()
	{
		ArkanoidPanel p = new ArkanoidPanel(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
		add(p);
		
		addKeyListener(this);
		requestFocus();
		
		setUndecorated(true);
		setResizable(false);
		
		przelaczNaPelnyEkran();
		ukryjKursorMyszy();
		
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		new Wat(p);
	}
	
	public void przelaczNaPelnyEkran()
	{
		DisplayMode displayMode = new DisplayMode(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height, 24, 75);
		GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice device = environment.getDefaultScreenDevice();
		device.setFullScreenWindow(this);
		
		
		try 
		{
			device.setDisplayMode(displayMode);
		} 
		catch (IllegalArgumentException e)
		{
			System.out.println("Wyjątek!");
		}
	}
	
	public void ukryjKursorMyszy()
	{
		GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice device = environment.getDefaultScreenDevice();
		
		Cursor invisibleCursor = Toolkit.getDefaultToolkit().createCustomCursor(Toolkit.getDefaultToolkit().getImage(""), new Point(0, 0), "invisible");
		device.getFullScreenWindow().setCursor(invisibleCursor);
	}
	
	public static void main(String[] args) {
		new Ark();
	}
}
//Cegielka.java
import java.awt.Graphics;


public class Cegielka {
	private int x, y;
	private int w, h;
	private boolean s;
	
	public Cegielka()
	{
		s = true;
	}
	
	public int getX()
	{
		return x;
	}
	
	public int getY()
	{
		return y;
	}
	
	public int getW()
	{
		return w;
	}
	
	public int getH()
	{
		return h;
	}
	 
	 public boolean getS()
	 {
		 return s;
	 }
	 
	 public void setX(int nX)
	 {
		 x = nX;
	 }
	 
	 public void setY(int nY)
	 {
		 y = nY;
	 }
	 
	 public void setW(int nW)
	 {
		 w = nW;
	 }
	 
	 public void setH(int nH)
	 {
		 h = nH;
	 }
	 
	 public void setS(boolean bS)
	 {
		 s = bS;
	 }
	 
	 public void wyswietlCegielke(Graphics g)
	 {
		 if (s)
			 g.fillRect(x, y, w, h);
	 }
	 
	 public Odcinek zwrocOdcinek(int num)
	 {
		 switch (num)
		 {
		 case 0: return new Odcinek(x, y, x + w, y);
		 case 1: return new Odcinek(x + w, y, x + w, y + h);
		 case 2: return new Odcinek(x, y + h, x + w, y + h);
		 case 3: return new Odcinek(x, y, x, y + h);
		 default: return null;
		 }
	 }
	 
	 
}
//Deska.java
import java.awt.Graphics;


public class Deska {
	private int x, y;
	private int w, h;
	
	public Deska(int xE, int yE)
	{
		setWH(xE, yE);
		x = (int)((xE - w) / 2);
		y = (int)(0.95 * yE);
	}
	
	public void setX(int nX)
	{
		x = nX;
	}
	
	public void setY(int nY)
	{
		y = nY;
	}
	
	public void setWH(int xE, int yE)
	{
		w = (int)(0.1 * xE);
		h = (int)(0.01 * yE);
	}
	
	public int getX()
	{
		return x;
	}
	
	public int getY()
	{
		return y;
	}
	
	public int getW()
	{
		return w;
	}
	
	public int getH()
	{
		return h;
	}
	
	public void wyswietlDeske(Graphics g)
	{
		g.fillRect(x, y, w, h);
	}
	
	public Odcinek zwrocOdcinek()
	{
		return new Odcinek(x, y, x + w, y);
	}
	
	public double punktDeski(Kulka k)
	{
		return (double)w / (k.getX() + k.getR() / 2 - x);
	}
}
//Kulka.java
import java.awt.Graphics;
import java.util.Random;


public class Kulka {
	private double x, y;
	private int r;
	private double angle;
	
	public Kulka(int xE, int yE, Deska d)
	{
		setR(xE, yE);
		x = d.getX() + d.getW() / 2 - r / 2;
		y = d.getY() - r;
		katZZakresu(45, 135);
	}
	
	public void setX(int nX)
	{
		x = nX;
	}
	
	public void setY(int nY)
	{
		y = nY;
	}
	
	public void setR(int xE, int yE)
	{
		r = (int)(xE * yE / 100000);
	}
	
	public void setA(double dA)
	{
		angle = dA;
	}
	
	public int getX()
	{
		return (int)x;
	}
	
	public int getY()
	{
		return (int)y;
	}
	
	public int getR()
	{
		return r;
	}
	
	public double getA()
	{
		return angle;
	}
	
	public void wyswietlKulke(Graphics g)
	{
		g.fillOval((int)x, (int)y, r, r);
	}
	
	public void katZZakresu(int n1, int n2)
	{
		setA(((new Random()).nextInt(n2 + 1 - n1) + n1) * Math.PI / 180);
	}
	
	public double zwrocKat(int n1, int n2)
	{
		return ((new Random()).nextInt(n2 + 1 - n1) + n1) * Math.PI / 180;
	}
	
	public void przesun()
	{
		x += Math.cos(angle);
		y -= Math.sin(angle);
	}
	
	public void zmienKatCegielka(int num)
	{
		if (num == 0 || num == 2)
			angle = 2 * Math.PI - angle;
		
		else if (num == 1 || num == 3)
			angle = 3 * Math.PI - angle;
	}
	
	public void zmienKatDeska(Deska d)
	{
		angle = d.punktDeski(this) * zwrocKat(90, 90) + zwrocKat(45, 45);
	}
	
	public void zmienKatBanda(int num)
	{
		if (num == 0 || num == 2)
			angle = 2 * Math.PI - angle;
		
		else if (num == 1 || num == 3)
			angle = 5 * Math.PI - 2 * angle;
	}
}
//Odcinek.java
public class Odcinek {
	private int x1, y1, x2, y2;
	
	public Odcinek(int nX1, int nY1, int nX2, int nY2)
	{
		x1 = nX1;
		y1 = nY1;
		x2 = nX2;
		y2 = nY2;
	}
	
	public int getX1()
	{
		return x1;
	}
	
	public int getY1()
	{
		return y1;
	}
	
	public int getX2()
	{
		return x2;
	}
	
	public int getY2()
	{
		return y2;
	}
}
//Wat.java
import java.awt.Component;



public class Wat implements Runnable
{
		private final Component c;
		
		public Wat(Component c)
		{
			this.c = c;
			(new Thread(this, "F")).start();
		}

		@Override
		public void run() {
			while (true)
			{
				c.repaint();
				
				try {
					Thread.sleep(1);
				} catch (Exception e)
				{
					System.out.println("Wyjątek!");
				}
			}
			
		}
}

Dodatkowo załączam plik jar gotowej gry

0

ja bym zaczął od tego, żeby się dało przegrać ;] bo tak w sumie można tę grę zostawić w spokoju i sama się wygra ( w sensie że dolna krawędź nie powinna odbijać piłeczki).
I nie wiem czy to wina kolorów czy samej aplikacji, ale piłeczka trochę smuży.

Co do odbić, wygląda na to że nie uwzględniasz rozmiarów kulki, tylko sprawdzasz czy środek kulki jest "w" cegiełce/ścianie/desce. Musisz sprawdzać na krawędzi.
Żeby się lepiej przyjrzeć możesz zmniejszyć prędkość piłki ( x+=v*Math.cos(angle))
Ja pisałem Arkanoid w Pascalu w liceum, fajna zabawa, ale trzeba było z języka dużo wycisnąć ;]

0

Dzięki za odpowiedź, już sobie poradziłem:

  1. Jeżeli chodzi o odbicia od deski, to wpisałem w złej kolejności parametry (w / nawias zamiast nawias / w).
  2. Jeżeli chodzi o odbicia od ścian, to zmieniłem wzór dla ścian pionowych na 3 * PI - kąt

To na razie szkielet gry. Dodam bajery jak życia punkty itp. Ale to stopniowo, nie wszystko na raz :)

Pozdrawiam
Michał

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