BGT — первая бродилка

Всем привет!
Сегодня мы разберём важную тему в создании игр.
Мы попытаемся создать бродилку.
Вы будете двигаться по четырём направлениям, находить некоторые объекты.
Думаю, что вы уже не раз сталкивались с подобными играми. Примером такой игры может послужить operation black square, eggs master и так далее.
Наша игра будет не такой глобальной, будет простенькой.
Она будет такой:
игрок ходит по полю, на котором где-то лежит ключ.
Найдя ключ, игрок идёт в верхний левый угол поля, где выходит с этого игрового поля, открыв дверь ключом.
Соответственно без ключа он не сможет выйти.
Такой вот бредовый проект посетил мою голову. D
Давайте создадим папку нашего нового проекта, как уже делали в прошлом.
Назовём её «my game».
Название конечно не самое прекрасное, но пока нам этого хватит.
Зайдём в эту папку, создадим в ней файл play.bgt.
Хочу предупредить сразу, что пока мы не будем использовать позиционирование звуков, ибо это сложный процесс, о котором я расскажу позже.
Сейчас ваша задача, понять принцип создания.
Нам понадобятся звуки:
Несколько звуков шагов, при этом одинаковых по типу.
Назовите их примерно так:
step1.wav, step2.wav, step3.wav ну и так далее.
Ещё должен быть звук того, что игрок возьмёт ключ.
Также понадобится звук того, что игрок открывает этим ключом дверь.
ещё нужен звук, сообщающий игроку, что дверь открыть нельзя, пока он не найдёт ключа.
Назовём звук ключа key.wav.
звук открывающейся двери Open_dore.wav
Звук того, что дверь открыть нельзя dore_disabled.wav
набрав все нужные звуки, начнём писать код.
Для начала напишем координаты игрока.
Это собственно две переменные x и y.
int x = 1;
int y = 1;
Таким образом изначальные координаты игрока будут 1/1. То есть он будет стоять в нижнем левом углу поля.
Кстати забыл сказать, что наше поле будет 10 на 10 клеток.
А зачем делать большое поле для нашей маленькой игры?
Ещё нужно создать координаты ключа и двери.
Давайте пока не будем указывать случайные координаты ключа, просто укажем:
int key_x = 5;
int key_y = 5;
Теперь ключ у нас лежит на координатах 5/5.
ещё нужны координаты двери, а как вы помните, она у нас находится в левом верхнем углу поля, значит её координаты будут таковы:
int dore_x = 1;
int dore_y = 10;
Теперь нам нужна переменная проверки, проверяющая наличие у игрока ключа.
Помните, я когда-то писал про переменные истины и лжи. true и false.
Вот этот тип переменных нам подходит больше всего.
bool check = false;
Переменная check изначально равна false. Ведь у игрока сначала нету ключа, а когда он возьмёт его, check будет равна true.
Теперь мы можем создать звуковые объекты всех наших звуков.
sound step;
sound key;
sound open_dore;
sound dore_disabled;
Ещё нам нужен таймер шагов. Ведь игрок не будет за секунду проходить сразу миллион шагов. В секунду он должен проходить 2-3 шага.
timer steper;
Всё, открываем главную функцию.
void main() {
Теперь думаю, что нам ещё Понадобится скрин ридер, без которого ну просто нельзя.
Помните, мы уже однажды включали скрин ридер в игру?
Давайте вернёмся к нашей папке, сбросим туда файл скрин ридера, который лежит в папке bgt в папке redist.
Теперь возвращаемся к нашему коду и пишем после открытия главной функции:
screen_reader_set_library_path(NVDA, «NVDA.dll»);
Ну или пишите имя своего файла место NVDA.dll, как вы там его назвали… это не суть.
Далее загружаем все звуки, кроме step. Объясню позже.
key.load(«key.wav»);
open_dore.load(«open_dore.wav»);
dore_disabled.load(«dore_disabled.wav»);
Теперь создадим окно нашей игры.
show_game_window(«Игра»);
Можете писать не игра, а что-нибудь другое. Как говорится, хоть горшком назови, только в печку не ставь. D
Ну теперь всё готово, чтобы преступить к созданию сценария игры.
while(true) {
Сначала нам нужно прописать движение игрока по полю и столкновение его со стенами.
Тут надо подумать. Если игрок нажмёт у нас стрелку вверх, то будет двигаться вверх, значит будет прибавляться координата y. Это ещё из школьного курса алгебры известно.
Если будет нажимать стрелку вправа, то будет двигаться вправа, соответственно будет прибавляться x.
для стрелки вниз будет уменьшаться y, а для стрелки влева уменьшаться будет x
Тут всё ясно. Теперь это нужно реализовать.
if(key_down(KEY_UP)) {
Это мы проверяем, зажата ли клавиша со стрелкой вверх.
запомните, что нажата и зажата — две разные вещи. если игрок нажал клавишу и тут же отпустил её — это называется нажата, а если игрок нажал клавишу и держит её — это называется зажата. Так вот, для зажата используется key_down, а для нажата используется key_pressed.
теперь пишем то, что будет происходить, если зажата клавиша со стрелкой вверх.
Для начала нужно проверить, превысел ли наш таймер заданное время. Ну вы ведь понимаете, что игрок в секунду должен делать 2-3 шага.
У нас игрок будет делать 3 шага.
пишем так:
if(steper.elapsed>300) {
Этим условием мы проверяем, прошло ли с запуска таймера 300 миллисекунд.
Вы спросите, после какого запуска? ведь мы не запускали никакой таймер.
Я отвечу:
А нам и не надо запускать его. BGT автоматом запустит такой таймер. Но бывают случаи, когда BGT сам таймер запускать не станет. В таком случае вам придётся написать его запуск. то есть restart()
Сейчас нам это не к чему.
Пишем то, что будет происходить каждые 300 миллисекунд.
y+=1;
int step_rand = random(1, 3);
Вот тут я остановлюсь.
Когда вы играете в игры, то ваш персонаж всегда ступает по-разному. Ну звук шага разный. Они немного, но отличаются.
Именно для этого я и просил вас собрать несколько шагов одного типа и обозвать их step1.wav, step2.wav и т. д.
Допустим, что у вас 3 таких звука step.
Нужно проигрывать их случайным образом, чтобы создавалось реалистичное впечатление того, что игрок идёт.
Иначе пользователю будет неинтересно.
Для этого я и создал переменную step_rand, в которой случайным образом выбираю число от 1 по 3.
Ведь у меня 3 звука шагов, может у вас 6 или вообще 10, тогда ваша переменная будет такова:
int step_rand = random(1, 6);
или
int step_rand = random(1, 10);
Дальше мы загружаем нужный нам звук.
step.load(«step»+step_rand+».wav»);
Помните, когда мы работали с типами данных, то делали что-то похожее.
Мы собирали несколько строк в одну.
Тут мы сделали тоже самое.
Сначала создали переменную, в которой выбрали случайное число, потом подставили её в название нашего звука при его загрузке.
А теперь осталось лишь воспроизвести звук.
step.play();
Поэтому мы и не стали загружать звук для step в начале, как поступили с остальными звуками.
А теперь нам нужно опять запустить таймер, ведь его действие кончилось, произошло то, что мы написали выше, но ведь пользователь хочет сделать следующий шаг, поэтому таймер мы возобновим.
steper.restart();
}
}
Последними фигурными скобками мы закрыли наши 2 условия.
Теперь проделаем обратное действие.
я уже не стану комментировать его, думаю, что вы разберётесь.
if(key_down(KEY_DOWN)) {
if(steper.elapsed>300) {
y-=1;
int step_rand = random(1, 3);
step.load(«step»+step_rand+».wav»);
step.play();
steper.restart();
}
}
Таким образом наш игрок уже может двигаться вверх и вниз по игровому полю. То есть вперёд и назад.
Сами попробуйте сделать движение влева и вправа.
Скажу лишь, что здесь нужно использовать переменную x и клавиши:
KEY_RIGHT и KEY_LEFT.
Мы создали движение нашего персонажа, но мы не оградили его в движении.
Он сейчас может идти себе, куда ему вздумается. Хоть в минусовые координаты.
это не есть хорошо, поэтому оградим его всего лишь полем 10 на 10 клеток.
пишем такой код:
if(x>10) {
x-=1;
step.stop();
}
if(x<=0) {
x+=1;
step.stop();
}
Попробуйте сделать тоже самое с y.
Ну вот, теперь наш друг будет двигаться только по этому полю. Давайте назовём это поле комнатой. А то поле — как-то не звучит.
Из комнаты может вести наружу дверь, а с поля нет. Поэтому нам лучше комната, нежели поле.
Теперь реализуем то, как игрок будет брать ключ.
Вы должны понимать, что чтобы игроку взять ключ, ему надо встать на координаты этого самого ключа.
пишем так:
if(x==key_x and y==key_y and check==false) {
Это условие называют сложным.
Оно позволяет нам внести в него сразу несколько условий, соединённых оператором and.
Переведём на русский язык:
если x равна key_x и y равна key_y и check==false
Вы заметили, что я зачем-то приплёл сюда переменную check
Дело в том, что если координаты игрока равны координатам ключа, то всё время будет происходить условие. Но если игрок будет стоять на месте, а в условии у вас написано играть звуки, то эти звуки будут играть постоянно, пока он не сойдёт с места. Нам этого не хотелось бы, поэтому мы и написали дополнительное условие.
Дальше всё поймёте.
check=true;
key.play();
screen_reader_speak(NVDA, «Вы подняли ключ»);
}
Вот тут и пригодилась наша переменная check.
Теперь, если игрок наступит на это же место, ключа там уже не будет, потому что переменная check равна true, соответственно никакого ключа на этом месте уже нету.
Далее надо написать условия для двери.
if(x==dore_x and y==dore_y) {
Это условие, в котором мы проверяем, стоит ли игрок на координатах двери.
if(key_pressed(KEY_RETURN)) {
Этим условием мы проверяем, нажата ли клавиша энтер.
if(check==false) {
Если переменная check равна false
screen_reader_speak(NVDA, «К сожалению, у вас нет нужного ключа!»);
dore_disabled.stop();
dore_disabled.play();
}
if(check==true) {
open_dore.play_wait();
оператор play_wait() позволяет нам играть звук, остановив все остальные процессы в игре, пока звук не кончится.
Это нужно, ведь дальше мы сделаем выход из игры.
screen_reader_speak(NVDA, «У вас был ключ, которым вы открыли дверь и убежали из странной комнаты!»);
exit();
}
}
}
Ну и нужно создать выход из игры. Об этом никогда не забывайте.
if(key_pressed(KEY_ESCAPE)) {
exit();
}
ещё нужно не забыть закрыть наш while и главную функцию
}
}
Всё, бинго, мы наконец создали нашу небольшую стоящую игру.
Все вопросы задавайте в комментариях и в чате.

BGT — первая бродилка: 20 комментариев

  1. friker800, А почему у вас написано if(x10) {
    Ведь это даже не условие.

  2. Большое спасибо! Статья очень полезна. У меня всё получилось вроде. Щас пытаюсь сделать стрельбу. ) Попробовать хочу написать маленькую игрушку.

  3. это не есть хорошо, поэтому оградим его всего лишь полем 10 на 10 клеток.
    пишем такой код:
    if(x10) {
    x-=1;
    step.stop();
    }

  4. friker800, дико извиняюсь! моя ошибка. всё, исправил.

  5. best_reader, спасибо. Ну если что, то пиши сюда свой код стрельбы, помогу, если что не получится)

  6. еще одна ошибка есть, я разобрался, а другие вдруг нет.
    dore_open.play_wait();
    хотя имя файла подрозумевалось как звук открывающейся двери Open_dore.wav

  7. и еще нужно добавить строки:
    if(x<1) {
    x+=1;
    step.stop();
    }
    а то новички не поймут как сделать ограждение слева и снизу

  8. вот блииин. ну я тоже человек, со мной тоже косяки случаются. извините все, кто узрел эти ошибки. всё будет исправлено. а насчёт if(x<=1) надо не 1 а 0, ну ладно, тоже напишу про это.

  9. да все норм, ни на одном сайте нет таких объяснений
    а ошибки могут быть у всех!

  10. friker800, нет. сказано ведь, что x может быть меньше нуля, а может и равняться нулю. то есть даже если x равна нулю, то всёравно срабатывает условие.

  11. Ого, заработало.
    Я думал что код работать не будет 🙂
    Сделал всё как написано, круто, получилось, спасибо 🙂

  12. хм , странно , я даже скопировал весь код с статьи , но всеравно звук почему-то не воспровоизводиться , может ктонибудь с такой же проблемой сталккивался , и поможет ее решить .

  13. здравствуйте я только изучаю bgt и хотел узнать мне не совсем понятно для чего когда мы пишем то что будет происходить каждые 300 миллисекунт, используем строку y+=1; что это означает?

    1. Персонаж находится в поле системы координат xy. То есть x- это перемещение влево-вправо, а y- перемещение вверх-вниз. В участке кода, который вы упомянули проверяется: если зажата клавиша «стрелка вверх», значит координата y должна увеличиваться на 1 через каждых 300 миллисекунд. Надеюсь доступно объяснил, и ничего не попутал.

  14. asffix здравствуйте! в статье первая бродилка я написал всё так как вы писали но компелятор выводит ошибку не могли бы вы взглянуть на мой код? int x = 1;
    int y = 1;
    int key_x = 5;
    int key_y = 5;
    int dore_x = 1;
    int dore_y = 10;
    bool chech = false;
    timer steper;
    sound dore_open;
    sound key;
    sound step;
    void main() {
    screen_reader_set_library_path(NVDA, «nvda.dll»);
    dore_open.load(«dore_open.wav»);
    key.load(«key.wav»);
    show_game_window(«опасная комната»);
    while(true) {
    if(key_down(KEY_UP)) {
    if(steper.elapsed>300) {
    y+=1;
    int step_rand = random(1, 3)
    }
    }
    step.load(«step»+step_rand+».wav»);
    step.play();
    steper.restart();
    }
    }
    if(key_down(KEY_DOWN)) {
    if(steper.elapsed>300) {
    y-=1;
    int step_rand = random(1, 3);
    step.load(«step»+step_rand+».wav»);
    step.play();
    steper.restart();
    }
    }
    if(key_down(KEY_RIGHT)) {
    if(steper.elapsed>300) {
    x+=1;
    int step_rand = random(1, 3);
    step.load(«step»+step_rand+».wav»);
    step.play();
    steper.restart();
    }
    }
    if(key_down(KEY_LEFT)) {
    if(steper.elapsed>300) {
    x-=1;
    int step_rand = random(1, 3);
    step.load(«step»+step_rand+».wav»);
    step.play();
    steper.restart();
    }
    }
    if(x>10) {
    x-=1;
    step.stop();
    }
    if(x10) {
    y-=1;
    step.stop();
    }
    if(y<=0) {
    y+=1;
    step.stop();
    }
    if(x==key_x and y==key_y and check==false) {
    check=true;
    key.play();
    screen_reader_speak(NVDA, "вы подняли ключ");
    }
    if(x==dore_x and y==dore_y) {
    if(key_pressed(KEY_RETURN)) {
    if(check==false) {
    screen_reader_speak(NVDA, "чтобы пройти туда, вам нужен ключ от двери.");
    }
    if(check==true) {
    dore_open.play_wait();
    screen_reader_speak(NVDA, "вы открыли дверь ключём, и убежали из опасной комнаты!");
    exit();
    }
    }
    }
    if(key_pressed(KEY_ESCAPE)) {
    exit
    }
    }
    }

Обсуждение закрыто.