1. Description des exigences
1. Exigences fonctionnelles
Dans l'étape d'analyse des exigences fonctionnelles, notre tâche principale est de spécifier les services que le système doit fournir, de définir les fonctions complètes du logiciel et de les fournir à ces personnes. Les exigences fonctionnelles sont une exigence de base du développement de logiciels et une partie indispensable de l'analyse de la demande. Tank War est un jeu classique. Ce jeu a appris certaines des expériences des prédécesseurs. Dans l'ensemble, le jeu est divisé en deux côtés de l'ennemi et des États-Unis. Les chars qui participent principalement à la bataille sont contrôlés par les joueurs. Les réservoirs ennemis peuvent apparaître intelligemment et au hasard sur l'écran et se déplacer, lançant un certain nombre de balles; Les joueurs peuvent déplacer des chars à volonté dans la zone spécifiée. Lorsqu'une balle frappe le joueur, le joueur meurt et que le jeu se termine; Les réservoirs ennemis courent intelligemment. Puisqu'ils doivent avoir un certain degré d'intelligence, ils apparaissent au hasard sur l'écran et tournent librement, comme: connaître la direction lorsqu'ils rencontrent une frontière; Les balles se déroulent: les réservoirs sont contrôlés par les joueurs et les balles de tir en fonction des différentes positions de chars. S'ils atteignent la cible, un effet d'explosion sera produit; Il disparaîtra également à l'écran.
2. Exigences de performance du système
Les exigences de configuration des performances du jeu basées sur les systèmes informatiques visent à s'assurer que le programme peut s'exécuter rapidement et stable et peut répondre en temps opportun lors de l'exécution. Lorsque le réservoir du joueur est détruit dans le jeu, provoque rapidement des informations sur l'échec du jeu et répond en temps opportun pour répondre aux exigences de règle du jeu. De plus, il est également nécessaire de s'assurer que la taille de la fenêtre principale ne peut pas être modifiée à volonté lorsque vous jouez au jeu, assurant la jouabilité.
3. Solutions fonctionnelles
Le taux d'utilisation du code est très bon dans le jeu. Après tout, c'est un travail en temps réel. Chaque milliseconde, il y aura de nombreuses balles tirées et le mouvement des coordonnées de nombreux réservoirs. J'ai comparé le nombre de balles frappant le réservoir d'innombrables fois, et les événements de surveillance du clavier, la mise en œuvre de l'interface de thread et le dessin de redessine et de rafraîchissement; Le sens de la logique doit être fort et l'affichage orienté objet est entièrement affiché; Même la relation entre eux n'est pas claire et il est facile d'avoir des situations inattendues; Afin de faire l'ajout de beauté et d'ajouter une explosion dans le jeu, il faut que lorsque le réservoir ennemi décède, un carrousel court et rapide de places fixes des images sur le panneau extérieur pour obtenir un effet d'explosion;
En général, les fonctions de base à remplir dans les batailles de chars incluent: l'interface graphique, les différences dans les styles de chars ennemis à moi, les réservoirs peuvent tirer des balles pour attaquer l'adversaire, mais ne peuvent pas attaquer ses coéquipiers et les réservoirs définissent certains points de santé;
2. Analyse des fonctions principales
Dans le processus de développement du jeu de la guerre des réservoirs, les principales fonctions sont fournies aux utilisateurs pour une utilisation, donc vous devez d'abord dessiner un réservoir.
1. Dessinez le réservoir du joueur: vous devez régler une peinture () sur le panneau JPanel et dessiner la forme approximative du réservoir avec un pinceau;
2. Les chars des joueurs peuvent se déplacer: si le réservoir se déplace, ils doivent changer les coordonnées du réservoir et repeindre constamment le panneau. Cependant, lorsque les réservoirs se déplacent, l'interface du mécanisme de surveillance des événements (surveillance du clavier) peut être implémentée dans la classe du panneau. Lorsque le joueur appuie sur la touche W / D / S / A, il peut monter, descendre, gauche et droite;
3. et dessiner des réservoirs ennemis sur ma peinture en papier de dessin (); Étant donné que les réservoirs ennemis et les réservoirs de joueurs sont sur la même interface, ils doivent être dessinés sur la même planche à dessin;
4. Les chars des joueurs peuvent tirer des balles: si un joueur veut tirer des balles, il doit avoir une source d'événement. Lorsque l'utilisateur appuie sur la touche J, la surveillance des événements tirera immédiatement une balle, mais elle doit être affichée devant les yeux de l'utilisateur pour voir l'effet, donc peinture () dessine la balle sur le panneau; Étant donné que la balle est lancée et se déplace constamment vers le lancement, les coordonnées de la balle doivent être modifiées constamment et que la vitesse de la balle doit être appropriée, elle doit donc être implémentée avec des fils et que le panneau est constamment redessiné pour voir l'effet;
5. Les joueurs peuvent tirer des balles d'affilée et tirer jusqu'à cinq: si le joueur veut contrôler le nombre de balles, il doit savoir si le nombre de balles survivant actuellement est inférieur à 5 lorsque le joueur appuie sur la touche j. Lorsque les conditions sont remplies, une balle sera créée. Lorsque le joueur tire plus de cinq balles, la fonction de tir du système ne sera plus appelée; Étant donné que le lancement de balles ne tire pas seulement une balle, établit un ensemble de balles pour générer une balle à la fois pour savoir que les balles meurent lorsqu'ils atteignent la frontière et meurent;
6. Lorsque le réservoir du joueur frappe le réservoir ennemi, il disparaît et produit un effet d'explosion; Premièrement, il est nécessaire de déterminer si la balle du réservoir du joueur frappe l'ennemi, il y a donc une fonction pour juger constamment l'ennemi. Lorsque la balle fonctionne sur le réservoir ennemi, la vie du réservoir doit se terminer et une bombe est générée, et une bombe est dessinée dans la peinture ();
7. Le réservoir ennemi peut se déplacer intelligemment: si le réservoir ne peut que bouger, il doit générer de manière aléatoire la direction du mouvement. En raison du mouvement constant, la méthode est écrite dans la fonction d'exécution du thread et le thread est contrôlé pour dormir pour atteindre le problème de la vitesse de déplacement;
8. Les réservoirs ennemis peuvent tirer des balles: tout en dessinant l'ennemi, définissez un certain sommeil dans le fil pour générer des balles de directions différentes et différents nombres de réservoirs, et retirer chaque balle sur le panneau et le dessiner;
9. Lorsque la balle ennemie frappe le joueur, le joueur disparaît: continuez à éliminer chaque balle de l'ennemi et à la comparer avec le réservoir du joueur. Lorsque la balle touche le joueur, l'explosion du joueur disparaît;
3. Conception de résumé
• Paramètres d'attribut de rôle
Tank: l'emplacement où le réservoir est généré, la couleur de différents types de réservoirs, l'identifiant de vie du réservoir, la vitesse du mouvement du réservoir et les réservoirs dans différentes directions;
Tank des joueurs: Après avoir hérité des attributs de base du réservoir, il est réalisé sur la base de la deuxième base, et le réservoir du joueur se déplace librement de haut en bas et de gauche et de droite; Et le réservoir des joueurs a la fonction de tirer et de tirer des balles;
Tank ennemi: Après avoir hérité des attributs de réservoir de base, il est nécessaire de réaliser le mouvement intelligent du réservoir ennemi, et en même temps, il doit également lancer des fils de balle sur des chars de différentes positions;
Bullets: Les balles doivent avoir une position de coordonnées, la vitesse, la santé et les balles devraient pouvoir se déplacer, et les balles doivent également mettre en œuvre la méthode de la fonction de mort;
Bomb: les coordonnées de la bombe, de la vie et de la fonction de la méthode d'effet de la vie progressive progressive;
• Paramètres de propriété fonctionnelle
Dessin de papier: peinture () doit dessiner le réservoir du joueur, le réservoir ennemi et afficher l'effet d'explosion du réservoir de mort;
Surveillance des événements: Lorsque l'utilisateur appuie sur WDSA, le réservoir de joueur correspondant doit modifier la direction. Lorsque l'utilisateur tire J, il y a une balle dans le sens du lancement, et elle devrait fonctionner jusqu'à la mort, à moins qu'elle n'atteigne l'ennemi;
Frappez le réservoir: lorsque la balle frappe un réservoir ennemi, une explosion est générée et ajoutée à l'ensemble d'explosion, et les informations d'explosion sont dessinées à la surface;
Les ennemis frappent le joueur: retirez les soi-disant ennemis du jeu et les balles de chaque ennemi correspondent à mon réservoir pour déterminer s'il fallait le frapper;
Les joueurs frappent l'ennemi: retirez chaque balle du joueur, associez chaque réservoir ennemi pour déterminer s'il faut le frapper; et mettre les jugements liés à la frappe du réservoir dans le fil de fil () pour porter des jugements concurrents continus;
Le diagramme d'analyse fonctionnelle spécifique est le suivant:
• Diagramme d'analyse d'attribut de caractère de réservoir
Diagramme d'analyse de la planche à dessin fonctionnel
Diagramme d'analyse globale du réservoir xmind
Attribut de caractères de réservoir xmind diagramme
Attributs de la fonction du réservoir
Iv. Implémentation du système
• membres.java
//Members.javapackage mytank9; import java.util. *; Bombe de classe {// définir les coordonnées de la bombe int x, y; // la vie de la bombe est int life = 9; booléen isLive = true; bombe publique (int x, int y) {this.x = x; this.y = y; } // diminuer la santé publique vide lifEdown () {if (life> 0) {life--; } else {this.islive = false; }}} Class Shot implémente Runnable {int x; int y; int Direct; Int Speed = 1; booléen isLive = true; Public Shot (int x, int y, int Direct) {this.x = x; this.y = y; this.Direct = Direct; } public void run () {while (true) {try {thread.sleep (50); } catch (exception e) {e.printStackTrace (); } switch (Direct) {case 0: y- = Speed; casser; Cas 1: x + = vitesse; casser; Cas 2: y + = vitesse; casser; Cas 3: x- = vitesse; casser; } // Déterminez si le champ touche le bord if (x <0 || x> 400 || y <0 || y> 300) {this.islive = false; casser; }}}} Class Tank {// Tank Horizontal Coordate Int x = 0; // g Coordonnées verticales int y = 0; // Direction du réservoir // 0 indique la tige, 1 indique à droite, 2 indique plus bas, 3 indique la gauche Int Direct = 0; // Speed de Tank Int Speed = 1; // Tank Color Int Color; booléen isLive = true; public int getColor () {return couleur; } public void setColor (int colore) {color = color; } public int getSpeed () {return Speed; } public void setSpeed (int Speed) {this.speed = speed; } public int getDirect () {return Direct; } public void setDirect (int Direct) {this.Direct = Direct; } Public Tank (int x, int y) {this.x = x; this.y = y; } public int getX () {return x; } public void setx (int x) {this.x = x; } public int gety () {return y; } public void sey (int y) {this.y = y; }} // Tank Classe ennemi Enemytank étend les implémentés du réservoir Runnable {int times = 0; // définir un vecteur qui peut stocker des balles ennemies Vector <fit> ss = nouveau vecteur <shot> (); // ennemi ajoute des balles après le réservoir et le réservoir de l'ennemi vient d'être créé et le réservoir de l'ennemi est décédé en Enemytank (int x, int y) {super (x, y); } @Override public void run () {// TODO GÉNÉRÉ AUTO GÉNÉRÉ SUB WHAD (true) {switch (this.direct) {case 0: // indique que le réservoir se déplace pour (int i = 0; i <30; i ++) {// Le réservoir ennemi se déplace dans ma plage si (y> 0) {y- = speed; } essayez {Thread.Sleep (50); } Catch (InterruptedException e) {// TODO Block de catch généré automatiquement e.printStackTrace (); } } casser; Cas 1: pour (int i = 0; i <30; i ++) {if (x <400) {x + = speed; } essayez {Thread.Sleep (50); } Catch (InterruptedException e) {// TODO Block de catch généré automatiquement e.printStackTrace (); } } casser; Cas 2: pour (int i = 0; i <30; i ++) {if (y <300) {y + = speed; } essayez {Thread.Sleep (50); } Catch (InterruptedException e) {// TODO Block de catch généré automatiquement e.printStackTrace (); } } casser; Cas 3: pour (int i = 0; i <30; i ++) {if (x> 0) {x- = vitesse; } essayez {Thread.Sleep (50); } Catch (InterruptedException e) {// TODO Block de catch généré automatiquement e.printStackTrace (); } } casser; } // Déterminez si vous devez ajouter une nouvelle balle au réservoir This.Times ++; if (fois% 2 == 0) {if (isLive) {if (ss.size () <5) {shot s = null; switch (Direct) {case 0: // Créer une balle s = new Shot (x + 10, y, 0); // Ajouter la balle au vecteur SS.ADD (S); casser; Cas 1: S = nouveau tir (x + 30, y + 10, 1); SS.ADD (S); casser; Cas 2: S = nouveau tir (x + 10, y + 30, 2); SS.ADD (S); casser; Cas 3: S = nouveau tir (x, y + 10, 3); SS.ADD (S); casser; } // Démarrez le thread de balle thread t = nouveau thread (s); t.start (); }}} // Laissez le réservoir générer de manière aléatoire une nouvelle direction this.Direct = (int) (math.random () * 4); // Vérifiez si le réservoir ennemi décède si (this.islive == false) {// après avoir laissé le réservoir mourir, quitter la rupture du processus; }}}} // mon héros de classe de réservoir étend Tank {vector <shit> s = new vector <sh shot> (); Shot S = null; Hero public (int x, int y) {super (x, y); } // Fire public void shudenemy () {switch (this.direct) {case 0: // créer une balle s = nouveau tir (x + 10, y, 0); // ajouter la balle au vecteur ss.add (s); casser; Cas 1: S = nouveau tir (x + 30, y + 10, 1); SS.ADD (S); casser; Cas 2: S = nouveau tir (x + 10, y + 30, 2); SS.ADD (S); casser; Cas 3: S = nouveau tir (x, y + 10, 3); SS.ADD (S); casser; } Thread t = nouveau thread (s); t.start (); } // Tank Move Up Public void movup () {y- = Speed; } // tank moveright () {x + = speed; } public void soverown () {y + = speed; } public void moweleft () {x- = speed; }} • mytankgame4.java
//Mytankgame4.java/* * Fonction: Tank Game 2.0 * 1: Dessinez le réservoir * 2: Mon réservoir peut se déplacer vers le haut et vers le bas * 3: dessiner le réservoir ennemi * 4: Mon réservoir peut tirer des balles * 5: Les balles peuvent tirer (jusqu'à cinq coups consécutifs) * 6: Lorsque mon réservoir frappe le réservoir ennemis, quand il disparaît (Explosion * 『 Explosion: 1 Préparez trois images d'abord; 2 Définir la classe de bombes; 3 mettez des bombes lorsque vous frappez le vecteur de char java.awt.event. *; import java.io.file; import java.util. *; public class mytankgame4 étend jframe {mypanel mp = null; public static void Main (String [] args) {// Mytankgame4 () {mp = new MyPanel (); t.start (); this.add (MP); // Inscrivez-vous pour écouter this.addkeyListener (MP); this.setSize (400, 300); this.setDefaultCloseOperation (jframe.exit_on_close); this.setVisible (true); }} La classe MyPanel étend Jpanel implémente KeyListener, Runnable {// définir un My Tank Hero Hero = NULL; // Définir le vecteur de réservoir ennemi <EnemyTank> ets = nouveau vecteur <enemytank> (); // définir un ensemble de bombes Vector <bombe> bombs = new / bombe> (); // combien de tanks ennemis sont des bombes = 3; / / // // Définissez la commutation de trois images pour former une image d'image de bombe1 = null; Image image2 = null; Image image3 = null; // construire public mypanel () {Hero = new Hero (100,100); // Initialisation du réservoir ennemi pour (int i = 0; i <ensize; i ++) {// Créer l'objet de réservoir ennemi EnemyTank et = new EnemyTank ((i + 1) * 50, 0); et.setColor (0); et.setDirect (2); // Démarrer le fil du réservoir ennemi T = nouveau thread (ET); t.start (); // négocier une balle au tir du réservoir ennemi s = nouveau tir (et.x + 10, et.y + 30,2); ET.SS.ADD (S); Thread t2 = nouveau thread (s); t2.start (); // jointure ets.add (et); } try {image1 = imageo.read (nouveau fichier ("bomb_1.gif")); image2 = imageo.read (nouveau fichier ("bomb_2.gif")); image3 = imageo.read (nouveau fichier ("bomb_3.gif")); } catch (exception e) {e.printStackTrace (); } // initialise trois images // image1 = toolkit.getdefaulttoolkit (). GetImage (panneau.class.getResource ("/ bomb_1.gif")); // image2 = toolkit.getdefaulttoolkit (). GetImage (pannel.class.getResource ("/ bomb_2.gif")); // image3 = Toolkit.getDefaultToolkit (). GetImage (panneau.class.getResource ("/ bomb_3.gif")); } // Repaindre la peinture publique de public (graphiques g) {super.paint (g); g.fillrect (0, 0, 400, 300); // dessiner votre propre tank if (Hero.islive == true) {this.drawtank (héros.getx (), héros.gety (), g, this.hero.direct, 1); } // Supprimez chaque balle de SS et dessinez pour (int i = 0; i <Hero.ss.size (); i ++) {// Sortez les balles Shot Myshot = Hero.Ss.get (i); // dessinez une balle et dessinez une balle. Comment dessiner plusieurs balles? Traversal if (myshot! = null && myshot.islive == true) {g.draw3Drect (myshot.x, myshot.y, 1, 1, false); } if (myshot.islive == false) {// Supprimez la balle du vecteur ss Hero.ss.remove (myshot); }} // dessiner la bombe pour (int i = 0; i <bombs.size (); i ++) {bomb b = bombs.get (i); if (b.Life> 6) {g.DrawImage (image1, bx, par, 30,30, this); } else if (B.Life> 4) {g.drawImage (image2, bx, by, 30,30, this); } else {g.drawImage (image3, bx, by, 30,30, this); } // Réduisez la valeur de santé de B B.lifedown (); // Si la valeur de santé de la bombe == 0, expulsez-la if (b.life == 0) {bombs.remove (b); }} // dessiner le réservoir ennemi pour (int i = 0; i <ets.size (); i ++) {EnemyTank et = ets.get (i); if (et.islive) {this.Drawtank (et.getx (), et.gety (), g, et.getDirect (), 0); // dessiner la balle ennemie pour (int j = 0; j <et.ss.size (); j ++) {a tiré Enemyshot = et.ss.get (j); if (Enemyshot.islive) {g.draw3Drect (Enemyshot.x, Enemyshot.y, 1, 1, false); } else {// Le réservoir ennemi est mort et.ss.remove (ennemies); }}}}}} Athè if (et.islive == true) {for (int j = 0; j <et.ss.size (); j ++) {// retirer le tir de la balle ennemieshot = et.ss.get (j); if (Enemyshot.islive == true) {this.hittank (Enemyshot, Hero); }}}}}}} Athè Pour éliminer chaque réservoir et juger pour (int j = 0; j <ets.size (); j ++) {EnemyTank et = ets.get (j); if (et.islive == true) {this.hittank (myshot, et); }}}}}}}}}}} // Pour écrire une fonction spécifiquement pour déterminer si la balle frappe le réservoir public vide hittank (Shot S, Tank ET) {Switch (et.Direct) {// Si la direction du réservoir ennemie est la base supérieure ou inférieure 0: cas 2: if (sx> et.x && s.x <et.x + 20 && s.y> et.y && s.y <et.y + 30) {// hit Death S.islive = false; // Tank Death et.islive = false; // créer une bombe et la mettre dans une bombe vectorielle b = nouvelle bombe (et.x, et.y); bombes.add (b); } Cas 1: cas 3: if (sx> et.x && s.x <et.x + 30 && s.y> et.y && s.y <et.y + 20) {{// hit Death S.islive = false; // Enemy Tank Death et.islive = false; Bombe b = nouvelle bombe (et.x, et.y); bombes.add (b); }}}}}}} // Draw the tank public void drawtank (int x, int y, graphics g, int Direct, int type) {// tank type switch (type) {case 0: g.setColor (color.cyan); casser; Cas 1: G.SetColor (Color.yellow); casser; } // Interrupteur de direction du réservoir (direct) {// CASE UP 0: // Dessinez le réservoir sur la gauche g.fill3Drect (x, y, 5, 30, false); // drawline (x + 10, y + 15, y + 15, 5, 30, false); // dessiner le rectangle moyen g.fill3Drect (x + 5, y + 5, 10, 20, faux); // dessiner la forme d'origine G.fill y + 10, 10, 10); // dessiner la ligne droite g.drawline (x + 10, y + 15, x + 10, y); casser; Cas 1: // à droite // dessinez le rectangle supérieur g.fill3Drect (x, y, 30, 5, false); // dessiner le rectangle inférieur g.fill3Drect (x, y + 15, 30, 5, false); // dessiner le rectangle inférieur G.Fill3Drect (x, y + 15, 30, 5, false); // drawline (x + 15, y +, x + 30, y + 10); casser; Cas 2: // Dessinez le réservoir sous G.Fill3Drect (x + 15, y + 10, x + 30, y + 10); // dessinez le réservoir sur la droite g.fill3Drect (x + 15, y + 10, x + 30, y + 10); // dessinez le réservoir sur le droit g.fill3Drect (x + 15, y, 5, 30, false); // dessiner le rctangle G.fill3Drect (x + 5, false); // dessiner le rctangle G.fill3Drect (x + 5, false); // Tire le RECTANGE G.Fill3Drect (X + 5, FAUX); // Tire le RECTANGE G.FILL3 (X + 5, FAUX); // Traque y + 5, 10, 20, false); // dessiner le rectangle g.fill3Drect (x + 5, y + 5, 10, 20, false); // drawline (x + 10, y + 10, 10, 10); // dessiner une ligne droite g.drawline (x + 10, y + 15, x + 10, y + 30); casser; Cas 3: // à gauche // dessinez le rectangle supérieur g.fill3Drect (x, y, 30, 5, false); // dessiner le rectangle inférieur g.fill3Drect (x, y + 15, 30, 5, false); // dessiner le rectangle moyen G.Fill3Drect (x + 5, y + 5, 20, 10, false); // dessiner le cercle g. 10); // Drawline (x + 15, y + 10, x, y + 10); casser; }} // Appuyez sur la touche et traitez-la. une gauche en bas D à droite. @Override public void keyTyped (keyEvent e) {// TODO Méthode générée automatiquement Stub} @Override public void keyPressed (keyEvent e) {// Todo Method-Generated Method Stub if (e.getkeycode () == keyEvent.vk_w) {this.hero.setDirect (0); this.hero.moveup (); } else if (e.getKeyCode () == keyEvent.vk_d) {this.hero.setDirect (1); this.hero.moveright (); } else if (e.getKeyCode () == keyEvent.vk_s) {this.hero.setDirect (2); this.hero.movedown (); } else if (e.getKeyCode () == keyEvent.vk_a) {this.hero.setDirect (3); this.hero.moveleft (); } if (e.getKeyCode () == keyEvent.vk_j) {// Déterminez si le joueur appuie sur J // Fire if (this.hero.ss.size () <= 4 && this.hero.islive == true) {this.hero.shotenemy (); }} // Le panneau doit être repeint this.repaint (); } @Override public void keyrelent (keyEvent e) {// TODO Méthode générée automatiquement Stub} public void run () {while (true) {try {thread.sleep (100); } catch (exception e) {e.printStackTrace (); } this.HiteMyTank (); // La fonction détermine si la balle de l'ennemi me frappe ce.hitme (); this.repaint (); }}}5. Résultats des tests
Le jaune est le joueur, frappez le joueur
Bullets de tir ennemis
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.