Всем привет!
Наверно многие уже слышали про проект под названием HabraWars, если коротко — это игра для программеров, в которой вы сами пишите искусственный интеллект для собственного робота на JS.
Я думаю что это будет не первая моя статья на данную тему, хотя бы потому, что здесь я не собираюсь раскрывать всю тему, а лишь ее часть. Но сначала, я думаю, нужно сформировать некую концепцию робота… Сразу говорю, что в js я далеко не спец и вообще мои знания этого языка, на мой взгляд, довольно скудны… Итак, как-же должен выглядеть наш робот изнутри, а изнутри у него должна быть логика, как бы это очевидно не звучало, но логика это довольно сложная штука, она будет управлять роботом, задавая вопросы(типа: «Летит ли в меня(робота) снаряд») и основываясь на ответах вызывать функции, отвечающие за действия робота… Но начну я не с логики(я сам еще не начинал даже ее писать:)), а начну с функций, отвечающих за выполнение действий, порученных логикой.
Значит так, начнем. В этом посте будет обсуждаться именно атака нашего робота(в следующем наверно увороты от пуль, читай защита). Накидываем для начала такой сухой код:
Надеюсь с комментами в коде все понятно… Итак мы имеем несколько методов, которые еще не описаны, но использованы, значит нужно их написать, вот что мы щас будем писать:
Описываем метод getNearestEnemy(enemies, myCoords, myAngle):
Теперь метод getAngleDeflection(myCoords, enemyCoords, myAngle):
И последний метод — fire(myCoords, enemyCoords, myAngle, distance), он нам говорит стрелять или нет(например если энергия у нас 100 процентов но робот еще не успел нацелиться то стрелять НЕ надо):
Все готово, теперь можно собрать нашего робота по кусочкам:
Конечно это не всё и можно еще много чего придумать, например частенько если робот стреляет из далека, то пуля не долетает, это можно исправить зная направление движения врага…
Наверно многие уже слышали про проект под названием HabraWars, если коротко — это игра для программеров, в которой вы сами пишите искусственный интеллект для собственного робота на JS.
Я думаю что это будет не первая моя статья на данную тему, хотя бы потому, что здесь я не собираюсь раскрывать всю тему, а лишь ее часть. Но сначала, я думаю, нужно сформировать некую концепцию робота… Сразу говорю, что в js я далеко не спец и вообще мои знания этого языка, на мой взгляд, довольно скудны… Итак, как-же должен выглядеть наш робот изнутри, а изнутри у него должна быть логика, как бы это очевидно не звучало, но логика это довольно сложная штука, она будет управлять роботом, задавая вопросы(типа: «Летит ли в меня(робота) снаряд») и основываясь на ответах вызывать функции, отвечающие за действия робота… Но начну я не с логики(я сам еще не начинал даже ее писать:)), а начну с функций, отвечающих за выполнение действий, порученных логикой.
Значит так, начнем. В этом посте будет обсуждаться именно атака нашего робота(в следующем наверно увороты от пуль, читай защита). Накидываем для начала такой сухой код:
- this.enemyId = 0;
-
- this.action = function(my_state, enemies, shots, params){
- if(!this.enemyId){// Если мы еще не выбрали врага, то есть это первая итерация данной функции
- /*
- Получаем ID ближайшего врага и записываем его в переменную, которая не изменится при построении
- следующего фрейма игры...
- */
- this.enemyId = this.getNearestEnemy(
- enemies,
- {x: my_state.x, y: my_state.y},
- my_state.angle
- );
- }
- for(var key in enemies){
- if(enemies[key]['id'] == this.enemyId) var enemy = enemies[key];
- }
- if(typeof(enemy) == 'undefined'){// Если наш враг уже умер, то нужно находить нового...
- this.enemyId = this.getNearestEnemy(
- enemies,
- {x: my_state.x, y: my_state.y},
- my_state.angle
- );
-
- for(var key in enemies){
- if(enemies[key]['id'] == this.enemyId) var enemy = enemies[key];
- }
- }
- /*
- Этот метод(который ниже) мы создадим чтобы он нам говорил в какую сторону
- нужно отклониться, чтобы нацелиться на врага, он будет возвращать
- -1 если нужно повернуться по часовой стрелке, и 1 если нужно повернуться
- против часовой стрелки... ну или 0 если мы уже нацелены...
- напомню для тех кто забыл школьный курс геометрии: ноль градусов
- располжены там где 3 часа на стенных часах, соответственно 90 градусов
- на 12-ти часах...
- */
- var angle = this.getAngleDeflection(
- {x: my_state.x, y: my_state.y},
- {x: enemy.x, y: enemy.y},
- my_state.angle
- );
- /*
- Дистанцию до врага можно вычислить по формуле архимеда: c^2 = a^2 + b^2 - сумма
- квадратов катетов равна квадрату гипотенузы... => c = sqrt(a^2 + b^2)
- */
- var distanceToEnemy = Math.sqrt(
- Math.pow(enemy.x - my_state.x, 2)
- + Math.pow(enemy.y - my_state.y, 2)
- );
- return [
- 0.5,
- angle,
- this.fire(
- {x: my_state.x, y: my_state.y},
- {x: enemy.x, y: enemy.y},
- my_state.angle,
- distanceToEnemy
- ),
- distanceToEnemy
- ];
- };
* This source code was highlighted with Source Code Highlighter.
Надеюсь с комментами в коде все понятно… Итак мы имеем несколько методов, которые еще не описаны, но использованы, значит нужно их написать, вот что мы щас будем писать:
- getNearestEnemy(enemies, myCoords, myAngle)
- getAngleDeflection(myCoords, enemyCoords, myAngle)
- fire(myCoords, enemyCoords, myAngle, distance)
Описываем метод getNearestEnemy(enemies, myCoords, myAngle):
- this.getNearestEnemy = function(enemies, myCoords, myAngle){
- var howLong = Array(); // В этом массиве будут содержаться ID врагов и его дальность от нас
- var distance = Array(); // В этом массиве будут содержаться ID и дальность самого близеого к нам врага
- for(var i = 0; i < enemies.length; i++){
- howLong[i] = Array();
- /*
- Получаем направление в градусах от нас до врага
- */
- var direction = get_direction(myCoords.x, myCoords.y, enemies[i]['x'], enemies[i]['y']);
- /*
- Теперь разницу между нашем направлением и направлением в сторону врага. Эта разница тоже имеет значение,
- т.к. на поворот тоже затрачивается время
- */
- direction = angle_size(direction, myAngle);
- /*
- Теперь суммируем расстояние и разницу углов...
- */
- howLong[i]['distance'] = Math.sqrt(
- Math.pow(enemies[i]['x'] - myCoords.x, 2)
- + Math.pow(enemies[i]['y'] - myCoords.y, 2)
- ) + direction;
- howLong[i]['id'] = enemies[i]['id'];
- }
- for(var i = 0; i < howLong.length; i++){// Здесь отбриаем ID самого ближайшего робота
- if(!i) distance = howLong[i];
- else if(distance['distance'] > howLong[i]['distance']) distance = howLong[i];
- }
- return distance['id'];
- };
* This source code was highlighted with Source Code Highlighter.
Теперь метод getAngleDeflection(myCoords, enemyCoords, myAngle):
- this.getAngleDeflection = function(myCoords, enemyCoords, myAngle){// Ну здесь вроде все и так понятно)
- return get_angle_control(
- myAngle,
- get_direction(myCoords['x'], myCoords['y'], enemyCoords['x'], enemyCoords['y'])
- );
- };
* This source code was highlighted with Source Code Highlighter.
И последний метод — fire(myCoords, enemyCoords, myAngle, distance), он нам говорит стрелять или нет(например если энергия у нас 100 процентов но робот еще не успел нацелиться то стрелять НЕ надо):
- this.fire = function(myCoords, enemyCoords, myAngle, distance){
- var direction = get_direction(myCoords['x'], myCoords['y'], enemyCoords['x'], enemyCoords['y']);
- var angle = angle_size(direction, myAngle); // Приравниваем переменной разность углов
- if(distance != 0 && angle != 0){// Если какая-то из переменных равна нулю, то теоретически стрелять можно
- /*
- 10 делим на произведение расстояния и разности углов, получаем коэффициент "нацеленности"
- */
- if(10/(distance*angle) > 0.6) return true;
- else return false;
- }else return true;
- }
* This source code was highlighted with Source Code Highlighter.
Все готово, теперь можно собрать нашего робота по кусочкам:
- this.getNearestEnemy = function(enemies, myCoords, myAngle){
- var howLong = Array();
- var distance = Array();
- for(var i = 0; i < enemies.length; i++){
- howLong[i] = Array();
- var direction = get_direction(myCoords.x, myCoords.y, enemies[i]['x'], enemies[i]['y']);
- direction = angle_size(direction, myAngle);
- howLong[i]['distance'] = Math.sqrt(
- Math.pow(enemies[i]['x'] - myCoords.x, 2)
- + Math.pow(enemies[i]['y'] - myCoords.y, 2)
- ) + direction;
- howLong[i]['id'] = enemies[i]['id'];
- }
- for(var i = 0; i < howLong.length; i++){
- if(!i) distance = howLong[i];
- else if(distance['distance'] > howLong[i]['distance']) distance = howLong[i];
- }
- return distance['id'];
- };
-
- this.getAngleDeflection = function(myCoords, enemyCoords, myAngle){
- return get_angle_control(
- myAngle,
- get_direction(myCoords['x'], myCoords['y'], enemyCoords['x'], enemyCoords['y'])
- );
- };
-
- this.fire = function(myCoords, enemyCoords, myAngle, distance){
- var direction = get_direction(myCoords['x'], myCoords['y'], enemyCoords['x'], enemyCoords['y']);
- var angle = angle_size(direction, myAngle);
- if(distance != 0 && angle != 0){
- if(10/(distance*angle) > 0.6) return true;
- else return false;
- }else return true;
- }
-
- this.enemyId = 0;
-
- this.action = function(my_state, enemies, shots, params){
- if(!this.enemyId){
- this.enemyId = this.getNearestEnemy(
- enemies,
- {x: my_state.x, y: my_state.y},
- my_state.angle
- );
- }
- for(var key in enemies){
- if(enemies[key]['id'] == this.enemyId) var enemy = enemies[key];
- }
- if(typeof(enemy) == 'undefined'){
- this.enemyId = this.getNearestEnemy(
- enemies,
- {x: my_state.x, y: my_state.y},
- my_state.angle
- );
-
- for(var key in enemies){
- if(enemies[key]['id'] == this.enemyId) var enemy = enemies[key];
- }
- }
- var angle = this.getAngleDeflection(
- {x: my_state.x, y: my_state.y},
- {x: enemy.x, y: enemy.y},
- my_state.angle
- );
- var distanceToEnemy = Math.sqrt(
- Math.pow(enemy.x - my_state.x, 2)
- + Math.pow(enemy.y - my_state.y, 2)
- );
- return [
- 0.5,
- angle,
- this.fire(
- {x: my_state.x, y: my_state.y},
- {x: enemy.x, y: enemy.y},
- my_state.angle,
- distanceToEnemy
- ),
- distanceToEnemy
- ];
- };
* This source code was highlighted with Source Code Highlighter.
Конечно это не всё и можно еще много чего придумать, например частенько если робот стреляет из далека, то пуля не долетает, это можно исправить зная направление движения врага…