forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Проекты на BlitzMax (http://forum.boolean.name/forumdisplay.php?f=106)
-   -   Vivo (http://forum.boolean.name/showthread.php?t=16218)

Nikich 24.04.2012 10:18

Ответ: Vivo
 
Вложений: 1
А не могли бы в еще отписаться о скорости ваших жестких дисков, ведь как я понял, при прямом использовании файлов(они открываются, оттуда считывается информация, они закрываются, и все это в риалтайме) важна именно она.
В аттаче версия, без чанков, без файлов, просто двумерный массив. Просто и сердито. Карта 10000х10000(381 мб рамки). Генерируется приблизительно 5 секунд. Также, пожалуйста, отпишитесь о фпс и укажите характеристики своего компьютера( тут уже скорость винчестера не влият:) ).
Хотя признаюсь, был шокирован столь низким фпс в предыдущей версии. Видимо всё же с массивами надо колдовать...

RBK 24.04.2012 12:18

Ответ: Vivo
 
Цитата:

Генерируется приблизительно 5 секунд
:) Генерировалось примерно 10 минут.

ФПС стабильный, около 55, без падений.

Nikich 24.04.2012 12:22

Ответ: Vivo
 
Почти:)
А в предыдущей версии(кликабельно)?
Nite, блин, как у тебя всё просто. "А если он решит и назад прогуляться генерируешь новые чанки". Отлично! Игрок решил прогуляться за грибами, возвращается, а на месте его дома уже чистая земелька. Так ведь тоже не катит. Не выйдет тут массивами. По крайней мере так просто не выйдет.
И кстати, у Нотча всё разбито на файлы.

Пруф


"Игровой мир (или Карта) представляет собой иерархическую систему директорий и файлов, хранящую информацию о каждом блоке, предмете и существе в мире и об их состоянии."

Жека 24.04.2012 13:20

Ответ: Vivo
 
Какова цель игры? Может игроку и нет смысла на 10 тыщ клеток ходить, а достаточно сделать более насыщенное игровое действо на поле меньшего размера.

RBK 24.04.2012 13:42

Ответ: Vivo
 
В предыдущей версии фпс около 27, иногда падения до 5 - 10

При переходах между квадтатами постоянно подтормаживает.

Nikich 24.04.2012 13:53

Ответ: Vivo
 
О целях дискуссии уже были.
Эту игру можно смело называть клоном майнкрафта, с более выраженным упором на выживание. Целей нету. Хотя нет, неверно. Цель такая же как в майнкрафте.
Бесконечная (МоКа, большая :) ) карта, скорее всего просто как испытание. Я сомневаюсь что и в майнкрафте всем так нужна бесконечная( большая ) карта. Просто ЧСВ, да игра солиднее выглядит. Согласитесь, фраза:" Ну карта не бесконечная, не смог ", звучит слабовато. А то что площадь мира в моей игре больше площади Земли в 36 164 раз звучит очень даже круто.

Nikich 24.04.2012 20:54

Ответ: Vivo
 
Вложений: 1
Фух, мозг что-то вообще варить перестал, как я за эти массивы взялся. Пожалуйста, можете помочь? Видимо мой способ не является самым лучшим, так как столько геморроя я ещё не испытывал. Сейчас я объясню свою задумку максимально подробно.
Возьмём массив Sector(6,6,15,15), первые два элемента которого отвечают за х и у чанка, относительно игрока(!). Для начала их заполним, взяв всю инфу из файлов. А вот как они должны рисоваться:
Код:

for i=0 to 6
for i1=0 to 6
for i2=0 to 15
for i3=0 to 15
drawimage block(Sector(i,i1,i2,i3)),((3-i)+chunk_x)*512+32*i2-camera_x,((3-i1)+chunk_y)*512+32*i3-camera_y
next
next
next

А теперь комментарии. block(Sector(i,i1,i2,i3)) - картинка, соответствующая блоку.((3-i)+chunk_x)*512+32*i2-camera_x - на первый взгляд вообще дикая непонятная формула, в которой никто не захочет разбираться. Но всё достаточно просто. Игрок всегда должен находится в 3 чанке, относительно сектора, поэтому мы берём значение 3. ''-i'' мы берём я определение местоположения чанка относительно чанка в котором расположен игрок.
Таблица, поясняющая суть:

Больший квадрат - сектор, меньшие - чанки, центральный - тот в коором находится игрок. Как вы могли заметить, находить он в 3,3 - вот откуда берётся это i-3. ((3-i)+chunk_x)*512 - почему же 512? Потому что 512 - это количество пикселей, которое занимает один чанк(он состоит из 16 блоков, 32х32 каждый). i2*32 - координата блока, умноженная на 2 из-за его ширины. С осью у тоже самое.
Фух, с пробежкой мы разобрались. Теперь нам надо сделать так, чтобы если игрок переходит на следующий чанк, массив подгружал в себя новые чанки, и записывал в файл крайние чанки. Тут то и заключается проблема. Я вообще не знаю, как бы это красиво обыграть. Знаю как некрасиво - взять наш Sector, сделать четверной перебор, чтобы сдвинуть все чанки, потом ещё перебор на загрузки новых чанков, а потом ещё перебор на выгрузку старых. Остановился я на определении, в какую сторону нужно производить сдвиг. Вот моя функция для перемещения игрока:
Код:


Function UpdateCamera()
dy=KeyDown(31)-KeyDown(17)
dx=KeyDown(32)-KeyDown(30)
chunk_x=(camera_x+R1/2)/512
chunk_y=(camera_y+R2/2)/512                                       
If (dx<>0 And dy=0) Or (dy<>0 And dx=0) Or (dy<>0 And dx<>0) gdx=dx:gdy=dy
If MilliSecs()-frame_timer>40 frame=frame+1:frame_timer=MilliSecs()
If frame>10 frame=0



next_chunk_x=(camera_x+dx*6*player_speed+R1/2)/512
next_chunk_y=(camera_y+dy*6*player_speed+R2/2)/512
If Not Collision()
If (dx=0 And dy<>0) Or (dx<>0 And dy=0)
camera_x=camera_x+dx*player_speed
camera_y=camera_y+dy*player_speed
Else
camera_x=camera_x+dx*diag_player_speed
camera_y=camera_y+dy*diag_player_speed
EndIf
EndIf

change_x=(camera_x+R1/2)/512-chunk_x
change_y=(camera_y+R2/2)/512-chunk_y

End Function

Поскольку название переменных у меня совпадает с их назначением, пояснять и думаю их не надо. Конечно, это выглядит так, будто я хочу чтоб вы мне написали готовые функции. Но это не так! Всё это я показал лишь для того, чтобы если вы захотели помочь мне, оперировали не просто словами, а теми переменными которые у меня используются.
З.Ы. особо интересует объяснения Nite'a. Как я понял, у него есть идея по реализации, но что-то я в ней не особо варю:)

Randomize 24.04.2012 21:00

Ответ: Vivo
 
Аттачи не прикрепились

Nikich 24.04.2012 21:21

Ответ: Vivo
 
Пофикил.

Жека 26.04.2012 07:55

Ответ: Vivo
 
Я написал псевдо-код с комментариями, посмотри, может тебе пригодится такое.
Код:

Global chunks.TChunk[9] ;ближайшие к игроку чанки


Dim IMAGES%(100) ;масив для картинок-тайлов, идентификатор тайла соответствует идентификатору массива

;при старте уровня можно создать сколько-нибудь чанков
;при создании чанков указываем их соседей, тогда можно при движении в стороны сразу выцеплять соседей
Local xx%, yy%, countX% = 100, countY% = 100
Local ch.TChunk, ch2.TChunk
Dim temp.TChunk(countX*countY) ;тут временно сохраним чанки, чтоб соседей назначить
;Local dx# = 32*16, dy# = 32*16
Local index%
For xx = 0 To countX-1
        For yy = 0 To countY-1
                ch = CreateChunk(xx,yy)
                temp(xx*yy) = ch
                ;тут соседей назначаем
                If(xx > 0)
                        index = GetLinearIndex(xx-1,yy,countX) ;чанк слева от нового
                        ch2 = temp(index)
                        ch\chunks[0] = ch2
                        ch2\chunks[2] = ch ;а этому ставим правого соседа
                EndIf
                If(yy > 0)
                        index = GetLinearIndex(xx,yy-1,countX) ;чанк сверху от нового
                        ch2 = temp(index)
                        ch\chunks[1] = ch2
                        ch2\chunks[3] = ch ;а этому ставим нижнего соседа
                EndIf
        Next
Next


;назначаем начальные чанки из середины поля
Local x0% = Rand(40,60)
Local y0% = Rand(40,60)
For xx=0 To 2
        For xx=0 To 2
                chunks[xx*yy] = temp(GetLinearIndex(x0+xx,y0+yy,countX))
        Next
Next


;в игровом цикле нужно рисовать только наши 9 чанков
For k% = 0 To 8
        DrawChunk(chunks[k], scrollX, scrollY) ;рисуем с учётом скролла
Next

;при движении игрока в сторону - по достижении границы чанков - делаем сдвиг чанков
ShiftChunks(direction) ;direction - направление: 0-влево, 1-вверх, 2-вправо, 3-вниз



;получение индекса в одномерном массиве через значения индексов двухмерного
Function GetLinearIndex%(x%, y%, dimX%)
        Return y*dimX + x
End Function


;сдвигаем, беря соседние в зависимости от направления
;и сохраняем то что уходит за экран
;если соседа нет, то загружаем из файла или генерируем
Function ShiftChunks(direction%)
        Local ch.TChunk;, ch2.TChunk
        Local xx%, yy%
        Select(direction)
                Case 0 ;сдвиг влево, сохраняем правый ряд
                        For yy=0 To 2
                                ch = chunks[GetLinearIndex(2,yy,3)]
                                SaveChunk(ch)
                                chunks[GetLinearIndex(2,yy,3)] = GetNextChunk(ch, 0) ;получаем соседний чанк
                                Delete(ch) ;и удаляем тех кто ушёл за экран
                        Next
                Case 1 ;сдвиг вверх, сохраняем нижний ряд
                        For xx=0 To 2
                                SaveChunk(chunks[GetLinearIndex(xx,2,3)])
                        Next
                Case 2 ;сдвиг вправо, сохраняем левый ряд
                        For yy=0 To 2
                                SaveChunk(chunks[GetLinearIndex(0,yy,3)])
                        Next
                Case 3 ;сдвиг вниз, сохраняем верхний ряд
                        For xx=0 To 2
                                SaveChunk(chunks[GetLinearIndex(xx,0,3)])
                               
                        Next
        End Select
        For xx=0 To 2
                For xx=0 To 2
                        chunks[xx*yy] = temp(GetLinearIndex(x0+xx,y0+yy,countX))
                Next
        Next
End Function

;получаем соседний чанк, если он есть
;если нет, то пробуем загрузить из файла
;если файла нет, то генерируем новый
Function GetNextChunk.TChunk(ch.TChunk, dir%)
        Local chunk.TChunk = ch\chunks[dir]
        If(chunk <> Null) Then Return chunk
        ;пробуем из файла
        Local path$
        If(dir = 0) ;влево идём
                path$ = "ch-"+(ch\cellX-1)+"-"+ch\cellY+".txt"
        Else If(dir = 0) ;влево вверх
                path$ = "ch-"+ch\cellX+"-"+(ch\cellY-1)+".txt"
        Else If(dir = 0) ;влево вправо
                path$ = "ch-"+(ch\cellX+1)+"-"+ch\cellY+".txt"
        Else If(dir = 0) ;влево вниз
                path$ = "ch-"+ch\cellX+"-"+(ch\cellY+1)+".txt"
        EndIf
        If(FileType(path) = 1)
                ;грузим
                chunk = New TChunk
                LoadChunk(chunk, path)
                Return chunk
        Else
                chunk = GenerateChunk() ;генерируем
        EndIf
        ;здесь нужно указать соседство левого с правым и т.д. для всех направлений
        ;и другие параметры/ cellX, cellY
        Return chunk
End Function


Function GenerateChunk.TChunk()
       
End Function


Function LoadChunk(ch.TChunk, path$)
       
End Function


Function SaveChunk(ch.TChunk)
        ;тут записываем в файл с именем ch-x-y.txt инфу о тайлах
        ;x - ch\cellX
        ;y - ch\cellY
End Function


;создание чанка
Function CreateChunk.TChunk(cellX%, cellY%, dimX%=15, dimY%=15, size%=32)
        Local ch.TChunk = New TChunk
        ch\dimX = dimX ;16-1
        ch\dimY = dimY ;16-1
        ch\size = size
        ch\cellX = cellX
        ch\cellY = cellY
        ch\x0 = cellX*size*(dimX+1)
        ch\y0 = cellY*size*(dimY+1)
        GenerateTiles(ch) ;генерим тайлики в чанк
        Return ch
End Function


;генерим тайлы для чанка - если есть файл с таким чанком то надо загрузить из файла
Function GenerateTiles(ch.TChunk)
        Local xx%, yy%
        For xx = 0 To ch\dimX
                For yy = 0 To ch\dimY
                        ch\imagesId[xx*yy] = Rand(0, IMAGES_COUNT-1) ;в реале конечно простой рандом не прокатит, это пример получения идентификатора картинки
                Next
        Next
End Function


;рисование чанка, х и у - сдвиг, который позволяет скроллировать карту
Function DrawChunk(chunk.TChunk, x#, y#)
        Local xx%, yy%
        For xx = 0 To chunk\dimX
                For yy = 0 To chunk\dimY
                        DrawImage(IMAGES(chunk\imagesId[xx*yy]), x+chunk\x0, y+chunk\y0)
                Next
        Next
End Function



Type TChunk
        Field cellX%, cellY% ;индекс чанка в глобальном мире
        Field x0#, y0# ;координаты левого верхнего угла, относительно которых будем рисовать
        Field dimX%, dimY% ;количество тайлов в чанке по х и по у, н-р: 16x16, или на 1 меньше хранить, чтоб в циклах не отнимать каждый раз
        Field size% ;размер тайла, н-р: 32
        Field imagesId%[16*16] ;идентификаторы картинок-тайлов. т.к. двумерный массив тут нельзя добавить, в одномерный вставим
        Field chunks.TChunk[4] ;соседи слева-справа-сверху-снизу
End Type


Nikich 27.04.2012 15:47

Ответ: Vivo
 
Вложений: 1
А теперь сколько фпс? Делал всё же по своему, но с массивами. Заметен не плавный переход в те области, где чанков ещё нету.

Жека 28.04.2012 06:31

Ответ: Vivo
 
фпс: 19-29, в основном 19-20, комп 4 ядра, но видео встроенная AMD 760G.

Я смотрю у тебя главный герой в картинке идёт в одну сторону, а в игре во все, то есть программно поворачивается, это тоже тормоза прибавляет. Как сказано в справке блитца для RotateImage: This command is not fast enough to render rotations in real time!
Но ты уже в сторону блитцмакса идёшь, так что поворот перестанет быть проблемой.

Nikich 28.04.2012 08:49

Ответ: Vivo
 
Я риалтаймом и не вращаю. Делаю массив, и в него вбиваю уже повернутые картинки, а потом рисую уже эти картинки, в зависимости от направления игрока.
З.Ы. Это точно из-за видеокарты, я забыл сделать так, чтобы рисовались только те блоки что видны:)

pax 28.04.2012 14:57

Ответ: Vivo
 
Стабильно 45 FPS - core i5 со встроенным видео.

radiobutton 28.04.2012 16:38

Ответ: Vivo
 
59 fps, i5 2500k 3.3, 4 ядра

Загрузка видна только 1 раз, когда пересекаю самую первую зону. Возможно в этот момент генерируется многа файлов сразу, поэтому так. А при остальных пересечениях не генерируются, пока не дойду до определенной зоны.


Часовой пояс GMT +4, время: 14:54.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot