Есть ли способ генерировать случайные числа с дискретным приращением с помощью math.random () в lua?

Я пытаюсь проверить игровую механику, написав код lua в среде разработки игр LÖVE. Я хочу, чтобы вражеские юниты появлялись на одной из пяти полос и перемещались по экрану. На данный момент я могу генерировать указанные юниты и ограничивать их границами «полос». Однако я не уверен, как заставить их появляться явно на одной из пяти дорожек.

Прямо сейчас я использую math.random (), чтобы выбрать число между верхней и нижней границами полос. Размер спрайтов вражеских юнитов составляет 32x32, поэтому пять отдельных полос будут покрывать в общей сложности 160 пикселей экрана. Прямо сейчас у меня установлены границы 240 и 400 (середина высоты экрана). Как мне сгенерировать случайное число с шагом 32, чтобы враги появлялись на одной из пяти возможных полос?

РЕДАКТИРОВАТЬ: Итак, кажется, что границы на самом деле не установлены на середину. Буду пытаться вычислить координаты на нем, но если кто-то может дать мне чаевые, я буду счастлив! : D

Мой текущий рабочий код выглядит следующим образом:

-- Axis-based collision detection. Effective for rectangular units; does not work well with circles and non-quad shapes.

function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
  return x1 < x2+w2 and
         x2 < x1+w1 and
         y1 < y2+h2 and
         y2 < y1+h1
end

debug = true


-- Timers declared here to reference later.
createEnemyTimerMax = 0.4
createEnemyTimer = createEnemyTimerMax

-- Delcares images; will actually be established in love.load and brought out in love.draw
enemyImg = nil

enemies = {}

function love.load(arg)
    enemyImg = love.graphics.newImage('assets/cat.png')
end


function love.update(dt)
    if love.keyboard.isDown('escape') then
        love.event.push('quit')
    end

    --Generates enemies.
    --Create 5 if/then conditions to account for each lane? 
    --Conditions dependent on createEnemyTimer being < 0 and # of enemies in lane < 5
    --First condition is met; how do we create the second?
    --Will each lane need its own timer?
    createEnemyTimer = createEnemyTimer - (.5 * dt)
    if createEnemyTimer < 0 then
        createEnemyTimer = createEnemyTimerMax

        -- Create an enemy
        randomNumber = math.random(240,400)
        newEnemy = { y = randomNumber, x = 650, img = enemyImg }
        table.insert(enemies, newEnemy)
    end

    --Updates position of enemies.
    for i, enemy in ipairs(enemies) do
        enemy.x = enemy.x - (200 * dt)

        if enemy.x < 0 then -- remove enemies when they pass off the screen
            table.remove(enemies, i)
        end
    end

    -- Collision detection.
    -- For MSJ, collision should prevent PC from moving onto enemy's square.

    --[[

    for i, enemy in ipairs(enemies) do
        for j, bullet in ipairs(bullets) do
            if CheckCollision(enemy.x, enemy.y, enemy.img:getWidth(), enemy.img:getHeight(), bullet.x, bullet.y, bullet.img:getWidth(), bullet.img:getHeight()) then
                table.remove(bullets, j)
                table.remove(enemies, i)
                score = score + 1
            end
        end

        if CheckCollision(enemy.x, enemy.y, enemy.img:getWidth(), enemy.img:getHeight(), player.x, player.y, player.img:getWidth(), player.img:getHeight())
        and isAlive then
            table.remove(enemies, i)
            isAlive = false
        end
    end

    ]]

end

function love.draw(dt)
    for i, enemy in ipairs(enemies) do
        love.graphics.draw(enemy.img, enemy.x, enemy.y)
    end
end

person Kyle Rogacion    schedule 20.06.2017    source источник


Ответы (1)


Я думаю, вам следует изменить подход к созданию пяти врагов, каждого на линии. Как насчет генерации 5 случайных чисел, которые отмечают относительное положение каждой полосы? Затем вы добавляете это относительное положение к началу каждой полосы. Например:

local enemies = {}
local origin_y, height = 240, 32
for i=1,5 do
   local relative_y = math.random(32)
   local y = origin_y + height * i  + relative_y
   table.insert(enemies, { x = math.random(), y = y})
end
person Diego Pino    schedule 20.06.2017
comment
Спасибо за ответ! Я все еще новичок в lua, не говоря уже о программировании, поэтому у меня есть несколько вопросов по вашему предложению, если вы не против помочь мне их разобраться. Для меня это процесс обучения! 1) Какова цель определения нескольких из этих переменных как локальных? Другие функции, вызывающие таблицу врагов, имеют дело только с их движением и изображениями. 2) Насколько я понимаю, во второй строке вы устанавливаете origin_y в качестве базовой координаты, но что вы определяете с помощью height = 240, 32? (продолжение во втором комментарии) - person Kyle Rogacion; 20.06.2017
comment
3) Когда вы определяете локальный y, что явно вычисляется? / 4) Почему в функции table.insert в конце кода для x установлено значение math.random ()? Есть ли для этого конкретная причина? Изначально я установил значение 650, чтобы враги генерировались за кадром. / 5) Также в функции table.insert, почему вы добавляете {x = math.random (), y = y} в конец массива? В исходном коде, который я опубликовал, table.insert () поместил переменную newEnemy в таблицу врагов, которая также установила файл изображения, используемый для врага. Это просто пропустили в вашем примере? - person Kyle Rogacion; 20.06.2017
comment
Ключевое слово @KyleRogacion local связывает переменную с областью действия блока, например let в Javascript, или определяет переменные в языках со строгой типизацией, таких как C или Java. Отсутствие локализации переменных делает переменную глобальной (переменные привязаны к глобальной области видимости (есть предопределенная таблица с именем _G, которая содержит все глобальные переменные). Что касается 2) Lua допускает множественное присвоение переменных. В этой строке origin_y равно 240, а высота - 32. 3) Каждая полоса имеет высоту 32, если базовая линия начинается с 240, базовые линии всех полос будут 240, 272, 304, 336, 369. - person Diego Pino; 20.06.2017
comment
@KyleRogacion Хорошо, я понимаю, что сделал там ошибку, высота должна быть 40, а базовые значения для всех полос должны быть 240, 280, 320, 360 и 400. На самом деле под высотой я имел в виду ширину полосы, так что, возможно, ширина лучше переменная название. Таким образом, y для каждой полосы является случайным значением между базовой линией полосы и максимальным значением (relative_y должно быть случайным значением от 0 до 40). 5) Верно, это было упрощение, я пропустил ваш код. - person Diego Pino; 20.06.2017
comment
Привет, извините за поздний ответ, но я хотел бы поблагодарить вас за ваш ответ. Я нашел способ добиться того, чтобы то, что я хочу, работало. Ваш обстоятельный ответ очень помог мне сориентироваться. - person Kyle Rogacion; 24.06.2017
comment
@KyleRogacion Иногда поиск решения проблемы - это не прямой ответ, а мыслительный процесс. В этом отношении я рад услышать, что мой ответ был в некотором роде полезен :) - person Diego Pino; 24.06.2017