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 22.04.2012 14:33

Ответ: Vivo
 
http://rghost.ru/36821364
Это последняя версия, на сколько я помню:)
Копи-паста предыдущего поста(из-за новой страницы его могли не заметить):


Пока моделлер работает, заняться мне нечем, поэтому решил-ка я позаниматься этим проектам. По-сколько кроме быдлокода я ничего в исходниках не нашёл, решил писать всё заново, отказавшись от экранов. Они были удобны, но многие говорили что это убивает геймлей. В общем, помогите с выбором:
1). Делать 9 чанков размером с экран, чтобы они окружали текущий экран.
2). Делать уйму маленьких чанков.
3). Послать всех и оставить экраны
P.S. в первых двух случаях игрок находится всегда в центре экрана.
И ещё, вдруг у кого завалялась инфа по данной теме, поделитесь, буду признателен( тоже к двум первым случаям относится).

Nikich 22.04.2012 16:59

Ответ: Vivo
 
В общем, что-то наподобие чанков:
Код:


Function CreateWorld()
loading_time=MilliSecs()

For i=-5 To 5
For i1=-5 To 5
fl=WriteFile("map\"+i+","+i1+".txt")
For i2=0 To 15
For i3=0 To 15

a=Rnd(20)
If a=1
WriteInt(fl,a)
Else
WriteInt(fl,0)
EndIf

Text R1/2-100,R2/2,"Loading: "+(i+5)*(i1+5)*i2*i3+" tiles generated"
Flip(False)
Cls

Next
Next
CloseFile(fl)
Next
Next


Text R1/2-100,R2/2,"Loading time: "+(MilliSecs()-loading_time)+" millisecs"
Flip
Delay 2000
End Function



Function Update_World()
chunk_x=Int((camera_x+R1/2)/512)
chunk_y=Int((camera_y+R2/2)/512)
For i=chunk_x-1 To chunk_x+1
For i1=chunk_y-1 To chunk_y+1
fl=OpenFile("map\"+i+","+i1+".txt")
For i2=0 To 15
For i3=0 To 15
DrawImage tile(ReadInt(fl)),512*i-camera_x+i2*32,512*i1-camera_y+i3*32
Next
Next
CloseFile(fl)
Next
Next

Посоветуйте что и как можно улучшить. Пока проблема в том, что показывается только нынешний чанк, и то расширенный.
P.S. R1 и R2 - ширина и высота экрана.

Nikich 22.04.2012 20:20

Ответ: Vivo
 
Все, основные баги убраны. Осталось только одно: как увеличить скорость данного кода?

NitE 22.04.2012 21:06

Ответ: Vivo
 
Можно например убрать Delay 2000.

Nikich 23.04.2012 00:27

Ответ: Vivo
 
Код:

Function Update_World()
chunk_x=(camera_x+R1/2)/512
chunk_y=(camera_y+R2/2)/512
For i=chunk_x-1 To chunk_x+1
For i1=chunk_y-1 To chunk_y+1
fl=OpenFile("map\"+i+","+i1+".txt")
For i2=0 To 15
For i3=0 To 15
;;;If 512*i-camera_x+i2*32<camera_x+R1 And  512*i1-camera_y+i3*32<camera_y+R2 And 512*i-camera_x+i2*32>camera_x And 512*i1-camera_y+i3*32>camera_y
DrawImage tile(ReadInt(fl)),512*i-camera_x+i2*32,512*i1-camera_y+i3*32
EndIf
Next
Next
CloseFile(fl)
Next
Next

Часть после ;;; почему-то не работает. Пожалуйста, помогите найти ошибку, но и вопрос с увеличением скорости тоже всё ещё актуален.

Жека 23.04.2012 10:02

Ответ: Vivo
 
For i=chunk_x-1 To chunk_x+1
For i1=chunk_y-1 To chunk_y+1
fl=OpenFile("map\"+i+","+i1+".txt")
For i2=0 To 15
For i3=0 To 15
;;;If 512*i-camera_x+i2*32<camera_x+R1 And 512*i1-camera_y+i3*32<camera_y+R2 And 512*i-camera_x+i2*32>camera_x And 512*i1-camera_y+i3*32>camera_y
DrawImage tile(ReadInt(fl)),512*i-camera_x+i2*32,512*i1-camera_y+i3*32
EndIf
Next
Next
CloseFile(fl)
Next
Next

Четверной цикл, это раз. грузишь из файла в главном цикле - это жестокое два. :)
За оперативку не беспокойся, грузи сразу все чанки своего уровня. А вот проход по чанкам делай в зависимости от того - влазит ли чанк в область экрана или нет. Те что не влазят просто пропускаются.

Nikich 23.04.2012 15:44

Ответ: Vivo
 
Код:

Function CreateChunk(i,i1)
fl=WriteFile("map\"+i+","+i1+".txt")
For i2=0 To 15
For i3=0 To 15
a=Rnd(20)
If a=1
WriteInt(fl,a)
Else
WriteInt(fl,0)
EndIf
Next
Next
CloseFile(fl)
End Function


Function ReplaceBlock(i,i1,i2,i3,i4)
fl=ReadFile("map\"+i+","+i1+".txt")
For j=0 To 15
For j1=0 To 15
chunk(j,j1)=ReadInt(fl)
If j=i2 And j1=i3 chunk(j,j1)=i4
Next
Next
CloseFile(fl)
fl=WriteFile("map\"+i+","+i1+".txt")
For j=0 To 15
For j1=0 To 15
WriteInt(fl,chunk(j,j1))
Next
Next
CloseFile(fl)
End Function

Нужна помощи в работе с файлами. Функция ReplaceBlock() работает, но согласитесь медленная она уж слишком. Пробовал через SeekFile, но результата вообще не было. Может кто знает способы получше, ведь мне надо лишь одно число заменить на другое, а значит точно должно быть решение по-лучше.

NitE 23.04.2012 16:33

Ответ: Vivo
 
Вообще плохо. Во-первых, ненадо при каждом вызове функций трогать файл. Его просто открываешь при запуске программы, а при выходе закрываешь и всё, больше его не трогаешь. Хотя на самом деле нужно весь файл при запуске слить в оперативку, и потом, при выходе записать туда все изменения.

Также файл - это не список. Тебе не обязательно перебирать все элементы чтобы изменить только один. А мгновенный доступ делается какраз через SeekFile(), просто ты с ним не разобрался. Но опять-же, если работать с данными в оперативке то весь этот лишний гемор будет не нужен.

Nikich 23.04.2012 17:53

Ответ: Vivo
 
На счет файла. Он всегда разный, не откроешь ты его один раз при запуске. Это файл с в котором находится инфа о чанке.
Слить в оперативку тоже не получится, ибо не удобно. В массиве элемент не может быть отрицательным( a(-5) - невозможно ), а х и у чанка могут быть отрицательными. В общем пойду курить SeekFile видимо.

Halk-DS 23.04.2012 18:00

Ответ: Vivo
 
Вот я играл в твою демку. Расскажи немного вообще про построение мира. Чанк єто один єкран? И сколько вообще у тебя должно быть чанков? И главное, у тебя по файлу на чанк?

NitE 23.04.2012 18:32

Ответ: Vivo
 
фейспалм.жпг

Если у тебя несколько файлов, то открой при запуске сразу все. При выходе соответсвенно все и закрой.

В массиве ествественно не может быть отрицательных элементов, но тебе никто не мешает сделать костыль самому, если уж так хочется.

Например у тебя 50 чанков. Функция вызова:

function getchunk(nr)
return chunkarr[nr+25]
end function

вводим от -25 до 25, на выходе получаем нужный чанк. И никаких проблем.

Nikich 23.04.2012 18:34

Ответ: Vivo
 
Nite
Их бесконечность, понимаешь? Бесконечность. Нету рамок никаких.
В той демке, что я давал все отличается от нынешнего. Могу описать как сейчас дела обстоят, или демку кинуть, для лучшего понимания.
В общем, один чанк это один текстовый файл, название которого равно его координатам. Он состоит из 256 блоков. Их id и хранится в файле. Чанков может быть неограниченое количество( вернее ограниченное свободным местом на диске), так что в рамку их не впишешь.

moka 23.04.2012 19:09

Ответ: Vivo
 
В компьютерном мире нету бесконечности.

Nikich 23.04.2012 19:34

Ответ: Vivo
 
Хорошо, очень-очень большой мир. Не -25,25, не -250,250, не -25000,25000. Массив не потянет.

Nikich 23.04.2012 21:36

Ответ: Vivo
 
Немного математики для наглядности размеров мира. Пока что, координаты чанков - integer, значит крайние число - 2,147,483,647. Один чанк - 512 пикселей. Скорость игрока - 2 пикселя за тик, максимальное фпс - 60, значит скорость игрока - 120 пикселей в секунду. (2,147,483,647*512)/120 - время за которое игрок пройдёт до конечного чанка. А это - 290 лет, если я не ошибся. Так что поверьте, это сравнимо с бесконечностью.

Halk-DS 23.04.2012 21:37

Ответ: Vivo
 
Припустим у тебя есть переменная PlayerRange -кеп сообщает что это обзор. Значит у тебя при PlayerRange=2 будет ситуация такова:
Перс стоит на чанке. Это 0+1 чанк на котором мы стоим
Видит он перед собой еще 2 чанка Это 0+1+PlayerRange
Видит он еще и за собой 2 чанка. Это 0+1+PlayerRange+PlayerRange
Соответственно общий размер локи будет PlayerRange*2+1
Делаешь массив Dim Chunks(PlayerRange*2,PlayerRange*2) - тут не делаешь +1 ибо нумерация массива начинается с нуля. Типо при PlayerRange*2+1 у тебя будет не 5 рядков и строк а 6 рядков и строк. А тут последняя нафик не нужна.
Теперь ахтунк!
Учишь это Связанные списки в Blitz3D
И учишся делать так, что б в массиве Chunks(PlayerRange*2,PlayerRange*2)
Каждая ячейка отвечала ТОЛЬКО АДРЕСУ на массив типов с инфой уже про каждый кубик.
Потом при передвижении игрока с одного чанка на второй программируешь сдвиг рядков(или столбцов) массива содержащего АДРЕСА на другие массивы с инфой про кубики. А освободившийся рядок(или столбец) заполняешь новой инфой с файлов и не мгновенно, а по кусочку за 1 проход цикла. (звучит это весьма просто, но на собственном опыте говорю - гемора выше крыши. Я с этим до конца не разобравшись забил болт и отложил эту цель на момент релиза игры.)
Вполне вероятно что ты меня плохо понимаешь, мой тебе совет, откажись от неограниченного мира, сделай хоть ограниченный но качественно. А потом думай над тем как делать его "бесконечным". Даже Нотч первые демки майнкрафта показывал с ограниченной локой(где то читал).

Halk-DS 23.04.2012 21:40

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

Сообщение от Nikich (Сообщение 226259)
Немного математики для наглядности размеров мира. Пока что, координаты чанков - integer, значит крайние число - 2,147,483,647. Один чанк - 512 пикселей. Скорость игрока - 2 пикселя за тик, максимальное фпс - 60, значит скорость игрока - 120 пикселей в секунду. (2,147,483,647*512)/120 - время за которое игрок пройдёт до конечного чанка. А это - 290 лет, если я не ошибся. Так что поверьте, это сравнимо с бесконечностью.

Сделай так, что б игрок открывший твою игру пробежал дольше 5 минут. А тогда парся о большем...

NitE 23.04.2012 21:45

Ответ: Vivo
 
Все эти проблемы к данной теме не относятся. Это вам не майнкрафт, который 3д, и в котором есть дальность обзора, например. Тут 2д (а может и 3д, это неважно) игра, с зафиксированным видом сверху. Так-что в любой момент времени максимум может понадобится отображать 3 чанка. О какой бесконечности речь? Короче, всё это реализуемо с помощью массивов и всю эту мизерную карту можно и нужно засунуть в 1 файл. Учите матчасть ТС.

Nikich 23.04.2012 21:52

Ответ: Vivo
 
Так я и отображаю только 3 чанка.
Кстати, у меня есть версия игры с массивами, карту можно пробежать за 44 часа, по моим расчётам. Вообще без чанков и всего такого.
Можете соизволить объяснить в чём файлы так ужасны? Чего все на них так набросились?
Nite
Видимо мы вообще говорим о разных вещах, я не понимаю о какой мизерной карте идёт речь. Можешь подробно объяснить, как с твоей точки зрения всё это выглядит?

Halk-DS 23.04.2012 21:54

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

Сообщение от NitE (Сообщение 226267)
Учите матчасть ТС.

Можно толчок в сторону той мат части о которой идет речь?

Nikich 23.04.2012 21:56

Ответ: Vivo
 

Да-да, и я не откажусь. На словах у Nite так всё просто звучит, аж интересно.

NitE 23.04.2012 23:19

Ответ: Vivo
 
Hulk-DS, Да, конечно. Основы программирования и тригонометрии, а так-же работа с векторами. Всё что я пытаюсь втолковать топикстартеру - это самые простые и очевидные вещи. Я не уверен что их можно будет так-же легко применить к такой модели мира в 3д, со свободным обзором.

Nikich, Тебе нужно, чтобы у игрока была земля под ногами, ну и например заранее ещё 8 чанков во все стороны от игрока (если предположить что 1 чанк у тебя по размерам как 1 экран). Итого у тебя в начале получается 9 чанков. А ты говоришь про какието 2 миллиарда:dontknow:. Потом, если игрок куда-то побежаль, начинаешь постепенно добавлять чанки, генерируя их в зависимости от ландшафта окружающих чанков. Вот собственно и вся логика. Если игрок бежит в одну сторону уже 2-3 часа, например, начинаешь с другого конца (тоест с позиции откуда игрок стартовал) удалять чанки, а потом, если когото приспичит ещё и назад прогулятся, то опять-же генерируешь новые чанки.

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

Nikich 23.04.2012 23:40

Ответ: Vivo
 
В одном файле ты всё не удержишь. Представь, когда игрок будет на чанке с координатами -25,25, то ты предлагаешь пробежаться по всему файлу дабы найти этот чанк?
Конечно, сразу полезу мысли, о том, что ведь можно это дело SeekFile'ом красиво обыграть, но так тоже не выйдет, так как нельзя определить в каком месте находится этот чанк( вдруг он был сгенерирован в самом начале игры, или когда уже было открыто 1000 чанков ). Так что на файлы разбивать точно придётся.
Хорошо, представь что у тебя есть эти 9 чанков. Как я понял, хранить ты их хочешь в каком-то отдельном файле. Так а смысл тогда использовать массив? Что я работаю напрямую с файлами, что по твоему способу я буду работать с файлами чтобы заполнить этот массив, а потом уже из массива брать информация о блоках. Где выгода?

Halk-DS 24.04.2012 00:23

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

Сообщение от Nikich (Сообщение 226293)
Конечно, сразу полезу мысли, о том, что ведь можно это дело SeekFile'ом красиво обыграть, но так тоже не выйдет, так как нельзя определить в каком месте находится этот чанк( вдруг он был сгенерирован в самом начале игры, или когда уже было открыто 1000 чанков ). Так что на файлы разбивать точно придётся.

Я думаю что именно в этом месте и нужно подтягивать мат часть. (п.с. Сам не пробовал так сделать...)
Кроме того у Нотча не лежит в папке пару тищь файлов когда пробежишься по карте.

NitE 24.04.2012 00:24

Ответ: Vivo
 
Да только SeekFileом и нужно. Тебе-же доступны координаты игрока. Темболее у тебя ведь даже не будет резких скачков, т.е. максимум может понадобиться сдвиг на один чанк в какую-то сторону. В одном файле нужно хранить чанки так-же как они расположены реально, т.е. будет требоваться полное переписывание файла с картой при добавлений нового чанка. Вот тут и вылазить причина преимущества массивов. Ты один раз загружаешь карту с медленного ЖД и один раз её туда-же и сохраняешь. При запуске и при выходе. А всё остальное время работаешь с быстрой оперативкой.
Вообще постоянный перебор чего-либо это обычно самые слабые и тормозящие места в логике. По возможности нужно этого избегать.

Что такое архив? Это 1(!) файл, который содержит в себе много(!!!) более мелких файлов. Уличная магия? Не, просто алгоритмы.

Nikich 24.04.2012 00:38

Ответ: Vivo
 
Вложений: 1
Ну, я сделал по-своему, просьба отписаться сколько у кого фпс, на каком железе.
А в том способе что ты сейчас написал, тоже есть изъян. Тебе ведь придеться расширить массив, если игрок решил далеко зайти. А для этого нужно выгрозить весь этот массив, расширить его и опять заполнить. Сколько же это гемора.
З.Ы. я верил в магию:(

Halk-DS 24.04.2012 01:46

Ответ: Vivo
 
В обычные моменты около 30
Когда приходят глюки от 8 и до 18 сильно скачет
Целерон 1 ядро 1.8

pax 24.04.2012 09:09

Ответ: Vivo
 
стабильно 39-40 FPS, i5 со встроенным видео.

St_AnGer 24.04.2012 09:14

Ответ: Vivo
 
25-30 fps, ёжик т101мт (конфиг в подписи). Вечером проверю на стационаре

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 раз, когда пересекаю самую первую зону. Возможно в этот момент генерируется многа файлов сразу, поэтому так. А при остальных пересечениях не генерируются, пока не дойду до определенной зоны.

Nikich 30.04.2012 09:06

Ответ: Vivo
 
Вложений: 1
Благодаря Максу теперь стало возможным сделать градиентный свет!

Randomize 30.04.2012 11:08

Ответ: Vivo
 
Реквестирую конфигу чтоб можно былом сменить разрешение и устанавливать оконный режим.
Comic Sans MS - плохой шрифт.

Nikich 30.04.2012 11:22

Ответ: Vivo
 
Оконный режим сделаю как в Майнкрафте, разрешение пока не знаю. Может тоже на F какой-нибудь. Менюшку делать так долго... И чем Comic Sans плох?
Кстати, можно тему перенести в проекты на Максе?

Randomize 30.04.2012 11:28

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

Сообщение от Nikich (Сообщение 226856)
Оконный режим сделаю как в Майнкрафте,

Повесь на Alt+Enter. В блицмаксе заново грузить ресурсы при смене разрешения не нужно так как там есть TPixmap
Цитата:

Сообщение от Nikich (Сообщение 226856)
И чем Comic Sans плох?

Плохо читается и не лаконичен. Шрифт сугубо декоративный и важную информацию им лучше не писать.



Цитата:

Сообщение от Nikich (Сообщение 226856)
Кстати, можно тему перенести в проекты на Максе?

Done.

Nikich 30.04.2012 11:59

Ответ: Vivo
 
Thanks!
а можно подробнее о пиксмапах?

Randomize 30.04.2012 12:19

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

Сообщение от Nikich (Сообщение 226859)
Thanks!
а можно подробнее о пиксмапах?

Есть оперативная память видео карты и есть оперативная память пк.
Вся твоя программа использует для работы оперативную память ПК, а визуализация графики происходит с использованием видео памяти.
Для того чтоб допустим вывести изображение на экран нужно его сначала считать с жёсткого диска потом преобразовать в нужный для видео карты формат, "закачать изображение" на видео карту и дать напутствие видео карте чтоб она вывела на экран наше изображение.

Дак вот в BlitzMax есть класс Image.
Он содержит в себе Pixmap и ссылку на хранимое в видеокарте изображение.

Pixmap это преобразованный специальным образом для видео карты универсальный набор пикселей. Который позволяет "на лету" менять разрешение экрана и даже сменять в реальном времени GAPI с DirectX на OpenGL например. Он хранится у тебя локально в оперативе компа. И когда стартует 3d девайз или перезапускается (смена разрешения) пиксмапа закачивается в видео память в виде 2D текстуры.

Работа с пиксмапой ничего не требует. Вся работа с ней скрыта за тенью LoadImage LoadAnimImage. И ты просто можешь менять разрешение "на лету" не перезагружая заново все ресурсы как бы это надо было бы делать в Blitz3D.

писал с бодуна, могу хреново выражаться

Nikich 30.04.2012 23:11

Ответ: Vivo
 
Можете подсказать, как обычно делается физика в платформерах? Меня волнует именно прыжки. Я решил перенести Виво на вид сбоку, и наткнулся на проблему с прыжками. Дело в том, что есть погрешность в пару пикселей . Подумав что это нормально, ведь нельзя добиться идеала, я зашёл в Террарию. И там я увидел что погрешностей там нет. Ну вообще нету. Вот мне и интересно, может я что-то не так делаю. Так что, если не сложно, напишите как кто делал прыжки в платформерах.

NitE 30.04.2012 23:36

Ответ: Vivo
 
Погрешность чего?

Nikich 30.04.2012 23:41

Ответ: Vivo
 
Есть расстояние между игроком и блоком под ним. Иногда он немного выше, иногда - в сам блок влазит. Дело косметическое, понимаю, но мелочь довольно не приятная. И вообще, как делаются правильно прыжки? Вот мой черновой вариант:
Код:

dx=KeyDown(KEY_D)-KeyDown(KEY_A)
If map[(camera_x+R1/2)/32,(camera_y-g+R2/2)/32+1]=1; Проверяем блок под игроком, если земля - g=0, если нет - g=g-3
g=0
If KeyDown(KEY_SPACE) g=20
Else
g=g-3
EndIf
If g<-5 g=-5



If map[(camera_x+dx*speed+R1/2)/32,(camera_y+R2/2)/32]=0; Проверяем следующий блок в который хочет пойти игрок
camera_x=camera_x+dx*speed
EndIf

camera_y=camera_y-g


Жека 01.05.2012 07:30

Ответ: Vivo
 
При завершении прыжка корректируй позицию игрока так, чтобы между блоком и игроком не было зазора. Просто проверяй на сколько подвинуть и двигай, т.к. координаты и размеры известны, то это легко получится.

Nikich 01.05.2012 23:46

Ответ: Vivo
 
Что-то всё равно не очень гладко выходит. Есть у кого исходники платформеров на максе ил блитц3д? Буду благодарен. Или пожалуйста, просто киньте сюда код отвечающий за передвижение и прыжки.

Жека 02.05.2012 05:42

Ответ: Vivo
 
Вот этот проект посмотри: http://forum.boolean.name/showthread.php?t=5751

Nikich 02.05.2012 14:29

Ответ: Vivo
 
Спасибо. Кстати, можно ли как-то сделать Include "abc.txt"? Мне очень понравилась система в Stranded 2. Там вообще можно новую игру в .txt написать.

Randomize 02.05.2012 14:42

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

Сообщение от Nikich (Сообщение 227066)
Спасибо. Кстати, можно ли как-то сделать Include "abc.txt"? Мне очень понравилась система в Stranded 2. Там вообще можно новую игру в .txt написать.

Нет. Блитзмакс это не скриптовик и он не может после компиляции обрабатывать Include.

То, что Include это не директива - странно, но этому есть применение.
Include может возвращать результат, Include можно вызывать по условию и тд.

По сути весь твой код внутри Include оборачивается как бы в функцию (на самом деле GOTO) и его можно вызывать сколь угодно раз, однако не советую так делать. Для этого есть функции/методы.

А при компиляции все твои Include компилируются в exe вместе с главным файлом вне зависимости от того как ты эти include используешь.

То, что ты хочешь сделать именуется скриптовым языком. В Stranded используется LUA. В BlitzMax уже есть модуль работы с LUA и даже несколько сторонних модулей упрощающих работу с ним.

Немного на русском
http://blitzetc.blitzmax.ru/index.php/BlitzMax_и_LUA

Wiki по встроенному в BlitzMax модулю LUA
http://en.wikibooks.org/wiki/BlitzMa...Other/Lua_Core


AXE LUA модуль
http://en.wikibooks.org/wiki/BlitzMax/Modules/Axe/Lua
http://lua-users.org/wiki/BlitzMax

Мануал по синтаксису LUA (можно особо не зачитываться так как луа простейший)
http://www.lua.org/manual/5.1/

Nikich 02.05.2012 17:16

Ответ: Vivo
 

Код:

Graphics DesktopWidth(),DesktopHeight()
Global R1=GraphicsWidth()
Global R2=GraphicsHeight()
SeedRnd MilliSecs()
Global player_image=LoadImage("images\player.png")
SetImageHandle player_image,15,32
Global dx,dy,camera_x,camera_y,g#,mouse_block_x,mouse_block_y
Global speed=5
camera_x=4000
camera_y=200
Global map_width,map_height
map_width=500
map_height=500
Global block[100]
block[0]=LoadImage("images\blocks\sky.png")
block[1]=LoadImage("images\blocks\ground.png")
Global map[map_width+1,map_height+1]
Global key_hit_1,key_hit_2
Global fps,lfps,tfps
Function Create_world()
For i=0 To 500
For i1=0 To 500
If i1>50
map[i,i1]=1
Else
map[i,i1]=0
EndIf
Next
Next
End Function

Create_world()

Function Update_camera()
dx=KeyDown(KEY_D)-KeyDown(KEY_A)




If map[(camera_x+R1/2)/16,(camera_y+R2/2)/16+1]=1
g=0

 If KeyDown(KEY_SPACE) g=5

camera_y=Int(camera_y/16+1)*16-6-g

Else
g=g-0.4
 If g<-3 g=-3

 If g>0
  If Not collision()
  camera_y=camera_y-g
  EndIf
 Else
  If map[(camera_x+R1/2)/16,(camera_y+R2/2)/16+1]=0
  camera_y=camera_y-g
  EndIf
 EndIf
EndIf



If Not collision()
camera_x=camera_x+dx*speed
EndIf


End Function

Function collision()

For i=(camera_x+dx*5*speed+R1/2)/16-2 To (camera_x+dx*5*speed+R1/2)/16+2
For i1=(camera_y+R2/2)/16-2 To (camera_y+R2/2)/16
If map[i,i1]=1
If ImagesCollide(player_image,R1/2,R2/2,0,block[map[i,i1]],i*16-camera_x,i1*16-camera_y,0)
Return True
EndIf
EndIf
Next
Next

End Function

Function Draw_world()
mouse_block_x=(camera_x+MouseX())/16
mouse_block_y=(camera_y+MouseY())/16

For i=camera_x/16 To (camera_x+R1)/16
For i1=camera_y/16 To (camera_y+R2)/16
DrawImage block[map[i,i1]],i*16-camera_x,i1*16-camera_y

If key_hit_1
If mouse_block_x=i And mouse_block_y=i1 map[i,i1]=1
EndIf
If key_hit_2
If mouse_block_x=i And mouse_block_y=i1 map[i,i1]=0
EndIf
Next
Next
DrawImage player_image,R1/2,R2/2

End Function


Function Update_HUD()
If MilliSecs()-tfps<1000 fps=fps+1
If MilliSecs()-tfps>1000 Then
lfps=fps
tfps=MilliSecs()
fps=0
EndIf
SetColor 255,255,255
SetAlpha 1

DrawText "FPS: "+lfps,0,0
DrawText "mouse_block_x: "+mouse_block_x+"  mouse_block_y: "+mouse_block_y+" g: "+g,0,24
End Function

While Not KeyHit(KEY_ESCAPE)
key_hit_1=MouseHit(1)
key_hit_2=MouseHit(2)
Update_camera()
Draw_world()
Update_HUD()
Flip(1)
Cls
Wend


Блин, что-то вконец ничего не получается. С осью y разобрался, а вот с x вообще лажа:( Помогите найти ошибку, пожалуйста. Проблема в том, что игрок всё равно может проникнуть через блок. Хотя я думаю что у меня подход неверный, коллизии в тайловой игре как-то не очень.
З.Ы. код jimon'a посмотреть не смог, файл удалили.

Spy4433 02.05.2012 17:48

Ответ: Vivo
 
а почему бы не взять физический движок ?

Nikich 02.05.2012 21:01

Ответ: Vivo
 
Потому что мне нужно только перемещение от физики.

Жека 03.05.2012 10:47

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

Сообщение от Nikich (Сообщение 227076)
Блин, что-то вконец ничего не получается. С осью y разобрался, а вот с x вообще лажа:( Помогите найти ошибку, пожалуйста. Проблема в том, что игрок всё равно может проникнуть через блок.

Выложи архив с кодом и медией.
Я сделал сам 3 картинки, игрока 16х32 и 2 тайла размером 16х16, но по Х-координате нет препятствий в твоей карте, есть сплошной пол и небо. даже не ясно движется игрок в сторону или нет.

Nikich 03.05.2012 11:21

Ответ: Vivo
 
Блоки можно ставить и разрушать на левую и правую кнопку мыши.

Nikich 03.05.2012 17:26

Ответ: Vivo
 
Вложений: 1
Вот он. Проблема та же - что-то не так с перемещением по "x". Добавил генерацию мира рэндомную, чтобы можно было не строить препятствия.


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

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