Jump to content
Unity Insider Forum

Leaderboard

Popular Content

Showing content with the highest reputation since 08/11/2021 in all areas

  1. Echt jetzt? Das ist es? Du ballerst eine verschlüsselte Fehlerbeschreibung ohne Punkt und Komma raus. Da drin steht dann etwas von einer Plattform, einer AudioSource, OnCollisionEnter2D, einem RB2D und "natürlich" FixedUpdate und Update. Völlig ohne Zusammenhang! Jetzt versucht @Peanutdir zu helfen und fragt dich etwas. Deine Antwort darauf ist "Nein". Kurz darauf fällt dir ein, dass ein RB ja nach unten Fallen würde und dein FixedUpdate trotzdem nicht funktioniert. Jetzt gibt dir Peanut die Info, dass man die Gravity bei einem RB ja ausschalten kann und er würde gerne mehr über das Problem erfahren, weil er dir immer noch helfen will. Und was machst du? Du schreibst, dass du das Problem gefunden hast und bedankst dich. Klasse! Niemand weiß, was dein Problem war und niemand weiß, wie du es gelöst hast. Dafür ist ein Forum nicht da. Ein Forum dient nämlich auch als Nachschlagewerk. Es kann anderen Leuten helfen, indem sie nach erstmal nach einem Problem suchen und auch eine mögliche Lösung dazu finden. Dieser Thread ist verschwendet, denn man kann nicht erkennen was eigentlich dein Problem war und eine Lösung gibt es auch nicht. Aber mach du mal.
    3 points
  2. Moin, laut Doku ist die Methode jetzt öffentlich, daher greift BindingFlags.NonPublic jetzt nicht mehr. https://docs.unity3d.com/2021.3/Documentation/ScriptReference/EditorGUIUtility.SetIconForObject.html Heißt aber auch, du benötigst keine Reflection mehr und kannst die Methode direkt aufrufen: private void DrawIcon(GameObject gameObject, int idx) { GUIContent[] icons = GetTextures("sv_label_", string.Empty, 0, 8); GUIContent icon = icons[idx]; EditorGUIUtility.SetIconForObject(gameObject, icon.image); }
    2 points
  3. Hallo, ich möchte euch ein kleines Video meines Projektes zeigen. Wo stehe ich im Moment? Jack erhält zu Beginn des Spiels eine Begrüßung von Fuchs Eddi, ein paar Anweisungen und seine erste Aufgabe. Dabei geht es erstmal nur um das Anbauen und Ernten von Maiskolben.
    2 points
  4. Jeah, nach gut 20 Stunden Arbeit bin ich nun fertig und es funktioniert völlig fehlerfrei. Hätte ich nie gedacht und wollte schon aufgeben 😂 ☺️ Wer möchte kann das Script gerne nutzen, vielleicht hat ja auch noch jemand bedarf an sowas. Dazu einfach das Input Script dem EventSystem unter das "Input System UI Input Module"(Wichtig, da darf nichts anderes dazwischen sein) geben und die Tags "Horizontal Menu" und "Vertical Menu" hinzufügen und den entsprechenden Panels zuweisen. Das InputModule, welches man erstellt muss man entweder umbenennen in InputManager, oder in Script InputSO alle "InputManger" durch was anderes ersetzen. Das gleich gilt auf für die ActionMaps. Bei mehr als einer wird man allerdings noch mehr Anpassungen vornehmen müssen, sofern diese die Funktionalität auch benötigen. Wenn noch jemand Anmerkungen und Verbesserungen hat, gerne her damit 😁 Input.cs using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.InputSystem.UI; using UnityEngine.UI; internal struct NavigationModel { public Vector2 move; public int consecutiveMoveCount; public MoveDirection lastMoveDirection; public float lastMoveTime; public AxisEventData eventData; public void Reset() { move = Vector2.zero; } } public class Input : BaseInputModule { public InputSO inputSO; private NavigationModel m_NavigationState; private string parentTag; private bool isDynamicList; protected override void OnEnable() { base.OnEnable(); inputSO.moveVector += SetInputDirection; inputSO.navigate += CheckDynamicListObject; inputSO.submit += SetParentOnSubmit; } protected override void OnDisable() { base.OnDisable(); inputSO.moveVector -= SetInputDirection; inputSO.navigate -= CheckDynamicListObject; inputSO.submit -= SetParentOnSubmit; } public void OnClick() { eventSystem.SetSelectedGameObject(eventSystem.firstSelectedGameObject); } private void ProcessNavigation(ref NavigationModel navigationState) { var usedSelectionChange = false; if (eventSystem.currentSelectedGameObject != null) { var data = GetBaseEventData(); ExecuteEvents.Execute(EventSystem.current.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler); usedSelectionChange = data.used; } if (!eventSystem.sendNavigationEvents) return; var movement = navigationState.move; if (!usedSelectionChange && (!Mathf.Approximately(movement.x, 0f) || !Mathf.Approximately(movement.y, 0f))) { var time = Time.unscaledTime; var moveVector = navigationState.move; var moveDirection = MoveDirection.None; if (moveVector.sqrMagnitude > 0) { if(parentTag == "Horizontal Menu") { if (Mathf.Abs(moveVector.x) > Mathf.Abs(moveVector.y)) moveDirection = moveVector.x > 0 ? MoveDirection.Right : MoveDirection.Left; } else if (parentTag == "Vertical Menu") { if (Mathf.Abs(moveVector.x) < Mathf.Abs(moveVector.y)) moveDirection = moveVector.y > 0 ? MoveDirection.Up : MoveDirection.Down; } else if (Mathf.Abs(moveVector.x) > Mathf.Abs(moveVector.y)) moveDirection = moveVector.x > 0 ? MoveDirection.Right : MoveDirection.Left; else moveDirection = moveVector.y > 0 ? MoveDirection.Up : MoveDirection.Down; } if (moveDirection != m_NavigationState.lastMoveDirection) m_NavigationState.consecutiveMoveCount = 0; if (moveDirection != MoveDirection.None) { var allow = true; if (m_NavigationState.consecutiveMoveCount != 0) { if (m_NavigationState.consecutiveMoveCount > 1) allow = time > m_NavigationState.lastMoveTime + GetComponent<InputSystemUIInputModule>().moveRepeatRate; else allow = time > m_NavigationState.lastMoveTime + GetComponent<InputSystemUIInputModule>().moveRepeatDelay; } if (allow) { Selectable newBtn = eventSystem.currentSelectedGameObject.GetComponent<Selectable>().FindSelectable(moveVector); if (newBtn.transform.parent.tag != parentTag) return; var eventData = m_NavigationState.eventData; if (eventData == null) { eventData = new AxisEventData(eventSystem); m_NavigationState.eventData = eventData; } eventData.Reset(); eventData.moveVector = moveVector; eventData.moveDir = moveDirection; ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, eventData, ExecuteEvents.moveHandler); usedSelectionChange = eventData.used; m_NavigationState.consecutiveMoveCount = m_NavigationState.consecutiveMoveCount + 1; m_NavigationState.lastMoveTime = time; m_NavigationState.lastMoveDirection = moveDirection; } } else m_NavigationState.consecutiveMoveCount = 0; } else m_NavigationState.consecutiveMoveCount = 0; if (!usedSelectionChange && EventSystem.current.currentSelectedGameObject != null) { var submitAction = GetComponent<InputSystemUIInputModule>().submit?.action; var cancelAction = GetComponent<InputSystemUIInputModule>().cancel?.action; var data = GetBaseEventData(); if (cancelAction != null && cancelAction.WasPressedThisFrame()) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler); if (!data.used && submitAction != null && submitAction.WasPressedThisFrame()) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler); } } public override void Process() { ProcessNavigation(ref m_NavigationState); if (parentTag != "Horizontal Menu" && parentTag != "Vertical Menu") { parentTag = eventSystem.currentSelectedGameObject.transform.parent.tag; UnityEditorInternal.ComponentUtility.MoveComponentDown(this); isDynamicList = false; } } public void SetInputDirection(Vector2 moveVector) { m_NavigationState.move = moveVector; } public void CheckDynamicListObject() { parentTag = eventSystem.currentSelectedGameObject.transform.parent.tag; if (!isDynamicList) { if (parentTag == "Horizontal Menu" || parentTag == "Vertical Menu") { isDynamicList = true; UnityEditorInternal.ComponentUtility.MoveComponentUp(this); } } } public void SetParentOnSubmit() { parentTag = eventSystem.currentSelectedGameObject.transform.parent.tag; } } InputSO.cs using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; [CreateAssetMenu(fileName = "AdvancedInput")] public class InputSO : ScriptableObject, InputManager.IMenuActions { public InputManager InputManager; public event UnityAction navigate; public event UnityAction<Vector2> moveVector; public event UnityAction submit; private void OnEnable() { if (InputManager == null) InputManager = new InputManager(); InputManager.Menu.SetCallbacks(this); InputManager.Menu.Enable(); } private void OnDisable() { InputManager.Menu.Disable(); } public void OnCancel(InputAction.CallbackContext context) { //throw new System.NotImplementedException(); } public void OnNavigate(InputAction.CallbackContext context) { navigate?.Invoke(); moveVector?.Invoke(context.ReadValue<Vector2>()); } public void OnSubmit(InputAction.CallbackContext context) { submit?.Invoke(); } }
    2 points
  5. Hallo, mir ist heute eine Idee für ein neues Projekt eingefallen. Ich bin zufällig beim "Googeln" auf das Retro-Spiel Hugo gestossen. Ist ja in der Tat ein Klassiker. Ob man das heute noch spielen möchte mag ich nicht zu beurteilen. Allerdings nehme ich dieses Spielprinzip mal auf und werde mich an eine Hugo Clone ranmachen. Einen Protadonisten habe ich auch schon. Es handelt sich um Teo Turtle, nicht schwer zu erraten, eine humanoide Schildkröte.
    2 points
  6. Also ich für mich persönlich habe knapp 10 Jahre verschiedene Techniken mit Unity ausprobiert. Habe eigene Libraries geschrieben, die leider auch unfertig sind (kaum Zeit dafür mittlerweile). Hier muss ich auch erwähnen, dass es nur meine persönliche Erfahrung und Meinung ist. Wie man schon durch @Sascha's langen Texten sehen kann, könnte man Bücher schreiben um zu erklären, welche Techniken man verwenden kann. Das ist auch der Grund warum ich mit Youtube Kanal anfing. Nicht um zu zeigen wie man machen sollte, eher um meine eigene Erfahrung, wie ich Sachen bewältige und was ich cool finde usw. Ich verfolge meist eine einzige Regel in Unity. So gut wie möglich alles in seinen eigenen Script packen. Um mal einen guten Beispiel zu geben. Ich benutzte DamageSystem.cs. Dort ist Health zu finden. Allerdings was ist nun hier das Problem? Ist doof zu erweitern. Möchte ich nun Armor hinzufügen muss ich diesen Script bearbeiten. Was ist also besser? Genau, wieso nicht gleich Health.cs, Armor.cs usw. unabhängig davon schreiben. Diese wiederum können so gut aufgebaut werden, dass bereits automatische Events usw. eingebaut werden. Beispiel UnityEvents, Automatische Veränderungschecks (quasi, ist der neue Wert wie der Alte? Nein? Dann Event auslösen usw.) Vorteil hier ist, ich kann beliebige neue Attributen einbauen und DamageSystem muss nicht angefasst werden, in dem ich Component reinziehe oder rausziehe. Hab ich Stamina.cs Component beim Spieler, dann hat er auch Stamina. In dem Fall muss mein DamageSystem gar nicht wissen, um was es geht. Es ist wie Lieferer, der weiß nicht was in dem Paket ist, aber kann damit arbeiten. Ebenfalls kann man auch mit GetComponent abfragen, ob Health, Armor, Stamina usw existiert und je nachdem anders handeln. Nun wie kann ich das nun mit UI dynamisch verbinden? Dasselbe Spiel dort auch. UI Elemente werden aktiviert oder deaktiviert je nachdem welche Componenten es existieren. Mit GetComponent oder TryGetComponent kann man abfragen, ob etwas existiert. Manager Es wurde ja bereits gesagt, dass bei Namen wie Manager Vorteile und Nachteile gibt. Um aber mal Proargumente abzugeben, kam bei mir auch ab und zu vor, dass irgendwo mal "Manager" entstanden ist, da keine eindeutige Namen zugewiesen werden konnte. Eben, weil sie gleich mehrere Aufgaben tun. Das ist manchmal auch gut so, denn ich möchte auch ein Component in Unity haben, dass es möglichst erleichtert etwas leicht zu konfigurieren. Ich bin auch kein Fan davon und benutze wirklich sehr selten sowas oder solche Namen (aber mir geht ja um Pro hier gerade). Für mich sind meist Manager, die irgendwie eine Art Überwachung betreiben. Ein Beispiel ist, wie finde einen bestimmten Gegner auf der Karte. Wo hole ich die Information her. EnemyManager oder EnemyManagement haben solche Informationen meistens (zugeben, würde ich nicht mal so machen, aber war ein Beispiel, was mir spontan einfiel). Z.B. EnemyManager.Find(id). Noch nie ist mir aber im Leben passiert, dass ich durch anderen 3rd Party Libraries bei einem Namen wie "Manager" aufgehalten wurde zu programmieren oder verwirrt war und ich dachte "Oh Gott, ich bin hilflos, was tut denn dieser Manager nun?" (um bissel zu übertreiben :D). Denn allein wenn man "Enemy.cs" sehen würden wissen wir ja auch nicht genau, was dort alles möglich ist. Wir wissen geht um Enemy. Was tut es denn?. Arbeitet Enemy denn mit Transform (also mit movements)? Hat es Health eingebaut? Benutzt es Animationen? Fragen über fragen. Oder sind die alle vllt. in separaten Components usw. unterteilt? Mal ja mal nein (in meinem Fall meistens, ja). Denn bei simplen Namensvergebungen aus Kombination meist aus Nominativ und (nominalisiertes) Verb also "Was ist das?" und "Was tut es?" wie zum Bespiel WorldSpawner, EnemyDamageReceiver" UIElementTransition ist man schnell informiert, aber bei komplexeren wie Util(s), DamageSystem, HUD, UI oder bei komplett erfundenen Namen wie Tama, Checky schauen wir trotzdem die Docs oder Source an um zu verstehen, was genau da möglich ist und passiert. Unabhängig davon behaupte ich mal, dass man selbst bei WorldSpawner dennoch anschauen würden, was eigentlich da alles möglich ist. Dank unser IDE sehen wir ja meist auch was möglich ist (yay!). Natürlich, würde es WorldManager heißen, würden man auch nicht wissen, ob es eine Spawn-Funktion hat und solche aufgeben erledigt. Allerdings hab ich mal solche Klassen gesehen, die auch eine Funktion hatte. Z.B. WorldSpawner.Spawn(World world). Klasse! Nehme als Beispiel mal Mirrors NetworkManager: Das ist ein Runtime - Component. Sowohl Einstellung, aber auch sowohl Aufgaben wie Verbindungaufbauen, Callbacks ausführen etc. tut dieser Manager. Nun was könnte hier der Name am besten sein, um präzise mir verständlich zu machen, was genau die Klasse macht? Man hätte vllt auch gleich Mirror nennen können. Würde trotzdem nichts aussagen für mich. Aber, muss ich denn genau wissen, was im Background passiert? Denn den Usern bzw. Programmierern wollen wir doch so einfach wie möglich machen. Ich will hier jetzt nicht als Pro Manager rüber kommen, aber ich wollte mal auch die guten Seiten mal darstellen, wieso man manchmal Manager verwendet. Ich weiß, nun man könnte ja Unterteilen. Genau dazu komm ich jetzt. Um Mal gegen zu argumentieren. Neben Mirror wurde aus der gleichen Projekt eine andere Version erstellt, nennt sich Mirage. Mirage ist das komplette Gegenteil von Mirrors Vorgehensweise. Mirage fokussiert sich auf die wesentlichen Elemente des C#'s OOP. In Mirage siehst du also die ganzen Unterteilungen zu Configuration, SceneManagement usw. in verschiedenen Komponenten. Eigentlich fand ich die IDEE super, denn genau mein Geschmack... dachte ich. Am Ende hatte mein GameObject nicht nur zwei Components, wie da oben wie wir sehen "NetworkManager" und "Transport", sondern knapp ca. 10 verschiedene. Das ist für mich einfach gesagt Spaghetti. Um mal was zu ändern muss ich die Components durch gehen und bei verschiedenen Stellen etwas einstellen. Ich verliere den Übersicht und lästige hin und her gehen nervt total. Mag sein, dass Mirage hier technisch was falsch tut, aber das ist ein Beispiel, wieso mal ein "Manager" gut tut. Ganz großer Nachteil Ein ganz großer Nachteil bei sowas ist, die Arbeit mit mehreren Personen. Manager sind echt nicht dafür gemacht. Manager sind meistens abhängig bzw. die Scripte sind abhängig von Manager. Das ist genau so auch bei Singleton so. Hab bereits dafür eine gute Technik entwickelt (yay!) und alles ist automatisiert. Sollte ich also mal Singleton, oder Manager verwenden müssen, dann spawnen die auch selbstständig jedes mal, egal in welcher Scene ich starte. Vorteile und Nachteile bei Fehlersuche Ich will ehrlich sein. Ich sehe da kein Unterschied, denn beide sind aufwendig für mich. Wenn man in seinem Manager ein Fehler hat, dann weiß man auch dieser Fehler ist irgendwo in dem Script ist. Aber wenn alles irgendwie miteinander verknüpft hat, auch wenn es decoupled arbeitet, dann hat man z.B. das Problem, dass man alles zurück verfolgen muss, wo dieser Fehler her kommt. Beispiel A->B->D, C->D, E->D, F->D und Der Fehler ist bei D. Nun muss ich heraus finden, wieso dieser Fehler bei D entstanden ist. Wie man durch Pfeile erkennen kann, kommen am Ende alle zu D. Das heißt A, B, C, E, F können dieser Fehler verursacht haben. Was ich zum Beispiel nicht mag, aber in dem Projekt mit arbeite und leider so eine Struktur hat ist z.B. sowas: Uff und wieso hat er Entwickler das so gemacht??? Das tun zum Beispiel auch viele und ich verstehe nicht weshalb sie das tun Hier heißt der Player zwar nur Player, aber ganz klar was wir hier sehen ist, dass es ein PlayerManager ist . Meine Empfehlung.. arbeite hier mit UnityEvents. UnityEvent UnityEvent ist Liebe <3. UnityEvents sorgt dafür, dass man zwei unabhängige Scripte zusammen arbeiten lassen kann, da du die Einstellung durch Inspector durchführst und nicht im Code. Dank Serialization kann Unity die Listener für uns registrieren. Sagen wir mal du hast Shoot() ausgeführt und mit Raycast machst du GetComponent<Health>() und nun kannst du health.ApplyDamage(int dmg) ausführen. Nun willst du ja UI oder Healthbar usw. updaten. UnityEvent kann das tun. Egal ob UI da ist oder nicht.. ApplyDamage wird immer funktionieren und die Scripte sind auch nicht abhängig davon. Man stelle sich UnityEvent wie ein unsichtbarer Middlesman vor. Jemand der für uns eine Aufgabe übernimmt im Background. Nachteil Leider hat auch UnityEvent einen doofen Nachteil, wenn man sie ganz normal verwendet. Wie kannst du nachvollziehen, wo du UnityEvent verwendet hast.? Ist schwer. Kannst du so gut wie gar nicht. Beispiel. Du hast ein UI Script und da steht public void UpdateHealthText(string text). Nun muss du irgendwie herausfinden, wo UpdateHealthText benutzt wird. Kannst du nicht (zumindest fällt mir da keine Idee ein, ob man das im Editor rausfinden kann). Vllt hast du es beim Spieler bei Health.cs verwendet, oder beim Player.cs oder einfach irgendwelche anderen Scripte usw. Fakt ist. Zwar wird ApplyDamage in Health funktionieren.. allerdings beim Invoke des UnityEvents wird eine Fehlermeldung rausspucken, dass UnityEvent eine Funktion nicht mehr findet. Sprich.. man muss darauf auch achten, dass man beim UnityEvent, wieder UpdateHealthText rausnimmt. Wäre eig schön, wenn UnityEvent die möglichkeit hätte sowas zu ignorieren. Dann wäre das kein Problem. Allerdings kann man dafür eigene Visualizer schreiben, wie hier gemacht wurde: https://assetstore.unity.com/packages/tools/utilities/event-visualizer-163380 (ich will nicht lügen, habe es gerade ergooglet). Um das umzugehen gibt es dafür gibt es ein paar Tricks. Listener und Receiver schreiben. Das ist zu deep um jetzt da reinzugehen, aber das Gute bei der Sache ist, dass der Listener immer da ist beim UI als Component und das Receiver genauso da ist beim Health. Der Listener kann quasi schauen, ob eine Instanz existiert if health == null, dann tue nix. Daher, ob du UI löschen tust, oder Health.. keine Fehlermeldung wird entstehen. Meine eigene Lösung dazu war eine anderes eigenes System. Den nannte ich SmartEvents und muss gecodet werden. Heißt hier arbeitet man nicht mit dem Inspector. Ich finde mit IDE zu arbeiten immer bequemer, da ich auch schauen kann, wo was benutzt wird. Dafür sind die IDEs einfach zu gut geworden mittlerweile. Wenn ihr UnityEvent liebt dann bitte downloaded unbedingt das heir: https://github.com/MerlinVR/EasyEventEditor EasyEventEditor fügt mehr Optionen hinzu. Beispiel private Methoden werden auch sichtbar. So oder so verstehe ich nicht, wieso das allgemein nicht möglich ist.. denn manchmal will ich private Methoden nur für UnityEvent benutzen. Wenn man richtig hardcore unterwegs sein will Schaue dir Serialization an. Wie es funktioniert. Wenn man seine eigene Serialization schreiben kann, kann man mächtige Sachen erschaffen. Ein Beispiel. Wir benutzen Tilemap. Wir finden aber Tilemap abzuspeichern sehr krass vom Speicherplatz her. Deswegen speichern wir die wichtigen Daten als JSON ab und lassen in Runtime da wieder lesen. Wir sparen dadurch über 80% Speicherplatz. Denn in der Scene oder als Prefab waren das für uns zu viel Daten. Ich bin leider nicht soweit gekommen, aber quasi damit wollte ich auch meine Scripte entkoppen und mit eigenen Serialization tool arbeiten. Quasi die eigenen EventSysteme werden in JSON abgespeichert und wieder geladen. Leider konnte ich das noch nicht testen, aber die Idee könnte gut funktionieren.
    2 points
  7. @Banenchen Du solltest deine Fragestellung mal etwas überarbeiten. Die Frage "Warum ... wenn ich dieses Script habe" würde ich jetzt beantworten mit "Weil du diesen Script benutzen tust". Wir kommen also so nicht weiter. Daher was ist dein Problem, wo vermutest du dein Fehler, was hast du probiert und was genau willst du erreichen?
    2 points
  8. Hm, ich dachte, ich hätte da einen Post irgendwo, aber ich finde ihn gerade nicht. Eine LayerMask ist eine Bitmaske. Bitmasken sind binäre Zahlen (so wie alle Zahlen im Rechner), bei denen jede Stelle ein Boolean darstellt. Wie bei Dezimalzahlen auch, sind rechts die kleineren Werte und nach links wird's immer größer. Daher ist das erste Bit ganz rechts, das zweite links daneben usw. Ich zähle im Folgenden von 0 an statt von 1, das macht's später einfacher. Wenn du also #0 und #2 "an"-haben willst, wäre das 101. Da wir einen bestimmten Datentypen benutzen, haben wir eine feste Anzahl an Bits. In der Regel nehmen wir ein int, das hat 32 Bits. Also wäre es eigentlich 00000000000000000000000000000101 Du kannst also 32 Bits (oder auch "Flags") an- oder ausschalten. Falls du dich mal gefragt hast, warum man genau 32 Layer definieren kann (naja, minus die 8 vorbelegten) - das ist der Grund. Als nächstes brauchst du Operatoren, um mit diesen Zahlen zu arbeiten. Es sind einfach nur ints, deshalb kannst du ganz normal + und - und so weiter benutzen. Aber für Bitmasks interessant sind sog. bitweise Operatoren. Da gibt es erstmal &, | und ^. & und | sind wie && und || ...nur halt bitweise. ^ ist dabei das bitweise Äquivalent zu !=. Das heißt, dass der Operator durch die beiden Zahlen links und rechts davon durchgeht und das 0te Bit mit dem anderen 0ten Bit vergleicht, dann die beiden ersten, usw. Dabei gilt: // UND (beide müssen 1 sein) 0 & 0 == 0 0 & 1 == 0 1 & 0 == 0 1 & 1 == 1 // ODER (mindestens eins von beiden muss 1 sein) 0 | 0 == 0 0 | 1 == 1 1 | 0 == 1 1 | 1 == 1 // EXKLUSIV-ODER (UNGLEICH) (eins muss 1 sein, das andere muss 0 sein) 0 ^ 0 == 0 0 ^ 1 == 1 1 ^ 0 == 1 1 ^ 1 == 0 Da das eben für jedes Bit der einen Zahl mit dem entsprechenden Bit der anderen Zahl gemacht wird, entsteht eine neue Bitmaske: 1010 & 0011 ====== 0010 1010 | 0011 ====== 1011 Jetzt kann man diese Zahlen ins Dezimalsystem übertragen und sieht unintuitive Zahlen: 1010 = 10 & 0011 = 3 ====== 0010 = 2 1010 = 10 | 0011 = 3 ====== 1011 = 11 Daran erkennt man, dass man die komischen Dezimalzahlen, die man bei der Arbeit mit Bitmasken vielleicht zu Gesicht bekommt, einfach ignorieren sollte. Dann hast du noch sog. Bitshift-Operatoren. Damit kannst du die Einsen in einer Bitmaske nach links oder rechts wandern lassen: // << lässt alle Einsen einmal nach links wandern 0101 << 1 == 1010 // mit >> geht's nach rechts 0110 >> 1 == 0011 Wenn du das mit den Binärzahlen verinnerlicht hast, wirst du vielleicht merken, dass << 1 verdoppeln und >> 1 halbieren heißt. Statt einer 1 kann man da auch eine größere Zahl oder 0 hinschreiben. Dann werden die Einsen nicht nur einmal verschoben, sondern eben so oft wie diese Zahl hoch ist. Wo wir bei binären Zahlen sind... du kannst zum Glück seit C#7 Binärzahlen über Literale definieren, heißt: Du schreibst sie einfach hin. Mit einem "0b" davor. int number = 0b1110; Debug.Log(number); // 14 Damit kann man evtl. ein bisschen rumexperimentieren. Zuletzt darf man auch den guten alten Vergleichsoperator nicht vergessen. Du kannst wunderbar eine Bitmaske mit == mit einer anderen vergleichen. Da kommt dann true heraus wenn alle Bits übereinstimmen (es also dieselbe Zahl ist - wer hätte es gedacht?). So... Wie benutzen wir das ganze jetzt? Wenn du eine LayerMask definierst (z.B. über ein serialisiertes Feld, sodass du es im Editor einstellst, oder über LayerMask.GetMask), dann hast du ein LayerMask-Struct, das sich wie ein int benutzen lässt. LayerMask.GetLayer gibt dir sogar direkt ein int zurück. Wenn du allerdings den Layer eines GameObjects anschaust, dann kriegst du eine Zahl, die keine Bitmaske ist, sondern den Index des Layers darstellt. Wenn du jetzt schauen willst, ob der Layer des Objekts auf der LayerMask angeschaltet ist, musst du eine LayerMask erstellen, in der der Layer des Objekts angeschaltet ist und der Rest aus diese LayerMask mit der gegebenen LayerMask vergleichen Für 1. nutzen wir Bitshift: int objectLayerMask = 1 << targetObject.layer; 1 ist ja 00000001, also eine einzelne 1 ganz rechts. Diese 1 schieben wir mit Bitshift so oft nach Links wie der Index des Layers ist. Ist das GO z.B. auf Layer 4, wird die 1 viermal nach links geschoben und wir erhalten 00010000. Jetzt nehmen wir den &-Operator und verrechnen diese Bitmaske mit der LayerMask: int andMask = layerMask & objectLayerMask; Da die zweite Zahl nur eine 1 enthält, werden alle anderen Bits des Ergebnisses 0, denn bei & müssen beide Bits 1 sein, damit 1 rauskommt. Das einzige Bit, bei dem 1 rauskommen kann, ist das vierte von rechts (von 0 an gezählt), da hier eine 1 in der Objekt-Bitmaske steht. Damit aber auch wirklich eine 1 herauskommt, muss genau dieses Bit auch bei der vorgegebenen LayerMask 1 sein. Es gibt also nur zwei mögliche Ergebnisse: Die LayerMask hat den Layer des GameObjects aus, dann hat das Ergebnis durchgehend nur Nullen. Die LayerMask hat den Layer an, dann kriegen wir eine Bitmaske als Ergebnis, die irgendwo eine 1 hat und sonst Nullen. Und damit haben wir die beiden Fälle abgedeckt: Layer ist in LayerMaske an, ja oder nein. Wir nehmen also != und schauen, ob das Ergebnis == 0 ist (alles Nullen) oder eben nicht: bool layerIsInLayerMask = andMask != 0; Oder, alles in einer Zeile: if ((layerMask & (1 << targetObject.layer)) != 0) Du kannst die auch eine nette Methode schreiben, um das lesbarer zu machen: using UnityEngine; public static class LayerMaskExtensions { public static bool HasLayer(this LayerMask layerMask, int layerIndex) { return (layerMask & (1 << layerIndex)) != 0; } } Jetzt kannst du sowas machen: myLayerMask.HasLayer(targetGameObject.layer)
    2 points
  9. Hallo Du könntest einen LineRenderer nutzen. https://docs.unity3d.com/Manual/class-LineRenderer.html Christoph
    2 points
  10. Persistent sind die Listener, die im Editor eingestellt werden. Mit AddListener, RemoveListener und RemoveAllListeners arbeitest du nur mit Listenern, die im Code behandelt werden. Du hast quasi zwei Listen: Die im Editor und die, die du im Code erzeugst.
    2 points
  11. Moin! 1. Die üblichere Schreibweise ist die Lambda-Schreibweise. Die gibt's in mehreren Sprachen und wird, wenn man sie erstmal kennt, meistens als angenehmer empfunden als da "delegate" hinzuschreiben. Ein Lambda-Ausdruck (genau wie mit "delegate") ist einfach eine Schreibweise für eine Methode ohne Namen. Man kann also als Beispiele Methoden nehmen und dann die entsprechenden Lambda-Ausdrücke zeigen: a) private void Foo() { Debug.Log(5); } als Lambda-Ausdruck wäre () => Debug.Log(5) b) private void Foo() { Debug.Log(5); Debug.Log(10); } als Lambda-Ausdruck wäre () => { Debug.Log(5); Debug.Log(10); } Hier braucht man geschweifte Klammern, weil mehr als eine Anweisung drinsteht. c) Jetzt mal mit Parametern: private void Foo(int number) { Debug.Log(number); } wäre number => Debug.Log(number) und private void Foo(int number, string text) { Debug.Log(number + text); } wäre (number, text) => Debug.Log(number + text) Man bemerke hier, dass keine Parametertypen angegeben werden - da steht also nix davon, dass "text" ein string ist. Das liegt daran, dass Lambda-Ausdrücke zu Methodenreferenzen evaluieren. Diese werden als normale Werte behandelt - man kann sie also in eine Variable speichern oder eben als Parameter übergeben. Und in diesen Fällen ist vom Typ der Variable bzw. des Parameters her schon vorgegeben, dass da eine Referenz auf eine Methode kommen muss, die ein int- und einen string-Parameter hat. Action<int, string> foo = (number, text) => Debug.Log(number + text); // und jetzt kann man die Methode aufrufen foo(5, " Stück"); Mit Lambda-Ausdrücken kann man einem Objekt mehr als nur simple Werte in die Hand drücken, sondern ganze Verhaltensweisen. Deshalb kannst du die Dinger benutzen, um Buttons zu sagen, was sie tun sollen. btn.onClick.AddListener(() => GetComponent<MenuManager>().ButtonAction(i)); Soviel erstmal dazu. 2. Jetzt musst du (leider) das Konzept von Closures kennenlernen. Eine Closure ist wie ein Objekt, also ein Ding, das bestimmte Werte hat. Und jede anonyme Methode (also die, die du mit einem Lambda-Ausdruck erzeugst), hat so eine. Sie enthält die für die Ausführung der Methode relevanten Variablen aus der Umgebung, in der der Lambda-Ausdruck steht. var number = 5; Action foo = () => Debug.Log(number); foo(); Hier wird eine int-Variable mit dem Wert 5 definiert, eine Methode die den Wert der Variable ausgibt, und dann wird diese Methode aufgerufen. Es sollte also recht klar sein, dass die Zahl 5 ausgegeben wird. Die Variable "number" ist Teil der Closure der Methode, die von der Variable "foo" referenziert wird. Jetzt kommt der Knackpunkt: Closures machen pass-by-reference. Das heißt, dass hier nicht die 5 in der Closure gespeichert wird, sondern eine Referenz auf die Variable "number". Wenn du folgendes tust: var number = 5; Action foo = () => Debug.Log(number); number = 10; foo(); dann wird tatsächlich 10 ausgegeben und nicht 5, weil beim Aufruf der Methode der aktuelle Wert der Variable angeschaut wird. Wenn du also eine Schleife hast und in dieser Schleife Methoden erzeugst, die irgendetwas mit der Zählvariable i tun, dann wird am Ende jede dieser anonymen Methoden den aktuellen Wert von i nehmen - und das wird nun einmal der Wert am Ende des Schleifendurchlaufs sein, also in deinem Fall 1 bei einem Button bzw. 6 bei sechs Buttons. Die Lösung des Problems ist jetzt ein bisschen stumpf: Du machst in der Schleife eine neue Variable und kopierst da den Wert rein; dann benutzt du diese Variable in deinem Lambda-Ausdruck statt i: for(int i = 0; i < list.count; i++) { var btn = list[i]; var index = i; btn.onClick.AddListener(() => GetComponent<MenuManager>().ButtonAction(index)); } Dann wird die Variable "index" angeschaut, wenn man auf einen Button klickt - und der Wert dieser Variable ändert sich nicht mehr, weil sie am Ende des jeweiligen Durchlaufs (eigentlich) out of scope geht. Übrigens kannst du es dir (so als Schmakerl) sparen, jedes Mal GetComponent aufzurufen, indem du das vorher einmal machst: var menuManager = GetComponent<MenuManager>(); for(int i = 0; i < list.count; i++) { var btn = list[i]; var index = i; btn.onClick.AddListener(() => menuManager.ButtonAction(index)); }
    2 points
  12. Hallo Das müsste passen https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/operators/operator-overloading Christoph
    2 points
  13. Entweder du nimmst einen Shader, der Beidseitig funktioniert, oder aber du erzeugst dir ein Kugel in einem 3d Programm, wie z.B. Blender, und drehst da einfach die Normalen der Flächen um.
    2 points
  14. Soda ist während des aktuellen Unity Asset Store Sales übrigens um stolze 50% reduziert! https://assetstore.unity.com/packages/tools/integration/soda-scriptableobject-dependency-architecture-137653
    2 points
  15. Mit dem Profiler wusste ich bis vor 3 Stunden noch nicht wirklich umzugehen. Ich konnte aber durch Zufall im Profiler das Problem oder Probleme lokalisieren und verstehe jetzt auch wo ich beim nächsten Mal suchen muss. Zum Glück hat sich ein weiterer Zufall dazu gesellt und ich konnte eine Lösung finden. Durch Spine 2D wurde ein Mesch-Generator angezeigt mit um die 40% Auslastung und im Deep Mode konnte ich das ganze auf Spine's Clipping Funktion zurück führen. Die Lösung war in diesem Fall das Clipping zu vermeiden, dafür genügt es den Hacken in der Skeleton Animation bei "Use Clipping" zu entfernen(Für Alle die das selbe Problem haben)(Clipping scheint ein Feature zu sein, welches ich in meinem Fall nicht benötige). MfG DI3FL4MM3
    2 points
  16. Hallo Ich will euch heute mal mein derzeitiges Projekt zeigen. Es heißt „Konsequenz“ und wie der Titel schon sagt, spielen Konsequenzen eine bedeutende Rolle. Einmal spielerisch, also welche Entscheidungen ich als Spieler treffe und auch die Geschichte dreht sich um die Folgen des eigenen Handels. Es gibt keinerlei Kämpfe, dafür viel zu lesen und zu reden. Mein großes Vorbild ist dabei „Disco Elysium“. Natürlich unerreichbar, aber als Richtung in die das Ganze zielt. Ich habe schon viele Zeilen Dialoge geschrieben und feile die ganze Zeit an den Texten. Hier ein paar Impressionen: Die Unterwelt: Das Inventar des Spielers mit dem detaillierten Blick auf ein Item: Das Questfenster: Und hier ein paar Dialogzeilen: Und hier mit einem „Angler“: Es wird drei Welten geben. Die erste ist nun fertig und ich muss zugeben, dass ich den Aufwand total unterschätzt habe. Ich habe bereits sehr viel Zeit investiert und es ist noch kein Ende in Sicht. Allein das Finden von Bugs ist dermaßen mühselig… Da es mein erstes richtiges Spiel wird, musste ich auch viel Lehrgeld zahlen. Einige Module habe ich komplett neu entwickelt, bei einigen habe ich auf bewährte Lösungen aus dem store gegriffen. Ich habe mir irgendwann die Frage gestellt, was ich eigentlich will: Spiele programmieren oder bsp. Lokalisierung. Ich habe mich dann manchmal für das Spiel entschieden! Es gibt noch viel zu tun: - Licht (hatte ich schon, aber zur Zeit aus, weil es noch zu hässlich war) - Sound - Ganz viel Finetuning (QoL – Sachen) Jetzt freue ich mich auf eure ehrliche Rückmeldung!! Christoph
    2 points
  17. Hallo im Inspector lasse ich mir ein ObjectField anzeigen. So sieht das in OnInspectorGUI(). SerializedProperty textComponentProperty = serializedObject.FindProperty("m_textComponent"); EditorGUILayout.ObjectField(textComponentProperty); if (GUI.changed) { Debug.Log(textComponentProperty.objectReferenceValue); serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(target); } Dort kann ich ein text component reinwerfen. Wenn ich nun ein Text component drag and drop mache, wird beim Debug.Log auch kein null angezeigt. Heißt, dass es funktioniert hat mit drag and drop, doch danach ist es sofort wieder null. Ich weiß gar nicht mehr was ich machen soll. Im selben component ist string dabei und das lässt sich speichern. Benutze 2020.2.3f1 Hab es doch heraus gefunden: Ich hab zwei Types die Text heißen und hat nach falschen Text gesucht. Unity hat mir aber keine Fehlermeldung gezeigt, dass die Types nicht passen, sondern machte daraus direkt null. Zweites Type ist ein Child von UI.Text.
    2 points
  18. Then why did you ask about it just 2 days ago? This is the dumbest thread I've seen in here for quite some time...
    2 points
  19. @Sascha Danke für den Tipp. Gut zu wissen. Dann werde ich das auch nicht mehr verwenden 😅 @Peanut Auch ein Danke an Dich für deinen Tipp. Es funktioniert jetzt 😄 Leider war ich erstmal etwas verzeifelt, weil es meine XML Datei nicht finden wollte. (Deshalb hab ich bisher AssetDatabase verwendet.) Durch die Documentary hab ich dann endlich festgestellt, dass ich einen extra Resources Ordner brauche, wo ich den Ordner mit der Datei reinziehen muss. Dann hat es funktioniert und ich bin mehr als nur froh darüber ✌️😅
    1 point
  20. using UnityEditor; Du kannst diesen Namespace nicht in Scripts benutzen, die im Build landen. Es gibt die UnityEditor.dll in Builds schlicht nicht, deshalb kannst du sie dort auch nicht benutzen. AssetDatabase fällt damit raus.
    1 point
  21. Vielen Dank. Du hast mir sehr geholfen. Bisschen Google und schon hab ich Tutorials gefunden, wie man UV-Maps in Blender macht. Funktioniert super. Vielen Dank 😘
    1 point
  22. Von der Logik her müssten die Static Variablen der sparsamste Weg sein, denn die sind immer an der selben Stelle im Speicher. Sie belegen aber auch immer ihren Platz, egal ob sie gebraucht werden, oder nicht. Es ist doch so, dass ein Szenenwechsel ja den alten Kram verwirft und alles neu einlädt, was in der neuen Szene jetzt nötig ist. Ein Scriptable Object, was ja an ein Script gebunden ist, wird mit dem Script neu eingeladen / verknüpft. Ein Singleton, was den Szenenwechsel überlebt, bleibt im Speicher. Aber wahrscheinlich wird in jeder Szene ein Singelton geladen (damit es beim laden einer bestimmten Szene auch da ist), was dann schaut ob es einzigartig ist und wenn nicht sich wieder zerstören würde. Da passiert also noch viel mehr als nur ein Einladen und das kostet alles eine gewisse Zeit. Hier und da würden also Daten neu eingelesen und in den Speicher geschoben werden. Nur von wo werden sie eingeladen? Sind sie nicht vielleicht schon längst im Speicher, weil die Engine weiß, dass sie fürs Spiel gebraucht werden? Ich weiß nicht, wie weit die Engine optimiert ist. Was relativ langsam ist, ist ja das Laden von einem mechanischen Laufwerk. Alles Andere geht so schnell, dass du keinen Unterschied feststellen wirst. Und wenn deine neue Szene nur eine einzige Textur oder einen Sound laden muss, die/der vorher noch nicht da war, dann sind deine paar Daten in den Variablen völlig nebensächlich.
    1 point
  23. Unity hat ja einen FoV-Wert, der den von der vertikalen Achse der Kamera abgedeckten Bereich beschreibt. Wenn ich deine Beschreibung richtig verstanden habe, dann möchtest du stattdessen einen Winkel für die horizontale Achse definieren. Dafür gibt's mehrere Möglichkeiten. Diese hier wäre einfach nur, dass du mit dieser Methode den festgelegten horizontalen Winkel reinschmeißt, den Aspect Ratio der Kamera (also Breite durch Höhe des Bildes) dazu, und dann eben einen Winkel für die vertikale Achse kriegst. Hab's nicht getestet, aber sowas in der Art: camera.fieldOfView = camera.HorizontalToVerticalFieldOfView(60, camera.aspect); Wobei man ja sowieso annehmen muss, dass die Methode intern nur eine Multiplikation macht Die 60 ersetzt du jedenfalls durch einen beliebigen Wert, bei dem dir der Bildausschnitt gefällt. Ausführen kannst du das dann in Start().
    1 point
  24. Hallo, heute gibt es etwas vom Gameplay zu sehen. Der Spieler hat den Auftrag sich in der Shanty-Town umzusehen und Informationen zu sammeln. Ein Soldat wird ihn dabei begleiten. Jetzt gibt es ein erstes Treffen mit den Zombies.
    1 point
  25. Hallo, das Militärlager, in dem der Spieler seine Mission beginnt, ist vom Leveldesign fertig. Der Start und somit die erste Mission erhält der Spieler dann vom Befehlshaber im Einsatzzelt. Hier ein kleines Video. Leider ist der Ton etwas dumpf, was mir erst aufgefallen ist, als das Video on war. Ich denke aber für einen ersten Eindruck sollte es trotzdem reichen.
    1 point
  26. Fehler gefunden und der war mal richtig blöd zu finden. Da ich die Camera nur brauche, wenn ich ein Bild machen will, ist die Komponente deaktiviert. Wenn ich ein Bild mache, aktiviere ich bevor ich das Bild machen möchte die Camera. Wenn der Frame zu Ende ist, wird das Bild gemacht. Anscheinend braucht die Camera mehr Zeit um aktiv zu werden. Sprich, das Bild wird gemacht, während die Camera noch gar nicht aktiv ist. Ich habe jetzt eine kleine Wartezeit zwischen Camera aktivierung und Bilderstellung eingebaut, jetzt funktioniert es.
    1 point
  27. Ich hab es gelöst. Oh man.. Ich habe die Schleife in die Start()-Methode geschrieben. Also insgesamt in: Start() RespawnPlayer() FindHeart() Mannoman. Vielen Dank für deine Hilfe Sascha!
    1 point
  28. Hallo var mousePos = Input.mousePosition; go.transform.position = mousePos; müsste gehen. Christoph
    1 point
  29. Sowas in der Art? https://twitter.com/unitygames/status/1437717832926695429 Als erstes würde ich versuchen die einzelnen Bruchstücke wirklich perfekt zu erstellen, also ohne overlap oder Lücken. Dazu braucht man ein Tool oder Editor Scripting. Manche machen das in Blender, andere wie in dem Video gezeigt mit ProBuilder oder anderen Unity-Tools. Begriffe: fracturing, destruction, destructible fracture, etc. Die Rigidbody Parameter sind eher komplex bei sowas. Ganz blöd gesagt: ich würde mal damit rumspielen, z.B. mit der Friction oder Drag. Bei höherer Friction oder mehr Drag glitchen Sachen oft weniger. Dazu am besten auch mal PhysicsMaterials ausprobieren. Damit kann man z.B. den Bounce auf 0 stellen und Friction sehr hoch oder umgekehrt und schauen wie sich das Ergebnis ändert. Aber am effektivsten ist wahrscheinlich den ganzen Effekt mit eye candy zu übertünchen: Die meisten verwenden eine Explosive Force um Bruchstücke umherfliegen zu lassen und spawnen dazu noch Particle Effects mit Staub, Flammen, Wölkchen. Am besten verschwinden die zerstörten Teile möglichst schnell aus der Spielwelt, damit keine unlogischen Gelegenheiten aufkommen. Zum Beispiel einfach nach 2 Sekunden despawnen oder komplett freezen. Dazu kann man auch kontinuierlich die friction erhöhen bis das Objekt zum Stillstand kommt.
    1 point
  30. Das Problem ist, dass die Unschärfe von der Kamera aus geht. Das ist ein Punkt und keine Ebene. Somt kann ein Objekt, welches sich auf der selben Z Ebene wie der Player bewegt trotzdem weiter von der Kamera weg sein, als der Player. Wenn du das in ein Top-Down Spiel einbauen willst, musst du die Objekte Z-Ebenen mäßig viel weiter trennen und die Unschärfe einiges später anfangen lassen. Das Unschärfe-Ende ist auch wichtig, denn damit steuerst du wie stark es unscharf wird, also ab wann etwas vom Startpunkt aus total unscharf ist. End solltest du mal einschalten und ausprobieren. Du kannst dein Spiel bei so einer Situation, wie im Bild zeigst, mal pausieren und dann mit den DOF Einstellungen spielen. Hake dafür mal das END an und stelle es auf 0 ein. Dadurch hast du einen ganz engen Bereich von scharf zu unscharf. Jetzt verschiebst du den Startpunkt einfach mal so, dass alles auf der gewünschten Z-Ebene scharf ist. Das wäre dann dein Startpunkt. Nun kannst du den End-Wert soweit vergrößern, dass du die gewünschte Unschärfe zu den hinteren Objekte hast. Beide Zahlen merken und dann im Inspector eintragen. So ähnlich kannst du das auch mit Bokeh machen. Da ist Focus Distance der Wert bei dem es scharf ist. Focal Length ist dann der Wert für die Stärke zum Unscharfen hin. Da müsstest du die Legth erstmal auf 300 stellen und danach mit der Distance von einen kleinen Wert zum großen Wert verschieben, bis deine Objekte auf der Z Achse alle scharf sind. Jetzt die Legth verkleinern, bis du mit der Unschärfe zufrieden bist. Wenn du es nicht schaffst, alle Objekte auf der gewünschten Z Achse scharf zu kriegen, ohne dass auch die hinteren Objekte scharf werden, musst du die Ebenen auseinander ziehen. Das ist halt alles sehr eng in der Einstellung.
    1 point
  31. Captain Future! Yes! Auch wenn das Posting schon etwas älter ist. Genial!!! Mehr davon! ps) Hast Du ein 3D Model für Unity?
    1 point
  32. 😄 habe meinen Fehler bemerkt und wollte den Eintrag schon abschließen, aber du bist ja unglaublich schnell...
    1 point
  33. Wieso kann ich da nichts drin bearbeiten? Gelöst: Einfach Dupliziert
    1 point
  34. Das kann schon normal sein, aber da ich sowas nie selber gebaut habe, weiss ich es nicht. Du kannst dich ja mal mit dem neuen Inputsystem vertraut machen. Da hast du Objekte oder Komponenten im Spiel, die all deine Inputs übernehmen. Die sollten, wenn sie beim Szenenwechsel aktiv bleiben, komplett durchgängig funktionieren. Aber ich muss dir sagen, so mächtig das neue Inputsystem auch ist, so schwierig ist es zu verstehen. Es gibt mindestens 3 unterschiedliche Arte, das Sytem einzubinden und alle haben Vor- und Nachteile. Ich nutze jedenfalls das neue System und bin zufrieden damit.
    1 point
  35. Hallo Habe ich schon, aber dein pooling asset habe ich mir gegönnt. Christoph
    1 point
  36. Hallo https://docs.unity3d.com/ScriptReference/Cursor-visible.html Das wird dir helfen. Btw ist das eine tolle Frage für Google... 😃 Christoph
    1 point
  37. Ne, ist schon der Normal Bias. Das ist halt immer ein bisschen problematisch mit dem. Man kann es kaum vermeiden, dass das Ding auf die eine oder andere Weise auffällt, wenn man nicht viele Details in der Szene hat. Hier ist ein bisschen was zum Lesen: https://docs.unity3d.com/2019.3/Documentation/Manual/ShadowPerformance.html https://www.reddit.com/r/Unity3D/comments/k3iipp/the_normal_bias_on_the_directional_light_seems_to/
    1 point
  38. Liebe Community, ich habe ein Problem mit Unity beim baken von AI Navigation Meshes. Beim Versuch erscheint eine "Hold On" Meldung (siehe Screenshot) und Unity selbst friert ein. Erst mittels Task-Manager-Kill und erneutem Start, ist Unity wieder bedienbar. Unity Version: 2020.3.6f1 (LTS) Terrain: 3x3 Tiles je ca. 512x512 Vertices mittels Gaia 2021 generiert wie ihr seht, habe ich das mehr als 3h laufen lassen in der Hoffnung, dass sich doch noch etwas tut. Leider vergebens. Ich bin relativ neu in Unity. Ich vermute mal, dass sich irgendein Skript während des Events "mouseUp" dazwischenschaltet und alles blockt. Allerdings ist das Projekt sehr gewachsen (1 Jahr Entwicklung) mit mehreren Dutzenden Skripten. Deshalb weiß ich nicht, wie ich das Problem lokalisieren soll. Kennt einer das Problem oder hat Vorschläge, wie man bei sowas am besten vorgeht? EDIT 30.10. 21:46 Uhr: Ich habe eine neue Scene erstellt Unity Terrain hinzugefügt (512x512). Bake getestet => funktioniert Per Gaia Manager ein sehr kleines Tiny Terrain hinzugefügt. Bake getestet => funktioniert Per Gaia Manager sehr großes Terrain hinzugefügt. Bake getestet => selbes Verhalten wie oben beschrieben Daraus schließe ich, dass es doch etwas mit der Größe des Terrains zutun hat. Aber so groß ist das Terrain eigentlich gar nicht. Und ich hatte vorher auch schon einige Terrain-Tiles beim Baken komplett rausgenommen. Also neue Frage: was sind meine Möglichkeiten? EDIT 30.10. 22:06 Uhr: Sorry, dass ich hier die ganze Zeit reineditiere.. aber als ich in dem "Navigation" Fenster -> im Reiter "Object" -> Häkchen bei "Navigation Static" bei allen Tiles außer einem rausgenommen habe, funktionierte das baken. (läuft gerade). Dabei ist Unitys RAM-Nutzung schlagartig auf 9 GB geklettert. Konnte meine RAM-Kapazität das Problem gewesen sein? Als nächstes werde ich versuchen, alle Tiles einzeln zu baken. Wenn ich eine Lösung gefunden habe, poste ich es zusammenfassend hier. Wenn einer direkt eine Lösung parat hat, gerne EDIT 30.10. 22:37 Uhr: Also jetzt weiß ich es ganz sicher: RAM Kapazität reichte nicht aus. Während ich mit 16GB RAM ganze 3 Tiles baken konnte, kann ich jetzt mit 32GB (ich hatte noch 2 Riegel rumliegen, die ich vorhin aus Interesse eingebaut habe) ganze 6 Tiles baken. Fehlen nur noch drei Tiles..
    1 point
  39. Super! Ja! Und das funktioniert nicht nur - es ist auch eine sehr gute Lösung. Drei kleine Änderungen würde ich jedoch vorschlagen: Du hast jetzt die Schleife Anfrage - Warten - Anfrage - Nochmal Das heißt, dass zwischen der zweiten und der dritten Abfrage keine Wartezeit liegt. Entferne einfach die zweite Anfrage aus deinem Code - die Wiederholung hast du ja schon durch die Schleife. while (enabled) { // Anfrage // Warten } Du benutzt "enabled" als Schleifen-Bedingung. Das ist super! Wenn du deine Komponente deaktivierst, arbeitet sie nicht mehr weiter. Genau dafür ist enabled ja auch da. Wenn du jetzt allerdings deine Komponente wieder anschaltest, dann wird die Coroutine nicht noch einmal neu gestartet. Start wird nur einmal pro Komponente ausgeführt. Du könntest die StartCoroutine-Zeile aber auch statt in Start in OnEnabled packen. Dann wird die Coroutine jedes Mal wieder gestartet, wenn du die Komponente reaktivierst. Um es komplett abzurunden, würde ich die Coroutine noch in OnDisable stoppen wollen. Wenn die Komponente deaktiviert ist und der Code-Fluss am "while (enabled)" ankommt, dann wird die Schleife, und damit die Coroutine, abgebrochen. Wenn du die Komponente aber deaktivierst, bricht die Coroutine deshalb noch nicht automatisch ab. Deaktivierst du deine Komponente und aktivierst du sie wieder, bevor die Schleife einmal ihre Bedingung überprüft, dann wird die Coroutine nicht beendet. Und wegen 2. startet dann eine neue, und du hast zwei gleichzeitig laufen. Daher einmal ein StopAllCoroutines() in OnDisable - nur zur Sicherheit.
    1 point
  40. Prinzipiell brauchst du dafür drei Elemente: Eine ganz normale Spielszene. Irgendetwas, das diese Szene daran hindert, als Spielszene zu funktionieren, bis sie auch wirklich gestartet wird. Dein Hauptmenü. 1. muss sein, weil du das Spiel ja direkt dort starten willst. Es reicht also keine Szene, die nur so aussieht, als wäre sie eine richtige Spielszene. Wenn du eine Fake-Szene nehmen könntest, würde 2. entfallen. Aber du willst natürlich nicht, dass man einfach anfangen kann zu spielen, solange das Menü noch offen ist. (Lustige Side Note: Bei mehreren 3D-Zelda-Spielen gibt es einen Glitch, bei dem man genau das machen kann.) Das Hauptmenü kannst du einmal komplett als Prefab anlegen und dann einfach instanziieren. Oder als Szene additiv laden. Ist vielleicht sogar netter. Jetzt, wo ich so darüber nachdenke, ist es vermutlich das beste, du lässt das Hauptmenü additiv die Spielszene laden. Du setzt also das Hauptmenü als erste Szene und packst da ein Script rein, das mit SceneManager.LoadScene deine Spielszene lädt, aber LoadSceneMode.Additive benutzt, damit das Hauptmenü nicht entladen wird. Vorher wird irgendein Schalter (z.B. eine statische bool-Variable) umgelegt, damit (2.) die Spielszene nicht sofort loslegt. Für die Implementation von 2. gibt es verschiedene Möglichkeiten. Du könntest die Zeit anhaltenoder die Spielfigur ausschalten oder gar nicht erst spawnen lassen, solange das Menü noch da ist.
    1 point
  41. Resources.Load will keine Dateiendungen. Also nur Resources.Load<TextAsset>("/Level/Level1") Und dann musst du diesen Pfad haben: Assets/[...]/Resources/Level/Level1.json wobei [...] alles mögliche sein kann, inklusive gar nichts (Resources-Ordner liegt direkt im Assets-Order). Die Alternative ist, dass du die TextAssets einfach irgendwo referenzierst: public TextAsset[] levels; und da ziehst du die Dateien dann rein.
    1 point
  42. Unity hat dazu allgemeine VR Packages, wo man nur beim Canvas ein Component reinpacken muss. Zusätzlich noch paar für die Controller für die Raycasts. Danach gehen diese Events auch normal für VR. https://docs.unity3d.com/Packages/com.unity.xr.interaction.toolkit@1.0/manual/index.html#ui-interaction-setup
    1 point
  43. Also @malzbie Vorschlag sollte die roten Fehler nicht ändern, denn das hat ja was eher mit dem Build zu tun. Ich kann ja theoretisch für Mac auch programmieren und würde keine Fehlermeldung sehen. Tippe daher auch auf @Sascha's Vorschlag, denn die Library oder Temp erstellen diese Sachen und binden es beim Projekt ein. Kann sein, dass in dem Fall nichts neues erstellt werden musste und daher Fehler auftauchen. Zur not kann man auch in der Unity Einstellungen die Visual Studio Projekte neu erzeugen lassen. Ich weiß gerade nicht aus dem Kopf wo genau das war.
    1 point
  44. Hast du denn alles umziehen lassen? Du willst nur dabei haben: Assets/ ProjectSettings/ Packages/ und so Sachen wie Temp/ oder Library/ sollten nicht mit umziehen, sondern immer nur lokal existieren. Lösche einfach mal diese Ordner, könnte schon reichen. Wobei die von @malzbie vorgeschlagene Lösung das vielleicht sogar automatisch mit macht; keine Ahnung.
    1 point
  45. Es gibt jetzt ein neues Video und noch viel mehr neues; schaut einfach mal in den ersten Post
    1 point
  46. Wenn Riffolk Ringe, Statuen oder anderen Schmuck oder Geglitzer benötigt, dann kann er Andarius einen Besuch abstatten. Andarius ist der dritte Händler im Dorf.
    1 point
  47. Hallo Also bei mir hat alles wunderbat geklappt. Dazu kam gleich noch der Erkenntnisgewinn, dass es ja Dinge gibt, die man über alle alle Szenen hinweg braucht. Hatte ich noch gar nicht verinnerlicht. Ein Logsystem ist genau so etwas. Das hatte ich bisher immer an einem GameManager hängen und da ich deine Abneigung kenne, habe ich mich immer schlecht dabei gefühlt. Des Weiteren hätte ich diesen in jeder neuen Szene neu erstellen müssen. So fällt das nun weg. Christoph
    1 point
  48. Also ein Trigger ändert nichts an irgendwelchen physikalischen Dingen, außer du machst im Code etwas! So wie du das beschreibst, muss im Code etwas passieren wenn du in den Tigger rein kommst und auch wenn du ihn wieder verlässt. Oder es doch kein Trigger.
    1 point

Announcements

Hy, wir programmieren für dich Apps(Android & iOS):

Weiterleitung zum Entwickler "daubit"



×
×
  • Create New...