Ich hatte zum ersten Mal seit einiger Zeit ein Spiel namens Metal Gear Solid gespielt, aber plötzlich fragte ich mich, welche Art von Algorithmus der vom Spieler kontrollierte Charakter für die Überwachungskamera und feindliche Soldaten sichtbar sein würde. Deshalb habe ich mich entschlossen, es selbst zu machen und Programmieren zu studieren. In diesem Artikel habe ich geschrieben, wie man es implementiert, wie man Fehler beseitigt und welche Lektionen ich gelernt habe. Für diejenigen, die gerade mit dem Programmieren begonnen haben, ist der Inhalt wie ein Lehrer: "Achten Sie darauf, keinen solchen Fehler zu machen."
Nehmen wir die folgenden Spezifikationen an.
Auf der Koordinatenebene befindet sich ein Spieler. Der Spieler bleibt still und bewegt sich nicht. ~~ Es ist mühsam, sich zu bewegen. ~~ Der Körper des Spielers kann als Punkt betrachtet werden, und die Koordinaten dieses Punktes sind ($ p_x $, $ p_y $).
Überwachungskameras werden in $ N $ -Einheiten auf der Koordinatenebene installiert. $ N $ ist eine ganze Zahl größer oder gleich 1. Die Überwachungskamera bleibt still und bewegt sich nicht. ~~ Wenn es sich bewegt (weggelassen) ~~ Das Objektiv jeder Überwachungskamera kann als Punkt betrachtet werden, und die Koordinaten dieses Punktes sind ($ x_i $, $ y_i $). $ I $ ist jedoch eine Ganzzahl von 1 oder mehr und $ N $ oder weniger, was die Nummer der Überwachungskamera angibt.
Die Entfernung, über die jede Überwachungskamera den Spieler sehen kann, beträgt $ d_i $ ($ d_i $> 0). Sei $ e_i $ der Winkel, der die Ausrichtung des Objektivs jeder Überwachungskamera darstellt, und $ f_i $ der Winkel, der das Sichtfeld der Kamera darstellt. $ e_i $ ist der Winkel zwischen der Geraden, die die Richtung der Kamera darstellt, und der positiven Richtung der $ x $ -Achse, und sowohl $ e_i $ als auch $ f_i $ sind 0 ° oder mehr und weniger als 360 °. Mit anderen Worten, der Bereich, in dem jede Überwachungskamera den Spieler sehen kann, ist der Umfang und das Innere der Gänseform mit einem Radius von $ d_i $ und einem zentralen Winkel von $ f_i $, wie in der folgenden Abbildung gezeigt.
Geben Sie Parameter über die Konsole im folgenden Format ein.
Zunächst möchte ich ablehnen, aber diesmal soll die Bedingung berücksichtigt werden, dass der Umfang und das Innere der Kürbisform Punkte enthalten, sodass es nicht möglich ist, Kapselung, Objektorientierung usw. strikt zu implementieren. __ Unterlassen Sie __. Ich kann nicht sagen ~~. ~~ Es mag viele andere Punkte geben, die nicht erreicht werden können, aber bitte vergib mir.
Erstellen Sie zunächst einen Klassenspieler, der die Positionsinformationen des Spielers verarbeitet. Der Klassenspieler hat $ x $ - und $ y $ -Koordinaten und kann seine Werte nach Bedarf zurückgeben. Darüber hinaus ist es möglicherweise nicht erforderlich, den Spieler zu einer Klasse zu machen. Wenn es sich jedoch um eine Systementwicklung handelt, kann davon ausgegangen werden, dass es viele Spieler gibt Ich werde die __idea __ klarstellen, dass sie die Informationen und Funktionen von Kajika hat. Außerdem ist die Klasse Player nur eine idea (ein abstraktes Konzept eines Objekts auf komplizierte Weise), und wir werden einen __player (auf komplizierte Weise eine Entität) erstellen, der später im wahrsten Sinne des Wortes existiert. Ist es zum Beispiel das Gefühl, dass es ein abstraktes Konzept der Menschheit gibt und dass ich und Sie als Substanz existieren?
class Player {
private double x; //Spieler x Koordinaten
private double y; //Spieler y Koordinate
public Player(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
}
Da es eine große Sache ist, werde ich ein wenig über die Kapselung erklären. In der Klasse Player werden Werte in doppelten Variablen x und y gespeichert, aber die Person, die das Programm schreibt (nicht immer ich. Kann mit jemandem zusammenarbeiten oder es an jemanden weitergeben. In einer Situation, in der (!) Auf ungeordnete Weise auf den Wert einer Variablen verweisen und diesen zuweisen kann, besteht das Risiko, einen Prozess (Fehler) zu beschreiben, der ursprünglich nicht erwartet wurde. Um die Verarbeitung zu verdeutlichen, die die Programmschreiber für die Klasse Player ausführen können, definiert der obige Code daher Folgendes.
--Variable x schreibt ihren Wert nicht direkt um! ⇒ Schreiben Sie private vor die Typdeklaration. Dann wird es unmöglich, "x = 100" zu schreiben, das der Variablen x direkt einen Wert zuweist (dies verursacht einen Fehler). ――Ich möchte die Variable x durch die x-Koordinate ersetzen, wenn ich einen echten Spieler erstelle! ⇒ Weisen Sie den Wert des Arguments der Variablen x im constructor (Methode mit demselben Namen wie die Klasse. Die Methode ist eine Zusammenfassung des Verarbeitungsablaufs) zu, die beim Erstellen eines vorhandenen Players immer aufgerufen wird.
Auf diese Weise ist der Mechanismus, der die erforderlichen Informationen sammelt und verarbeitet und verhindert, dass sie zufällig umgeschrieben werden, eine Klasse oder Kapselung. Das Schreiben des Programms erfordert etwas mehr Arbeit. Stattdessen bietet Java einen Mechanismus, um das Risiko von Fehlern zu verringern. Je größer der Entwicklungsumfang ist, desto wichtiger wird ein solcher Mechanismus.
Erstellen Sie als Nächstes eine Klassenkamera, die Informationen zur Überwachungskamera verarbeitet. Die Klassenkamera hat x-, y-Koordinaten, sichtbare Entfernung, Ausrichtung und Betrachtungswinkel. Es hat jetzt eine minimale Konfiguration, aber wenn wir den Prozess in Zukunft implementieren, werden wir weitere Methoden hinzufügen.
class Camera {
private double x; //Überwachungskamera x Koordinaten
private double y; //Überwachungskamera y Koordinate
private double distance; //Entfernung, die die Überwachungskamera sehen kann
private double dirAngle; //Ausrichtung der Überwachungskamera(direction)Winkel darstellend
private double viewAngle; //Betrachtungswinkel der Überwachungskamera
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;
}
}
Nachdem wir uns entschieden haben, wo und welche Art von Informationen gespeichert werden sollen, werden wir endlich den Verarbeitungsablauf beschreiben. Zunächst von der Hauptmethode. Wenn Sie ein Java-Programm ausführen, wird zuerst die Hauptmethode aufgerufen. Daher müssen Sie im gesamten Programm nur eine Hauptmethode schreiben. Vorerst werde ich nur den Teil erstellen, der den von der Konsole eingegebenen numerischen Wert liest.
class CameraTest {
public static void main(String[] args) {
//Eingang
Scanner sc = new Scanner(System.in);
//Spieler
double px = sc.nextDouble(); //Spieler x Koordinaten
double py = sc.nextDouble(); //Spieler y Koordinate
Player player = new Player(px, py);
//Überwachungskamera
int N = sc.nextInt(); //Anzahl der Überwachungskameras
for (int n = 0; n < N; n ++) {
//Eingabe / Verarbeitung für jede Überwachungskamera
double x = sc.nextDouble(); //Überwachungskamera x Koordinaten
double y = sc.nextDouble(); //Überwachungskamera y Koordinate
double d = sc.nextDouble(); //Entfernung, die die Überwachungskamera sehen kann
double e = sc.nextDouble(); //Ausrichtung der Überwachungskamera(direction)Winkel darstellend
double f = sc.nextDouble(); //Betrachtungswinkel der Überwachungskamera
Camera camera = new Camera(x, y, d, e, f);
}
sc.close();
}
}
Es ist wie statisch, Scanner, nextDouble, nextInt usw., aber wenn Sie anfangen, diese zu erklären, weicht es vom Zweck dieses Artikels ab, sodass ich die Erklärung weglasse. Zum Zeitpunkt der Erstellung des obigen Dokuments kann der gemäß den Spezifikationen eingegebene numerische Wert problemlos gelesen werden.
Das Lesen der Zahlen ist natürlich bedeutungslos. Fügen wir also einen Prozess hinzu, um festzustellen, ob die Kamera den Player tatsächlich sehen kann. In der zuvor erstellten Kamera-Klasse erstellen wir eine Methode findPlayer, die die Positionsinformationen eines Spielers liest und bestimmt, ob der Spieler visuell erkannt werden kann. Diese Methode ist der Schlüssel zu diesem Artikel.
//Zur Kameraklasse hinzufügen
public boolean findPlayer(Player player) {
double px = player.getX();
double py = player.getY();
//Beurteilung nach Entfernung
double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
if (d > this.distance) {
return false;
}
//Beurteilung nach Winkel
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;
}
Lassen Sie uns nun den Verarbeitungsablauf kurz erläutern. Es gibt zwei Schlüsselwörter: "Abstand" und "Winkel".
Zunächst bestimmt "Entfernung", wie der Name schon sagt, ob die Entfernung zwischen der Überwachungskamera und dem Player kleiner ist als die sichtbare Entfernung der Überwachungskamera. Der Abstand zwischen zwei Punkten ($ x_i $, $ y_i
\sqrt{(x_i - p_x)^2 + (y_i - p_y)^2}
Wird benötigt bei. Wenn dies kleiner als der Betrachtungsabstand $ d_i $ ist, können Sie ihn möglicherweise sehen, aber wenn er größer als $ d_i $ ist, kommt dies nicht in Frage. Daher wird in dem Teil, der nach Entfernung beurteilt, im letzteren Fall plötzlich false zurückgegeben, so dass eine unnötige Verarbeitung danach nicht erforderlich ist.
In Bezug auf die Verarbeitung von "Winkel" nach dem Löschen der Bedingung "Abstand" wird die Funktion $ \ arctan $ (Mathematik der High School) verwendet, die die Größe des Winkels zwischen der Geraden und der x-Achse aus der Neigung der Geraden berechnet, die durch die beiden Punkte verläuft. "Dreiecksfunktion" und "Umkehrfunktion") können verwendet werden, indem diese für zwei Punkte ($ x_i $, $ y_i
\arctan{\frac{y_i - p_y}{x_i - p_x}}
Sie finden es unter. Außerdem wird der Winkelbereich, den die Kamera sehen kann, durch $ e_i- \ frac {f_i} {2} $ oder mehr und $ e_i + \ frac {f_i} {2} $ oder weniger dargestellt, sodass der aus der Neigung erhaltene Winkel dieser Bereich ist. Gibt true zurück, wenn vorhanden, false, wenn nicht.
Zu diesem Zeitpunkt ist es fast abgeschlossen. Die zuvor erstellte Methode findPlayer gibt einen Wert vom Typ boolean zurück, sodass das Ergebnis nur gemäß diesem Wert ausgegeben wird. Dann werde ich das abgeschlossene (?) Programm veröffentlichen.
import java.util.Scanner;
class CameraTest {
public static void main(String[] args) {
//Eingang
Scanner sc = new Scanner(System.in);
//Spieler
double px = sc.nextDouble(); //Spieler x Koordinaten
double py = sc.nextDouble(); //Spieler y Koordinate
Player player = new Player(px, py);
//Überwachungskamera
int N = sc.nextInt(); //Anzahl der Überwachungskameras
for (int n = 0; n < N; n ++) {
//Eingabe / Verarbeitung für jede Überwachungskamera
double x = sc.nextDouble(); //Überwachungskamera x Koordinaten
double y = sc.nextDouble(); //Überwachungskamera y Koordinate
double d = sc.nextDouble(); //Entfernung, die die Überwachungskamera sehen kann
double e = sc.nextDouble(); //Ausrichtung der Überwachungskamera(direction)Winkel darstellend
double f = sc.nextDouble(); //Betrachtungswinkel der Überwachungskamera
Camera camera = new Camera(x, y, d, e, f);
if (camera.findPlayer(player)) {
System.out.println("Ich konnte sehen");
} else {
System.out.println("Ich konnte nicht sehen");
}
}
sc.close();
}
}
class Player {
private double x; //Spieler x Koordinaten
private double y; //Spieler y Koordinate
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; //Überwachungskamera x Koordinaten
private double y; //Überwachungskamera y Koordinate
private double distance; //Entfernung, die die Überwachungskamera sehen kann
private double dirAngle; //Ausrichtung der Überwachungskamera(direction)Winkel darstellend
private double viewAngle; //Betrachtungswinkel der Überwachungskamera
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();
//Beurteilung nach Entfernung
double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
if (d > this.distance) {
return false;
}
//Beurteilung nach Winkel
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;
}
}
Es ist endlich Zeit, die Leistung der Überwachungskamera zu überprüfen. Als Test legen wir die Koordinaten fest, an denen sich der Spieler befindet (10, 10), und testen mit drei Überwachungskameras. Zunächst werde ich bis zu dem Punkt eintreten, an dem die Verarbeitung der ersten Einheit fortgesetzt wird.
10 10
3
10 0 12 90 30
Ich konnte sehen
Die folgende Situation zeigt die eingegebenen Informationen in einem Diagramm. Sie können den Spieler perfekt sehen. Die Spannung ist gestiegen.
Gehen wir zum zweiten.
10 5 10 180 90
Ich konnte nicht sehen
Ich konnte den zweiten nicht sehen, aber es ist überhaupt kein Problem. Dies liegt daran, dass die Situation wie in der folgenden Abbildung dargestellt ist. Ich konnte den Entfernungszustand löschen, aber die Richtung der Überwachungskamera war falsch. Auch diesmal ist das Urteil perfekt!
Dann gehen wir mit dem drittletzten Auto zum Finale.
10 16 8 270 120
Ich konnte nicht sehen
Am Ende kann ich den dummen Spieler direkt vor der Überwachungskamera sehen ... __ Ich kann es nicht __. In Bezug auf ein Schießspiel ist es wie eine frontale Platzierung! (Werfen)
Das ist der Beginn einer lustigen Debugging-Arbeit, aber dieses Mal möchte ich sie hier abschneiden und mit dem zweiten Teil fortfahren. Wenn Sie sich fragen: „Warum nicht?“ Wie früher, denken Sie bitte darüber nach, bevor Sie den zweiten Teil lesen. __Warum konnte die dritte Überwachungskamera den Spieler nicht sehen, obwohl er ihn sehen konnte? Wie soll ich das Programm ändern? __ __
Recommended Posts