forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Общие вопросы (http://forum.boolean.name/forumdisplay.php?f=166)
-   -   Очередные вопросы от меня по игровой логике и скриптингу (http://forum.boolean.name/showthread.php?t=20854)

Crystal 13.10.2020 00:32

Очередные вопросы от меня по игровой логике и скриптингу
 
1. Что будет работать быстрее?

1.1 Массив перебираемый в цикле.
1.2. Листаемый свитч с вбитыми вариантами искуемого.

2. Как правильно организовать возврат из текущей сцены в предыдущую
без потери игрового процесса в сцене? (расположение и количество объектов
на сцене, их параметры, и так далее.)

2.1 Нужно писать загрузку\сохранение уровня,
или же как-то можно заморозить и запомнить всё в сцене
возможностями юнити, и просто когда надо вернуться
в нужную сцену и продолжить игру с текущего места?
2.2. Если это возможно только с загрузкой\сохранением
(что по моему мнению медленно), то не проще ли отказаться
от сцен, и делать всю игру в одной сцене просто перенося
игрока по разным координатам подальше, имитируя переход
в другую сцену?

pax 13.10.2020 09:47

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
1. Свитч, потому что он в итоге преобразуется в что-то типа словаря.
2. Надо делать сохранения (записывать например состояние сцены в файл json или xml или другой формат), а при загрузке сцены восстанавливать состояние из сохраненного файла. Возможности заморозить нет. Если ты можешь себе позволить делать все в одной сцене, то почему бы и нет? Но разве сохранения в итоге не потребуются далее? Если например игра для телефонов, то часто телефон будет уводить приложение в фон и если не сохранить прогресс, то можно его потерять...

ABTOMAT 13.10.2020 10:35

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Crystal (Сообщение 317739)
2.2. Если это возможно только с загрузкой\сохранением
(что по моему мнению медленно), то не проще ли отказаться
от сцен, и делать всю игру в одной сцене просто перенося
игрока по разным координатам подальше, имитируя переход
в другую сцену?

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

Crystal 13.10.2020 13:38

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от pax (Сообщение 317742)
1. Свитч, потому что он в итоге преобразуется в что-то типа словаря.
2. Надо делать сохранения (записывать например состояние сцены в файл json или xml или другой формат), а при загрузке сцены восстанавливать состояние из сохраненного файла. Возможности заморозить нет. Если ты можешь себе позволить делать все в одной сцене, то почему бы и нет? Но разве сохранения в итоге не потребуются далее? Если например игра для телефонов, то часто телефон будет уводить приложение в фон и если не сохранить прогресс, то можно его потерять...

Вот у меня вся логика пошаговости в игре полностью на свитчах
с условиями выкакана, там под 2к строк. Я думал это сделать
временным решением, и перевести всё на массивы с циклами
позже, но теперь я уже так не думаю. Засомневался.
У меня там прям рекурсия (свитчи в свитчах в свитчах в свитчах).

Цитата:

Сообщение от ABTOMAT (Сообщение 317743)
Это хорошая идея, но нужно тратить время на реализацию.
Плюс больше шансов где-то пролюбиться, ведь при рестарте игры надо будет всё не только грузить, но ещё и за собой вычистить, тут можно ошибиться и наловить багов.
А сцены это вариант для ленивых, чтобы не париться (ну или если есть реальные причины так не делать).


Когда нужно часто менять сцену, чуть ли не каждые пол минуты,
то постоянная загрузка может в конец выбесить игрока, нужно другое решение.

Возможно стоит вторую сцену реализовать внутри первой через слои,
например тормозим все объекты в первом слое, и отрубаем им рендер и коллайдеры,
и соответственно обратное делаем со второй сценой.
Всё будет происходить в тех же координатах игровых,
даже не надо куда-то в отдельные координаты переносить импровизированную сцену.

Randomize 13.10.2020 14:06

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Crystal (Сообщение 317745)
Возможно стоит вторую сцену реализовать внутри первой через слои,
например тормозим все объекты в первом слое, и отрубаем им рендер и коллайдеры,
и соответственно обратное делаем со второй сценой.

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

Crystal 13.10.2020 14:14

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Randomize (Сообщение 317746)
В блице мы просто скрывали пивот и за ним скрывалась вся иерархия.
Думаю тут можно делать тоже самое, только камеру переключи.

У меня в блитце рендер уровней был в свитче зашит.
Переключаем часть свитча, рендерится другая часть (считай другой слой),
вот тебе и другой уровень. Я это по большей части для меню использовал.

А так я чисто загрузку и сохранение реализовывал, локация создавалась нужная по месту,
выкорячивалась из массивов. У меня даже модели в массивах лежали.

---

В своём проекте в юнити есть идея просто сцену боя рисовать под
локацией открытого мира снизу. Этак пунктов на 50 ниже.
Она один хрен каждый раз под бой генерируется, все её объекты
всё равно исчезают после боя. А открытый мир сверху тупо на паузу
ставим (она кстати давно уже реализована).
Так-как в этой игре не предусмотрено смотреть камерой вверх,
то открытому миру сверху даже рендер отключать не надо,
как максимум источники света. Ну а камеру не надо переключать,
просто перенести в нужные координаты. Но возможно лучше и
переключать на другую, хз, тут подумать надо.

Randomize 13.10.2020 15:18

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Переключаем часть свитча, рендерится другая часть
Без RenderEntity было недостижимо. (в 3д)

Crystal 13.10.2020 17:18

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Вложений: 1
Цитата:

Сообщение от Randomize (Сообщение 317748)
Без RenderEntity было недостижимо. (в 3д)

Короче мож я чёто насвистел, посмотри сам.
10 лет блитц не видел, уже впадлу вспоминать чё там к чему.
Помню, что реализовал через свитч, при чём вторая часть его за рендер ворлдом.

Видео работы в архиве поста.
Вот прям из своего проекта код теме:


Код:

Graphics3D 1280,1024,32,1
SetBuffer BackBuffer()

Global ScreenSave#=0
Global ScreenZapusk#=0
Global ScreenNumber=1
Global ScreenShooting=0


Global Start=0
Global Sector#=2

font=LoadFont("courier",20)
font2=LoadFont("courier",100)
Dim Buttons(3)
Global kn1=LoadAnimImage("GUI-Button2.bmp",100,40,0,3)
Global kn2=LoadAnimImage("GUI-Button2.bmp",100,40,0,3)
Global kursor=LoadImage("GUI-Cursor.png")


Global Dom1=LoadMesh("Dom1.3DS")
HideEntity Dom1
Global Dom1_krisha=LoadMesh("Dom1_krisha.3DS")
HideEntity Dom1_krisha
Global Dom1_dver=LoadMesh("Dom1-dver.3DS")
HideEntity Dom1_dver

Global Di=LoadMesh("D.3DS")
HideEntity Di

Global God

Type Dom1
Field ent
Field ent_k
Field ent_d
Field pick#
Field Delet
End Type

Type Di
Field ent
Field pick#
End Type


Function ScreenShot(filename$)
If ScreenZapusk#=1 Then
If FileType(filename$+ScreenNumber+".BMP")=1 Then ScreenSave#=1
If FileType(filename$+ScreenNumber+".BMP")=0 Then ScreenSave#=0
If FileType(filename$+ScreenNumber+".BMP")=2 Then ScreenSave#=0
ScreenZapusk#=0
End If
If ScreenSave#=0 Then
SaveBuffer(FrontBuffer(),"ScreenShots\ScreenShot"+ScreenNumber+".bmp")
ScreenShooting=0
ScreenNumber=1
End If
If ScreenSave#=1 Then
ScreenNumber=ScreenNumber+1
ScreenZapusk#=1
End If
End Function



Function ConstructionsControl()
For c.Dom1=Each Dom1
If EntityDistance(c\ent_k,God)<7 Then
EntityAlpha c\ent_k,0.3
Else
EntityAlpha c\ent_k,1
End If
Next
End Function



Repeat
Select Sector#
Case 1

      Cls()


God=CreatePivot()
PositionEntity God,0,5,-3
camera=CreateCamera(God)
RotateEntity camera,40,0,0

light=CreateLight()
TurnEntity light,30,20,0

plane=CreatePlane()
EntityPickMode plane,2
planeTexture=LoadTexture("TEX38.BMP")
ScaleTexture planeTexture,2,2
EntityTexture plane,planeTexture
 

  Repeat

If Start=0 Then
Start=1
LoadMap("TestMap.sel")
End If

ConstructionsControl()

If KeyHit(88) Then
ScreenZapusk#=1
ScreenShooting=1
End If
If ScreenShooting=1 Then
ScreenShot("ScreenShots\ScreenShot")
End If

If KeyDown(32)=True Then TurnEntity God,0,-1,0
If KeyDown(30)=True Then TurnEntity God,0,1,0
If KeyDown(31)=True Then MoveEntity God,0,0,-0.05
If KeyDown(17)=True Then MoveEntity God,0,0,0.05



If Buttons(1)=1 Then
Sector#=2 Buttons(1)=0
Start=0
WorldClear()

      FreeEntity God
      FreeEntity plane
      FreeEntity light
End If


      UpdateWorld()
      RenderWorld()

SetFont font

      RefreshButton(kn1,1150,12,"Menu",1)
      DrawImage kursor,MouseX(),MouseY()

      Flip

     
  Until Sector#=2


Case 2


  Cls()

    camera=CreateCamera()
    PositionEntity camera,0,3,0
        CameraFogMode camera,1
        CameraFogRange camera,.1,30

    plane= CreatePlane()
   
    pltex=LoadTexture("TEX38.BMP")
    ScaleTexture pltex,2,2
    EntityTexture plane,pltex
      FreeTexture pltex

    lit=CreateLight()
 
     

  Repeat
 

      If KeyHit(1) And Sector#=2 Or Buttons(2)=1 And Sector#=2 Then exitprog=True Buttons(2)=0
      If  Buttons(0)=1 Then Sector#=1 Buttons(0)=0


      If exitprog=True End


      UpdateWorld()
      RenderWorld()

SetFont font

          RefreshButton(kn2,GraphicsWidth()/7,GraphicsHeight()/2.5,"Game",0)
      RefreshButton(kn2,GraphicsWidth()/7,GraphicsHeight()/2.2,"Exit",2)

SetFont font2

          Color 230,230,230
      Text GraphicsWidth()/5,GraphicsHeight()/5,"SCORCHED EARTH"
      DrawImage kursor,MouseX(),MouseY()

      Flip
  Until Sector#=1
      FreeEntity camera
      FreeEntity plane
      FreeEntity lit


End Select


Until  exitprog=True

Function RefreshButton(ImBtn,x,y,txt$,n)
mx=MouseX() : my=MouseY()
MHit=MouseDown(1)
If RectsOverlap(x+2,y+2,ImageWidth(ImBtn)-4,ImageHeight(ImBtn)-4,mx,my,1,1) Then
    f=1
    y2=0
    If MHit=True Then
          f=2
          y2=2
          Buttons(n)=1
    EndIf
Else
    f=0
    y2=0
EndIf
DrawImage ImBtn,x,y,f
Color 0,0,0
Text x + 0.5 * (ImageWidth(ImBtn) + 4 - Len(txt$) * FontHeight() * 0.5), y + 0.5 * (ImageHeight(ImBtn) - 4 - FontHeight()) + y2, txt$
End Function






Function LoadMap(Name$)

stroitelstvo#=0

file=ReadFile(Name$)

While Not Eof(file)

Load = ReadInt(file)
Select Load

        Case 1
                c.Dom1=New Dom1
                c\ent=CopyMesh(Dom1)
                c\ent_k=CopyMesh(Dom1_krisha)
                c\ent_d=CopyMesh(Dom1_dver)

                c\pick#=ReadFloat(File)
                a1#=ReadFloat(File)
                a2#=ReadFloat(File)
                a3#=ReadFloat(File)
                a4#=ReadFloat(File)
                a5#=ReadFloat(File)
                a6#=ReadFloat(File)       
               
                a7#=ReadFloat(File)
                a8#=ReadFloat(File)
                a9#=ReadFloat(File)
                a10#=ReadFloat(File)
                a11#=ReadFloat(File)
                a12#=ReadFloat(File)
               
                a13#=ReadFloat(File)
                a14#=ReadFloat(File)
                a15#=ReadFloat(File)
                a16#=ReadFloat(File)
                a17#=ReadFloat(File)
                a18#=ReadFloat(File)       
 
                ScaleEntity c\ent,0.01,0.01,0.01
                PositionEntity c\ent,a1#,a2#,a3#
                RotateEntity c\ent,a4#,a5#,a6#
               
                ScaleEntity c\ent_k,0.01,0.01,0.01
                PositionEntity c\ent_k,a7#,a8#,a9#
                RotateEntity c\ent_k,a10#,a11#,a12#

                ScaleEntity c\ent_d,0.01,0.01,0.01
                PositionEntity c\ent_d,a13#,a14#,a15#
                RotateEntity c\ent_d,a16#,a17#,a18#

        EntityPickMode c\ent,2

        Case 2

                co.Di=New Di
                co\ent=CopyMesh(Di)

                X2#=ReadFloat(file)
                Y2#=ReadFloat(file)
                Z2#=ReadFloat(file)
                P2#=ReadFloat(file)
                YA2#=ReadFloat(file)
                R2#=ReadFloat(file)
                SX2#=ReadFloat(file)
                SY2#=ReadFloat(file)
                SZ2#=ReadFloat(file)
                co\pick#=ReadFloat(file)

                PositionEntity co\ent,X2#,Y2#,Z2#
                ScaleEntity co\ent,0.01,0.01,0.01
                RotateEntity co\ent,P2#,YA2#,R2#


End Select

Wend
CloseFile(file)

End Function


Function WorldClear()

Cls

For d.Dom1 = Each Dom1
FreeEntity d\ent
FreeEntity d\ent_k
FreeEntity d\ent_d
Delete d
Next

For do.Di = Each Di
FreeEntity do\ent
Delete do
Next
End Function



Добавил: вот смотрю я код, а там функция ВорлдКлир.
По ходу не исключал из рендера, а загружал и удалял объекты.

ABTOMAT 13.10.2020 22:07

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Randomize (Сообщение 317746)
В блице мы просто скрывали пивот и за ним скрывалась вся иерархия.
Думаю тут можно делать тоже самое, только камеру переключи.

Всё верно, именно так и можно делать.

Если GameObject'у сделать SetActive(false) то он выключается из иерархии. Перестаёт рендериться, привязанные к нему скрипты перестают работать (возобновляются после SetActive(true)).

Можно сделать в корне сцены родительские объекты, к которым будут крепиться те, что относятся к соответствующей части игры (меню, мир, битва), это и будут "слои".

Чтобы не загружать заново ассеты, можно загрузить один раз и держать их образцы для клонирования.

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

Crystal 13.10.2020 22:39

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от ABTOMAT (Сообщение 317750)
Всё верно, именно так и можно делать.

Если GameObject'у сделать SetActive(false) то он выключается из иерархии. Перестаёт рендериться, привязанные к нему скрипты перестают работать (возобновляются после SetActive(true)).

Можно сделать в корне сцены родительские объекты, к которым будут крепиться те, что относятся к соответствующей части игры (меню, мир, битва), это и будут "слои".

Чтобы не загружать заново ассеты, можно загрузить один раз и держать их образцы для клонирования.

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

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

ABTOMAT 13.10.2020 23:38

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

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

Ты имеешь в виду, каждый объект в Update проверяет каждый кадр, не пора ли ему удолиться? Это не самый производительный вариант, потому что проверка будет идти каждый кадр. Это не очень хорошо.

Вообще такое можно сделать 2 способами:

Через эвенты.

1. Создаёшь UnityEvent battleOver и вызываешь его battleOver.Invoke() в момент, когда битва завершена.
2. Каждому объекту, который имеет отношение к, в OnEnable делаешь подписку (лайк, колокольчик) на этот эвент:

PHP код:

battleOver.AddEventListener(() => {Debug.Log("Я отреагировал на завершение битвы!");}); 

Ну и соответственно в листенере можешь делать то действие, какое надо при завершении битвы (например, удалять этот объект).

Вариант с эвентами хорош тем, что можно создать эвенты на все ключевые события, а потом объекты "подписывать" на них по мере надобности.


Второй способ через списки:

Иметь список всех однотипных объектов и при надобности перебирать их все.
public static List<Monster> allMonsters = new List<Monster>(); // Глобальный список

PHP код:

Monster.allMonsters.Add(this); // Каждого монстра при создании (OnEnable) заносим в список 

PHP код:

Monster.allMonsters.Remove(this); // Каждого монстра при удалении (OnDisable) убираем из списка 

Соответственно при создании и удалении у тебя автоматом будут заноситься или убираться монстры в список.
Если тебе надо удалить всех монстров (или что-то с ними сделать) то перебираешь список:

PHP код:

Monster.allMonsters.ForEach(monster => {Debug.Log($"А мы тут монстров перебираем: {monster}!");}); 


Способ со списками более простой, но я бы советовал раздуплить как работают эвенты, полезная штука.

pax 14.10.2020 00:01

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от ABTOMAT (Сообщение 317750)
Можно сделать в корне сцены родительские объекты, к которым будут крепиться те, что относятся к соответствующей части игры (меню, мир, битва), это и будут "слои".

Я бы предложил настроить слои самим объектам (https://docs.unity3d.com/Manual/class-TagManager.html). Сделать для каждой "сцены" свою камеру. В каждой камере отключить слой(слои), которые она не должна рендерить. А дальше просто включал бы только одну камеру нужной "сцены". Свободных слоев более 20, если потребуется настраивать коллизии физики слоями, то тоже должно хватить...

Arton 14.10.2020 01:07

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Randomize (Сообщение 317748)
Без RenderEntity было недостижимо. (в 3д)

Ты имел ввиду HideEntity?

Цитата:

Сообщение от Crystal (Сообщение 317749)
Помню, что реализовал через свитч, при чём вторая часть его за рендер ворлдом.

Свитчи в Блице, это кейсы.
В твоём коде они только в функции LoadMap, остальное на If'ах.


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

На сколько большая карта предполагается?
Потому что если у тебя вид сверху, всё относительно «мелкое», много повторяющихся элементов?
Я бы так и поступил, разместил всё в одной сцене.
Pax предложил отличную идею слоёв (как я сам не догадался).

По моим наблюдениями, в подобных играх (если я тебя правильно понимаю) далеко не всё содержимое мира сохраняют.

Crystal, не забывай пожалуйста прятать свои простыни кода под спойлер :(

P. S. В общем тут уже написали всё то что я хотел написать вчера, но почему-то забил.

Crystal 14.10.2020 06:07

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Ты имеешь в виду, каждый объект в Update проверяет каждый кадр, не пора ли ему удолиться? Это не самый производительный вариант, потому что проверка будет идти каждый кадр. Это не очень хорошо.
Не производительно что конкретно? Обращение к переменной другого скрипта?
У меня максимум объектов 50 могло бы так ожидать смерти читая переменную в отдельном статике.

Цитата:

Я бы предложил настроить слои самим объектам (https://docs.unity3d.com/Manual/class-TagManager.html). Сделать для каждой "сцены" свою камеру. В каждой камере отключить слой(слои), которые она не должна рендерить. А дальше просто включал бы только одну камеру нужной "сцены". Свободных слоев более 20, если потребуется настраивать коллизии физики слоями, то тоже должно хватить...
Выше в посте №4 я это уже предлагал:
https://forum.boolean.name/showpost....45&postcount=4

на самом деле в моём случае вообще не надо ничего, кроме перемещения камеры
на этаж с нужным уровнем.
Генерируем поле нужного размера, расставляем монстров и игрока,
телепортируем камеру в нужные координаты.
После боя возвращаем камеру обратно,
а поле с игроком и монстрами удаляем.
Нужно только источники света на локации выше выключить.

Цитата:

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

Цитата:

На сколько большая карта предполагается?
Открытый бесшовный мир, на сколько сил хватит.

Цитата:

Потому что если у тебя вид сверху, всё относительно «мелкое», много повторяющихся элементов?
Я бы так и поступил, разместил всё в одной сцене.
Вот я задумался перенести бой в минусовые Y координаты под открытым миром.

Цитата:

Crystal, не забывай пожалуйста прятать свои простыни кода под спойлер
Пробовал вчера offtop, клянусь святыми покемонами он вчера не работал,
только что в посте проверил, и работает! Вчера форум мне в посте проявлял тег, не читая его.

Randomize 14.10.2020 08:31

Ответ: Очередные вопросы от меня по игровой логике и скриптингу
 
Цитата:

Сообщение от Arton (Сообщение 317756)
Ты имел ввиду HideEntity?

Нет. Что имел то написал.
Осуществимо было при использовании FastExt или AShadow.


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

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