Jump to content
Unity Insider Forum

Script ( Berechnung+ Speichern)


snooop87

Recommended Posts

Hallo liebe Community,

 

mein größtes Problem ist die Berechnung der "Welt" , es sollen 15625 Räume mit zufälligen Farben,Fallen,Belohnungen,6 Zugänge/Verbindungen und Größen in einer offline-Datenbank, Bibliothek oder Datei gespeichert werden.

 

(sinn: der client soll einen Raum abfragen und die genannten inhalte wiedergeben)

 

Die Räume werden jeden Tag komplett neu geordnet(shuffle),dies geschieht am besten bei einer Abfrage beim Start des Clienten,es sollen nicht alle Räume gleichzeitig geladen werden, sondern nur der Raum, indem sich der Spieler befindet und die 6 anliegenden Räume.

 

( Gleich ne Frage vorweg:ist das Sinnvoll zur Ressourcen/ und Cpu Einsparung insgesamt nur 7 Räume darzustellen anstatt gleich alle 15625?)

 

ich bitte hier nicht um ein Fertiges Script,sondern eher um Rat /Tipps zur Umsetzung, Ich schreibe euch hier meine Code in Deutsch mal auf, den ich zurzeit im Kopf habe.

 

Abfrage ob 1 Tag vergangen ist,wenn ja tue
Variablen definieren DatenSatz-ID (hat  Raum,farbe,falle,belohnung,6verbindungen,groß)
Mische Zahl 1- 15625
und speicher Sie als DatenSatz ab
für jeden DatenSatz erstelle einen DatenSatz mit
ID (immer aufsteigend)
Farbe ( zufälliger int zwischen 1-20)
Fallen ( zufälliger int zwischen 1-20)
Belohnung( zufälliger int zwischen 1-20)
Verbindungen( ID von a,b,c,d,e,f näheres unten)
Groß ( chance von 1zu100 wenn ja dann int 1 sonst 0)
Speicher die Datensätze in Datei,Bibliothek,Datenbank

 

Wenn ich jetzt mein Client frage nach Datensatz 1, muss er unbedingt

( 1,15821,20,5,1,15393,15394,11223,12345,12341,8213,0) ausgeben

( ID,Raum,Farbe,Falle,Belohnung,Verbindung1,Verbindung2, Verbindung3,Verbindung4,Verbindung5,Verbindung6,groß)

 

Jetzt näheres zu der Generierung der Verbindung :da die Räume nicht nur nebeneinander sind sondern sich 25 nach rechts, 25 nach unten und 25 zur tiefe logisch aufbauen sollen, haben Sie feste Verbindungen, die ich in einer extra datei /script definiert habe über ( ID, Verbindung A,B,C,D,E,F)

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

( Gleich ne Frage vorweg:ist das Sinnvoll zur Ressourcen/ und Cpu Einsparung insgesamt nur 7 Räume darzustellen anstatt gleich alle 15625?)

 

Mal ehrlich .. was denkst du denn ?

 

Ich schreib hier mal jetzt kein Code sondern hinterfrage lediglich mal ein paar Sachen.

 

Erstmal wieso gerade 15625 Räume ?

Wieso jedesmal 7 Räume generieren, wieso generierst du nicht nur jeweils den Raum der als nächstes betreten wird ?

Ich würde mehrere Datenbanktabellen machen, Farbe, Falle etc. und dann würde ich aus den Listen per Zufall ein Raum generieren, da jede DB Tabelle eine ID hat würde ich aus den EinzelIDs eine Lange ID machen die ich bei Generierung des Raums sichere, durch den Vergleich eines neu erstellten Raums mit den abgespeicherten IDs kannst du dann sicherstellen das kein Raum doppelt generiert wird. (Sofern du das willst.)

Wieso muss man jeweils 1 Tag warten ?

Gibt es denn ein Ziel oder ist das ein Endlosgame ?

Wenn du alle Räume definiert generieren würdest, würde ich die Räume aus der Datenbank als ID-Code generieren und fest einem Raum zuweisen.

 

Im Spiel musst du dann nur noch abfragen welcher Raum vom Spieler betreten wird und die vorab erstellte Konstellation aus der DB laden.

 

Gruss Just

Link zu diesem Kommentar
Auf anderen Seiten teilen

danke für deinen Beitrag Just4Info, es sind 15625 Räume, weil man in einen Würfel-Labyrinth eingesperrt ist der aus 25*25*25 Würfeln besteht.

 

7 Räume generiert er, weil ich mir dachte, da die Türen nur 1 sekunde Animation haben, man den nächsten Raum sofort sieht( evlt Fallen vermeiden kann und wieder zurrückgehen kann)

das Problem denke ich ist auch das ich noch nicht probiert habe, den fertigen Raum mit allen vor mir zu Spawnen, warscheinlich unterschätze ich Unity

 

1 Tag warten: dient einzig und allein den Schwierigkeitsgrad, wenn man wenig spielt ,hat man wenig chance den Ausgang zu finden.

desweiteren, soll es den Spieler möglich sein( an einen Tag) alte räume wieaufzusuchen um sich Hinweise nocheinmal anzuschauen

 

Danke für deinen Ratschlag alles in mehrere Datenbanktabellen zu erstellen, welche Datenbank sollte ich deiner Meinung nach für nehmen, wenn der Spieler schnell die Räume ohne Fallen hinter sich lässt.Es Soll ein Abenteuer-Survival Spiel werden, ohne Ladezeiten

dein Letztes Klingt Supper, nur schafft das Unity flüssig?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstmal wieso gerade 15625 Räume ?

25^3 = 15625 (vermute ich mal als Grund)

 

Also die Verbindungen sind wohl redundant: Ich vereinfache mal mit einem 1000er-Raum also 10^3:

 

Jede dreistellige Zahl <abc> hat als Nachbarn diejenigen Zahlen deren einzelne Ziffern +1 oder -1 von der entsprechenden Ziffer in <abc> hat, sofern sie nicht den Rand (0 oder 9) sprengt. Im Beispiel ist es einfacher:

 

735 hat: 635 und 835, 725 und 745, sowie 734 und 736 als Nachbarn.

 

Schreibe ich eine Integer-Zahl A aus dem (Dezimal-)Bereich [0;15624] in einem Zahlensystem zur Basis 25 (heißt das dann Pentaeikosalsystem ? ;-) dann entsteht x*25^0 + y*25^1 + z*25^2, mit:

  • z = A / 625
  • y = (A - 625*z)/25
  • x = A - (625*z + 25*y)

Die Nachbarn sind dann (x-1; y; z), (x+1; y; z), (x; y-1; z), ... Natürlich ausgenommen an den Rändern also 0 und 25.

 

Ich würde mir daher eine Hilfsklasse RoomNo schreiben, in der du die Konvertierung vornimmst. Ich vermute du wirst für die Positionsberechnung etc. ohnehin immer wieder die 3 Koordinaten brauchen

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hab mich jetzt noch nicht direkt mit Datenbanken und Unity beschäftigt, jedoch mache ich das täglich auf der Arbeit mit anderen Programmen.

 

Datenbank würde ich MySQL empfehlen, ist kostenlos, schnell und habe gehört das man diese auch in Unity verwenden kann.

Die Datenbankstruktur und die Tabellen legst du ja direkt an, die Zufällige ID-Zusammenstellung und Zuweisung zu den Räumen muss ja nicht im Spiel passieren, das kann vorab passieren.

 

Bei Multiplayer machst du das einmal auf dem Server, damit es für alle gleich ist, beim Singleplayer kannst du das beim ersten start durchführen, oder schon zusammengestellt ausliefern.

 

Wenn das Spiel erfolgreich abgeschlossen wurde, könntest du z.B. einfach die Räume neu generieren, so bekommt dein Spiel ein Wiederspielwert, da es jedesmal anders sein kann.

 

Das mit dem Tag verstehe ich nicht, meinst du Realtime ? Wenn jemand dein Spiel mag und du Ihn so extrem beschränkst das er nur pro Tag 6 Räume betreten kann werden viele die mehr wollen vielleicht abspringen.

 

Oder bau nen Onlineshop drum rum wo man sich freie Tage kaufen kann :D (Kleiner Scherz)

 

Ob Unity den Raum schnell genug generieren kann hängt von mehrern Faktoren ab. Kommt drauf an was er halt so alles berechnen muss.

 

Du könntest die Zeit des Aufbaus mit der Zeit verknüpfen die die Tür brauch um geöffnet zu werden. Wenn die Tür offen ist = der Raum vollständig geladen.

Oder aber du setzt vor der Tür ein Trigger damit der Aufbau schon etwas früher beginnt.

Ich denke aber 6 Räume zu generieren wird jetzt auch nicht so viel Ressourcen kosten.

 

Versuch es doch erstmal einen Raum anhand von einigen Prefabs zu generieren, dann siehst du wie gut/schlecht das läuft. Wenns gut läuft, kannst du dann den Code gleich weiter verwenden, wenn nicht, denkst du dir was neues aus :)

 

Ich kenne den Film "The Cube" denke daher kommt deine Inspiration. Finde die Idee echt cool.

Ich würde es Multiplayertauglich machen wo man dann auch andere Spieler sieht und sozusagen schauen kann was dem anderen im nächsten Raum so passiert .. halt wie im Film.

 

Zur Idee des Spiels noch was .. fände ich ziemlich cool.

Wenn du es MP tauglich machst, würde ich immer Cubesessions machen, bedeutet, Spieler kommen alle in die gleiche Session, jeder kann solange spielen wie er mag, bis er entweder den Ausgang gefunden hat oder aber gestorben ist.

Leute die gestorben sind können erst wieder mitspielen wenn die nächste Session beginnt. (Entweder alle Teilnehmer tot oder aber einer hat den Ausgang gefunden = der Gewinner)

Wenn man ausloggt bleibt der Char im Cube in einer Schlafpose.. wie in Rust.. logged man wieder ein gehts dort weiter.

Der Gewinner kommt in eine Highscoreliste, vielleicht bekommt er auch nen keinen Bonus für die nächste Runde.

 

Bin mal gespannt wie du die Fallen umsetzt und dessen Tötlichkeit bzw. die Chance überhaupt länger dabei zu überleben.

 

Wenn ich Zeit hätte würde ich dir bei dem Spiel helfen, das Teil hat echt Potenzial

Link zu diesem Kommentar
Auf anderen Seiten teilen

Noch eine Idee: Brauchst du überhaupt die Datenbank?

 

Eigentlich könntest du auch mit Pseudozufallszahlen arbeiten also entweder was selbst gestricktes a la:

color = 2 * roomNo % 7 + roomNo % 6; // au weia :-)

oder besser gleich die Random-Klasse über Seed nutzen

color = new Random (roomNo).Next (20);

 

Das liefert dir garantiert immer den gleichen Wert für die gleiche roomNo. Um es zu verschleiern könnte man noch roomNo + MySecretColorOffset (= Konstante) nehmen. Wenn du sonst nichts persistent machen musst sondern nur die paar Zufallszahlen reproduzierbar brauchst, pack die Dinger in solche Formeln. Du bist mit wenigen Zeilen raus, sparst dir die Komplexität der DB-Anbindung und ist Performance-mäßig nicht zu toppen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke ,meine Inspiration kommt tatsächlich von Cube² und InTime, das Spiel soll Multiplayer fähig sein, und das Leben was jeder Spieler besitzt wird in Zeit gerechnet.

in+time+timberlake.jpg

 

Das Leben geht Quasi in Echtzeit den Bach runter, man bekommt Zeit für Archivments, Belohnungen,wenn du andere Spieler hilfst, und wenn du Fallen überlebst.(wenn du dich auslogst geht Sie natürlich nicht weiter)

 

Ich werde Morgen ein Video von mein Projekt erstellen, um dir mein Fortschritt zu zeigen, ich würde mich echt freuen, wenn mir jemand beim Scripten unter die Arme greift.

Link zu diesem Kommentar
Auf anderen Seiten teilen

das klingt supper mit den RandomSeed, funktioniert das auch im Multiplayer und wenn ich einen Reset haben möchte( 1day)?

Sollte kein Problem sein. Eine Möglichkeit wäre es, den aktuellen Tag in den Seed-Parameter zu integrieren, also so was:

DateTime today = DateTime.Today;
DateTime refDate = new DateTime (2000, 01, 01);
int noOfDays = (today - refDate).Days;
Random currentRandom = new Random (roomNo + noOfDays).

Müsste noch auf UTC oder ähnliches umgestellt werden wg. Zeitzonen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also wenn er wirklich noch ein Single-Player Spiel schreiben möchte dann würde ich kein MySQL empfehlen. Dann müsste ja jeder der sein Spiel spielen möchte vorher ersteinmal ein MySQL installieren und ein MySQL Benutzernamen/Passwort einrichten und dieses dann im Spiel konfigurieren damit das Spiel darauf zugreifen kann.

 

Wenn man eine relationale Datenbank in einem Spiel nutzen möchte führt wohl kein weg an SQLite vorbei. Umfangreichere Sachen wie MySQL oder PostgreSQL würde ich nur auf einem Server nutzen wenn du einen Multiplayer plannst und eine Internetverbindung zum Spiel vorraus setzt.

 

Ohnehin würde ich aber ebenfalls das überlegen was kayy sagte. Nämlich ob du alle Sachen überhaupt persistent abspeichern musst. Wenn du bei den Pseudo Random Generatoren immer den gleichen Seed vorgibst kommen auch immer die gleichen Zahlen dabei raus. Es würde also auch reichen wenn du die Raumnummer als Seed nutzt und dann alle Zahlen die du benötigst einfach zur Laufzeit generierst.

 

Zum anderen würde ich ebenfalls überlegen ob du überhaupt eine Datenbank benötigst. Du sprichst von 15625 Räumen und in deinem Beispiel hattest du 12 Zahlen die du speicherst. Wenn du diese als eine 32 bit integer speicherst dann sind das pro Raum gerade mal 48 Bytes speicher die du benötigst. Oder bei 15625 Räumen dann 750000 bytes also gerade mal 0,7 MByte an Speicher.

 

Selbst als SaveGame in einer Datei wäre das nicht wirklich bedeutend. Zwar kommt evtl. noch etwas Overhead dazu wenn du es als Datei serialisiert oder zur Laufzeit kommt noch etwas Overhead dazu wenn du daraus klassen erstellst etc. trotzdem reden wir hier von einer ziemlichen geringen Datenmenge.

 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Memory : MonoBehaviour {
public class Room {
	public int id          { get; set; }
	public int raum        { get; set; }
	public int farbe       { get; set; }
	public int falle       { get; set; }
	public int belohnung   { get; set; }
	public int verbindung1 { get; set; }
	public int verbindung2 { get; set; }
	public int verbindung3 { get; set; }
	public int verbindung4 { get; set; }
	public int verbindung5 { get; set; }
	public int verbindung6 { get; set; }
	public int groß        { get; set; }
	public Room (int id, int raum, int farbe, int falle, int belohnung, int verbindung1, int verbindung2, int verbindung3, int verbindung4, int verbindung5, int verbindung6, int groß) {
		this.id          = id;
		this.raum        = raum;
		this.farbe       = farbe;
		this.falle       = falle;
		this.belohnung   = belohnung;
		this.verbindung1 = verbindung1;
		this.verbindung2 = verbindung2;
		this.verbindung3 = verbindung3;
		this.verbindung4 = verbindung4;
		this.verbindung5 = verbindung5;
		this.verbindung6 = verbindung6;
		this.groß        = groß;
	}
}

// Use this for initialization
void Start () {
	long memUsageStart = System.GC.GetTotalMemory(true);

	Dictionary<int, Room> rooms = new Dictionary<int, Room>();
	for ( int i=0; i < 25 * 25 * 25; i++ ) {
		var room = new Room(
			id:          Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			raum:        Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			farbe:       Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			falle:       Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			belohnung:   Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			verbindung1: Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			verbindung2: Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			verbindung3: Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			verbindung4: Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			verbindung5: Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			verbindung6: Random.Range(0, (int) Mathf.Pow(2f, 32f)),
			groß:        Random.Range(0, (int) Mathf.Pow(2f, 32f))
		);
		rooms.Add(room.id, room);
	}

	long memUsageStop = System.GC.GetTotalMemory(true);

	Debug.Log(string.Format("Dictionary benötigt {0} bytes Speicher", memUsageStop - memUsageStart));
}
}

 

Ausgabe:

Dictionary benötigt 1503232 bytes Speicher
UnityEngine.Debug:Log(Object)
Memory:Start() (at Assets/Memory.cs:60)

 

Durch den Overhead von Klassen etc. verdoppelt sich dann in diesem Falle der Speicherbedarf auf gigantische 1.5 MByte. Das sind jedenfalls keine Datenmengen wo du überhaupt zu einer Datenbank greifen musst. Genauso kannst du auch alle 15625 Räume gleich bei Spielbeginn generieren. Damit meine ich zumindest die Daten zu den Räumen wie im oberen Skript es passiert.

 

Weder für die Datenmenge noch für die Rechenzeit benötigst du eine Datenbank.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Durch den Overhead von Klassen etc. verdoppelt sich dann in diesem Falle der Speicherbedarf auf gigantische 1.5 MByte. Das sind jedenfalls keine Datenmengen wo du überhaupt zu einer Datenbank greifen musst.

Stimmt und das kann man noch halbieren, indem man die 6 Verbindungen nicht speichert sondern berechnet, weil sie eh redundant sind s. mein erstes Posting.

 

Aber ich ja ohnehin eher Fan von generischen Lösungen a la Seed :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...