package personnages; import java.awt.Color; import java.awt.Graphics; import java.awt.Component; import java.awt.Rectangle; /** Modelise un Personnage pour une application graphique */ public abstract class Personnage extends Thread { /**Cette constante permet d'indiquer qu'un personnage doit se deplacer vers la droite. */ public static final int DROITE = 0; /** Cette constante permet d'indiquer qu'un personnage doit se deplacer vers la gauche. */ public static final int GAUCHE = 1; /** Cette constante indique une position au repos du personnage.*/ public static final int REPOS = 10; /** Cette constante indique une position de saut vers la gauche.*/ public static final int SAUTG = 20; /** Cette constante indique une position de saut vers la droite.*/ public static final int SAUTD = 21; /** L'abscisse du coin superieur gauche du personnage. */ protected int x; /** L'ordonnee du coin superieur gauche du personnage. */ protected int y; /** La couleur du personnage. */ protected Color couleur; /** La direction du personnage ; peut prendre les valeurs constantes DROITE ou GAUCHE. */ protected int direction = DROITE; /** La hauteur du personnage en pourcentage de la hauteur du composant. */ /** la hauteur du pesonnage, en pixels. */ protected int taille; /** Longueur d'un pas, en pixels. */ private int pas = 20; /** Vitesse d'un personnage en pixels par seconde, pour un personnage anime automatiquement */ private int vitesse = 100; /** Permet de gerer la vitesse */ private int attente = 1000 * pas / vitesse; /** Si la valeur vaut true, le personnage est dessine entoure d'un rectangle. */ private boolean tour = false; /** Temps d'un saut, en millisecondes */ private int tempsSaut = 500; /** memorise le type de silhouette du personnage (REPOS, SAUTG,..., ou autre). */ protected int silhouette = REPOS; /** Lorsque le personnage, en marchant, disparait d'un cote, si la valeur de cet attribue est a true, il reapparait de l'autre, sinon il disparait definitivement */ private boolean cyclique; /** Le composant graphique dans lequel le personnage est trace. */ protected Component zone; /** Cette variable sert a noter qu'un saut est a faire */ private boolean sautAFaire = false; /** indique si le thread du personnage a ete arrete */ private boolean stoppe; /** a true si le thread du personnage a ete demarre et est suspendu */ private boolean suspendu; /** indique si le personnage doit disparaitre totalement*/ private boolean supprime; /** cree un personnage abstrait sans aucune caracteristique ni fenetre d'attache. */ public Personnage() {} /** cree un personnage avec des caracteristiques initiales. le personnage apparait au depart avec les caracteristiques correspondant aux parametres. @param zone composant graphique dans lequel le personnage pourra s'afficher. @param x abscisse d'un point central du personnage. @param y ordonnee d'un point central du personnage, comptee a partir du haut de la fenetre. @param taille la hauteur du personnage en pourcentage de la hauteur du composant. Cette taille est limitee a 100. @param couleur la couleur du personnage. @param cyclique Lorsque le personnage, en marchant, disparait d'un cote, si la valeur de ce parametre est a true, il reapparait de l'autre, sinon il disparait definitivement */ public Personnage(Component zone, int x, int y, int taille, Color couleur, boolean cyclique) { initialiser(zone, x, y,taille, couleur, cyclique); } /** permet de fixer les differentes attributs du personnage. @param zone : composant graphique dans lequel le personnage pourra s'afficher. @param x abscisse d'un point central du personnage. @param y ordonnee d'un point central du personnage, comptee a partir du haut de la fenetre. @param taille la hauteur du personnage en pourcentage de la hauteur du composant. Cette taille est limitee a 100. @param couleur la couleur du personnage. @param cyclique Lorsque le personnage, en marchant, disparait d'un cote, si la valeur de ce parametre est a true, il reapparait de l'autre, sinon il disparait definitivement */ public void initialiser(Component zone, int x, int y, int taille, Color couleur, boolean cyclique) { this.zone = zone; this.x = x; this.y = y; if (taille > 100) taille = 100; if (taille < 1) taille = 1; this.taille = taille; this.couleur = couleur; this.cyclique = cyclique; } /**si la direction vaut DROITE, cette methode la change pour GAUCHE, et vice-versa. Par defaut, la direction vaut droite.*/ public void changerDirection() { if (direction == DROITE) direction = GAUCHE; else direction = DROITE; } /**dessine un personnage avec ses caracteristiques actuelles, et avec un rectangle qui l'entoure, si la variable correspondante a ete positionnee a vrai. @param g contexte graphique servant a dessiner le personnage */ public void dessiner(Graphics g) { if (stoppe) return; dessinerP(g); if (tour) { g.setColor(couleur); Rectangle r = getRectangle(); g.drawRect(r.x, r.y, r.width, r.height); } } /** retourne vrai si les dimensions et la position du personnage font qu'il est au moins partiellement visible de son composant graphique. */ public boolean estDedans() { Rectangle rectPerso = getRectangle(); Rectangle rectZone = zone.getBounds(); if (rectPerso.x + rectPerso.width < 0) return false; if (rectPerso.y + rectPerso.height < 0) return false; if (rectPerso.x > rectZone.height) return false; if (rectPerso.y > rectZone.width) return false; return true; } /** modifie selon les indications des parametres les caracteristiques du personnage et redessine celui-ci. @param prochaineSilhouette la nouyvelle silhouette a utilise @param prochainX abcisse a venir du personnage @param prochainY ordonnnee a venir du personnage */ public void faireMouvement(int prochaineSilhouette, int prochainX, int prochainY) { silhouette = prochaineSilhouette; x = prochainX; y = prochainY; zone.repaint(); } /** fait faire un pas au personnage (vers la droite ou vers la gauche selon la donnee direction qui vaut DROITE ou GAUCHE. */ public void fairePas() { fairePas(pas); } /** fait faire un pas au personnage (vers la droite ou vers la gauche selon la donnee direction qui vaut DROITE ou GAUCHE de lngueur pas. @param pas longueur du pas */ public void fairePas(int pas) { int prochainX = x; Rectangle rectPerso = getRectangle(); int largeur = zone.getBounds().width; if (direction == DROITE) if (rectPerso.x + pas > largeur) if (cyclique) prochainX = 0; else supprimer(); else prochainX = x + pas; else if (direction == GAUCHE) if (rectPerso.x + rectPerso.width - pas < 0) if (cyclique) prochainX = largeur; else supprimer(); else prochainX = x - pas; faireMouvement(silhouetteSuivante(), prochainX, y); } /** retourne la couleur du personnage. */ public Color getCouleur() { return couleur; } /** retourne le temps d'attente entre deux mouvements. Il est fixe de telle sorte que si cette attente a lieu entre deux pas, la vitesse du personnage est celle choisie.*/ public int getAttente() { return attente; } /** Lorsque le personnage, en marchant, disparait d'un cote, si la valeur de retour est a true, il reapparait de l'autre, sinon il disparait definitivement */ public boolean getCyclique() { return cyclique; } /** retourne la direction d'un personnage. @return vaudra DROITE ou GAUCHE */ public int getDirection() { return direction; } /** retourne le rectangele circonscrit au personnage. */ public abstract Rectangle getRectangle(); /** Donne l'entier correspondant a la silhouette du personnage */ public int getSilhouette() { return silhouette; } /** return la longueur du pas */ public void setPas(int pas) { this.pas = pas; attente = 1000 * pas / vitesse; } /** retourne la taille du personnage*/ public int getTaille() { return taille; } /** retourne la vitesse du personnage en pixels par seconde. */ public int getVitesse() { return vitesse; } /** Indique si le personnage a ete demarre et arrete definitivement */ public boolean estStoppe() { return stoppe; } /** Indiquela longueur d'un pas du personnage*/ public int getPas() { return pas; } /** Indique si le personnage est supprime*/ public boolean estSupprime() { return supprime; } /** Indique si le thread du personnage a ete demarre puis suspendu */ public boolean estSuspendu() { return suspendu; } /** retourne l'abscisse d'un point central du personnage dans la fenetre.*/ public int getX() { return x; } /** retourne l'ordonnee d'un point central du personnage dans la fenetre.*/ public int getY() { return y; } /** peut modifier la couleur du personnage, qui est noir par defaut. @param couleur la couleur souhaitee du personnage */ public void setCouleur(Color couleur) { this.couleur = couleur; zone.repaint(); } /** Lorsque le personnage, en marchant, disparait d'un cote, si la valeur du parametre est a true, il reapparait de l'autre, sinon il disparait definitivement */ public void setCyclique(boolean valeur) { cyclique = valeur; } /** modifie la direction du personnage. @param direction doit valoir DROITE ou GAUCHE. */ public void setDirection(int direction) { if ((direction != DROITE) && (direction != GAUCHE)) return; this.direction = direction; } /** Permet de choisir la silhouette du personnage @param silhouette constante correspondant a la silhouette choisie */ public void setSilhouette(int silhouette) { this.silhouette = silhouette; } /** change la taille du personnage et le redessine. @param taille la taille souhaitee du personnage */ public void setTaille(int taille) { if (taille > 100) taille = 100; if (taille < 1) taille = 1; this.taille = taille; zone.repaint(); } /** fixe le temps pendant lequel un personnage effectue un saut */ public void setTempsSaut(int tempsSaut) { this.tempsSaut = tempsSaut; } /** pour que le personnage soit ou non entoure d'un rectangle. @param valeur indique si le personnage doit etre ou non etre entoure d'un rectangle */ public void setTour(boolean valeur) { if (valeur == tour) return; tour = valeur; zone.repaint(); } /** permet de fixer l'abscisse d'un point central du personnage dans la fenetre. @param x l'abscisse souhaitee du personnage*/ public void setX(int x) { this.x = x; zone.repaint(); } /** permet de fixer l'ordonnee d'un point central du personnage dans la fenetre. @param y l'ordonnee souhaitee du personnage */ public void setY(int y) { this.y = y; zone.repaint(); } /** permet de fixer la vitesse du personnage en pixels par seconde. Par defaut, la vitesse vaut 100 */ public void setVitesse(int vitesse) { if (vitesse <= 0) attente = Integer.MAX_VALUE; else { this.vitesse = vitesse; attente = 1000 * pas / vitesse; if (attente == 0) attente = 1; } } /** si on applique dormir() entre deux pas du personnage, le personnage aura la vitesse accessible par la méthode getVitesse(). */ public void dormir() { dormir(attente); } /** fait dormir le pesonnage pendant le temps indique en parametre ; autrement dit interrompt le thread dans lequel tourne cette methode pendant le temps indique. @param temps duree de l'arret du thread */ synchronized public void dormir(int temps) { try { wait(temps); } catch (InterruptedException e) { System.out.println("interruption"); } } private void effacer() { Color sauvegardeCouleur = couleur; couleur = zone.getBackground(); Graphics g = zone.getGraphics(); dessiner(g); couleur = sauvegardeCouleur; g.dispose(); } /** fait sauter le personnage. Les sous-classes doivent preciser la facon de dessiner le personnage si la silhouette vaut SAUTD ou SAUTG. */ synchronized public void sauter() { if (!isAlive()) { int sauvegardeY = y; int hauteur = zone.getBounds().height; int sauvegardeSilhouette = silhouette; Graphics g = zone.getGraphics(); effacer(); if (direction == GAUCHE) silhouette = SAUTG; else silhouette = SAUTD; y = hauteur / 4; dessiner(g); dormir(tempsSaut); y = sauvegardeY ; silhouette = sauvegardeSilhouette; zone.repaint(); } else { sautAFaire = true; notify(); } } public void run() { int sauvey = y; int sauveSilhouette = silhouette; int hauteur = zone.getBounds().height; while (!stoppe) { synchronized(this) { try { while ((suspendu) & (!sautAFaire) && (!stoppe)) wait(); } catch(InterruptedException exc) {} } if (stoppe) break; if (sautAFaire) { if (direction == GAUCHE) faireMouvement(SAUTG, x, hauteur/4); else faireMouvement(SAUTD, x, hauteur/3); dormir(tempsSaut); faireMouvement(sauveSilhouette, x, sauvey); sautAFaire = false; } fairePas(); yield(); dormir(); } } /** fait demarrer le thread */ public void demarrer() { if (!isAlive() && (!stoppe)) start(); } /** Dessine le personnage dans une position au repos.*/ public void positionRepos() { faireMouvement(REPOS, x, y); } /** si un personnage est en train de marcher, avec sa propre methode run (dans un thread propre), cette méthode suspend le mouvement */ synchronized public void reprendre() { suspendu = false; notify(); } /** si un personnage est en train de marcher, avec sa propre methode run (dans un thread propre), cette méthode suspend le mouvement */ public void suspendre() { suspendu = true; positionRepos(); } /** interrompt définitivement le mouvement du personnage lorsque celui-ci marche automatiquement (dans un thread, avec sa methode run) */ public void stopper() { stoppe = true; } /** fait stopper le personnage et le rend invisible. */ synchronized public void supprimer() { stoppe = true; supprime = true; if (isAlive()) notify(); zone.repaint(); } /**indique si le rectangle du personnage intersecte le rectangle du personnage indique en paramètre. */ public boolean touche(Personnage promeneur) { if (promeneur == null) return false; if (this.getRectangle(). intersects(promeneur.getRectangle())) return true; return false; } /**indique si le rectangle du personnage intersecte le rectangle du personnage indique en paramètre. */ public boolean evite(Personnage promeneur) { int xP, yP, wP, hP; int x, y, w, h; if (promeneur == null) return false; xP = promeneur.getRectangle().x; wP = promeneur.getRectangle().width; yP = promeneur.getRectangle().y; hP = promeneur.getRectangle().height; x = getRectangle().x; w = getRectangle().width; y = getRectangle().y; h = getRectangle().height; if ((((xP + wP / 2 > x) && (x > xP - wP / 2)) || ((x + w / 2 > xP) && (xP > x - w / 2))) && (y > yP + hP)){ return true; } return false; } /** Retourne true ou false selon que le point de coordonnees x et y est dans le rectangle circonscrit au personnage */ public boolean estDedans(int x, int y) { return getRectangle().contains(x, y); } /*permet de dessiner le personnage selon ses attributs. Les sous-classes devront préciser en fonction de chaque silhouette, les dessins correspondant. */ /** dessine le personnage selon ses attributs. Les sous-classes devront preciser en fonction de chaque silhouette, les dessins correspondant. @param g le contexte graphique servant a dessiner le personnage */ public abstract void dessinerP(Graphics g); protected abstract int silhouetteSuivante (); }