Статьи

Создание простой игры в баскетбол с помощью Corona Game Edition

Физический движок, который поставляется с Corona Game Edition, является невероятно мощным и простым в использовании инструментом. В этом уроке мы расскажем о завершении элементарной игры в баскетбол с использованием этой захватывающей технологии.

1
2
3
4
5
6
7
display.setStatusBar(display.HiddenStatusBar)
 
local physics = require «physics»
physics.start()
physics.setGravity(9.81, 0) — 9.81 m/s*s in the positive x direction
physics.setScale(80) — 80 pixels per meter
physics.setDrawMode(«normal»)

Первое, что мы делаем (как и во многих программах), это избавляемся от строки состояния в верхней части экрана. Далее, мы делаем необходимое требование для использования физики и сохраняем результат в метко названной переменной «физика». Вещи становятся более интересными в следующих нескольких строках. В пятой строке мы устанавливаем гравитационное ускорение. Как правило, сила тяжести устанавливается в 9,8 м / с * с в положительном направлении Y, но в этом случае мы хотим, чтобы сила тяжести притягивалась в положительном направлении X, потому что приложение будет иметь альбомную ориентацию. Кроме того, мы устанавливаем масштаб до 80 пикселей на метр. Это число может немного отличаться в зависимости от размера объектов в вашем приложении, и вам, возможно, придется поиграть с ним, чтобы придать игре правильное ощущение. Я выбрал 80 пикселей / м, потому что хочу разместить на экране около 15 футов вертикального пространства. Зная это, это просто вопрос преобразования единиц, чтобы получить значение.

Примечание: важно попытаться связать все с объектами реального мира в приложениях с физикой. Чем больше реальных измерений вы используете, тем меньше будет догадок и тем более реалистичным будет ваше приложение.

Мы закруглим эти несколько линий, установив режим рисования в нормальный режим. Эта строка облегчает переход в режим отладки позже, если нам нужно исправить непреднамеренное поведение при столкновениях. Установка этого значения в нормальное является поведением по умолчанию и рисует фигуры так, как их увидит пользователь в финальной игре.


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
local background = display.newImage(«CourtBackground.png»)
local score = display.newText(«Score: 0», 50, 300)
score:setTextColor(0, 0, 0)
score.rotation = -90
score.size = 36
local floor = display.newRect(320, 0, 1, 480)
local lWall = display.newRect(0, 480, 320, 1)
local rWall = display.newRect(0, -1, 320, 1)
local ceiling = display.newRect(-1, 0, 1, 480)
 
staticMaterial = {density=2, friction=.3, bounce=.4}
physics.addBody(floor, «static», staticMaterial)
physics.addBody(lWall, «static», staticMaterial)
physics.addBody(rWall, «static», staticMaterial)
physics.addBody(ceiling, «static», staticMaterial)

Этот блок устанавливает границы арены и свойства всех статических объектов в приложении. Мы начинаем с добавления простого изображения к фону. Внутри белого прямоугольника на фоновом изображении мы размещаем некоторый текст, чтобы отобразить текущий счет. Поскольку приложение будет отображаться в ландшафтном режиме, мы также вносим необходимые корректировки вращения здесь. Арена должна поймать мяч в пределах видимой части экрана. Мы достигаем этого с помощью четырех статических прямоугольников (пол, lWall, rWall, потолок), размещенных просто вне поля зрения.

Далее мы возвращаем физику в уравнение. Вместо того, чтобы перепечатывать таблицу для физических свойств каждого объекта, мы создаем имя таблицы staticMaterial для повторного использования для каждой из стен и самой цели. Я выбрал довольно стандартные значения для этих свойств, хотя я призываю вас поиграть с ними. Еще один шаг, который мы должны сделать, это сказать Corona, что эти объекты должны участвовать в физических расчетах. Мы делаем это, вызывая функцию addBody объекта физики. Эта функция принимает три аргумента:

  1. Объект
  2. Дополнительный модификатор
  3. Таблица физических свойств

Мы уже определили свойства и объекты, поэтому остается только дополнительный модификатор. Мы используем «статический» для предотвращения смещения наших стен гравитацией или любой силой в этом отношении!


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
— Create the goal
local vertPost = display.newRect(110, 5, 210, 10)
vertPost:setFillColor(33, 33, 33)
local horizPost = display.newRect(110, 10, 10, 40)
horizPost:setFillColor(33, 33, 33)
local backboard = display.newRect(55, 50, 85, 5)
backboard:setFillColor(33, 33, 33)
 
physics.addBody(vertPost, «static», staticMaterial)
physics.addBody(horizPost, «static», staticMaterial)
physics.addBody(backboard, «static», staticMaterial)
 
—Create the Ball
local ball = display.newCircle(50, 200, 10)
ball:setFillColor(192, 99, 55)
 
physics.addBody(ball, {density=.8, friction=.3, bounce=.6, radius=10})

Одним махом мы создаем остальные визуальные элементы нашего приложения. Все это должно выглядеть очень знакомым. Есть только две вещи, на которые я хотел бы указать. Во-первых, некоторые значения для позиционирования цели могут показаться неправильными. Это для учета ландшафтной ориентации. Цель появится в вертикальном положении, когда устройство повернуто на бок. Кроме того, обязательно включите свойство radius в таблицу свойств шара, чтобы он вел себя правильно.


1
local function drag( event ) local ball = event.target local phase = event.phase if «began» == phase then display.getCurrentStage():setFocus( ball ) — Store initial position ball.x0 = event.x — ball.x ball.y0 = event.y — ball.y — Avoid gravitational forces event.target.bodyType = «kinematic» — Stop current motion, if any event.target:setLinearVelocity( 0, 0 ) event.target.angularVelocity = 0 else if «moved» == phase then ball.x = event.x — ball.x0 ball.y = event.y — ball.y0 elseif «ended» == phase or «cancelled» == phase then display.getCurrentStage():setFocus( nil ) event.target.bodyType = «dynamic» end end return true end ball:addEventListener(«touch», drag)

Эта функция дает нам очень простую поддержку перетаскивания. Некоторые из главных моментов включают установку кинематического bodyType шара, чтобы сила тяжести не вытащила шар из рук пользователя ( Примечание: обязательно установите его обратно в динамический после завершения касания ). Линии сразу после этого одинаково важны. Там мы останавливаем все движения шара при касании, чтобы избежать той же проблемы, что у нас была с гравитацией.

Если вы запустите приложение таким, какое оно есть сейчас, вы, вероятно, заметите, что мяч теряет весь свой импульс, как только вы перестаете его касаться. Чтобы исправить это, нам нужно создать функцию для отслеживания скорости мяча, а затем соответствующим образом установить скорость мяча после окончания касания.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
local speedX = 0
local speedY = 0
local prevTime = 0
local prevX = 0
local prevY = 0
 
function trackVelocity(event)
    local timePassed = event.time — prevTime
    prevTime = prevTime + timePassed
     
    speedX = (ball.x — prevX)/(timePassed/1000)
    speedY = (ball.y — prevY)/(timePassed/1000)
 
    prevX = ball.x
    prevY = ball.y
end
 
Runtime:addEventListener(«enterFrame», trackVelocity)

Мы создаем trackVelocity в качестве прослушивателя события enterFrame, поэтому оно вызывается каждый раз при перерисовке экрана. Что он делает, так это находит изменение в скорости во времени, чтобы найти скорость шара в пикселях в секунду. Там на самом деле не так много. Добавьте следующую строку в функцию перетаскивания, чтобы правильно установить линейную скорость мяча.

1
ball:setLinearVelocity(speedX, speedY)

Мы начнем с некоторой визуальной работы, но теперь вы должны быть профессионалом в прямоугольниках, поэтому это должно быть безболезненно. Следующий код создает обод. Обратите внимание, что средняя часть обода не будет частью физической системы, потому что мы хотим, чтобы мяч проходил свободно.

1
2
3
4
5
6
7
8
9
local rimBack = display.newRect(110, 55, 5, 7)
rimBack:setFillColor(207, 67, 4)
local rimFront = display.newRect(110, 92, 5, 3)
rimFront:setFillColor(207, 67, 4)
local rimMiddle = display.newRect(110, 62, 5, 30)
rimMiddle:setFillColor(207, 67, 4)
 
physics.addBody(rimBack, «static», staticMaterial)
physics.addBody(rimFront, «static», staticMaterial)

Далее нам нужен способ узнать, когда мяч прошел через ворота. Самый простой способ сделать это, обозначив небольшой участок экрана рядом с ободком как «зону очков». Всякий раз, когда мяч находится в этой зоне, мы можем увеличивать счет. Чтобы избежать неправильного подсчета очков, когда мяч задерживается вокруг обода, мы отслеживаем время последнего гола и обеспечиваем достаточное расстояние между каждым последующим голом. Задержка в одну секунду должна работать хорошо.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
scoreCtr = 0
local lastGoalTime = 1000
 
function monitorScore(event)
    if event.time — lastGoalTime > 1000 then
        if ball.x > 103 and ball.x < 117 and ball.y > 62 and ball.y < 92 then
            scoreCtr = scoreCtr + 1
            print(score)
            lastGoalTime = event.time
            score.text = «Score: » .. scoreCtr
        end
    end
end
Runtime:addEventListener(«enterFrame», monitorScore)

Несмотря на то, что это приложение могло быть создано со стандартной версией Corona SDK, было бы очень много усилий, чтобы отслеживать коллизии, трение, гравитацию и т. Д. Corona Game Edition решает более сложные физические задачи, оставляя у вас больше времени сосредоточиться на содержании и игровом процессе вашей игры.