Бонусы
Ладно, худо-бедно, уровень нарисован , но какой-то он однообразный, давайте что-ли добавим сюда еще парочку элементов. Ну какая игра, скажите мне, будет без бонусов? Всевозможных монеток, кристаллов, и т. д. Предлагаю поместить их и на нашем уровне. Для этого напишем еще один тип TBonus
Type TBonus
Field x:Int Field y:Int Field width:Int Field height:Int
Field points:Int Field miny:Int Field maxy:Int Field diry:Int Field speed:Int Field AnimDelay:Int End type
Вообще-то (у меня) и бонус тоже будет прямоугольником, только желтого цвета (при хорошем воображении можно представить, что это слиток золота). Он меньше, чем тайл, естественно. Его размеры будут: 16х6. И помните - бонус должен находиться только в проходимом тайле, а иначе как его возьмет игрок? Посмотрите повнимательнее на свойства (переменные) нашего нового типа. Первые 4 понятны и так. А про остальные надо рассказать отдельно:
- points - это очки, которые получит игрок при подборе(?) этого бонуса,
-
miny и maxy - наш бонус не просто будет висеть в воздухе, а будет раскачиваться вверх-вниз, т.е . двигаться по оси Y, как это часто бывает в играх. Так вот эти переменные указывают амплитуду раскачивания, смотрите рисунок:
- Diry - это направление движения при раскачивании бонуса <-1> означает, что бонус движется вверх, а <+1> - соответственно, вниз. (При Diry = 0 бонус двигаться не будет.)
- Speed - скорость, с которой двигается бонус, то есть на сколько пикселей вверх/вниз он переместится.
- AnimDelay - это задержка, с которой раскачивается бонус. Регулируя эту переменную, можно регулировать скорость раскачивания.
Да, кстати , не забудем создать список для хранения наших бонусов:
Global BonusList:TList = CreateList() ' вот так
Теперь перейдем непосредственно к функции Create для типа TBonus. Эта функция будет создавать бонус на указанном тайле, и заполнит все поля типа(которые я тока что описал) нужной информацией, надо только указать координаты на тайловой карте и очки за этот бонус:
Function Create(sx:Int,sy:Int,pts:Int)
Local TB : TBonus = New TBonus TB.Width = 6 TB.Height = 16 TB.x = sx * TILESIZE + ((TILESIZE - TB.width) / 2) TB.y = sy * TILESIZE + ((TILESIZE - TB.height) / 2) TB.points = pts TB.miny = TB.y - 4 TB.maxy = TB.y + TB.Height + 4 TB.speed = 1 TB.diry = -1 TB.AnimDelay = 5 ListAddLast(BonusList ,TB) End Function
Вот картинка, которая поможет вам в понимании вышеизложенной функции:
Из кода и приведенной картинки все становится очевидным и доходчивым, переводим тайловые координаты в экранные, помещаем бонус в центре тайла и раскачиваем его на 4 пикселя вверх и 4 пикселя вниз, скорость (speed) = 1, начальное направление вверх (diry = -1). Да, чуть не забыл, при достижении бонусом miny или maxy, мы должны поменять направление раскачивания, учтем это при написании нашего кода. А вот и он:
Method Update()
If(Animdelay < 0)
If ( miny > (y) Or maxy < (y + height - 1) ) diry = -diry End If
y = y + speed * diry
AnimDelay = 5 End If
AnimDelay :- 1
End Method
Method Draw() SetColor(255 , 255 , 0) DrawRect(x,y,Width,Height) End Method
В методе ничего примечательного нет. Там устанавливается желтый цвет и рисуется прямоугольник, то есть наш воображаемый бонус. А метод рассмотрим поподробнее. Здесь как раз и будет происходить раскачивание бонуса , а точнее в строке
y = y + speed * diry
новое положение по оси <у> вычисляется как прибавление к старому значению и скорости (speed) домноженной на направление (diry), как я говорил раньше, diry может принимать только 2 значения - <-1> и <+1>, а потому произведение дает разные ПО ЗНАКУ значения speed, что в свою очередь влияет на то, будет ли скорость вычитаться или прибавляться к текущей координате. Например: текущая позиция по y = 5, направление - вверх , то есть diry = -1 и скорость (speed) =1, тогда новое значение у:
y = 5 + 1 * (-1) = 5 - 1 = 4
если diry = +1 ,то есть направление вниз:
y = 5 + 1 * 1 = 5 + 1 = 6
вот так diry влияет на вычисление новой позиции нашего бонуса. Нет, мы ,конечно, могли бы сделать и так: если двигаемся вверх, то вычитать скорость, а если вниз ,то прибавлять.
If diry = 1
y = y + speed else if diry = -1 y = y - speed
end if
Но этот способ мне кажется более громоздким, по сравнению с изяществом первого. Впрочем, вы можете использовать любой. Теперь надо ограничить наши движения maxy и miny. Первое что приходит в голову это сделать так:
If (y =< miny) ' если достигли верха
diry = 1 ' направить вниз end if
if (y + height >= maxy) ' если достигли низа diry = -1 ' направить вверх end if
Но я сделаю чуть иначе:
If ( miny >= (y) Or maxy =< (y + height) )
diry = -diry End If
Строка diry = -diry означает изменить знак diry, то есть если diry был -1, то -(-1) = +1, а если diry = +1 ,то -(+1) = -1. Говоря по-другому ,что важно для нас - эта строка, меняет направление движения на противоположное.
Я привел оба эти варианта для того ,чтобы показать, что одну задачу можно решить двумя разными способами, тремя и даже больше. Так что не бывает правильного и не правильного кода, хорошего или плохого. Бывает код ,который работает, то есть выполняет свою прямую задачу, и код ,который не работает! Главное ,чтобы вы сами понимали, то что пишете. А уж потом, когда заматереете в программинге, можно модернизировать и оптимизировать свой код.
Вот в общем-то и всё. А нет, не всё! У нас ведь еще введена задержка анимации (AnimDelay). Не каждый вызов метода Update() приводит к перемещению нашего бонуса, а лишь тот, когда AnimDelay < 0 . Ну а если больше нуля, то от задержки отнимается единица, через пять циклов условие соблюдается и движение бонуса происходит. Нехитрый способ задержки, думаю вы его переделаете со временем. Итак, у нас есть функция создания бонусов (Create), метод качания (Update) и метод рисования (Draw). Так чего же мы ждем? Давайте разместим наши бонусы на карте и нарисуем их!
Для инициализации их на карте я создал отдельную функцию:
Function Init_All_Bonuses ()
TBonus.Create(15 , 1 , 100) Tbonus.Create(7 , 4 , 100) Tbonus.Create(1 , 1 , 25) Tbonus.Create(3 , 8 , 25) Tbonus.Create(4 , 8 , 25) Tbonus.Create(5 , 8 , 25) Tbonus.Create(9 , 7 , 10) Tbonus.Create(4 , 6 , 10) Tbonus.Create(9 , 2 , 10) Tbonus.Create(14 , 7 , 10) Tbonus.Create(17 , 6 , 10) Tbonus.Create(17 , 4 , 10) Tbonus.Create(18 , 4 , 10) Tbonus.Create(3 , 3 , 10)
End Function
Здесь 14 бонусов, 2 по 100 очков, 4 по 25 и остальные по 10 очков. Ну теперь осталось отобразить их все на экране. Вы тоже можете создать для этого отдельную функцию, ну а я решил впихнуть всё это в Tlevel.Render(), сразу после рисования тайлов:
For Local CurBonus:Tbonus= EachIn BonusList
CurBonus.Update() CurBonus.Draw() Next
Запускаем и любуемся. Если не получилось, смотрите исходник:
SuperStrict
Global ScrWidth : Int = 640 Global ScrHeight : Int = 480
Global TileList:TList = CreateList() Global BonusList:TList = CreateList()
Const TILESIZE:Int = 32
Type TTile Field x:Int Field y:Int
Field xTBle:Int Field yTBle:Int Field Width:Byte Field Height:Byte
Field Walkable:Byte Function Create(sx:Int, sy:Int, WB:Byte) Local TT:TTile = New TTile TT.width = TiLESIZE TT.height = TiLESIZE TT.xTBle = sx TT.yTBle = sy TT.x = TT.xTBle * TT.width TT.y = TT.yTBle * TT.height TT.Walkable = WB
ListAddLast(TileList , TT) End Function
Method update() If walkable 'walkable SetColor(255 , 0 , 0) 'red Else 'NOT walkable SetColor(0 , 255 , 0) 'green End If End Method
Method Draw() DrawRect(x,y,Width,Height) End Method
End Type
Type TLevel Field Width : Byte Field Height : Byte
Field Map:Int[,] Function Create:TLevel(MyMap:Int[],map_width:Int,map_height:Int) Local TM : TLevel = New TLevel TM.Width = map_width TM.Height = map_height
TM.map = New Int [TM.Width, TM.Height] TM.load(myMap) Return TM End Function Method Load(arrMap:Int[]) For Local i:Int = 0 Until Height For Local j:Int = 0 Until Width Map[j , i] = arrMap[j + (i * Width)] If Map[j , i] TTile.Create(j , i , True) Else TTile.Create(j , i , False) End If Next Next End Method
Method Render() For Local CurTile:TTile = EachIn TileList CurTile.Update() CurTile.Draw() Next For Local CurBonus:TBonus= EachIn BonusList CurBonus.Update() CurBonus.Draw() Next End Method End Type
Type TBonus Field x:Int Field y:Int Field width:Int Field height:Int Field points:Int Field miny:Int Field maxy:Int Field diry:Int Field speed:Int Field AnimDelay:Int Function Create(sx:Int,sy:Int,pts:Int) Local TB : TBonus = New TBonus TB.Width = 6 TB.Height = 16 TB.x = sx * TiLESIZE + ((TiLESIZE - TB.width) / 2) 'center it TB.y = sy * TiLESIZE + ((TiLESIZE - TB.height) / 2) 'center it TB.points = pts TB.miny = TB.y - 4 TB.maxy = TB.y + TB.Height + 4 TB.diry = -1 TB.speed = 1 TB.AnimDelay = 5 ListAddLast(BonusList ,TB) End Function Method Update() If(Animdelay < 0)
If ( miny > (y) Or maxy < (y + height - 1) ) diry = -diry End If y = y + speed * diry AnimDelay = 5
End If AnimDelay :- 1 End Method Method Draw() SetColor(255 , 255 , 0) DrawRect(x,y,Width,Height) End Method End Type
Global LevMap:Int[]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,.. 1,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,.. 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,.. 1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,.. 1,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,.. 1,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,.. 1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,.. 1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,.. 1,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,.. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
Global MyLevel : TLevel = New TLevel.Create(LevMap , 20 , 10)
Function Init_All_Bonuses() TBonus.Create(1 , 1 , 25) TBonus.Create(3 , 8 , 25) TBonus.Create(4 , 8 , 25) TBonus.Create(5 , 8 , 25) TBonus.Create(15 , 1 , 100) TBonus.Create(7 , 4 , 100) TBonus.Create(9 , 7 , 10) TBonus.Create(4 , 6 , 10) TBonus.Create(9 , 2 , 10) TBonus.Create(14 , 7 , 10) TBonus.Create(17 , 6 , 10) TBonus.Create(17 , 4 , 10) TBonus.Create(18 , 4 , 10) TBonus.Create(3 , 3 , 10) End Function
'----------------------------- main loop ----------------------------- Graphics(ScrWidth, ScrHeight)
Init_All_Bonuses()
Repeat Cls
MyLevel.Render() Flip Until KeyDown(KEY_ESCAPE) Or AppTerminate()
End
|