Partage
  • Partager sur Facebook
  • Partager sur Twitter

Chevauchements

    25 avril 2010 à 19:20:02

    Bonjour,

    Je développe un billard et je n'arrive pas à corriger les problèmes de chevauchements des différentes boules les unes avec les autres. Lorsque la vitesse de la boule est trop grande ou qu'il y a beaucoup de boules qui entrent en collision en même temps je me retrouve avec des boules les unes sur les autres...

    Que faire? il me semble qu'un message parlait de ce problème de façon générale mais je n'arrive plus à mettre la main dessus

    Merci d'avance
    • Partager sur Facebook
    • Partager sur Twitter
      25 avril 2010 à 20:17:35

      On peut pas deviner là comme ça ^^'
      Revois ton algorithme de détection de collisions.
      Revois ton algorithme d'affichage.

      Est-ce que de manière logique les boules se chevauchent ? C'est-à-dire est-ce que les coordonnées de tes boules sont bien à la bonne place ?
      Si c'est un problème de logique c'est très facile à résoudre.
      Si c'est un problème d'affichage, c'est plus ou moins facile selon ton architecture.

      Tu utilises l'active rendering pour un jeu de billard ? Ca devrait le faire à coups de repaint() mais bon sait-on jamais.
      T'as bien une classe Boule avec une méthode draw() ?
      • Partager sur Facebook
      • Partager sur Twitter
        30 avril 2010 à 11:25:13

        Salut,
        désolé pour le long silence mais j'ai eu beaucoup de boulot. :o
        Bon alors j'utilise le pattern MVC donc je redessine effectivement à coup de repaint().
        (d'ailleurs j'aurais une question à propos de ça aussi mais on vera après ...)
        je pense que mes boules sont à la bonne place.
        voila mes classes:
        BallView:

        package view;
        
        import java.awt.Color;
        
        //Cette classe represente la partie graphique d'une boule.
        //Elle permet donc de dessiner une boule en fonction de ses caracteristiques (dimension et position).
        
        public class BallView extends ShapeView{
        
        	private static final long serialVersionUID = 1L;
        	private int radius;
        	private Color color;
        	private Point2D.Double posInit;
        	private Ball ball;
        	
        	public BallView(Drawing drawing, Ball ball) {
        		this.drawing = drawing;
        		this.position = ball.getPosition();
        		this.color = ball.getColor();
        		this.radius = ball.getRadius();
        		this.posInit = ball.getPosInit();
        		this.ball = ball;
        	}
        	
        	@Override
        	public void paintComponent(Graphics g) {
        		this.position = ball.getPosition();
        		g.setColor(this.color);
        		int radiusMouche = 3;
        		if(!g.getColor().equals(Color.red) && !g.getColor().equals(Color.white))
        			g.fillOval((int) (posInit.x - radiusMouche) ,(int) (posInit.y - radiusMouche), 2*radiusMouche, 2*radiusMouche);
        		
        		g.fillOval((int) (position.x - radius) ,(int) (position.y - radius), 2*radius, 2*radius);
        	}
        
        	
        }
        



        ShapeView:

        package view;
        
        import java.awt.Graphics;
        
        //Cette super-classe regroupe les objets graphiques qui servent a dessiner des "Shapes".
        //Elle implemente egalement le pattern Observer pour pouvoir actualiser les dessins.
        
        public abstract class ShapeView extends Rectangle implements Observer{
        	
        	private static final long serialVersionUID = 1L;
        	// Origine du dessin par rapport ‡ la table.
        	protected Point2D.Double position = new Point2D.Double();
        	protected Drawing drawing;
        	
        	public Point2D.Double getPosition(){
        		return position;
        	}
        	
        	// Dessine la forme sur un objet graphic.
        	public abstract void paintComponent(Graphics g);
        
        	@Override
        	public void update() {
        		drawing.repaint();
        	}
        	
        	public void delete(){
        		ArrayList<ShapeView> shapes = drawing.getShapes();
        		for(int i = 0 ; i < shapes.size() ; i++){
        			if(shapes.get(i) == this)
        				shapes.remove(i);
        		}
        		
        	}
        }
        



        BallsList:
        package model;
        
        import java.awt.Color;
        
        //Cette classe permet de particulariser la liste de balles.
        //Cela signifie qu'elle ajoute des fonctionnalites qui permettent de gerer une liste de boules d'un jeu de billard.
        //En particulier, elle va creer les boules (en les positionnant) et gerer leurs rebonds entre elles.
        
        public class BallsList extends ArrayList<Ball>{
        
        	private static final long serialVersionUID = 1L;
        	
        	protected int ballsRadius;
        	protected int nbrBalls;
        	protected Ball whiteBall;
        	protected Color colorFirstBallTouched = null;
        	
        	public void initialize(){
        		
        		//boule blanche
        		double posX = __Pool.tablePosX + __Pool.tableWidth - __Pool.whiteLinePos;
        		double posY = __Pool.tablePosY + __Pool.tableHeight/2 + 2*ballsRadius;
        		
        		Point2D.Double pos = new Point2D.Double(posX,posY);
        		whiteBall = new WhiteBall(pos, Color.WHITE, ballsRadius);
        		
        		//ajoute la boule blanche
        		this.add(whiteBall);
        
        	}
        	
        	public boolean add(Ball b){
        		super.add(b);
        		return true;
        	}
        
        	public void bounce(Ball a, Ball b){
        		//Modifie les vitesses de deux boules a et b qui se collisionnent
        		
        		double posAPRBX = a.getPosition().x - b.getPosition().x; // Position relative de A par rapport  B selon x.
        		double posAPRBY = a.getPosition().y - b.getPosition().y; // Position relative de A par rapport  B selon y.
        		double inclinaisonAB = 0;
        		try{
        			inclinaisonAB = Math.atan(posAPRBY/posAPRBX);
        		}
        		catch (ArithmeticException e) {
        			inclinaisonAB =  Math.PI/2;
        		}
        		inclinaisonAB = Math.abs(inclinaisonAB);
        		
        		double speedAParaAB = (Math.abs(a.getSpeed().x * Math.cos(inclinaisonAB))) + Math.abs((a.getSpeed().y * Math.sin(inclinaisonAB)));
        		double speedBParaAB = (Math.abs(b.getSpeed().x * Math.cos(inclinaisonAB))) + Math.abs((b.getSpeed().y * Math.sin(inclinaisonAB)));
        
        		if((speedAParaAB-speedBParaAB)>0){
        				
        			Point2D.Double newSpeedAParaAB = new Point2D.Double ((int) (Math.signum(b.getSpeed().x) * speedBParaAB * Math.cos(inclinaisonAB)), (int) (Math.signum(b.getSpeed().y) * speedBParaAB * Math.sin(inclinaisonAB)));
        			Point2D.Double newSpeedBParaAB = new Point2D.Double ((int) (Math.signum(a.getSpeed().x) * speedAParaAB * Math.cos(inclinaisonAB)), (int) (Math.signum(a.getSpeed().y) * speedAParaAB * Math.sin(inclinaisonAB)));
        		 
        			Point2D.Double speedALeft = new Point2D.Double ( a.getSpeed().x - newSpeedBParaAB.x, a.getSpeed().y - newSpeedBParaAB.y); // chaque boule a perdu la vitesse transmis a l'autre
        			Point2D.Double speedBLeft = new Point2D.Double ( b.getSpeed().x - newSpeedAParaAB.x, b.getSpeed().y - newSpeedAParaAB.y);
        		 
        			Point2D.Double finalSpeedA = new Point2D.Double ( speedALeft.x + newSpeedAParaAB.x, speedALeft.y + newSpeedAParaAB.y);
        			Point2D.Double finalSpeedB = new Point2D.Double ( speedBLeft.x + newSpeedBParaAB.x, speedBLeft.y + newSpeedBParaAB.y);
        		 
        			a.setSpeed(finalSpeedA);
        			b.setSpeed(finalSpeedB);
        		}
        	}
        	
        	public void collisions (Ball b)
        	{	//Verifie tous les rebonds que la boule b va engendrer
        		//Cette fonction est recursive car quand une boule a collisionne une boule b (et donc change sa vitesse), il faudra alors reverifier tous les rebonds que la boule b pourrait engendrer avec cette nouvelle vitesse.
        		if (b.isMoving()){
        			Ball copyBall = null;
        			try {
        				//pour Èviter les chevauchements on cree une copie de la boule
        				copyBall = b.clone();
        				copyBall.move();
        				// On fait rebondir les boules
        				for(Ball c : this){
        					// test si une boule possede une intersection avec une autre (attention a ne pas tester entre une boule et elle meme)
        					if (copyBall.isOnShape(c) && b != c)
        					{
        						// on rÈcupËre la couleur de la premiËre balle touchÈe et on s'assure d'en avoir touchee une
        						if (colorFirstBallTouched == null && (b.getColor() == Color.white || c.getColor() == Color.white)){
        							if (b.getColor() == Color.white)
        								colorFirstBallTouched = c.getColor();
        							else
        								colorFirstBallTouched = b.getColor();
        						}
        						this.bounce(b,c);
        						collisions (c);
        					}
        				}
        			} catch (CloneNotSupportedException e) {
        				// TODO Auto-generated catch block
        				e.printStackTrace();
        			}
        		}	
        	}
        	
        	public Ball getWhiteBall()
        	{
        		Ball whiteBall = null;
        		try{
        			for (Ball c : this)
        				if (c.getColor() == Color.white)
        					whiteBall = c;
        		}
        		catch (NullPointerException e)
        		{
        		}
        		
        		return whiteBall;			
        	}
        	
        	public boolean isRemovable(int i)
        	{
        		return true;
        	}
        	
        	public void move(){
        		//Fais bouger toutes les boules de la liste.
        		for(Ball b : this){
        			if(b.isMoving())
        				b.move();
        		}
        	}
        	
        	public int getBallsRadius()
        	{
        		return ballsRadius;
        	}
        	
        	public Color getColorFirstBallTouched()
        	{
        		return colorFirstBallTouched;
        	}
        	
        	public void setColorFirstBallTouched(Color colorFirstBallTouched)
        	{
        		this.colorFirstBallTouched = colorFirstBallTouched;
        	}
        }
        


        Ball:
        package model;
        
        import java.awt.Color;
        
        //Cette classe contient els principales caracteristiques d'une boule.
        //C'est elle qui s'occupe de la faire bouger en fonction de la vitesse et quand c'est demande.
        
        public class Ball extends Shape implements Cloneable{
        
        	private static final long serialVersionUID = 1L;
        
        	private int radius;
        	private Color color;
        	private Point2D.Double posInit;
        	private Point2D.Double speed;
        	
        	public Ball(Point2D.Double posInit, Color color, int radius) {
        		// TODO Auto-generated constructor stub
        		this.color = color;
        		this.radius = radius;
        		this.position = posInit;
        		this.posInit = new Point2D.Double(posInit.x,posInit.y);
        		this.speed = new Point2D.Double();
        		this.setBounds(this.position.x - radius, this.position.y - radius, 2*radius, 2*radius);	
        	}
        	
        	public Ball(){
        		
        	}
        	
        	protected void delay(int waitTime){
        		try{
        			Thread.sleep(waitTime);
        		}catch(InterruptedException e) {}
        	}
        	
        	public void replacement(__Pool pool){}
        	
        	public void move(){
        		
        		int divFactor = 5;
        		position.x += speed.x/divFactor;
        		position.y += speed.y/divFactor;
        		
        		this.setPosition(new Point2D.Double(position.x,position.y));
        		
        		speed.x *= 1 - Table.frotTable;
        		speed.y *= 1 - Table.frotTable;
        	
        		this.setBounds(position.x - radius,position.y - radius, 2*radius, 2*radius);
        	}	
        	
        	public boolean overLine(boolean vertical, double positionTopLeft, double positionDownRight)
        	{
        		if(vertical){
        			return ((this.position.x+this.radius>positionDownRight && this.speed.x>0) || (this.position.x-this.radius<positionTopLeft && this.speed.x<0));
        		}
        		else{
        			return ((this.position.y+this.radius>positionDownRight && this.speed.y>0) || (this.position.y-this.radius<positionTopLeft && this.speed.y<0));
        		}
        	}
        	
        	public boolean isMoving()
        	{// Arret la balle lorsque sa vitesse est trop faible (sinon elle met trop de temps pour s'arreter)
        		double norm = Math.sqrt((speed.x*speed.x) + (speed.y*speed.y));
        		boolean motion = false;
        		
        		if(norm  <  1.0) 
        			setSpeed(new Point2D.Double(0,0));
        		else
        			motion =  true;
        		
        		return motion;
        	}
        	
        	public Ball clone() throws CloneNotSupportedException{ 
        		Ball ball = null;
        		try {
        			ball = (Ball) super.clone();
        			ball.posInit = (Double) posInit.clone();
        			ball.speed = (Double) speed.clone();
        		} catch(CloneNotSupportedException cnse) {
        			cnse.printStackTrace(System.err);
        		}		
        		return ball; 
        	} 
        
        	
        	/*********************************************************************
        	 * 				
        	 * 								ACCESSEURS
        	 * 
        	 ********************************************************************** */
        	@Override
        	public void setPosition(Point2D.Double p){
        		this.position = p;
        		this.setBounds(this.position.x - radius, this.position.y -radius, 2*radius, 2*radius);
        		
        		//Des que la position de la bille change, il faut le signaler a la vue
        		notifyObserver();
        	}
        
        	public Point2D.Double getSpeed() {
        		return this.speed;
        	}
        
        	public void setSpeed(Point2D.Double speed) {
        		this.speed = speed;
        	}
        
        	public int getRadius() {
        		return this.radius;
        	}
        
        	public Color getColor() {
        		return this.color;
        	}
        	
        	public Point2D.Double getPosInit() {
        		return posInit;
        	}
        	
        }
        

        • Partager sur Facebook
        • Partager sur Twitter
          30 avril 2010 à 11:53:45

          Euh là comme ça j'ai pas envie de chercher l'erreur.
          C'est toi qu'a le programme complet tu devrais pouvoir te débrouiller :)
          Trouve un système pour afficher la position de tes boules à n'importe quel instant. Puis vérifie si elles se chevauchent.
          Pour ton algo de collision je suis persuadé que tu as une méthode isCollision() par exemple. Grâce à elle tu peux savoir si les positions des boules semblent correctes.

          Mais c'est primordial de localiser l'erreur pour pouvoir la gérer ^^
          • Partager sur Facebook
          • Partager sur Twitter
            30 avril 2010 à 12:02:30

            Oui la méthode est isOnShape.
            Sinon j'avoue que j'ai la flèmme de chercher j'ai déjà passé beaucoup de temps.
            Ce que je voulais c'est comprendre de manière générale le principe pour éviter les chevauchements entre boules j'imagine que cela dépend de la vitesse de la boule et de la fréquence de rafraichissement.
            Si la boule est trop rapide la collision se fait à l'interieur de l'autre boule et donc avec sa nouvelle vitesse (plus petite que la vitesse initiale) la boule n'a pas le temps de resortir avant qu'il y ait un nouveau calcul de collision.
            Donc elle est piégée à l'intérieur de la boule avec laquelle il y a collision.
            Bref c'est un peu pénible ce genre de problèmes.... :(
            • Partager sur Facebook
            • Partager sur Twitter
              30 avril 2010 à 12:24:23

              Ben ce problème est possible si l'affichage est trop long à se faire.
              Si tu n'as pas de rafraîchissements saccadés, les repaint() suffisent probablement.

              Le principe général est déjà d'éviter que les positions des boules ne se chevauchent dans leur état logique. Je te conseille de contrôler ça avec des sysout pour vérifier tes variable position en abscisse et ordonnée de tes boules.
              Ensuite il faut s'assurer que l'affichage se fait précisément après la mise à jour logique et qu'il dure assez peu de temps pour que la prochaine mise à jour soit effectuée après le rendu.

              Normalement, pour un jeu de billard, à mon avis, les repaint() suffisent.
              Le problème de repaint() est que cette méthode ne repaint pas directement l'écran, mais poste une série d'actions qui une fois dépilées repeindront l'écran. Si deux repaint() sont effectués sans que la première série d'action ait finie d'être dépilée, alors il peut arriver que la JVM mélange les deux repaint() en un seul. Ce qui fait que tu perds une image dans le processus (un FPS quoi).

              Pour s'assurer qu'un repaint() ait bien le temps de s'effectuer en entier, il n'y a pas de méthode.
              Pour pallier à ce problème on utilise l'active rendering, qui est un système permettant de contrôler entièrement l'affichage de l'application.
              Le principe en gros est de désactiver le système de peinture automatique de Swing et de s'en occuper dans son intégralité.

              Pour découvrir le fonctionnement, je te laisse chercher sur le net, ou bien encore à cette adresse : http://java.sun.com/docs/books/tutoria [...] endering.html

              Bon courage, n'hésite pas si t'as encore des questions.

              P.S. J'ai pas trop structuré ce message désolé. Il existe également une méthode pour choisir une région qui doit être repeinte (on appelle ça le clipping). Au lieu de repeindre tout l'écran, ce qui peut être coûteux, on ne repaint qu'un rectangle choisi. C'est peut-être un moyen d'éviter la dernière méthode que j'ai indiquée.
              • Partager sur Facebook
              • Partager sur Twitter
                30 avril 2010 à 12:31:42

                Merci c'est pas grave pour la structure le contenu y est ;) .
                En fait, le clipping ça m'interesse plus que de résoudre mon soucis de collisions :p .
                Ce serait bien de repeindre juste les objets en mouvement et non pas tous les objets genre la table c'est vraiment ridicule....mais je bloque complètement... j'avais essayé de faire this.repaint() dans l'objet en question au lieu de drawing.repaint() qui redessine tout mais ça ne marchait pas du tout :( .
                Je vais voir comment fonctionne le clipping alors
                • Partager sur Facebook
                • Partager sur Twitter

                Chevauchements

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown