Jump to content
Unity Insider Forum

Zer0Cool

Members
  • Content Count

    1,966
  • Joined

  • Last visited

  • Days Won

    139

Everything posted by Zer0Cool

  1. Kommt auf das Zielsystem an (Mac usw. kenn ich mich nicht aus), bei Windows würde ich es in der Registry verstecken, also nicht PlayerPrefs sondern über die Windows-API. Die kann man auch über C# modifizieren. Wasserdicht ist es natürlich nicht, der Spieler kann alles auf seinem lokalem PC alles "manipulieren". Es gibt auch diverse Tools womit man leider Registryänderungen einfach "tracken" kann. Wenn man noch mehr machen will kann man Informationen auch innerhalb von Plattenpartitionen verstecken (hidden blocks), da bin ich mir aber nicht sicher ob man da über C# rankommt.
  2. Wenn man etwas weiter ausholt: - einen NavMesh für deine Szene erstellen damit du einen Navmesh-Agent verwenden kannst - einen Controller verwenden oder selbst programmieren der den Agent steuern kann - dieser Controller sollte ebenfalls die Animationen des Gegners steuern können und diese mit der Bewegung des Agents synchronisieren Je nachdem ob du diesen "AI-Controller" selbst programmierst oder wie viel dieser Controller können soll (sauber synchronisierte Rootmotion-Animationen zwischen Navmesh-Agent oder nur einfache Animationen ohne Rootmotions) entsprechend aufwendig oder weniger. Wenn man beispielsweise einen fertigen Controller aus dem Asset-Store verwendet hat man die Punkte 2 und 3 relativ schnell erledigt. Hat man die oberen Punkte alle abgehakt bzw. entschieden, dann kommt man zu dem Punkt was @chrische5 vorgeschlagen hat, wo man sich dann um die eigentliche KI-Logik kümmern muss. Aber auch hier gibt es schon fertige Skripts wie "Follow" oder "Patrol" oder "Attack" (für einige Controller) oder man taucht selbst in die Skripte ein. Hier kann man gut und gerne auch als Anfänger selbst Hand anlegen. Die Entwicklung eines Controllers ist schon etwas aufweniger, aber je nachdem was man alles haben will ... natürlich kann man auch ohne NavMesh auskommen (dann bleibt der Gegner halt mal an irgend einer Ecke hängen) und nur einfach eine Laufanimation abspielen wenn der Gegner sich bewegt (was halt optisch nicht AAA ist aber für kleinere Spiele vollkommen ausreichend).
  3. Ist halt auch nicht gerade günstig: https://assetstore.unity.com/packages/tools/terrain/path-painter-163352 kostet weniger aber ob es was taugt weiß ich nicht: https://assetstore.unity.com/packages/tools/terrain/terrain-mountain-road-maker-60550 Ansonsten die Terrain Splatmap(s) exportieren, in Photoshop bearbeiten und dann wieder importieren ist am billigsten. PS: Ich bin gerade dabei eine Art Terrain-Deformer zu erstellen, theoretisch sollte dieser in der Lage sein einen Pfad auf einem Terrain zu berechnen. Ich müsste das Tool nur im einen Spline und Meshgenerator ergänzen. Das Tool ist wenn es fertig ist dazu in der Lage das Terrain an beliebige Geometrie anzupassen. Vornehmlich war die Idee damit Häuser ins Terrain einzubetten ...
  4. Ja ist ein Webserver (und Apache kann man natürlich auch verwenden) und die Kommunikation läuft über HTTP, aber HTTP zu verwenden sollte für einen Gameserver in Ordnung sein. Klar hat HTTP einiges an Overhead das durch die Leitung geht, daher kann eine Lösung wohl auch ein TCP-Server oder sowas sein, aber damit kenne ich mich nicht aus. Ich denke je höher der Traffic des Spiels später sein wird desto mehr sollte man vielleicht in Richtung TCP gehen um Bandbreite zu sparen. Man kann sogar mit Unity einen "schlanken" Server bauen, hätte den Vorteil das Client und Server zusammenpassen. Und dann gibt es auch noch Frameworks wie Photon- oder Smartfox-Server ... Einige Smartphonespiele verwenden sowas und sind vollkommen zufrieden damit. Hier hat auch mal jemand danach gefragt, aber so genau kenne ich mich mit Socket-Programmierung nicht aus:
  5. Ja, du musst auch nicht den ganzen Server "neu" entwickeln. Man nimmt beispielsweise einen Tomcat-Server (ist derzeit recht verbreitet), dieser läuft sowohl auf Windows als auch auf Linux problemlos. Im nächsten Schritt entwickelt man dafür beispielsweise ein Servlet (in Java) welches die Kommunikation mit den Clients implementiert. Das fertig programmierte Servlet wird dann auf den bereits laufenden Tomcat unter Linux deployed. Während der Entwicklung lässt man den Server dann lokal unter Windows laufen. Ein Servlet ist zumindest für kleinere Games völlig ausreichend, aber selbst größere Games könnte ich mir damit gut vorstellen, wenn man entsprechend die Skalierbarkeit mit einplant. Die Verwendung eines Tomcat hat auch den Vorteil das einige "sicherheitsrelevante" Mechanismen bereits implementiert sind und man sich darum nicht mehr im Detail kümmern muss. Zudem kann man in der Entwicklung ein "Hot-Deploy" einrichten wobei der Server nicht neu gestartet werden muss, wenn man Änderungen am Servlet deployen möchte.
  6. Ich kann dir nur berichten, dass es mit Java kein Problem darstellt. Mit C# unter Linux habe ich keine Erfahrung, lese aber gerade Mono und .Net Core wird unter Linux unterstützt. Nach meiner Erfahrung lässt man C# dann aber eher auf Windows-Servern laufen und die meisten Cloud-Anbieter bieten beide Servertypen an. Da jetzt Java und C# sich doch ziemlich ähnlich sind würde ich in deinem Fall dann eher in Java entwickeln.
  7. Ich vermute mal du hast die Bäume auf das Terrain gemalt... Ab einem bestimmten Abstand rendert Unity dabei nicht mehr die Bäume, sondern ersetzt diese durch einfache Billboards (die sind einfache 2D-Grafiken die sich immer zu der Kamera drehen) die das Terrainsystem automatisch erzeugt. Die Bäume werden dann über einen Billboard-Renderer gerendert. Du kannst einmal Testen, ob die grauen Bäume tatsächlich Billboards sind, indem du die Distanz ab dem die Billboards angezeigt werden verschiebst. Dabei müsst du den "Billboard Start" verändern: https://docs.unity3d.com/Manual/terrain-OtherSettings.html Leider kenne ich das Problem mit den grauen Billboards. Das Problem kann dabei folgende (mir bekannte) Ursachen haben: Deine Light-Settings in der Scene sind noch nicht korrekt eingestellt. Hier kann man beispielsweise die Lightmap für die Scene erzeugen (siehe "Generate Lightning"): https://docs.unity3d.com/Manual/Lightmapping.html Damit bekommen auch die Billboards eine andere "Beleuchtung": Eine andere Ursache war einmal die Fog-Einstellungen in Unity. War der Fog aktiviert, dann führte dies dazu das die Billboards quasi als im Nebel dargestellt wurden und damit grau wurden. Die Einstellung für Fog ist ebenfalls im Lightning-Fenster im Szene-Tab (oder bei HDRP im Post-Processing Profil). Du kannst ja mal schauen, ob hier ein Haken gesetzt ist. Sollte man hier die Einstellung verändert haben, dann kann es sein, dass man noch einmal all Texturen der Bäume bzw. das Asset neu importieren muss, damit Unity die Billboard-Texturen neu berechnet. Eine weitere Ursache (und auf diese Ursache würde ich tippen) kann das verwendete Baum-Asset sein, es gibt leider Assets bei denen die Erzeugung der Billboards über Unity nicht richtig funktionert, hier hilft es meist nur das Asset auszutauschen. Dabei kann das Problem die verwendeten Shader dieses Assets sein, das verwendete Baummodel oder allgemein ein "falsch" eingestelltes Asset. Es gibt auch "Lösungen" die dann den Billboard-Renderer manipulieren, aber meist erzeugt man dann damit nur andere Probleme (wie glänzende oder weiße Bäume in der Nacht etc.) Bezüglich der Shader, du kannst auch einmal prüfen, ob dein Baum-Asset einen der folgenden Shader in seinen Materials verwendet, wenn nicht, dann könnten die verwendeten Shader "inkompatibel" mit dem Unity-Terrain sein und so das Problem verursacht werden:
  8. Schwer zu erkennen, da ich den Inhalt einiger Variablen nicht kenne, normal sollten Input-Eingaben immer in der Update-Methode gemacht werden. Ansonsten bau doch mal ein Debug.Log ein und schau was bei dem Mausklick herauskommt: (siehe Scene-View) Vector2 moveToPos = playerPosition - direction * distance Debug.Log("Wir bewegen uns zu: " + moveToPos); Debug.DrawLine(new Vector3(playerPosition.x,playerPosition.y,transform.position.z) , new Vector3(moveToPos.x,moveToPos.y,transform.position.z), Color.red, 2.5f); rb2d.MovePosition(moveToPos);
  9. Habe es mal ausprobiert. Wenn du eine Texture mit 128x128 Pixel hast musst du die PPU auch auf 64 stellen. Damit erstreckt sich dieses Sprite nun über 128x128 Pixel im Game. Das Ganze klappt auch bei Texturen wie beispielsweise 512 x 64 (also wie bei deiner Healthbar). Dabei muss man bei der Healthbar ja nicht alle 64 Pixel "ausfüllen", da man die anderen Pixel ja über den Alphachannel ausblenden kann.
  10. zu 2) Der Gedanke dahinter ist denke ich, dass der Pixel eines Sprites exakt einem Pixel der horizontalen Bildschirmaufösung entsprechen sollen und damit auch die PPU ein ganzzahliger Teiler der horizontalen Bildschirmauflösung in Pixel sein sollten. Beispiel: Bildschirmauflösung: 1024x768 (ratio = 1.33) PPU = 64 = 64 Pixel pro Unity-Einheit damit 1024 Pixel / 64 Pixel = 16 Units (ein Unity-Würfel mit Scale 16) => Wir wollen also das 16 Einheiten auf den Bildschirm passen, damit 16 Sprites nebeneinander die volle Breite des Bildschirms in Pixel ausfüllen => damit die Ränder der 16 Unity-Einheiten links und rechts mit dem Bildschirmrand abschließen muss die Orthographic -Kamerasize wie folgt berechnet werden: (16 / 2) * 768/1024 = 6 (Camera ortographic size) Nimmt man nun beide Formeln und vermischt diese, dann kann man die Formel entsprechend kürzen: Number Units = W / PPU = 1024 Pixel / 64 Pixel = 16 Camera ortographic size = (16 / 2) * 768/1024 = ((W / PPU) / 2) * 768/1024 = (W / PPU / 2) * H/W = W / (PPU * 2) * H/W = W *H / (PPU * 2) * W = H / (PPU * 2) = H / PPU / 2 Damit ist das Spielfeld bestehend aus 16 Unity-Einheiten voll in der Kamerasicht (Viewport) und die 16 Sprites (64x64) in horizontaler Reihe sollten den Screen füllen So sieht dann das Ergebnis in Unity aus (16 Figuren-Sprites a 64 Pixel in einer Reihe nebeneinander = 64 * 16 = 1024 Pixel):
  11. Markier mal Vector3 und drück RMB und geh auf "Go to Definition" dann sollte er eigentlich in den struct Vector3 im Namespace "UnityEngine" springen. Theoretisch als test kannst du auch mal schreiben: public UnityEngine.Vector3 pos; dann sollte UnityEngine grau angezeigt werden und Vector3 diese blau-ähnliche Farbe. (wobei er bei dir oben die Namespaces auch nicht eingefärbt hat, hat er bei mir aber bei UnityEngine auch nicht gemacht)
  12. siehe auch https://docs.unity3d.com/ScriptReference/Physics.Raycast.html oder https://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html
  13. Schau mal ob du hier: https://docs.unity3d.com/2017.3/Documentation/Manual/FBXImporter-Rig.html Animationtype auf "Humaniod" gestellt hast, wenn es dann immer noch nicht klappt nimm ein anderes Model.
  14. Wenn dein Hund-Png da mit einem non-kinematic Rigidbody2d verbunden ist müsste man sogar die FixedUpdate()-Methode verwenden.
  15. Ich geh mal davon aus, das die Distanz-Berechnungen und der Direction-Vector stimmt. Das solltest du mal mit Debug.Line prüfen. Ansonsten sehe ich du übergibst hier eine Mask (playerMask) und dann auch noch falsch, weil an der 3. Position die Distanz übergeben wird. RaycastHit2D hit2D = Physics2D.Raycast(transform.position,direction*distance, playerMask); Probier es mal so: Debug.DrawRay(transform.position, direction*distance, Color.green, 2f); RaycastHit2D hit2D = Physics2D.Raycast(transform.position, direction*distance);
  16. Ja was ich vorgeschlagen hatte funktioniert nur für ein Child des gleichen Typs, bei mehreren ist dann deine Methode gut.
  17. _slotImages.Add(GameObject.Find("ItemIcon").GetComponent<Image>()); _slotAmounts.Add(GameObject.Find("Amount").GetComponent<TextMeshProUGUI>()); Hab mir nicht alles im Detail angeschaut, aber hier durchsuchst du alle GOs nach dieser Komponente (und damit findet er vermutlich immer nur den 1. Button), was falsch ist, du willst ja nur das aktuelle GO durchsuchen. Hier gibt es diese Methode die ich verwenden würde: GameObject button = Instantiate(_slotButtonPrefab, _slotButtonCanvas.transform, true) as GameObject; _buttons.Add(button.GetComponent<Button>()); _slotImages.Add(button.GetComponentInChildren<Image>()); _slotAmounts.Add(button.GetComponentInChildren<TextMeshProUGUI>());
  18. GPU-Instancing muss man in Unity über eine Klasse (Script) ansteuern und spezielle Methode aufrufen, wenn du das mit diesem Shader nicht geplant hast, dann kannst du den ganzen Block aus dem Shader rauswerfen, da es nie benutzt wird. HDRP und LWRP haben bereits ihren eigenen visuellen Shader-Editor (Shader Graph) integriert, hab ich aber auch noch nicht benutzt, ist aber für 3D Artists ein wichtiges Tool was schon eine Weile überfällig war. Für das "normale" Unity (nennt sich glaub Built-In Unity Renderer) gab es aber auch schon visuelle Editoren, aber nicht von Unity selbst. Ich würde um einen performanten Shader zu schreiben auch einen Shader verwenden mit Fragment und Vertex Funktion, weil nur hier siehst du was der Shader intern so treibt. Bei der "fancy" Shaderlab-Syntax oder der Syntax von Surface-Shadern treibt er ggf. einige Sachen im Hintergrund was wieder ungewollt Performance kosten kann.
  19. Ja, es darf nur eine Start-Methode geben und dann quasi so void Start() { currentLevel = SceneManager.GetActiveScene().buildIndex; rb = GetComponent<Rigidbody>(); count = 0; SetCountText(); winText.text = ""; }
  20. Wenn du das noch einbaust, dann wird currentLevel immer auf das aktuell geladene Level gesetzt: private int currentLevel = 0; void Start () { currentLevel = SceneManager.GetActiveScene().buildIndex; } void SetCountText() { countText.text = "Count: " + count.ToString(); if (count >= 12) { winText.text = "You Win!"; StartCoroutine (LoadNextLevel(++currentLevel, 5f)); // Läd Level mit Index "currentLevel + 1" nach 5 Sekunden } } IEnumerator LoadNextLevel(int level, float timetowait) { yield return new WaitForSeconds(timetowait); // wartet timetowait Sekunden SceneManager.LoadScene(level); // Läd das Level mit dem Index level } Damit wird die Reihenfolge der Level nun über den Build-Index bestimmt, siehe Dialog oben wo du die Szenen einstellst, man kann hier auch die Reihenfolge verschieben ...!
  21. Wenn ich es richtig verstanden habe, dann wolltest du folgendes (vielleicht mathematisch nicht die beste Lösung aber sie funktioniert). "Nachladen" speichert die bereits benutzten Nachlade-Aktionen des Spielers. private HashSet<int> Nachladen = new HashSet<int>(); private int reloadCounter = 100; private int currentScore; void Update() { if (Input.GetKeyDown(KeyCode.R)) // zum Test: der Spieler bekommt Punkte beim Drücken der R - Taste { currentScore = currentScore + Random.Range(1,5); // Zum Test: Der Spieler bekommt zwischen 1..5 Punkte Debug.Log(currentScore); if (currentScore / reloadCounter > 0) { if (!Nachladen.Contains(currentScore / reloadCounter)) { Debug.Log("Nachladen!"); Nachladen.Add(currentScore / reloadCounter); // MehrSchuss(); } } } }
  22. Schau dir mal den LineRenderer an, der sollte eine gute und relativ einfache Möglichkeit sein: https://docs.unity3d.com/Manual/class-LineRenderer.html Hier noch ein alter Thread wo du einige Beispiele finden kannst:
  23. Du musst die Szenen die du laden möchtest in den Build-Settings eintragen. Dabei bekommt jede Szene einen Index, dieser Index muss beim Laden der Szenen angegeben werden. Deine Start-Szene hat den Index 0. Weitere Level dann z.B. den Index 1 , Index 2 usw. File -> "Build Settings" -> "Add Open Scenes" Hier der Code wie du die Level dann laden kannst. Ich habe dies so erweitert, dass du einstellen kannst wie lange Unity noch warten soll bis er das Level läd, damit der Spieler noch seine erreichte Punktzahl sehen kann: private int currentLevel = 0; void SetCountText() { countText.text = "Count: " + count.ToString(); if (count >= 12) { winText.text = "You Win!"; StartCoroutine (LoadNextLevel(++currentLevel, 5f)); // Läd Level mit Index "currentLevel + 1" nach 5 Sekunden } } IEnumerator LoadNextLevel(int level, float timetowait) { yield return new WaitForSeconds(timetowait); // wartet timetowait Sekunden SceneManager.LoadScene(level); // Läd das Level mit dem Index level }
  24. Ich hab mal noch einen Highlight-Shader eingebunden und damit jeder was davon hat kommt es hier in den Thread. Der Shader ist nicht ganz perfekt aber dafür kostenlos und man muss kein Postprocessing betreiben (was mehr Performance kostet) um das Gleiche zu erreichen. Damit man nicht den Unity-Standardshader anpassen muss verwende ich hier einfach 2 Materials für den gleichen Mesh. Das 1. Material rendert den Mesh und das 2. Material rendert die Outline um den Mesh. Man könnte das ganze auch in einen Shader packen, aber sobald sich der Unity-Standardshader ändert muss man diese Code wieder nachziehen. Die Klasse Selectable muss entsprechend angepasst werden um diesen Shader zu verwenden: using System.Collections; using System.Collections.Generic; using UnityEngine; public class Selectable : MonoBehaviour { public Material defaultMaterial; public Material highlightMaterial; public float maxDistanceCamera = 10f; public float outLineWitdh = 0.0005f; private Camera m_Camera; private SelectionManager m_SelectionManager; private Renderer m_Renderer; private Transform originalParent; private Vector3 originalPosition; private Quaternion originalRotation; private Material originalMaterial; private float distanceToCamera; // Start is called before the first frame update void Start() { originalParent = this.transform.parent; originalPosition = this.transform.position; originalRotation = this.transform.rotation; m_SelectionManager = GameObject.FindObjectOfType<SelectionManager>(); m_Renderer = this.GetComponentInChildren<Renderer>(); m_Camera = GameObject.FindObjectOfType<Camera>(); originalMaterial = m_Renderer.material; } public void Reset() { this.transform.parent = originalParent; this.transform.position = originalPosition; this.transform.rotation = originalRotation; m_Renderer.material = defaultMaterial; m_SelectionManager.CurrentSelection = null; } void OnMouseDown() { distanceToCamera = (transform.position - m_Camera.transform.position).magnitude; if (distanceToCamera < maxDistanceCamera) { m_SelectionManager.CurrentSelection = this.gameObject; this.transform.parent = m_SelectionManager.SelectableHandle; this.transform.localPosition = Vector3.zero; } } //If your mouse hovers over the GameObject void OnMouseOver() { distanceToCamera = (transform.position - m_Camera.transform.position).magnitude; if (distanceToCamera < maxDistanceCamera) { //m_Renderer.material = highlightMaterial; Material[] materials = m_Renderer.materials; materials = new Material[2]; materials[0] = highlightMaterial; materials[0].SetFloat("_Outline", outLineWitdh); materials[1] = originalMaterial; m_Renderer.materials = materials; } } //The mouse is no longer hovering over the GameObject void OnMouseExit() { //m_Renderer.material = defaultMaterial; Material[] materials = new Material[1]; materials[0] = originalMaterial; m_Renderer.materials = materials; } } Das Selectable-Skript bekommt nun ein Material mit diesem Shader zugewiesen: Das Ergebnis sieht dann so aus: Für jedes Mesh muss leider separat die Dicke der Outline eingestellt werden, so hat z.B. die Vase eine Dicke von 0.01 und die Figur rechts daneben 0.0005. Der Shader ist im Anhang. Silhouette Only.shader
  25. Ja, das kann gut sein. Schieß mal einen Raycast von der Position der Kamera ab (in Richtung des GO) und schau was sie trifft...
×
×
  • Create New...