Лес безумных

Лес безумных — это игра, представляющая собой сайт-скроллер, в котором вы движетесь по лесу, а на встречу вам двигаются люди, судя по озвучке находящиеся немного не в себе.
Также по пути вам встречаются ямы, которые нужно перепрыгивать.
Управление производится следующими клавишами:
Стрелки вправо и влево — движение игрока вперёд или назад.
Стрелка вверх — подпрыгнуть. (Во время прыжка возможно движение).
Клавиша H — узнать здоровье.
Клавиша CTRL — стрельба.
Данная игра озвучивается скринридером NVDA.
Перехвата клавиатуры, даже при запущенном NVDA не происходит.
Ниже следует исходный код игры.
Автор постарался как можно подробнее прокомментировать каждую строку кода.
Там, где комментариев нет, но у читателя могут возникнуть вопросы, авторы перевода данного руководства добавили свои комментарии.
Автор кода Fluttery

Код

//подключаем необходимые файлы
#include"sound_pool.bgt"
#include"classes.bgt"
#include"player.bgt"

//объект sound_pool
sound_pool sounder;

//координаты игрока
int plx;
int ply;
//его здоровье
int phealth;
//переменная для проверки здоровья
int check_health;
//патроны у игрока
int ammo;
//скорость игрока
int speed;
//направление игрока
int direction;

//уровень, правда в этой игре он 1
int level;

//переменная, ограничивающая поле справа
int max;

//состояние прыжка, если истинно, то игрок летит в воздухе, если ложно, то игрок идёт по земле
bool jump;

//таймер движения, прыжка и атаки
timer steper;
timer jumper;
timer attacker;

//главная функция
void main()
{
//окно игры
show_game_window("Лес безумных");
//дистанция, на которой слышны звуки
sounder.max_distance=70;
//установка скрин ридера nvda, загрузка его библиотеки
screen_reader_set_library_path(NVDA, "NVDA.dll");
//вызыв функции level1(), где и происходят все действия
level1();
}

//создаём массив врагов, в который будем добавлять элементы
human[] people;
//тоже самое и с ямами
hole[] wind;

void level1()
{
//задаём начальные координаты игрока
plx=1;
ply=1;
//конец поля
max=300;
//задаём фоновый звук
sound ambiant;
ambiant.load("ambiant1.wav");
ambiant.play_looped();
//создаём местность, записываем её в словарь
for(int i=1; i<300+1; i++)
board.set(i+":"+ply, "1");
//задаём кол-во патронов
ammo=50;
//уровень
level=1;
//задаём здоровье
phealth=300;
check_health=phealth;
//задаём скорость игрока
speed=300;
//бросаем ямы через каждые 50 клеток
int k=1;
hole w;
for(int i=0; i<5; i++)
{
wind.insert_at(i, w);
wind[i].install(k*50, 1);
k++;
}
//тоже самое с врагами
k=1;
human p;
for(int i=0; i<5; i++)
{
people.insert_last(p);
people[i].install(k*53, 1);
k++;
}
//цикл игры
while(true)
{
//пользователь может проверять здоровье по клавише h
if(key_pressed(KEY_H))
screen_reader_speak(NVDA, phealth+" здоровья");
//ограничиваем игрока с левой стороны, чтобы в минусовые координаты не свалил
if(plx<=0)
plx+=1;
//У нас в игре 1 уровень, поэтому, когда игрок достигнет координаты 300, просто выведем сообщение о том, что первый уровень пройден и сделаем выход из игры
if(plx==max)
{
alert("Победа", "Вы прошли первый уровень!");
exit();
}
//запускаем обработчик ям
for(int i=0; i wind[i].action();
//обработчик врагов
for(int i=0; i people[i].action();
//вызываем функцию player из файла player.bgt
player();
//обновляем слушателя
sounder.update_listener_2d(plx, ply);
//делаем выход из игры
if(key_pressed(KEY_ESCAPE))
exit();
// устанавливаем итерацию в 5 милисекунд
wait(5);
}
}

Файл player.bgt

//функция, в которой происходят все действия с игроком
void player()
{
//проверка жизни игрока, если она меньше или равна нулю, то он умирает
if(phealth<=0)
{
alert("Сообщение", "Вас убили!");
exit();
}
//игрок начинает стрелять по нажатию клавиши левый контрол, стреляет, пока есть патроны
if(key_down(KEY_LCONTROL) and attacker.elapsed>100)
{
if(ammo>0)
{
ammo-=1;
sounder.play_stationary("attack.wav", false);
//создаём цикл всех врагов, в котором вызывается функция hit, которая у нас есть в классе врага. Таким образом происходит попадание пуль во врага
for(int i=0; i people[i].hit(plx, ply, 7, 2);
}
else
{
sounder.play_stationary("empty.wav", false);
}
attacker.restart();
}
//это условие проверяет, если в игрока попали и у него уменьшилось здоровье, то воспроизводится звук его крика
if(phealth {
sounder.play_stationary("hit"+random(1, 2)+".wav", false);
check_health=phealth;
}
//движение в прыжке
if(key_pressed(KEY_LEFT) and jump==true)
plx-=1;
if(key_pressed(KEY_RIGHT) and jump==true)
plx+=1;
//сам прыжок
if(key_pressed(KEY_UP) and jump==false)
{
ply=5;
jump=true;
jumper.restart();
sounder.play_stationary("jump.wav", false);
}
//если игрок в воздухе находится больше 800 милисекунд, то падает на землю грешную
if(jumper.elapsed>800 and jump==true)
{
ply=1;
jump=false;
sounder.play_stationary("step"+pp(plx, ply)+"-"+random(1, 3)+".wav", false);
}
//движение игрока по земле
if(key_down(KEY_LEFT) and steper.elapsed>speed and jump==false)
{
direction=1;
plx-=1;
sounder.play_stationary("step"+pp(plx, ply)+"-"+random(1, 3)+".wav", false);
steper.restart();
}
if(key_down(KEY_RIGHT) and steper.elapsed>speed and jump==false)
{
direction=2;
plx+=1;
sounder.play_stationary("step"+pp(plx, ply)+"-"+random(1, 3)+".wav", false);
steper.restart();
}
}

//функция, возвращающая строку, в которой при помощи входных параметров проверяется, какой пол под игроком и в зависимости от результата проигрывается нужный звук шагов. Все плитки пола у нас храняться в словаре, который я сделал в файле clasis.bgt
string pp(int pplx, int py)
{
string a;
board.get(pplx+":"+py, a);
return a;
}

Файл classes.bgt

//Создаём словарь плиток, в котором будут храниться местности. Его можно было создать и в main.bgt, но я создал здесь. Это не суть важно.
dictionary board;
//Создаём класс ямы
class hole
{
//создаём её координаты
int x;
int y;
//создаём переменную звука для ямы
int slot;
//создаём функцию, с помощью которой можно яму разместить в пространстве
void install(int i_x, int i_y)
{
this.x=i_x;
this.y=i_y;
//в словарь записываем местность для ямы, чтобы, если игрок приближается к яме, изменились его шаги
board.set((i_x-1)+":"+i_y, "0");
board.set((i_x-2)+":"+i_y, "0");
board.set(i_x+":"+i_y, "-1");
board.set((i_x+1)+":"+i_y, "0");
board.set((i_x+2)+":"+i_y, "0");
this.slot=sounder.play_2d("hole.wav", plx, ply, this.x, this.y, true);
}
//создаём функцию обработки, которая всегда будет знать, что происходит с ямой
void action()
{
//создаём условие, когда игрок падает в яму
if(plx==this.x and ply==this.y)
{
alert("Сообщение", x+", "+y+", "+this.x+", "+this.y+"Вы упали в яму и расшиблись на смерть!");
wait(5);
exit();
}
}
}

//создаём класс врага
class human
{
//создаём координаты врага, его здоровье, таймер движения и переменную жизни, если она равна истине, то враг живёт, а если она ложна, то враг мёртв
int x;
int y;
int health;
int speed;
int slot;
bool life;
timer mover;
//также создаём переменную урона, который враг может нанести и таймер атаки, по истечению которого он будет наносить игроку вред
timer attacker;
int attack;
//привычная функция, которая создаёт врага на поле
void install(int i_x, int i_y)
{
this.x=i_x;
this.y=i_y;
this.health=random(5, 20);
this.speed=random(150, 600);
this.life=true;
this.attack=random(150, 500);
this.slot=sounder.play_2d("human voice"+random(1, 6)+".wav", plx, ply, this.x, this.y, true);
}
//функция обработки, которая всегда проверяет состояние врага
void action()
{
if(this.life==true)
{
//проверяем, если игрок находится в близи врага, то враг наносит ему вред
if(plx>this.x-5 and plxthis.attack)
{
phealth-=5;
sounder.play_stationary("fists"+random(1, 2)+".wav", false);
this.attacker.restart();
}
//вызываем функцию смерти врага, в которой всегда проверяется его здоровье. если оно меньше или равно нулю, то он умирает.
this.die();
//задаём движение врага к игроку. Если враг находится от игрока на расстоянии 30 клеток, враг идёт в сторону игрока
if(plx>this.x-30 and plx this.move(1);
if(plxthis.x)
this.move(2);
}
}
//функция движения врага
void move(int d)
{
if(this.life==true)
{
if(this.mover.elapsed>this.speed)
{
if(d==1)
this.x-=1;
if(d==2)
this.x+=1;
sounder.update_sound_2d(this.slot, this.x, this.y);
sounder.play_2d("step"+pp(this.x, this.y)+"-"+random(1, 3)+".wav", plx, ply, this.x, this.y, false);
this.mover.restart();
}
}
}
//функция, в которой проверяется, если игрок находится близко к врагу и стреляет в него, то у врага уменьшается здоровье. Всё зависит от входных параметров
void hit(int dx, int dy, int dist, int damage)
{
if(this.life==true)
{
if(dx>this.x-dist and dx {
this.health-=damage;
sounder.play_2d("human hit"+random(1, 5)+".wav", plx, ply, this.x, this.y, false);
}
}
}
//функция смерти, которую вызывал выше
void die()
{
if(this.health<=0)
{
sounder.destroy_sound(this.slot);
sounder.play_2d("human die"+random(1, 5)+".wav", plx, ply, this.x, this.y, false);
this.life=false;
}
}
}
Скачать архив с исходниками.
Содержание

Поделитесь с друзьями

WordPress Lessons