J'avais joué à un jeu appelé Metal Gear Solid pour la première fois depuis un certain temps, mais je me suis soudainement demandé quel type d'algorithme le personnage contrôlé par le joueur serait visible par la caméra de surveillance et les soldats ennemis. Par conséquent, j'ai décidé de le faire moi-même, ainsi que d'étudier la programmation. Dans cet article, j'ai écrit comment l'implémenter, comment éliminer les bugs et quelles leçons j'ai apprises. Pour ceux qui viennent de commencer à étudier la programmation, le contenu est semblable à celui d'un enseignant: "Faites attention à ne pas faire une telle erreur."
Supposons les spécifications suivantes.
Il y a un joueur sur le plan des coordonnées. Le joueur reste immobile et ne bouge pas. ~~ Il est difficile de bouger. ~~ Le corps du joueur peut être considéré comme un point, et les coordonnées de ce point sont ($ p_x $, $ p_y $).
Les caméras de surveillance sont installées en unités $ N $ sur le plan de coordonnées. $ N $ est un entier supérieur ou égal à 1. La caméra de surveillance reste immobile et ne bouge pas. ~~ Quand il bouge (omis) ~~ La lentille de chaque caméra de surveillance peut être considérée comme un point, et les coordonnées de ce point sont ($ x_i $, $ y_i $). Cependant, $ i $ est un entier de 1 ou plus et $ N $ ou moins, ce qui indique le numéro de la caméra de surveillance.
La distance à laquelle chaque caméra de surveillance peut voir le joueur est $ d_i $ ($ d_i $> 0). Soit $ e_i $ l'angle représentant l'orientation de l'objectif de chaque caméra de surveillance, et $ f_i $ l'angle représentant le champ de vision de la caméra. $ e_i $ est l'angle entre la ligne droite représentant la direction de la caméra et la direction positive de l'axe $ x $, et les deux $ e_i $ et $ f_i $ sont de 0 ° ou plus et de moins de 360 °. En d'autres termes, la plage dans laquelle chaque caméra de surveillance peut voir le joueur est la circonférence et l'intérieur de la forme d'oie avec un rayon de $ d_i $ et un angle central de $ f_i $ comme le montre la figure suivante.
Entrez les paramètres de la console au format suivant.
Tout d'abord, je voudrais décliner, mais cette fois le but est de considérer la condition que la circonférence et l'intérieur de la forme de la gourde incluent des points, il n'est donc pas possible d'implémenter strictement l'encapsulation et l'orientation de l'objet __ Ne pas __. Je ne peux pas dire ~~. ~~ Il peut y avoir de nombreux autres points qui ne peuvent être atteints, mais pardonnez-moi s'il vous plaît.
Tout d'abord, créez une classe Player qui gère les informations de position du joueur. Class Player a les coordonnées $ x $ et $ y $ et a la possibilité de renvoyer leurs valeurs selon les besoins. De plus, il n'est peut-être pas nécessaire de faire du joueur une classe, mais s'il s'agit d'un développement de système, il y a une possibilité qu'il y ait beaucoup de joueurs, donc "De toute façon, le joueur est caché. Je clarifierai l'idée __ qu'il a les informations et les fonctions de Kajika. De plus, la classe Player n'est qu'une idea (un concept abstrait d'un objet d'une manière compliquée), et nous allons créer un __player (d'une manière compliquée, une entité) qui existe dans le vrai sens plus tard. Par exemple, est-ce le sentiment qu'il existe un concept abstrait de l'humanité, et que vous et moi existons en tant que substance?
class Player {
private double x; //Coordonnées du joueur x
private double y; //Coordonnées du joueur y
public Player(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
}
Comme c'est un gros problème, je vais vous expliquer un peu l'encapsulation. Dans la classe Player, les valeurs sont stockées dans des variables de type double x et y, mais la personne qui écrit le programme (pas toujours moi. Peut collaborer avec quelqu'un ou le lancer à quelqu'un. Dans une situation où (!) Peut faire référence à et attribuer la valeur d'une variable de manière désordonnée, il y a un risque de décrire un processus (bug) différent de l'hypothèse d'origine. Par conséquent, afin de clarifier le traitement que le ou les rédacteurs de programme peuvent effectuer pour la classe Player, le code ci-dessus définit comme suit.
De cette manière, le mécanisme qui rassemble les informations et les traitements nécessaires et les empêche d'être réécrit aléatoirement est une classe ou une encapsulation. Il faut un peu plus de travail pour écrire le programme, mais à la place, Java fournit un mécanisme pour réduire le risque de créer des bogues. Plus l'échelle du développement est grande, plus un tel mécanisme devient important.
Ensuite, créez une caméra de classe qui gère les informations de la caméra de surveillance. La caméra de classe a les coordonnées x, y, la distance visible, l'orientation et l'angle de vue. Il a une configuration minimale maintenant, mais à mesure que nous implémenterons le processus à l'avenir, nous ajouterons plus de méthodes.
class Camera {
private double x; //Coordonnées X de la caméra de surveillance
private double y; //Caméra de surveillance coordonnée y
private double distance; //Distance que la caméra de surveillance peut voir
private double dirAngle; //Orientation de la caméra de surveillance(direction)Angle représentant
private double viewAngle; //Angle de vision de la caméra de surveillance
public Camera(double x, double y, double d, double e, double f) {
this.x = x;
this.y = y;
this.distance = d;
this.dirAngle = e;
this.viewAngle = f;
}
}
Maintenant que nous avons décidé où et quel type d'informations stocker, nous allons enfin décrire le flux de traitement. Tout d'abord, de la méthode principale. Chaque fois que vous exécutez un programme Java, la méthode principale est appelée en premier. Par conséquent, vous ne devez écrire qu'une seule méthode principale dans tout le programme. Pour le moment, je ne créerai que la partie qui lit la valeur numérique saisie depuis la console.
class CameraTest {
public static void main(String[] args) {
//contribution
Scanner sc = new Scanner(System.in);
//joueur
double px = sc.nextDouble(); //Coordonnées du joueur x
double py = sc.nextDouble(); //Coordonnées du joueur y
Player player = new Player(px, py);
//Caméra de surveillance
int N = sc.nextInt(); //Nombre de caméras de surveillance
for (int n = 0; n < N; n ++) {
//Entrée / traitement pour chaque caméra de surveillance
double x = sc.nextDouble(); //Coordonnées X de la caméra de surveillance
double y = sc.nextDouble(); //Caméra de surveillance coordonnée y
double d = sc.nextDouble(); //Distance que la caméra de surveillance peut voir
double e = sc.nextDouble(); //Orientation de la caméra de surveillance(direction)Angle représentant
double f = sc.nextDouble(); //Angle de vision de la caméra de surveillance
Camera camera = new Camera(x, y, d, e, f);
}
sc.close();
}
}
C'est un peu comme static, Scanner, nextDouble, nextInt, etc., mais si vous commencez à les expliquer, cela s'écartera du but de cet article, je vais donc omettre l'explication. Quoi qu'il en soit, au moment de la création de ce qui précède, la valeur numérique saisie selon les spécifications peut être lue sans aucun problème.
Bien sûr, la simple lecture des chiffres n'a pas de sens, ajoutons donc un processus pour déterminer si la caméra peut réellement voir le joueur. Dans la classe Camera créée précédemment, créons une méthode findPlayer qui lit les informations de position d'un joueur et détermine si le joueur peut être reconnu visuellement. Cette méthode est la clé de cet article.
//Ajouter à la classe Appareil photo
public boolean findPlayer(Player player) {
double px = player.getX();
double py = player.getY();
//Jugement à distance
double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
if (d > this.distance) {
return false;
}
//Jugement par angle
double a = Math.toDegrees(Math.atan2(py - this.y, px - this.x));
double aMin = this.dirAngle - this.viewAngle/2;
double aMax = this.dirAngle + this.viewAngle/2;
if (a < aMin || aMax < a) {
return false;
}
return true;
}
Maintenant, expliquons brièvement le flux de traitement. Il existe deux mots-clés, "distance" et "angle".
Tout d'abord, la «distance», comme son nom l'indique, détermine si la distance entre la caméra de surveillance et le joueur est inférieure à la distance visible de la caméra de surveillance. La distance entre deux points ($ x_i $, $ y_i
\sqrt{(x_i - p_x)^2 + (y_i - p_y)^2}
Est requis à. Si celle-ci est inférieure à la distance de visualisation $ d_i $, vous pourrez peut-être la voir, mais si elle est supérieure à $ d_i $, c'est hors de question. Par conséquent, dans la partie qui juge par distance, dans ce dernier cas, faux est retourné soudainement de sorte qu'un traitement inutile après cela n'est pas nécessaire.
Ensuite, concernant le traitement de "angle" après avoir effacé la condition de "distance", la fonction $ \ arctan $ (mathématiques du lycée) qui calcule la taille de l'angle entre la droite et l'axe des x à partir de l'inclinaison de la droite passant par les deux points. "Fonction triangulaire" et "fonction inverse") peuvent être utilisées, donc en les combinant pour deux points ($ x_i $, $ y_i
\arctan{\frac{y_i - p_y}{x_i - p_x}}
Vous pouvez le trouver sur. De plus, la plage d'angles que la caméra peut voir est représentée par $ e_i- \ frac {f_i} {2} $ ou plus et $ e_i + \ frac {f_i} {2} $ ou moins, donc l'angle obtenu à partir de l'inclinaison est cette plage. Renvoie vrai s'il y en a, faux sinon.
À ce stade, c'est presque terminé. La méthode findPlayer créée précédemment renvoie une valeur de type boolean, donc elle ne produit que le résultat en fonction de cette valeur. Ensuite, je publierai le programme terminé (?).
import java.util.Scanner;
class CameraTest {
public static void main(String[] args) {
//contribution
Scanner sc = new Scanner(System.in);
//joueur
double px = sc.nextDouble(); //Coordonnées du joueur x
double py = sc.nextDouble(); //Coordonnées du joueur y
Player player = new Player(px, py);
//Caméra de surveillance
int N = sc.nextInt(); //Nombre de caméras de surveillance
for (int n = 0; n < N; n ++) {
//Entrée / traitement pour chaque caméra de surveillance
double x = sc.nextDouble(); //Coordonnées X de la caméra de surveillance
double y = sc.nextDouble(); //Caméra de surveillance coordonnée y
double d = sc.nextDouble(); //Distance que la caméra de surveillance peut voir
double e = sc.nextDouble(); //Orientation de la caméra de surveillance(direction)Angle représentant
double f = sc.nextDouble(); //Angle de vision de la caméra de surveillance
Camera camera = new Camera(x, y, d, e, f);
if (camera.findPlayer(player)) {
System.out.println("J'ai pu voir");
} else {
System.out.println("Je ne pouvais pas voir");
}
}
sc.close();
}
}
class Player {
private double x; //Coordonnées du joueur x
private double y; //Coordonnées du joueur y
public Player(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
}
class Camera {
private double x; //Coordonnées X de la caméra de surveillance
private double y; //Caméra de surveillance coordonnée y
private double distance; //Distance que la caméra de surveillance peut voir
private double dirAngle; //Orientation de la caméra de surveillance(direction)Angle représentant
private double viewAngle; //Angle de vision de la caméra de surveillance
public Camera(double x, double y, double d, double e, double f) {
this.x = x;
this.y = y;
this.distance = d;
this.dirAngle = e;
this.viewAngle = f;
}
public boolean findPlayer(Player player) {
double px = player.getX();
double py = player.getY();
//Jugement à distance
double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
if (d > this.distance) {
return false;
}
//Jugement par angle
double a = Math.toDegrees(Math.atan2(py - this.y, px - this.x));
double aMin = this.dirAngle - this.viewAngle/2;
double aMax = this.dirAngle + this.viewAngle/2;
if (a < aMin || aMax < a) {
return false;
}
return true;
}
}
Il est enfin temps de vérifier les performances de la caméra de surveillance. À titre de test, testons avec trois caméras de surveillance, avec les coordonnées où se trouve le joueur (10, 10). Tout d'abord, j'entrerai jusqu'au point où se déroulera le traitement de la première unité.
10 10
3
10 0 12 90 30
J'ai pu voir
La situation ci-dessous montre les informations saisies dans un diagramme. Vous pouvez parfaitement voir le joueur. La tension est montée.
Passons au second.
10 5 10 180 90
Je ne pouvais pas voir
Je n'ai pas pu voir le second, mais ce n'est pas du tout un problème. En effet, la situation est celle illustrée dans la figure ci-dessous. J'ai pu effacer la condition de distance, mais la direction de la caméra de surveillance était erronée. Le jugement est parfait cette fois aussi!
Ensuite, passons à la finale avec la troisième dernière voiture.
10 16 8 270 120
Je ne pouvais pas voir
À la fin, je peux voir le joueur stupide juste devant la caméra de surveillance ... __ Je ne peux pas le faire __. En termes de jeu de tir, c'est comme un placement frontal! (Lancement)
C'est le début d'un travail de débogage amusant, mais cette fois, j'aimerais le couper ici et continuer avec la deuxième partie. Si vous vous demandez "Pourquoi n'est-ce pas?" Comme je l'étais avant, pensez-y avant de lire la deuxième partie. __Pourquoi la troisième caméra de surveillance ne pouvait-elle pas voir le joueur alors qu'il pouvait le voir? Aussi, comment dois-je modifier le programme? __
Recommended Posts