[Из песочницы] Учим Искусственный Интеллект играть в игру
Итак, сканер — прямая. У нас есть координаты одной из её точек (координаты игрока) и угол относительно оси OX, вторую точку мы можем получить, используя тригонометрические функции sin и cos.
Отсюда получаем направляющий вектор прямой, а значит можем построить канонический вид уравнения этой прямой.
Чтобы получить значение на сканер, нужно посмотреть, пересекает ли какой-нибудь шар эту прямую, а значит, нужно представить уравнение прямой в параметрическом виде и подставить всё это в уравнения окружности, последовательно для каждой окружности для поля.
Если привести эту подстановку к общему виду, получится параметрической уравнение относительно a, b и с, где эти переменные — коэффициенты квадратного уравнения, начиная с квадрата соответственно.
Предлагаем читателю более подробно ознакомиться с этим алгоритмом самостоятельно, используя простейшие определения линейной алгебры
Ниже представлен код сканеров
Ball.scaners: { //сканеры
length: 1000,
i: [], //значения на сканерах
get_data: function(){ //Ball.scaners.get_data / Получение данных со сканеров
var angl = 0;
var x0 = Ball.x,
var y0 = Ball.y;
var l = Ball.scaners.length;
for(let k = 0; k < 32; k++){
x1 = l*Math.cos(angl),
y1 = l*Math.sin(angl);
Ball.scaners.i[k] = 0;
for(i = 0; i < bombs.length; i++){
if(((k >= 0) && (k <= 8) && (bombs[i].x < x0) && (bombs[i].y < y0)) || ((k >= 8) && (k <= 16) && (bombs[i].x > x0) && (bombs[i].y < y0)) || ((k >= 16) && (k <= 24) && (bombs[i].x > x0) && (bombs[i].y > y0)) || ((k >= 24) && (k <= 32) && (bombs[i].x < x0) && (bombs[i].y > y0))){ //Проверка областей видимости сканеров
var x2 = bombs[i].x,
y2 = bombs[i].y;
var p = true; //проверка на наличие решения
var pt = true; //проверка на наличие ДВУХ корней
var t1, t2;
var a = x1*x1 + y1*y1,
b = 2*(x1*(x0 - x2) + y1*(y0 - y2)),
c = (x0 - x2)*(x0 - x2) + (y0 - y2)*(y0 - y2) - bombs[i].r*bombs[i].r;
//------------------------------Проверка восьми возможных случаев
if((a == 0) && (b != 0)){
t = -c/b;
pt = false;
}
if((a == 0) && (b == 0)){
p = false;
}
if((a != 0) && (b != 0) && (c == 0)){
t1 = 0;
t2 = b/a;
}
if((a != 0) && (b == 0) && (c == 0)){
t1 = 0;
pt = false;
}
if((a != 0) && (b == 0) && (c != 0)){
t1 = Math.sqrt(c/a);
t2 = -Math.sqrt(c/a);
}
if((a != 0) && (b != 0) && (c != 0)){
var d = b*b - 4*a*c;
if(d > 0){
t1 = (-b + Math.sqrt(d))/(2*a);
t2 = (-b - Math.sqrt(d))/(2*a);
}
if(d == 0){
t1 = -b/(2*a);
}
if(d < 0){
p = false;
}
}
//-----------------------------------
if(p == true){
if(pt == true){
let x = t1*x1 + x0;
let y = t1*y1 + y0;
let l1 = Math.pow((x - Ball.x), 2)+Math.pow((y - Ball.y), 2);
x = t2*x1 + x0;
y = t2*y1 + y0;
let l2 = Math.pow((x - Ball.x), 2)+Math.pow((y - Ball.y), 2);
if(l1 <= l2){
Ball.scaners.i[k] += 1 - l1/(l*l);
}else{
Ball.scaners.i[k] += 1 - l2/(l*l);
}
}else{
let x = t1*x1 + x0;
let y = t1*y1 + y0;
Ball.scaners.i[k] += 1 - (Math.pow((x - Ball.x), 2)+Math.pow((y - Ball.y), 2))/(l*l);
}
}else{
Ball.scaners.i[k] += 0;
}
}else{
continue;
}
}
angl += Math.PI/16;
}
//!---------------Для зелёных
for(k = 32; k < 64; k++){
x1 = l*Math.cos(angl),
y1 = l*Math.sin(angl);
Ball.scaners.i[k] = 0;
for(i = 0; i < apples.length; i++){
if(((k >= 32) && (k <= 40) && (apples[i].x < x0) && (apples[i].y < y0)) || ((k >= 40) && (k <= 48) && (apples[i].x > x0) && (apples[i].y < y0)) || ((k >= 48) && (k <= 56) && (apples[i].x > x0) && (apples[i].y > y0)) || ((k >= 56) && (k <= 64) && (apples[i].x < x0) && (apples[i].y > y0))){
var x2 = apples[i].x,
var y2 = apples[i].y;
var p = true; //проверка на наличие решения
var pt = true; //проверка на наличие ДВУХ корней
var t1, t2;
var a = x1*x1 + y1*y1,
b = 2*(x1*(x0 - x2) + y1*(y0 - y2)),
c = (x0 - x2)*(x0 - x2) + (y0 - y2)*(y0 - y2) - apples[i].r*apples[i].r;
//------------------------------Проверка восьми возможных случаев
if((a == 0) && (b != 0)){
t = -c/b;
pt = false;
}
if((a == 0) && (b == 0)){
p = false;
}
if((a != 0) && (b != 0) && (c == 0)){
t1 = 0;
t2 = b/a;
}
if((a != 0) && (b == 0) && (c == 0)){
t1 = 0;
pt = false;
}
if((a != 0) && (b == 0) && (c != 0)){
t1 = Math.sqrt(c/a);
t2 = -Math.sqrt(c/a);
}
if((a != 0) && (b != 0) && (c != 0)){
var d = b*b - 4*a*c;
if(d > 0){
t1 = (-b + Math.sqrt(d))/(2*a);
t2 = (-b - Math.sqrt(d))/(2*a);
}
if(d == 0){
t1 = -b/(2*a);
}
if(d < 0){
p = false;
}
}
//-----------------------------------
if(p == true){
if(pt == true){
let x = t1*x1 + x0;
let y = t1*y1 + y0;
let l1 = Math.pow((x - Ball.x), 2)+Math.pow((y - Ball.y), 2);
x = t2*x1 + x0;
y = t2*y1 + y0;
let l2 = Math.pow((x - Ball.x), 2)+Math.pow((y - Ball.y), 2);
if(l1 <= l2){
Ball.scaners.i[k] += 1 - l1/(l*l);
}else{
Ball.scaners.i[k] += 1 - l2/(l*l);
}
}else{
let x = t1*x1 + x0;
let y = t1*y1 + y0;
Ball.scaners.i[k] += 1 - (Math.pow((x - Ball.x), 2)+Math.pow((y - Ball.y), 2))/(l*l);
}
}else{
Ball.scaners.i[k] += 0;
}
}else{
continue;
}
}
angl += Math.PI/16;
}
Ball.scaners.i[64] = (1000 - Ball.x) / 1000; //левая граница
Ball.scaners.i[65] = Ball.x / 1000; //правая граница
Ball.scaners.i[66] = (500 - Ball.y) / 500; //верхняя граница
Ball.scaners.i[67] = Ball.y / 500; //нижняя граница
}
}