I had been playing a game called Metal Gear Solid for the first time in a while, but suddenly I was wondering what kind of algorithm the player-controlled character would be visible to the surveillance cameras and enemy soldiers. So, I decided to actually make it myself, as well as studying programming. In this article, I wrote how to implement it, how to crush bugs, and what lessons I learned. For those who have begun to study programming, the content is like a teacher, on the other hand, "Be careful not to make such a mistake."
Let's assume the following specifications.
There is one player on the coordinate plane. The player stays still and does not move. ~~ It's troublesome to move. ~~ The player's body can be regarded as a point, and the coordinates of that point are ($ p_x $, $ p_y $).
Surveillance cameras are installed in $ N $ units on the coordinate plane. $ N $ is an integer greater than or equal to 1. The surveillance camera is still and does not move. ~~ When it moves (omitted) ~~ The lens of each surveillance camera can be regarded as a point, and the coordinates of that point are ($ x_i $, $ y_i $). However, $ i $ is an integer of 1 or more and $ N $ or less, which indicates the number of the surveillance camera.
The distance that each surveillance camera can see the player is $ d_i $ ($ d_i $> 0). Let $ e_i $ be the angle representing the direction of the lens of each surveillance camera, and $ f_i $ be the angle representing the field of view of the camera. $ e_i $ is the angle between the straight line representing the direction of the camera and the positive direction of the $ x $ axis, and both $ e_i $ and $ f_i $ are 0 ° or more and less than 360 °. That is, the range in which each surveillance camera can see the player is the circumference and the inside of the goose shape with a radius of $ d_i $ and a central angle of $ f_i $ as shown in the following figure.
Input the parameters from the console in the following format.
First of all, I would like to say that this time, the purpose is to consider the condition that the circumference and the inside of the gourd shape include points, so it is not possible to strictly implement encapsulation or object orientation. I won't __. I can't say ~~. ~~ There may be many other points that cannot be reached, but please forgive me.
First, create a class Player that handles the player's location information. The class Player has $ x $ and $ y $ coordinates and has the ability to return their values as needed. In addition, it may not be necessary to make the player a class, but if this is system development, it is possible to assume a situation where there are many players, so "Anyway, the player is hidden. I will clarify the __idea __ that it has the information and functions of Kajika. Also, the class Player is just a idea (an abstract concept of an object in a complicated way), and we will create a __player (an entity in a complicated way) that exists in the true sense. For example, is it a feeling that there is an abstract concept of human beings, and that I and you exist as the substance?
class Player {
private double x; //Player x coordinate
private double y; //Player y coordinate
public Player(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
}
Since it's a big deal, I'll explain a little about encapsulation. In class Player, the values are stored in double type variables x and y, but the person who writes the program (not always me. May collaborate with someone or throw it to someone. In a situation where variable values can be referenced and assigned in a disorderly manner (!), There is a risk of writing a process (bug) that is not what was originally expected. Therefore, in order to clarify the processing that the program writer (s) can do for the class Player, the above code defines as follows.
--Variable x does not directly rewrite the value! ⇒ Write private before the type declaration. Then, it becomes impossible to write "x = 100;" that directly assigns a value to the variable x (it causes an error). --I want to substitute the x coordinate for the variable x when creating a real player! ⇒ Assign the argument value to the variable x in the constructor (method with the same name as the class. The method is a summary of the processing flow) that is always called when creating an existing player. --I want to be able to refer to the value of variable x later! ⇒Create a dedicated method getX (). If you write public before the type declaration, you can call it from various places. --The same applies to the variable y.
In this way, a class or encapsulation is a mechanism that summarizes necessary information and processing and prevents it from being rewritten randomly. It takes a little more work to write a program, but Java provides a mechanism to reduce the risk of creating bugs instead. The larger the scale of development, the more important such a mechanism becomes.
Next, create a class Camera that handles surveillance camera information. Class Cameras have x, y coordinates, visible distances, and angles that represent orientation and viewing angle. It has a minimal configuration now, but as we implement the process in the future, we will add more methods.
class Camera {
private double x; //X coordinate of surveillance camera
private double y; //Y coordinate of surveillance camera
private double distance; //Distance visible to surveillance cameras
private double dirAngle; //Direction of surveillance camera(direction)Angle representing
private double viewAngle; //Viewing angle of surveillance camera
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;
}
}
Now that we have decided where and what kind of information to store, we will finally describe the processing flow. First, from the main method. Whenever you run a Java program, the main method is called first. Therefore, you have to write only one main method in the whole program. For the time being, I will create only the part that reads the numerical value entered from the console.
class CameraTest {
public static void main(String[] args) {
//input
Scanner sc = new Scanner(System.in);
//player
double px = sc.nextDouble(); //Player x coordinate
double py = sc.nextDouble(); //Player y coordinate
Player player = new Player(px, py);
//Surveillance camera
int N = sc.nextInt(); //Number of surveillance cameras
for (int n = 0; n < N; n ++) {
//Input / processing for each surveillance camera
double x = sc.nextDouble(); //X coordinate of surveillance camera
double y = sc.nextDouble(); //Y coordinate of surveillance camera
double d = sc.nextDouble(); //Distance visible to surveillance cameras
double e = sc.nextDouble(); //Direction of surveillance camera(direction)Angle representing
double f = sc.nextDouble(); //Viewing angle of surveillance camera
Camera camera = new Camera(x, y, d, e, f);
}
sc.close();
}
}
It's kind of like static, Scanner, nextDouble, nextInt, etc., but if you start explaining these, it will derail the purpose of this article, so I will omit the explanation. Anyway, at the time of creating the above, the numerical value entered according to the specifications can be read without any problem.
Of course, just reading the numbers is meaningless, so let's add a process to determine if the camera can actually see the player. In the Camera class created earlier, let's create a method findPlayer that reads the player's position information and determines whether the player can be visually recognized. This method is the key to this article.
//Add to Camera class
public boolean findPlayer(Player player) {
double px = player.getX();
double py = player.getY();
//Judgment by distance
double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
if (d > this.distance) {
return false;
}
//Judgment by 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;
}
Now, let's briefly explain the processing flow. There are two keywords, "distance" and "angle".
First of all, "distance", as the name implies, determines whether the distance between the surveillance camera and the player is smaller than the visible distance of the surveillance camera. The distance between two points ($ x_i $, $ y_i
\sqrt{(x_i - p_x)^2 + (y_i - p_y)^2}
Is required at. If this is less than the viewing distance $ d_i $, it may be visible, but if it is larger than $ d_i $, it is out of the question. Therefore, in the part that judges by distance, in the latter case, false is returned suddenly so that unnecessary processing after that is not necessary.
Next, regarding the processing of "angle" after clearing the condition of "distance", the function $ \ arctan $ (high school mathematics) that calculates the size of the angle between the straight line and the x-axis from the slope of the straight line passing through the two points. "Trigonometric function" and "inverse function") can be used, so by combining these for two points ($ x_i $, $ y_i
\arctan{\frac{y_i - p_y}{x_i - p_x}}
You can find it at. Also, the range of angles that the camera can see is represented by $ e_i-\ frac {f_i} {2} $ or more and $ e_i + \ frac {f_i} {2} $ or less, so the angle obtained from the tilt is this range. Returns true if there is, false if not.
At this point, it's almost complete. The method findPlayer created earlier returns a boolean type value, so it only outputs the result according to that value. Then, I will post the completed (?) Program.
import java.util.Scanner;
class CameraTest {
public static void main(String[] args) {
//input
Scanner sc = new Scanner(System.in);
//player
double px = sc.nextDouble(); //Player x coordinate
double py = sc.nextDouble(); //Player y coordinate
Player player = new Player(px, py);
//Surveillance camera
int N = sc.nextInt(); //Number of surveillance cameras
for (int n = 0; n < N; n ++) {
//Input / processing for each surveillance camera
double x = sc.nextDouble(); //X coordinate of surveillance camera
double y = sc.nextDouble(); //Y coordinate of surveillance camera
double d = sc.nextDouble(); //Distance visible to surveillance cameras
double e = sc.nextDouble(); //Direction of surveillance camera(direction)Angle representing
double f = sc.nextDouble(); //Viewing angle of surveillance camera
Camera camera = new Camera(x, y, d, e, f);
if (camera.findPlayer(player)) {
System.out.println("I was able to see");
} else {
System.out.println("I couldn't see");
}
}
sc.close();
}
}
class Player {
private double x; //Player x coordinate
private double y; //Player y coordinate
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; //X coordinate of surveillance camera
private double y; //Y coordinate of surveillance camera
private double distance; //Distance visible to surveillance cameras
private double dirAngle; //Direction of surveillance camera(direction)Angle representing
private double viewAngle; //Viewing angle of surveillance camera
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();
//Judgment by distance
double d = Math.sqrt(Math.pow(this.x - px, 2) + Math.pow(this.y - py, 2));
if (d > this.distance) {
return false;
}
//Judgment by 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;
}
}
It's finally time to check the performance of the surveillance cameras. As a test, let's test using three surveillance cameras with the coordinates where the player is (10, 10). First of all, I will try to input until the process of the first unit is advanced.
10 10
3
10 0 12 90 30
I was able to see
The situation below shows the entered information in a diagram. You can see the player perfectly. The tension has risen.
Let's go to the second one.
10 5 10 180 90
I couldn't see
I couldn't see the second one, but it's not a problem at all. This is because the situation is as shown in the figure below. I was able to clear the distance condition, but the direction of the surveillance camera was bad. The judgment is perfect this time as well!
Then, let's go to the finale with the third last car.
10 16 8 270 120
I couldn't see
At the end, I could see the stupid player right in front of the surveillance camera ... __ I couldn't do it __. In terms of a shooting game, it's like a frontal placement! (Throwing)
That's the beginning of fun debugging work, but this time I'd like to cut it here and continue to the second part. If you're wondering, "Why isn't it?" Like I used to be, please think about it before reading the second part. __ Why couldn't the third surveillance camera see the player even though he could see it? Also, how should I modify the program? __
Recommended Posts