Проект LitDev #1 "Шарик в мире условностей"

Задача

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

Видео с готовым результатом


Вспомогательные материалы

Вам понадобятся изображения. Скачайте их и загрузите в папку res вашей программы.
ball.png

danger.png

finish.png

grass.png

sky.png

stone.png


Ход работы

1. Создание игрока

1.1. Создадим шаблон игрового проекта
Sub setup
  width = 800
  height = 600
  dir = Program.Directory

  GraphicsWindow.Width = width
  GraphicsWindow.Height = height
  LDPhysics.SetBoundaries(0,width,0,height)
EndSub

setup()
While "True"
  moveBall()
  checkCollision()
  LDPhysics.DoTimestep()
  Program.Delay(20)
EndWhile

1.2. Добавим подпрограмму-конструктор игрока-мячика.
Sub createBall
  ballImg = dir + "/res/ball.png"
  ball = Shapes.AddImage(ballImg)
  LDPhysics.AddMovingShape(ball,1,0,1)
  LDPhysics.SetPosition(ball,25,25,0)
  LDPhysics.SetShapeGravity(ball,0,200)
  mass = LDPhysics.GetMass(ball)
EndSub
Не забудьте вызвать эту подпрограмму в setup()

2. Управление игроком, придание ему импульса.

2.1. Добавим обработчики нажатия на клавиши:
' ================ EVENT LISTENERS ==============
GraphicsWindow.KeyDown = onKeyDown
GraphicsWindow.KeyUp = onKeyUp

Sub onKeyDown
  k = GraphicsWindow.LastKey
  If (k = "Left") Then
    left = 1
  ElseIf (k = "Right") Then
    right = 1
  ElseIf (k = "Up") Then
    up = 1
  ElseIf (k = "Down") Then
    down = 1
  EndIf
EndSub

Sub onKeyUp
  k = GraphicsWindow.LastKey
  If (k = "Left") Then
    left = 0
  ElseIf (k = "Right") Then
    right = 0
  ElseIf (k = "Up") Then
    up = 0
  ElseIf (k = "Down") Then
    down = 0
  EndIf
EndSub

2.2. Напишем подпрограмму для движения мячика
Sub moveBall
  If (left = 1) Then
    LDPhysics.SetImpulse(ball,-4*mass,0)
  EndIf
  If (right = 1) Then
    LDPhysics.SetImpulse(ball,4*mass,0)
  EndIf
  If (up = 1) Then
    LDPhysics.SetImpulse(ball,0,-8*mass)
  EndIf
EndSub
Не забудьте вызывать её из игрового цикла

3. Создание игрового поля.

3.1. Это самая сложная часть этого проекта. Идея в том, что вместо загрузки целого изображения, мы грузим тайлы – детальки. И из тайлов собираем готовый мир.
Добавим подпрограмму для создания игрового поля:
Sub createWorld
  
EndSub

3.2. Загрузим изображения и напишем массив текстового кода для уровня. Предварительно такой уровень можно нарисовать на листике в клеточку:

Sub createWorld
  rockImg = dir + "/res/stone.png"
  dangerImg = dir + "/res/danger.png"
  grassImg = dir + "/res/grass.png"
  skyImg = dir + "/res/sky.png"
  finishImg = dir + "/res/finish.png"
  
  ' s - sky, g - grass, d - danger, r - rock, f - finish
  world[1]  = "sgssssgggddsgddf"
  world[2]  = "srssssrrrsssrsss"
  world[3]  = "srssssrrrsssrsss"
  world[4]  = "srsdssrrrsrsrdsd"
  world[5]  = "srsrssdddsrsrsss"
  world[6]  = "srsrssssssrsrdss"
  world[7]  = "srsrssssssrsrssd"
  world[8]  = "srsrssdddsrsrsss"
  world[9]  = "sssdssgggsrsrdss"
  world[10] = "ssssssrrrsrsssss"
  world[11] = "sgsdssrrdsrsssss"
  world[12] = "drsrssssssddddsd"
  
EndSub

3.3. Теперь для того, чтобы отрисовать уровень по массиву с текстовыми данными, нужно пробежаться циклом по каждому символу и в зависимости от того, какой там символ, нужно выставить тот или иной тайл.
  world[12] = "drsrssssssddddsd"

  For j=1 To 12
    For i=1 To 16
      tileCode = Text.GetSubText(world[j],i,1)
      If tileCode = "s" Then
        tile = Shapes.AddImage(skyImg)
        Shapes.Move(tile,(i-1)*50,(j-1)*50)
      ElseIf tileCode = "g" Then
        tile = Shapes.AddImage(grassImg)
        Shapes.Move(tile,(i-1)*50,(j-1)*50)
        LDPhysics.AddFixedShape(tile,0,0)
      ElseIf tileCode = "d" Then
        tile = Shapes.AddImage(dangerImg)
        Shapes.Move(tile,(i-1)*50,(j-1)*50)
        LDPhysics.AddFixedShape(tile,0,0)
      ElseIf tileCode = "r" Then
        tile = Shapes.AddImage(rockImg)
        Shapes.Move(tile,(i-1)*50,(j-1)*50)
        LDPhysics.AddFixedShape(tile,0,0)
      ElseIf tileCode = "f" Then
        tile = Shapes.AddImage(finishImg)
        Shapes.Move(tile,(i-1)*50,(j-1)*50)
      EndIf
    EndFor
  EndFor

4. Программирование столкновений. 
4.1. Библиотека Litdev имеет метод для получения массива всех объектов, столкнувшихся с данным. Добавим подпрограмму проверки коллизий и будем вызывать её из игрового цикла.
Sub checkCollision
  collisions = LDPhysics.GetCollisions(ball)

  ' Посмотрим, что выдаётся в collisions при помощи отладочного кода:
  TextWindow.WriteLine(collisions) 
EndSub

Запустите программу и посмотрите, что выводятся имена шейпов, с которыми сталкивается мяч. 

4.2. Будем добавлять все "опасные" шейпы в массив опасных шейпов. Изменим немного подпрограмму создания мира.
world[12] = "drsrssssssddddsd"
  
  dangerIndex = 1
  For j=1 To 12
  ...

      ElseIf tileCode = "d" Then
        tile = Shapes.AddImage(dangerImg)
        Shapes.Move(tile,(i-1)*50,(j-1)*50)
        LDPhysics.AddFixedShape(tile,0,0)
        dangerTiles[dangerIndex] = tile
        dangerIndex = dangerIndex + 1

4.3. Итоговая подпрограмма будет выглядеть так:
Sub checkCollision
  collisions = LDPhysics.GetCollisions(ball)
  For i=1 To Array.GetItemCount(dangerTiles)
    If Array.ContainsValue(collisions,dangerTiles[i]) Then
      LDPhysics.SetPosition(ball,25,25,0)
    EndIf
  EndFor
EndSub

Запустите проект, проверьте, что всё правильно работает.

Задания

Задание 1*. Добавьте обработку касания мячика к финишному тайлу.

Задание 2**. Добавьте таймер, который показывает время прохождения игры.

Задание 3*****. Создайте свой второй уровень, который будет загружаться после касания к финишному тайлу.

Комментарии