Implementieren wir die Bedingung, dass der Umfang und das Innere der Ougi-Form in Java enthalten sind [Teil 1]

1. 1. Einführung

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."

2. Problemstellung

Nehmen wir die folgenden Spezifikationen an.

Spieler

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 $).

Überwachungskamera

Ü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.

Sichtweite jeder Überwachungskamera

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. quiita_おうぎ形 - コピー.png

Parametereingabe / -ausgabe

Geben Sie Parameter über die Konsole im folgenden Format ein.      p_x p_y      N      x_1 y_1 d_1 e_1 f_1 (Weggelassen)      x_i y_i d_i e_i f_i (Weggelassen)      x_N y_N d_N e_N f_N Die Parameter jeder Zeile sind durch einen Abstand von halber Breite zu trennen. Außerdem wird jedes Mal, wenn die Informationen jeder Überwachungskamera eingegeben werden, bestimmt, ob die Überwachungskamera den Player sehen kann oder nicht, und wenn sie gesehen werden kann, wird sie als "sichtbar" ausgegeben, und wenn sie nicht gesehen werden kann, wird sie als "nicht sichtbar" ausgegeben. Und.

3. 3. Implementierung der Datenstruktur

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;
	}
}

4. Implementierung des Algorithmus

Eingang

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.

Kann die Überwachungskamera den Player sehen?

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 ), ( p_x $, $ p_y $)

\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 ), ( p_x $, $ p_y $) kombiniert werden.

\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.

Ausgabe

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;
	}
}

5. Hinrichtung und ...

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. quiita_おうぎ形2.png

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! quiita_おうぎ形3.png

Dann gehen wir mit dem drittletzten Auto zum Finale.

10 16 8 270 120
Ich konnte nicht sehen

quiita_おうぎ形4.png

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)

6. Und zu debuggen ...

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

Implementieren wir die Bedingung, dass der Umfang und das Innere der Ougi-Form in Java enthalten sind [Teil 2]
Implementieren wir die Bedingung, dass der Umfang und das Innere der Ougi-Form in Java enthalten sind [Teil 1]
Dies und das der Implementierung der zeitlichen Beurteilung von Daten in Java
[Android 9.0 Pie Java] Implementieren Sie setOnTouchListener am Rand von RecyclerView und schließen Sie die Softtastatur
[Java] Was tun, wenn sich der in der Datenbank gespeicherte Inhalt und der Name der Aufzählung in der Aufzählung unterscheiden, die die Definition der Datenbank widerspiegelt?
Ein Programm (Java), das die Summe von ungeraden und geraden Zahlen in einem Array ausgibt
Rufen Sie Java im Zentrum von Technologiethemen und Elementartechnologien, die Java-Ingenieure 2017 verfolgen sollten.
JSON in Java und Jackson Teil 1 Gibt JSON vom Server zurück
[Java] Ordnen Sie die Daten des vergangenen Montags und Sonntags der Reihe nach an
Betrachten wir die Bedeutung von "Stream" und "Collect" in der Stream-API von Java.
Lassen Sie uns eine TODO-App in Java 5 erstellen. Schalten Sie die Anzeige von TODO um
Geben Sie die Reihenfolge an, in der die Konfigurationsdateien und Klassen in Java geladen werden
Das Problem, dass der Inhalt von Parametern vollständig in der Ansicht [Rails] angezeigt wird
Die Geschichte, zu vergessen, eine Datei in Java zu schließen und zu scheitern
Lassen Sie uns darüber nachdenken, was deklarative Programmierung in Java und Elm ist (Teil 1).
Beispielprogramm, das den Hashwert einer Datei in Java zurückgibt
Finden Sie das Maximum und Minimum der fünf in Java eingegebenen Zahlen
Überprüfung von "seltsamem Java" und Java-Wissen, das in Java Bronze oft vergessen wird
[Java] Implementieren Sie eine Funktion, die eine im Builder-Muster implementierte Klasse verwendet
[Einführung in die Informatik Teil 1: Versuchen wir es mit maschinellem Lernen] Implementieren wir die k-Mittelungsmethode in Java - Über das Konzept der Koordinaten -
Holen Sie sich das Ergebnis von POST in Java
Was sind die aktualisierten Funktionen von Java 13
Die Geschichte des Schreibens von Java in Emacs
Diskriminierung von Enum in Java 7 und höher
Ich habe die Daten der Reise (Tagebuchanwendung) in Java erhalten und versucht, sie # 001 zu visualisieren
[Java] Wo befindet sich die Implementierungsklasse der Annotation, die in BeanValidation vorhanden ist?
10 Sperrfeuer mit ● oder ■, die wahrscheinlich im Training auftreten (Java)