Чтобы принять участие в соревновании, используя язык программирования Java, вы можете cкачать готовый Maven проект по этой ссылке:
https://vesnasoft.org/downloads/vesnasoft-ai-2016-java-sdk.zip
Этот проект нужно импортировать в вашей IDE или cкачать .jar файл:
https://vesnasoft.org/downloads/vesnasoft-ai-2016-java-sdk.jar
со всем необходимым, и подключить его к проекту как библиотеку.
В проекте вы увидите следующие Java классы:
XY - простенький класс, который в себе несет всего две переменные типа float : х
и y
.
С помощью него мы можем назначать вектор движения, или направление пушки, а также узнать свои координаты, или координаты других игроков.
public class XY {
public float x; // координата X
public float y; // координата Y
}
Работать с XY очень легко. Нужно просто создать новый объект:
XY someVector = new XY(1.0, 0,3);
// Можно создать вектор, сразу присвоив значения
XY nextVector = new XY();
// Можно создавать вектор вот так, но тогда вектор будет (0,0)
Player - класс, который описывает каждый танк, и ваш в том числе ;)
В этом классе есть переменные типа String - на пример имя игрока, типа int - на пример время перезарядки орудия, и класса XY - которые описывают положение игрока на поле, или направление движения.
public class Player {
public String mType; // тип обьекта - в данном случае - игрок
public int mId; // уникальный номер обьекта - этот номер не повторяется
public String mUser; // имя игрока (указывается при создании клиента)
public int mClientTick; // какой последний тик видел этот игрок
public int mCreated; // тик создания объекта
public XY mXy; // где находится игрок
public int mHealthMax; // начальноe значение брони
public int mHealth; // текущее значение брони
public XY mMoveXy; // куда едет танк
public float mMoveSpeedMax; // максимальная скорость танка
public float mMoveSpeed; // текущая скорость, для простоты: 0 или 50
public XY mGunXy; // куда смотрит пушка
public int mGunDamage; // урон от попадания
public int mGunReloadMax; // максимальное время перезарядки пушки
public int mGunReload; // Текущее время перезарядки
public float mBodyRadius; // радиус танка
}
Shell - класс, который описывает снаряд. На пример его положение, скорость и направление - все что нужно, что вовремя увернуться.
Игроки и снаряды - основные объекты нашего игрового мира. Анализируя их положение, уровень брони, направление и скорость, мы можем совершать ответные действия - на пример двигаться в определенном направлении или стрелять.
public class Shell {
public String mType; // тип обьекта - снаряд
public int mId; // уникальный номер объекта
public String mUser; // имя игрока, который запустил снаряд
public int mCreated; // тик, в который был произведен выстрел
public XY mXy; // текущее положение снаряда
public XY mMoveXy; // вектор направления снаряда
public float mMoveSpeed; // скорость снаряда
public float mDamage; // урон от попадания
public int mBodyRadius; // радиус снаряда
}
Bonus - полезная штука. Через определенные периоды времени на поле появляются бонусы, обозначенные иконками.
public class Bonus {
public String mType; // тип объекта - бонус
public String mBonus; // тип бонуса
public XY mXy; // расположение на поле
public int mCreated; // тик, в который был показан бонус
public int mId; // уникальный номер объекта
}
WorldState - один из самых главных классов. Этот класс содержит всю информацию о игровом поле - положение каждого противника, каждого снаряда и бонуса, размер карты, текущее время в игре.
public class WorldState {
public int mTick; // текущее игровое время
public XY mSize; // размер карты
public ArrayList<Player> mPlayerList; // список всех игроков
public ArrayList<Shell> mShellList; // список всех летящих снарядов.
public ArrayList<Bonus> mBonusList; // список всех бонусов
}
Input - это наш игровой джойстик. В нем всего три переменные: куда двигаться, куда направить пушку и стрелять ли.
public class Input {
public XY move; // вектор движения танка
public XY gun; // вектор направления пушки
public boolean fire; // true, если мы хотим выстрелить
}
С помощью этих простых штук вы обязательно победите. Но сначала нужно узнать, как же присоединиться к соревнованию?
Если вы скачали Maven-проект, в начале нужно распаковать .rar архив в любое удобное место, а затем импортировать его в среде разработки.
Откройте класс Example. В нем вы видите функцию main
, в которой будет самое интересное.
Если же вы скачали не Мавен-проект, а .jar файл, то функция main()
по содержанию изначально должна быть такой как в примере ниже, чтобы все заработало.
public class Example {
public static void main(String[] args) throws InterruptedException {
// Чтобы начать соревнование, нужно создать клиент:
// Ваш логин пароль роль в игре
final VesnaSoftClient client = new VesnaSoftClient("John", "123", "player");
client.addPlayer(new Play() {
// Реализация этой функции - и есть "интеллект" вашего танка
@Override// Возвращает она новый объект Input() - ввод "джойстика"
public Input doSomething(WorldState state) {//<- state - состояние мира
Input i = new Input();
i.move.x = (float) Math.random(); // вектор(направление) движения
i.move.y = (float) Math.random(); //
i.gun.x = (float) Math.random(); // направление пушки
i.gun.y = (float) Math.random(); //
i.fire = true; // стрелять ли
return i; // Ура! Теперь танк что-то сделает
}
}
);
new CountDownLatch(1).await(); // Эта штука не даст программе закончить работу слишком рано :)
}
}
final VesnaSoftClient client = new VesnaSoftClient("John", "123", "player");
Этот код создает объект клиента для соревнования. Там где сейчас John - введите свой логин (но помните, что он не должен совпадать с логином других игроков), вместо “123” - укажите свой пароль. “player” - это ваша роль в игре. Пусть останется “player”.
Важно:
VesnaSoftClient client = new VesnaSoftClient("John", "123", "player");
client.mThisPlayer - таким образом мы можем получить наш танк в любой точке программы. Очень удобно. Например:
XY someCoordinates = client.mThisPlayer.mXy; // Таким образом узнаем наши координаты
@Override
public Input doSomething(WorldState state) {
Input inp = new Input();
// ваш код будет тут ;)
return inp;
}
Эта функция - самая важная для вас, в ней вы напишите свой код.
WorldState state
- параметр, который получает функция.
Вы уже знакомы с этим классом, он содержит всю информацию о игровом мире. Анализируя это состояние, вы напишите интеллект для танков.
Возвращает функция объект Input
- ввод джойстика. На основе анализа состояния мира, можно указать направление движение танка, направление орудия и стрелять ли.
Далее - примеры кода:
@Override
public Input doSomething(WorldState state) {
Input i = new Input(); // создаем новый ввод
i.move = new XY(1.0f, 0.0f); //двигаемся точно вправо, x = 1.0, y = 0
//i.move = new XY(0.0f, 1.0f); //двигаемся точно вниз x = 0.0, y = 1.0
//i.move = new XY(0.0f, -1.0f); //двигаемся точно вверх x = 0.0, y = -1.0
i.fire = true; // а по ходу движения стреляем
return i; // возвращаем новый ввод
}
@Override
public Input doSomething(WorldState state) {
Input i = new Input();
//Чтобы двигаться в нужную точку, нужно узнать вектор - просто
//От координат пункта назначения, отобрать свои координаты.
//На пример, хотим двигаться к первому танку в списке
if (state.mPlayerList.size() > 1){ // А на поле вообще больше одного танка?
Player other = state.mPlayerList.get(0); // получаем первого игрока из списка игроков
if (other.mUser.equals(client.mThisPlayer.mUser)) // Если это - мы, то получаем второго
other = state.mPlayerList.get(1);
// цель.x - наш танк.x, цель.y - наш танк.y
i.move = new XY (other.mXy.x - client.mThisPlayer.mXy.x, other.mXy.y - client.mThisPlayer.mXy.y);
}
return i;
}
@Override
public Input doSomething(WorldState state) {
Input i = new Input();
if (state.mPlayerList.size() > 1){ // А на поле вообще больше одного танка?
Player other = state.mPlayerList.get(0); // получаем первого игрока из списка игроков
if (other.mUser.equals(client.mThisPlayer.mUser)) // Если это - мы, то получаем второго
other = state.mPlayerList.get(1);
XY vec = new XY (other.mXy.x - client.mThisPlayer.mXy.x, other.mXy.y - client.mThisPlayer.mXy.y);
// нашли vec - направление к другому танку
i.move = vec; // движемся в этом направлении
i.gun = vec; // стреляем в этом направлении
i.fire = true; // стреляем
}
return i;
}
Объявляем статическую переменную counter в классе Example И просто добавляем к желаемой точке движения результаты вычисления синуса и косинуса из переменной counter. И нужно не забыть увеличивать counter :)
public static float counter = 0;
@Override
public Input doSomething(WorldState state) {
Input i = new Input();
i.move.x = (float) ((Math.sin(counter) + client.mThisPlayer.mXy.x) - client.mThisPlayer.mXy.x);
i.move.y = (float) ((Math.cos(counter) + client.mThisPlayer.mXy.y) - client.mThisPlayer.mXy.y);
counter += 0.1;
return i;
}
Чтобы эффективно справиться с управлением, часто вам придется узнавать расстояние до другого объекта - снаряда, или другого танка. Сделать это очень просто - в этом нам поможет всем известная теорема Пифагора. В данном случае - расстояние между объектами является гипотенузой.
public static int getDistantion(Shell shell, Player thisPlayer){
return (int) Math.sqrt(Math.pow(shell.mXy.x - thisPlayer.mXy.x, 2) + Math.pow(shell.mXy.y - thisPlayer.mXy.y,2));
Эта функция может принимать на вход другой объект: в данном примере - снаряд, и ваш танк. Возвращает - текущее расстояние. Если вы хотите найти расстояние не до снаряда, а, например, до танка, то просто замените в аргументах функции объект Shell на обьект Player.
public static Player getNearestEnemy(WorldState state, Player thisPlayer){
if (state.mPlayerList.size()<2 || thisPlayer == null || state == null)
return null; // Если что-то не так - выходим
Player nearestEnemy = null;
int dist = state.mPlayerList.get(0).mUser.equals(thisPlayer.mUser) ? getDistantion(state.mPlayerList.get(1), thisPlayer) : getDistantion(state.mPlayerList.get(0), thisPlayer);
for (Player player : state.mPlayerList){ // проходим по списку игроков
int n = getDistantion(player, thisPlayer); // находим дистанцию по функции выше
if (dist >= n && !thisPlayer.mUser.equals(player.mUser)){ // если дистанция меньше
dist = n; // то сохраняем ссылку на
nearestEnemy = player; // этого соперника
}
}
return nearestEnemy; // Ура, мы нашли ближайшего соперника)
}