Понедельник, 06.05.2024, 02:09
Personal dimanche13 site
Главная | Регистрация | Вход Приветствую Вас Гость | RSS
Категории каталога
Мои статьи [22]
BlitzMax [17]
раздел содержит статьи относящиеся к языку программирования BlitzMax
SDL [9]
раздел содержит статьи на тему SDL
Code::Blocks [3]
в этом разделе рассказывается как прикрутить движок к интегрированной среде разработки(IDE) Code::Blocks
Форма входа
Поиск
Друзья сайта
Главная » Статьи » BlitzMax

Тайловая игра на BlitzMax, часть 1(4)

Один список

Блин, что-то мне не нравится. И не нравится вот что. При добавлении нового типа в игру. Надо не только его описать, но и создать список для хранения объектов этого типа. А потом еще крутить вертеть все эти списки по очереди, чтобы всё проапдейтить и нарисовать. Вот было бы здорово иметь ОДИН список, для объектов всех типов. А? Потом просто разок пройтись по этому списку в цикле и всё, красотаааа. И в BlitzMaxе есть такая возможность! Нам поможет механизм наследования. Так, что это вы сразу отворачиваетесь и краснеете? Кто не вкурил руководство от Wave, кто думал что обойдется без этого? Кто у нас слабое звено? Ладно, попытаюсь объяснить. Но начнем по порядку. Стираем на фиг, все списки для хранения тайлов, бонусов и платформ. И создаем один :

Global ALLGameObjList : TList = CreateList()

Вот так, гордо и пафосно, я назвал новый список, в котором будут содержаться все объекты. Соответственно в каждой функции создания нового объекта Create() надо добавлять созданный объект уже в этот список.

ListAddLast(ALLGameObjList , Tobj)

Сделали? Теперь все объекты будут в одном списке! А в циклах отрисовки бонусов и платформ, замените прошлые листы на наш супер-мега-пупер-лист. Для бонуса, это будет например так:

  For Local CurBonus:TBonus = EachIn ALLGameObjList
    CurBonus.Update()
    CurBonus.Draw()
  Next

Компилим: клево работает!!! Блин, а чего мы выиграли-то? 2 строчки кода (((. Хоть и список у нас теперь один, а так и осталось - для каждого типа свой цикл. Думаем дальше: Вот если бы все объекты были одного типа, то было бы достаточно прокрутить с ним список один раз. То есть сделать один единственный цикл! И нам в этом поможет наследство. Плотнее товарищи, не вижу улыбок на лицах. Наследование - это один из важнейших принципов ООП. И кстати самый благозвучный, остальные без пол-литра не выговоришь. Давайте посмотрим по внимательнее на наши типы, а точнее на их свойства (Field). У них всех есть одинаковые параметры: x, y, width, height. Предлагаю сделать еще один тип - базовый или ,если угодно, родительский. Куда мы их и вынесем :

Type TParent
  Field x:int
  Field y:int
  Field width:int
  Field height:int
End type

А для чего я это сделал? Представьте, как было бы здорово не писать каждый раз эти одинаковые параметры в новый тип. А взять их из отдельного места. Из другого типа. Или другими словами <унаследовать> их. Я не зря назвал тип <TParent>, то есть <родитель>. Ведь типы, которые от него наследуют параметры, будут его детьми. Это как одна дружная семья типов. И как это сделать, да очень просто. Вот, к примеру, как ваше имя - отчество? Ну, к примеру, зовут вас Иван Сергеевич. Это значит что ваше имя - Ваня, а имя вашего отца (родителя) - Сергей. Вы не поверите, но в Блице это ни чуть не сложнее чем в жизни:

Type MyName Extends FatherName        'Type Иван Extends Сергеевич

То есть пишется сначала имя наследника и через Extends имя родителя. И это означает, что вы, то есть ваш тип, теперь обладает теми же параметрами, что и родитель. Тут надо заметить, что параметры имеют только одинаковые названия, но данные в разных типах не одинаковы. Как говорят в Одессе, это две большие разницы. Ну, теория теорией, а я предпочитаю практику. Закомментируем во всех наших типах поля <x>, <y>, <width> и <height>. И давайте первым делом <усыновим> тип TTile, как вы уже догадались, это будет выглядеть так:

Type TTile Extends TParent

На примере этого типа <усыновите> и остальные(TBonus и TMovingX). Компильте скорее! Все идет. А для чего мы все это делали? Нет, конечно, хорошо, что мы вынесли общие для наших типов параметры в отдельный тип. Но не это самое главное, а то, что теперь все наши типы имеют одного предка, то есть это <дети> одного отца. И имя ему - <TParent>. Ну что, уловили полет мысли? Ага, мы будем крутить цикл с базовым типом, вот так:

  For Local CurObj:TBase = EachIn ALLGameObjList
    CurObj.Update()
    CurObj.Draw()
  Next

А уж он будет обращаться, ко всем своим родственникам в нашем супер-пупер-мега-списке. То есть он пройдет и по TTile и по TBonus и по TMovingX - объектам, если вы их, конечно, усыновили. Компилим:и : опс, не работает. А что пишет-то? Мол, нет у типа TParent метода Update(). Да согласен - нет. У этого типа вообще нет ни одного метода. Мы хотим, чтобы методы Update() и Draw() вызывались не базового типа, а его наследников, так если CurObj - это Bonus, то и вызывать надо Bonus.Update() и так далее. Аналогично дело обстоит и с методом Draw(). Мы-то знаем, что хотим, но BlitzMax не знает. Для того? чтобы он это понял, надо все-таки объявить эти два метода в нашем базовом типе, НО не писать никакого кода, а сделать их АБСТРАКТНЫМИ или по-другому виртуальными:

  Method Update()     Abstract
  Method Draw()       Abstract

Как раз это ключевое слово (Abstract) и подсказывает BlitzMax-у, чтобы он обращался не к методам предка, а к методам его производных типов. Это называется полиморфизм, второй из важнейших признаков ООП. Цитата: <Полиморфизм реализуется с помощью наследования классов (в BlitzMaxe - типов). Класс-потомок наследует сигнатуры методов класса-родителя, но реализация этих методов может быть другой, соответствующей специфике класса-потомка. Это называется переопределением метода.>(Wikipedia). То есть в зависимости от того, к какому типу принадлежит текущий объект, метод такого типа и вызывается - это как раз то, чего мы хотели. Ну, надеюсь, вы поняли. А если нет, то курите, други мои, руководство от Wave, а я пошел пивка попью. Ах, да, теперь все, компилим и радуемся. Вот исходник:

SuperStrict
 
Global ScrWidth : Int  = 640
Global ScrHeight : Int = 480

'Global TileList:TList = CreateList()
'Global BonusList:TList = CreateList()
'Global MovingXList:TList = CreateList()

Global ALLGameObjList : TList = CreateList()

Const TILESIZE:Int   = 32

Type TBase
  Field x:Int
  Field y:Int
  Field Width:Byte
  Field Height:Byte
 
  Method update() Abstract
  Method draw() Abstract
End Type  

Type TTile Extends TBase
' Field x:Int
' Field y:Int
' Field Width:Byte
' Field Height:Byte
 
  Field xTile:Int
  Field yTile:Int
  Field Walkable:Byte
 
  Function Create(sx:Int, sy:Int, WB:Byte)
    Local TT:TTile = New TTile
      TT.width  = TiLESIZE    
      TT.height = TiLESIZE    
      TT.xTile = sx      
      TT.yTile = sy            
      TT.x = TT.xTile * TT.width    
      TT.y = TT.yTile * TT.height  
      TT.Walkable = WB        

    ListAddLast(ALLGameObjList , TT)  
  End Function  

  Method update()
    If    walkable       'not walkable
      SetColor(255 , 0 , 0)  'red
    Else             ' 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 ALLGameObjList
'     CurTile.Update()
'     CurTile.Draw()
'   Next  
'  
'   For Local CurBonus:TBonus = EachIn ALLGameObjList
'     CurBonus.Update()
'     CurBonus.Draw()
'   Next      
'  
'   For Local CurMovingX:TMovingX = EachIn ALLGameObjList
'     CurMovingX.Update()
'     CurMovingX.Draw()
'   Next        
   
    For Local CurObj:TBase = EachIn ALLGameObjList
      CurObj.Update()
      CurObj.Draw()
    Next  
   
  End Method
 
End Type

Type TBonus Extends TBase
' 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(ALLGameObjList , TB)
  End Function  
 
  Method Update()
    If(Animdelay < 0)

         If ( miny >= (y) Or maxy <= (y + height) )
             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

Type TMovingX Extends TBase
' Field x:Int
' Field y:Int
' Field width:Int
' Field height:Int
 
  Field mindir:Int
  Field maxdir:Int

  Field dirx:Int
  Field speed:Int
 
  Function Create(xt:Int , yt:Int , mn:Int , mx:Int , d:Int)
    Local TMX:TMovingX = New TMovingX

      TMX.x = xt * TILESIZE
      TMX.y = yt * TILESIZE

      TMX.width = TILESIZE
      TMX.height = TILESIZE

      TMX.speed = 1

      TMX.dirx = d

      TMX.mindir = (mn + xt) * TILESIZE
      TMX.maxdir = (mx + xt + 1) * TILESIZE  

    ListAddLast(ALLGameObjList , TMX)
  End Function

  Method Update()
   
    If( mindir >= x Or maxdir <= (x + width) )  
        dirx = - dirx
    EndIf
   
      x :+ speed * dirx
 
  End Method  
 
  Method Draw()
    SetColor(128 , 128 , 128)  ' gray
    DrawRect(x , y , Width , Height)  
    SetColor(255 , 255 , 255)  ' white line
    DrawLine(x , y , x + width - 1 , y)
  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  

TMovingX.Create(13 , 3 , - 2 , 5 , 1)


'----------------------------- main loop -----------------------------
Graphics(ScrWidth, ScrHeight)

Init_All_Bonuses()

Repeat
   Cls

    MyLevel.Render()
   
   Flip
Until KeyDown(KEY_ESCAPE) Or AppTerminate()

End

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

Выведение

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

Категория: BlitzMax | Добавил: dimanche (24.05.2008) | Автор: Dmitriy
Просмотров: 920 | Комментарии: 2 | Рейтинг: 0.0/0 |
Всего комментариев: 1
1 Alex  
0
Круто! Очень полезная статья, чувак! Благодарствую)

Имя *:
Email *:
Код *:
Copyright MyCorp © 2024