Beiträge von Tomura

    Was aber seltsam ist, das nur der Server die PlayerController für die Clients hat nicht die Clients selber.


    Ist das normal?

    Ja.

    Der PlayerController existiert nur auf der Maschine des Besitzers (der Player der vom PlayerController repräsentiert wird) und auf dem Server (da der ja alles Kontrolliert).

    Player spezifische Daten die auf allen Maschinen verfügbar sein sollen, sollte man in ein Kind der PlayerState Klasse packen.

    Moin,


    also das Problem steht schon im Titel. Wenn ich mir z.B. Tutorials zu Materials ansehe, so wird das bei so gut wie allen innerhalb von maximal 5 Sekunden angezeigt wie das Materials aussieht. Bei mir dauert das aber manchmal bis zu 2 Minuten. Und das compiling bzw. wenn ich auf Save oder Apply drücke, dauert dass auch ziemlich lange. Das ganze stört ziemlich den Workflow. Hat da wer ähnliche Erfahrungen oder Probleme?


    Danke schon mal im voraus :)

    Es kommt etwas darauf an was du machst, aber bei so typischen Dingen wie z.B. ein Material in dem nur Texturen in gewisse Outputs geroutet werden, würde ich empfehlen paar Typische Master-Materials mit Parametern zu erstellen, und dann nur über Material Instances zu Arbeiten:

    Das hat folgende Vorteile:

    • Du musst nicht Kompilieren, solange du das Master-Material nicht bearbeitest
    • Der Re-Use, des selben Materials sorgt dafür dass die Instances auf das selbe Shader Kompilat zugreifen, statt dass du viele Shader laden musst, die funktional eigentlich gleich sind.
    • Wenn du das Master Material verbesserst, wirkt sich die Verbesserung gleich auf alle instances aus.

    Falls das keine Möglichkeit ist hilft nur bessere Hardware.

    Eine schnelle SSD, ein schneller CPU (vorallem einer mit vielen cores/threads) machen das kompilieren schneller.


    Edit: Z.B. wäre hier mal ein Beispielhaftes Master-Material, was im Grunde für so gut wie jedes Material as Substance Painter Funktioniert. Als zusatz feature habe ich noch min/max Roughness Parameter eingefügt, um zur Not die Roughness in-engine anpassen zu können, anstatt noch mal in ein anderes Tool zu gehen, um es anzupassen.



    Hast du so etwas einmal kannst du einfach in Material instances ohne zu kompilieren Materials des selben Formats erstellen:

    Um das richtig zu verstehen.

    Pawn -> MyCharacter (Actor)?

    Ja. Ein Character ist eine Art Pawn, ein Pawn ist aber nicht unbedingt ein Character (z.B. könnte ein Pawn auch ein Spectator Pawn sein).


    Ich glaube das könnte das Problem dabei sein.

    Den PlayerController brauche ich vor dem laden der ganzen Widgets (Menüs), damit diese entsprechend zugeteilt werden können.

    An der Stelle wüsste ich auch nicht wie ich die ganzen Menüs auslagern sollte, denn die werden eben zum spielen gebraucht.

    Also du solltest unbedingt mal recherchieren wie das Gameplay Framework von UE4 abläuft:

    Ganz grob gesagt:

    Ganz oben ist die GameEngine diese existiert ab dem Start des Spiels, genauso die GameInstance, diese könnt nach der Engine. Beim Start wird eine Map/World geladen, die World lebt solange wie das Level existiert. Die Welt halt einen GameMode, welcher erzeugt wird nachdem die Settings der Welt verfügbar sind. Auch wird für jeden Spieler ein PlayerController erzeugt (+ das was noch so dazugehört), basierend darauf was im GameMode eingestellt ist. Der PlayerController spawnt dann einen Pawn und wenn der Pawn fertig gespawnt ist, dann wird dieser Possessed.


    Jetzt muss man sich das mal anschauen:

    1) Controller spawnt einen Pawn

    2) Pawn ist fertig gespawnt => Pawn->BeginPlay

    3) Controller übernimmt pawn d.h. der Controller des Pawns wird gesetzt => Pawn->Possessed


    D.h. wie ich gesagt habe, nimm das Possessed Event. Es gibt hier auch keine echte Verzögerung, das das ganze normalerweise im selben Frame stattfindet.


    Folgendes:

    Der Player Controller existiert vor dem Pawn. Der Pawn wird zuerst sauber gespawned inklusive BeginPlay Event. Erst danach wird der Pawn possessed, da erst hier alles was beim Spawn passieren soll passiert ist.

    Das heißt benutze nur Begin Play für Dinge die gemacht werden sollen nachdem der Pawn gespawnt ist und nur das innere des Pawns betrifft. An diesem Punkt hat der Pawn noch kaum Infos.

    Das mit den Breakpoints habe ich überall getestet.

    Wenn ich den Breakpoint auf CastToPlayerController setzte, wird dieser sofort ausgelöst.

    Setze ich den Breakpoint auf SetPlayerController dann lädt der bis zur unendlichkeit (das Problem was ich derzeit habe).

    Dann ist es doch klar. Der Cast schlägt fehl und du kommst nicht weiter. Also ist der Input des Casts Null oder ein PlayerController mit falscher Klasse. Da du in Begin Play bist, ist der Player Controller wahrscheinlich null, da dein Pawn noch nicht Possessed wurde. Also schieb die ganze Logik in das Possessed Event.

    Gibt es eine Möglichkeit eine Art "STOP" einzubauen bei der etwas ausgeführt und dann gestoppt wird, bis etwas anderes geladen ist, damit dann wenn geladen, nach dem Stop weiter geladen wird?

    Wenn du das machen musst machst du etwas falsch. Informiere dich über die Events die es gibt und den generellen Ablauf des Gameplay Frameworks. Was du vorschlägst ist eine riesige Verschwendung von Performance.

    PS: Könnt ihr mir eine grobe Auflistung schreiben, also von der Logik her, wie genau ein perfekter Start aussieht?

    Z.B.

    Wenn du den Perfekten Start eines Levels selbst programmieren musst, machst du etwas falsch. Wie gesagt die UE4 bietet schon ein Gameplay Framework, du musst nur wissen welche Events du Implementieren musst und welche Funktionen du überladen und erweitern musst.
    Von daher, wie ich schon öfter sage. Recherchier genau wie die Unreal Engine funktioniert, das kann auch paar Wochen/Monate dauern. Am einfachsten ist es natürlich einfach den C++ Code grob anzuschauen, aber es sollte auch z.T. erklärt ein. Wüsste aber nicht wie gut Epics Doku ist.


    BTW falls du Multiplayer machst:

    Das Possessed Event läuft nur auf dem Server. D.h. du musst für Client seitige Dinge auch Client Funktion aufrufen. In vielen Fällen geht auch das Restart Event, dort ist 100% klar dass alles abgehandelt wurde, aber wenn ich mich richtig erinnere feuert es nur beim Spawn des Pawns aber nicht, falls dieser mitten in seiner Lebenszeit possessed und unpossessed wird. Man könnte ja ein Spiel so programmieren, dass Spieler andere Pawns übernehmen oder die Kontrolle abgeben, etc. dann wird natürlich kein Restart Event gefeuert, weil der Pawn ja schon "gestartet" wurde.

    Grundsätzlich ist der Unterschied - wie Epic auch schreibt - daß der PlayerController immer erhalten bleibt - also auch wenn der pawn vernichtet wird. Ich würde so wenig wie möglich in den Player Controller packen - weil der eben wie gesagt auch erhalten bleibt wenn der Pawn zerstört ist - das kann das Spiel durchaus entlasten. Aber wenn es Sinn macht den PlayerController zu nehmen - eben weil man etwas durchgehend haben will - dann muss man das machen.

    Dem kann ich zustimmen. Mach dir einfach Gedanken, wo es hin passt. Bei Player Input wäre es z.B. schon gut dass es im Controller ist, da das Verhalten des Inputs sich ja verändern kann je nach Status des Players. Also z.B. wenn der Player im Options Menü ist, soll er ja nicht seinen Charakter steuern. So hast du eine recht guten architektorische Zwischenstufe um im Nachhinein zusätzliche Checks einzubauen die logisch eher dem Spieler gehören, als dem Charakter.

    Generell macht es mMn sinn das was den Spieler betrifft auch im Controller zu machen und das was den Pawn betrifft im Pawn und die Schnittstellen zwischen den beiden zu einfach wie möglich zu halten. So ist, wenn du nach dem Code einer bestimmten Funktionalität suchst sehr klar wo du schauen musst.


    BTW wenn du den Player Controller benötigst, solltest du auf der Pawn Seite nicht Begin Play nutzen. Das Funktioniert nur in Ausnahmefällen. Es sollte ein OnPossessed Event geben. Dies signalisiert, dass der Pawn von einem Controller übernommen wurde. Begin Play feuert aber gleich nachdem der Pawn gespawned wurde, aber noch nicht unbedingt Possessed.

    Dein Fehler kommt wahrscheinlich daher, dass der Pawn noch gar keinen Player Controller hat. Das kannst du recht einfach rausfinden indem du in deinen Blueprint reingebuggst über Breakpoints und Watchers.

    Oder einfach das Spiel packen und testen, da der Bug nur übern Play-Button in UE4 zu existieren scheint^^

    Was auch funktionieren könnte ist wie im Bug report den UE4Editor.exe mit dem argument "-game" zu starten (z.B. über ein .bat oder eine Verknüpfung.)


    Also wie folgt:

    <pfad zu UE4Editor.exe> <pfad zu deinem *.uproject file> -game


    statt der "<...>" entsprechenden Pfad angeben. Nicht vergessen dass "" nötig sein kann, falls der Pfad Leerzeichen oder sonstiges enthält.

    Damit startet die Engine wie ein normales Spiel, benötigt aber keine cooked Assets.

    Find ich jetzt aber nicht verwerflich. Sind ja die gleichen Rahmenbedingungen wie momentan bei Epic vs Google und Apple.

    Ist ähnlich. Hier ist es aber schwieriger in die Richtung zu argumentieren, da man ja trotzdem alternative Stores nutzen kann und darf, während das auf einem iPad/iPhone nicht möglich ist. Es kommt drauf an in welcher Macht-Position man im Markt steht, da die Gesetze das Ziel haben einen fairen Wettbewerb zu fördern und Monopole oder ähnliches (z.B. auch Preisabstimmungen zwischen Firmen, um sich gegenseitig einen Vorteil zu verschaffen) zu verhindern. Deswegen ist sowas oft eine schwere Sache, die oft mehrere längere Prozesse und Prüfungen benötigt.


    Mein Wissen dazu ist aber auch recht grob, aber ich muss hin und wieder Mal Schulungen zu solchen Themen anhören/durcharbeiten, weil solche Themen durchaus im Arbeitsalltag vorkommen können in einer größeren Firma. Sagen wir mal man zwingt als klarer Marktführer einen Händler, dass er Konkurrenzprodukte nicht anbieten und bewerben darf, wenn er das Produkt des Marktführers anbieten will, dann kann es durchaus ein solches Thema werden, wenn die restlichen Rahmenbedingungen stimmen.

    [...]

    Klar kann man jetzt über Apple, Google, Sony und Microsoft jammern - alles Ausbeuter und Monopolisten - aber die haben nunmal die Hardware, die Plattformen und ein Ökosystem mit vielen Kunden die auch wirklich Geld ausgeben geschaffen. Da kommt mir der Spruch "Die Hand beissen die einen füttert" in den Sinn. Klar findet die 30% kaum einer wirklich "fair" oder "gerecht", aber ganz ohne wir es nunmal nie gehen. Das ist wie wenn man auf der Strasse 100 leute fragt ob man morgen die Steuern abschaffen sollte, da sagen bestimmt die meisten sofort "ja" und würden sich morgen wundern warum es keine Polizei, Feuerwehr, Krankenhäuser und Strassen mehr gibt.

    [...]

    Das Problem bzw. die Argumentationsgrundlage ist die folgende:

    Das Problem was Epic hat ist, dass eine App auf dem App store auch für in-app-purchases 30% abgeben muss. Dies kommt daher, dass der einzige Zahlungsdienstleister der erlaubt ist, Apple ist. Technisch könnte man ja als Entwickler auch einen anderen Zahlungsdienstleister anbieten, was aber verboten ist. Genauso ist es auch verboten innerhalb der App darauf hinzuweisen. Ein ähnliches Verfahren läuft/lief zwischen Spotify und Apple, auch hier geht es darum dass Spotify gezwungen ist für ein Abo, was über die App abgeschlossen wurde 30% an Apple zu geben, nur weil Spotify gezwungen ist Apple als Zahlungsdienstleister zu nutzen. In falle von Spotify macht es dies noch schlimmer, da Apples eigenen Streamingdienste ihr Abo ohne die 30% anbieten können und somit einen unfairen Wettbewerbs und Preisvorteil haben können.

    https://ec.europa.eu/commissio…rner/detail/en/ip_20_1073


    Es geht also nicht einfach darum, dass Apple seinen Service billiger macht, sonder darum, dass Apple seinen Service aufzwingt und sich somit eine Monopolstellung verschafft. So die grobe Argumentation. Ob das nun rechtlich wirklich so ist wird sich zeigen. Ich fände es aber schon schön wenn das ganze Apple Ökosystem offener wird.

    Nochmal ein Nachtrag, da hier mMn etwas am Thema vorbei argumentiert wurde.


    Mit dem Kauf der Programme hast du nicht die Nutzungsrechte an der Marke gekauft. Daher solltest du definitiv klären ob du die Marke in deinem Trailer nutzen darfst oder nicht. Du solltest auch schauen ob es gewisse Richtliniengibt zur Darstellung der Marke (Brandguide, Abstände, Farben, etc.).


    Auch ist es nicht so, dass wenn du z.B. "Unreal Engine" in deinem Trailer nennst, Werbung für die Unreal Engine machst. Der Gegenteil ist hier eher der Fall: Du nutzt die Marke "Unreal Engine", um Werbung für dein Produkt zu machen.


    TLDR: Du musst nach Erlaubnis fragen und dich mit deren Regeln vertraut machen.


    BTW: Es gibt auch viele Firmen die ihre Guidelines zur Nutzung der Trademark öffentlich bereitstellen: Hier z.B. die Unreal Engine (nicht das Epic Logo, dies ist wahrscheinlich schwieriger zu nutzen, da das Epic Logo die Firma selbst repräsentiert):

    https://www.unrealengine.com/en-US/branding

    Z.B. steht hier unter anderem, dass du ein Formular ausfüllen und an Epic schicken musst. Epic schreibt hier auch klar, dass sie die Nutzung der Trademark untersagen können, falls das Produkt nicht mit Epics eigenem Image konform ist.


    Es gibt viele Firmen die sowas haben. Wenn du es nicht findest, kannst du einfach nachfragen.

    Also std::string funktioniert nicht zwischen interop Grenzen, da ein C# System.String und ein C++ std::string einen anderen Aufbau haben. Daher ist char* schon der richtige interop freundliche typ. Kenne mich leider nicht zu gut in dem Gebiet aus, also kann ich nicht mehr beitragen.

    Ich würde mal einfach vorschlagen auf auf stackoverflow zu suchen.

    Du solltest wenn du an der Code/BP stelle nicht 100% sicher sein kannst, dass in der Variable auch etwas ungleich NULL steht immer zuerst prüfen ob der Inhalt der Variable Valide ist.

    Dazu kannst du den IsValid-Node nutzen. Davon gibt es 2 Varianten. Eine gibt einen Bool zurück, eine ist direkt ein Branch. Den letzteren würde ich eher empfehlen, da du so sicherstellst, dass der Execution Path klarer ist.


    Is Valid checkt ob eine Objekt variable nicht Null ist, oder der inhalt nicht auf "pending Kill" gesetzt ist und demnächst vom Garbage Collector gekillt wird.


    Wie du dann vorgehst ist dir überlassen. Du musst festlegen was passieren soll, daher auch die Fehlermeldung. Dazu hast du folgende Möglichkeiten:

    a) Die Ausführung der Funktion endet beim Fehlschlag. Dies ist sinnvoll wenn die Ausführung ohne validen inhalt keinen Sinn ergibt.

    b) Der Grund des Fehlers wird behoben. D.h. wenn z.B. eine Objekt Variable die geprüft wurde nicht Valid ist, dann könnte man ja einfach ein neues Spawnen und dann weiter machen. (Macht natürlich nicht immer sinn)

    c) Man geht über auf eine Ersatzlösung die das Objekt nicht benötigt. (Vielleicht gibt es ja eine andere Lösung oder eine Approximation)

    d) Man kommt in einen ganz anderen Pfad. Dies ist sinnvoll wenn die Validität das verhalten der Funktion grundlegend beeinflussen soll.

    e) Es wird ein Fehler ausgespuckt, am besten mit einer Fehlermeldung die genügend Informationen hergibt um das Bug Hunting so einfach wie möglich zu machen. (In der Releaseversion gibt es die Meldung nicht.) Kleiner Tipp: Je kritischer der Fehler desto nerviger muss es sein, damit man auch einen Anreiz hat den Bug zu fixen. (Hab aber auch mal mit Experten zu tun gehabt, die das ganze fixen indem sie die Fehlermeldung raus programmieren, Problem war natürlich, dass der Bug nicht weg ist ...)


    Bei deinem Problem kann ich mir vorstellen, dass du Ghost Building nicht vernünftig gesetzt hast, bzw. die RTS Cam versucht auf GhostBuilding zuzugreifen, nach dem es zerstört wurde, aber noch kein neues Ghost Building gespawnt wurde.

    Eine Struct kann auch als Array gesetzt werden. Dann sind alle Elemente eine Struct.

    Aber wir können ja auch weg vom Struct. Das selbe ist ja auch mit ein normalen Array. zB Float.

    Sagen wir mal so, 10 Elemente als Float sind in ein Array und das Array ist repliziert. Die 10 Elemente werden alle mit ein ForEachLoop gelesen. Wird jetzt 10 mal einzelnd repliziert, oder nur einmal das ganze array repliziert und dann gelesen. Evtl ist die Frage auch überflüssig, wenn alle Elemente, egal wie, einzeln gesendet werden.

    Ich glaube, Tomarr hat es einfach falsch verstanden, weil die ausdrucksweise etwas holprig ist.

    Bei dem was du beschreibst handelt es sich um einen "Array of Structs".

    Bei dem Satz "Eine Struct kann auch als Array gesetzt werden" könnte man denken, dass du ein struct in ein Array wandeln willst, oder sonst etwas. Es gibt sogar sprachen wo es geht, wobei dort die Array sich eher wie Maps verhalten (Zugriff über einen Key, statt einem Index.)

    Moin, hab das sicherlich schon mal gefragt, aber irgendwie bin ich mir unsicher bei mein jetziges Verfahren.

    Wenn ich das richtig beobachtet habe, werden alle Variable in einer Struct repliziert, egal ob man nur eine Variable verwendet.

    Aber was ist mit ein Array? Wenn ich ein Array komplett durchlaufe, zB eachLoop, werden alle Elemente hintereinander repliziert, oder wird einmal ein Array repliziert und dann local durchsucht?


    mfg EKI

    Ist etwas schwer für mich das genau zu erklären aber folgendes weiß ich:

    Variablen Replication findet soweit mir bekannt ist nicht statt, wenn sich ein Wert ändert, sondern, wenn ein "Dirty" state festgestellt wird. D.h. wenn der server, während er prüft, was er replizieren muss, merkt, dass sich die Variable zum vorher replizierten Stand verändert hat. Genrell müsste der Check am Ende des Frames sein, d.h. es zählt der Status den deine Variable am Ende des Frames hat.


    Soweit ich mich erinnern kann sollte auch die Array Replication halbwegs intelligent sein und nicht immer alles replizieren den kompletten Array übertragen, sondern nur die Änderung. [Quelle] Da müsstest du aber noch einmal Recherchieren. Bei structs sollte es auch so sein dass nur die member übertragen werden die sich verändert haben. [Quelle]

    Sind beides aber keine direkten Epic aussagen, aber jeweils von Entwicklern die recht fit in UE4 sind.

    Das ganze kann dir aber in Blueprint egal sein, denn auf die Tiefe, welches Element oder welcher Member in der entsprechenden Replikation verändert wurden hast du keinen zugriff. Als BP Entwickler weißt nur nur, dass entsprechendes struct/array repliziert wurde.


    Generell versuche ich persönlich Array Replication zu vermeiden, außer es handelt sich um etwas was nur wenige Male repliziert wird.

    Danke für eure Antworten.


    Janinus habe jetzt eine billige Alternative gefunden: über "Select Object", darin kann man Grafiken auswählen.

    https://docs.unrealengine.com/…s/SelectObject/index.html

    EDIT: Mist, ich sehe gerade da kann man nur 2 auswählen :(

    Über den allgemeinen Select Block solltest du eigentlich so viele Outputs bekommen wie dein Enum Einträge hat. Einfach aus dem input wo das ganze rein soll einen Pfad rausziehen und einfach "Select" auswählen (ohne Object oder so)

    Dann sollte ein Select Block erscheinen der keinen typen als input hat. Dort schliest du dann einen Pfad von Typ deines Enums an und es sollten dann entsprechende zusätzliche inputs erscheinen.


    https://docs.unrealengine.com/…ilities/Select/index.html

    Also was du willst gibt es so nicht direkt. Also müsstest du dies in eine Funktion packen.

    Entweder kommt dies A) In das BP was deine Quests Managed. B) In eine Blueprint Function Libary.


    An sich glaube ich aber dass dein Ansatz allgemein nicht sehr ideal ist:

    Auch wenn es blöd ist, dass du dein Quest System Ändern müsstest folgender Vorschlag:


    Du nutzt Objekt Orientierte Programmierung mal voll aus:

    Statt eines Structs sollten deine Quests Objects sein. D.h. Du erstellst zuerst eine Blueprint Klasse basierend auf dem Typ Object (oder Actor, falls du Replication benötgist). Dieser fügst du entsprechende Eigenschaften (Variablen) hinzu, wie z.B. das Icon, Quest Titel, Quest Text, etc. Dort kannst du auch das Verhalten programmieren was jede Quest hat oder entsprechende Schnittstellenfunktionen, falls nötig.

    Dies ist deine Basis Klasse für alle Quests.


    Nun erstellst du von dieser Blueprint Klasse neue Child Klasses. Diese benennst du nach deinen Quest Typen. Dort kannst du dann schon das entsprechende Icon Setzen. Auch hier kannst du die Logik die jede Quest des Unter-Typs sich teilt, programmieren. Eine Transport Quest z.B. hat ja durchaus gemeinsamkeiten, das hilft dir dass du ensprechenden Code nur an einer Stelle ändern musst.


    Wenn nun eine Quest Instanz erzeugen willst. Dann erzeugst du einfach ein Object vom Typ des Quests über "Construct Object From Class" und setzt nur noch Titel und Beschreibung. Da das Icon auch eine Eigenschaft der Quest ist, kannst du diese natürlich auch pro Instanz ändern.


    Wo ist der Vorteil?

    Die Logik der Quest ist in dem Typ des Quests enthalten, damit kannst du woanders Logik entfernen und dir mehr Übersicht schaffen.

    Das System arbeitet über Objekte, d.h. rein logisch sind alle variablen die auf die Quest Zeigen, zeiger auf die Quest. D.h. ein "==" bedeutet "ist es die selbe Quest" während ein "==" bei einem struct fragt ob es "die gleiche Quest" ist.

    Du hast dadurch auch viel Modularität und wenig Code Duplikation, was dir den Wartungs aufwand verringert, dadurch dass du nur einmal Programmieren musst. Damit sind verbesserungen gleich auch auf alle unter Klassen verteilt.

    Erweitern des Systems geht einfach durch erstellen eines neuen Kindes. Entfernen geht durch löschen des entprechenden Quest BP.


    Wahrscheinlich wird das etwas Arbeit für dich sein, weil ich glaube dass du dich etwas einarbeiten müsstest in OOP und die denkweise, aber ich glaube dass es sich lohnen würde.

    Ich habe jetzt den Ansatz von Tomura fertig umgesetzt, funktioniert tadellos und ich hab noch was gelernt dabei. Ich wusste gar nicht, dass man vom allseits beliebten Viewport erben und sowas damit anstellen kann. Geschweige denn von den abgefahrenen Delegates, die im ShooterGameInstance verwendet werden. Danke vielmals, für die interessanten Ansätze, das mit dem Post Process schaue ich mir auf jeden Fall auch mal an, das klingt interessant.

    Ja man kann die recht viele Engine Klassen vererben, was ich z.B. gemacht habe um bei Travel/Network failures entsprechende Nachrichten im GUI anzuzeigen, etc.

    Ich weiß leider nicht ob das in Blueprint möglich ist.

    Ich musste C++ dafür nutzen.


    Für normale Map Travels muss der Loading Screen über ein extra LoadingScreen Modul gezeigt werden. Dieses Modul wird beim Laden nicht blockiert.


    Bei einem Seamless Map Travel (z.B. server wechselt die map ohne Spieler zu kicken) muss dann aber über ein Slate/UMG Widget gearbeitet werden. In meinem Fall war es ein Slate Widget, damit sich das Loading Screen Modul und meine Viewport Klasse das gleiche Widget Teilen.


    Genaueres kannst du sehen, wenn du den Quellcode von dem ShooterGame example anschaust. Dazu musst du aber gutes C++ und UE4 Architektur Verständnis haben.

    Hier mal kein Kleiner Guide:


    Ausgehend davon dass du folgendes schon hast:

    Ein Mesh bei dem du über Materials verschiedene farben zugeweisen hast mit fertiger UVW Map.


    Dann erstellst du dir im UV Editor über den New Button ein neues Bild:


    Dann fügst du im Shader Editor jedem deiner Color Materials dieses neue Bild hinzu. Dies ist nötig damit der Baker weiß in welches Bild er schreiben muss.


    Dann musst du noch im Rendering Tab folgendes machen:



    Du stellst du Engine von Evee auf Cycles um. Im Tab Bake musst du dann den BakeType auf Diffuse stellen und bei Influence dafür sorgen dass nur "Color" markiert ist (die anderen beiden sorgen, dafür dass diffuse lighting mit gebaked wird, was du nicht willst). Dann wählst du dein Objekt im Object Mode aus und Drückst auf Bake.

    Wenn du dann in den UV Editor gehst solltest du sehen dass deine Textur die du erstellt hast nun mit den Farben gebaked ist.



    Du siehst hier auch dass das ganze etwas übersteht. Das kannst du mit "Margin" verändern, du solltest aber immer ein wenig überstehen lassen, damit etwas Sicherheit ist, bei den MipMaps die später von der Engine generiert werden.

    Feal :


    NOpen und NOpenGL sing wahrscheinlich Normal Map formate. In Unreal Engine wirst du wahrscheinlich die NOpen nutzen müssen, da in UE4 im vergleich zum Open GL Standard der Grün-Kanal (Y) Invertiert ist. (Hier geht es nur um konventionen/standards und nicht darum ob jetzt DirectX oder OpenGL genutzt wird.)


    Du kannst aber auch in der Unreal Engine dies manipulieren:

    Daher ist es eigentlich egal welche die importierst, solange du die Einstellung in der Engine richtig setzt.


    Hier siehst du mal den Effekt. Wenn du "Flip Green Channel" falsch gesetzt hast, solltest du es daran erkennen, dass die Schattierung nicht stimmt. Einfach ausprobieren, wenn du dir nicht sicher bist.