Game Maker - создание игр | HellRoom Games
Декабрь 13, 2025, 18:34:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.

Войти
Новости:
 
   Начало   Game Maker Помощь Правила форума Поиск Календарь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: [Example]Столкновения с массивом  (Прочитано 6227 раз)
0 Пользователей и 1 Гость смотрят эту тему.
VladTheCat
Немного
GM Pro user
*

Репутация: 145
Offline Offline

Пол: Мужской
Награды:
1000 сообщений!За постоянность! [100 дней на форуме]Настоящий игродел!
API: Love
Деятельность: Целая игростудия, состоящая из одного кота.
Сообщений: 1435



« : Март 04, 2013, 21:16:47 »

Всем привет. Хочу рассказать о важной вещи для создателей клонов Minecraft и Terraria (Ну или для тех, кто хочет использовать для карты тайлы, а не объекты)  - это столкновения игрока с массивом. За чистоту кода не отвечаю, так что, если у вас есть свои более оптимальные варианты реализации, то буду рад =)


Сразу для сокращения кода введу пару переменных, которые являются ссылками на модули Love. Также подготовлю главные 3 функции любого проекта.

Код:
gr = love.graphics
kb = love.keyboard
m = math
 
function love.load()
end
 
function love.update(dt)
end
 
function love.draw()
end
 
function sign(n)
    if n == 0 then
        return 0
    end
        return n / math.abs(n)
end
 
function div(a, b)
    return m.floor(a / b)
end

Для тех, кто сидит на GM или другом языке, но не на Lua функции sign и div (В GM это оператор, но в Lua его нет, поэтому функция) понятны. А для остальных поясню:

Сначала сделаем поле, по которому будет бегать наш “игрок”. генерация простая – сверху-донизу поле забивается нулями, но если высота ниже заданной, то забиваются в случайном порядке единицы. Так же зададим переменную размера блока
Все это в love.load

Код:
field = {}
for x = 0, 20 do
    field[x] = {}
    for y = 0, 20 do
        field[x][y] = 0
        if y > 10 and math.random(3) < 3 then
            field[x][y] = 1
        end
    end
end
bsize = 32
Далее создадим самого игрока и зададим ему переменные координат, ширины и высоты, скорости
Код:
bsize = 32
player = {}
player.x = 300
player.y = 100
player.w = 20
player.h = 30
player.vsp = 0
player.hsp = 0
Так как мой способ не идеальный (есть 1 баг), то лучше игрока сделать меньше блока, а то он может пролететь сквозь него.

C load закончили. Переходим к update. Для начала просто зададим увеличение вертикальной скорости игрока, смены горизонтальной скорости по нажатию “A” и “D” и рестарта по нажатию “R”:

Код:
if love.keyboard.isDown('r') then love.load() end
player.vsp = player.vsp + 500 * dt
if kb.isDown('a') then
   player.hsp = player.hsp - 500 * dt
elseif kb.isDown('d') then
   player.hsp = player.hsp + 500 * dt
end

А дальше самое главное – сами движения с столкновения. Сначала я опишу принцип работы:
Что нам нужно, чтобы столкнуть 2 объекта? Проверить их коордитаты. Тоже самое используется для столкновение “объект – массив”, но тут это чуть сложнее, так как нам нужно преобразовывать координаты игрока, чтобы можно было их сравнить с определенной ячейкой нашей карты. На картинке приблизительный вариант:


Как, надеюсь, видно на картинке, мы проверяем 4 крайние точки игрока.
Проверяемая точка, координаты которой нацело поделены на размер блока, равна индексу блока, в котором находится эта уже поделенная координата. Надеюсь, понятно объяснил =)
Теперь же, нам надо реализовать это в коде. Но мы же хотим сделать еще и перемещение, а не только столкновения. Причем желательно эти движения сделать точными, без заездов в блоки. Это можно сделать следующим способом: Ставим цикл, на количество шагов, равное модулю скорости. И уже в этом цикле, проверять столкновения и в зависимости от них смещать игрока на dt (так как если смещать на 1, то это будет слишком быстро). Добавляем в love.update
Код:
for i = 1, m.abs(player.vsp) do
    pvsp = sign(player.vsp)
    px = div(player.x, bsize)
    pxw = div(player.x + player.w, bsize)
    py = div(player.y + pvsp, bsize)
    pyw = div(player.y + player.h + pvsp, bsize)
    if field[ px ][ pyw ] == 0 and
       field[ pxw ][ pyw ] == 0 and
       field[ px ][ py ] == 0 and
       field[ pxw ][ py ] == 0 then
        player.y = player.y + pvsp * dt
    else
        player.vsp = 0
        if kb.isDown('w') then player.vsp = -200 end
    end
end   
 
for i = 1, m.abs(player.hsp) do
    phsp = sign(player.hsp)
    px = div(player.x + phsp, bsize)
    pxw = div(player.x + player.w + phsp, bsize)
    py = div(player.y, bsize)
    pyw = div(player.y + player.h, bsize)
    if field[ px ][ py ] == 0 and
       field[ pxw ][ py ] == 0 and
       field[ px ][ pyw ] == 0 and
       field[ pxw ][ pyw ] == 0 then
        player.x = player.x + phsp * dt
    else
        player.hsp = 0
    end
end
Как вы видите, тут мы и использовали наши функции sign и div. Объясняю.
Вертикальное перемещение: Мы проверяем 4 вершины игрока со смещением в 1 пиксель в сторону вертикальной скорости, и если на деленных координатах вершины чисто, то двигаем игрока, если нет – останавливаем его и даем ему возможность прыгнуть при нажатии “W”.

Горизонтальное: Все тоже самое, только горизонтально и без прыжка.
Забыл сказать – если выберетесь за пределы массива, то игра вылетит с ошибкой. Тут надо делать либо проверки, либо ставить стенки.

Ну вот и все, наш герой бегает и прыгает по массиву! Только.. с прыжком есть 1 баг, вернее, недочет: Даже если игрок столкнулся с блоком сверху, а не снизу, то он может прыгнуть. Это дает возможность лазать по потолкам. Давайте считать это фичей =D
А… забыл еще одно: рисование =) тут все просто. Рисуем массив и игрока:

Код:
function love.draw()
    for x = 0, 20 do
        for y = 0, 20 do
            if field[x][y] == 1 then
                gr.rectangle('line', x * bsize, y * bsize, bsize, bsize)
            end
        end
    end
    gr.rectangle('fill', player.x, player.y, player.w, player.h)
end
Вот и все! Вот полный листинг кода статьи:
Ну и, конечно, вы можете скачать .love пример

Всем спасибо за внимание.
Записан


Будьте вежливы: Вам помогли? Не забудьте поставить плюс. А то банда злобных апельсинов придет за вами. И даже тех. поддержка вам не поможет. :3

Когда я что-то пишу в "<>", то это значит, что содержимое надо заменить на свое значение.
Cuper479
Участник
****

Репутация: 8
Offline Offline

Пол: Мужской
API: Love
Деятельность: PixelArt,C++,Lua,Java
Сообщений: 153


« Ответ #1 : Март 06, 2013, 19:15:41 »

Можем здесь посмотреть
http://love2d.ru/25109/
Записан
VladTheCat
Немного
GM Pro user
*

Репутация: 145
Offline Offline

Пол: Мужской
Награды:
1000 сообщений!За постоянность! [100 дней на форуме]Настоящий игродел!
API: Love
Деятельность: Целая игростудия, состоящая из одного кота.
Сообщений: 1435



« Ответ #2 : Март 06, 2013, 20:57:43 »

Там моя же статья :3
Записан


Будьте вежливы: Вам помогли? Не забудьте поставить плюс. А то банда злобных апельсинов придет за вами. И даже тех. поддержка вам не поможет. :3

Когда я что-то пишу в "<>", то это значит, что содержимое надо заменить на свое значение.
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

HellRoom Games © 2006-2012 All Rights Reserved
Powered by SMF 1.1.21 | SMF © 2013, Simple Machines
Страница сгенерирована за 0.093 секунд. Запросов: 28.