Nicht eingeloggt
Registrieren

Einsteiger Scripting-Tutorial für die Unreal Engine 3

Scripting-Tutorial für die UnrealEngine3

Hi!

In diesem Tutorial möchte ich dir die Grundlagen vom Scripten erklären.

Vom Tetris-Mod bis hin zum ultra realistischen Kriegs-Mod ist so ziemlich alles möglich. Es
gibt aber auch ausnahmen. Dazu später mehr.

Worauf ich hinaus will ist, dass man (fast) unbegrenzten Zugriff auf das Spiel geschehen hat.
Wenn du schon mal eine TotalConversion-Mod gespielt hast kannst du sehen, wie die Mod vom eigentlichen UT abweicht.


Was macht man also mit dem Scripten?

Ganz „einfach“:

Was tun, wenn zb. Der Spieler sachen aufnehmen, und werfen können soll?

Ein Script schreiben natürlich!

In diesem Script würde etwa folgendes stehen: (Hier mal auf Deutsch )

Code:
Der Spieler hat E gedrückt!
Einen Trace (So eine Art Pistolen-Schuss, der einem sagt, wo und was getroffen wurde) durchführen, und checken was der Spieler gerade anguckt
Es ist ein Werfbares Objekt?
Ja: Tu es in die Hand und sag dem Spieler:“ Du kannst was werfen!“
Nein:  Gar nichts tun
Weiter würde es heißen:

Code:
Wurftaste wurde gedrückt!
Aus der Spieler-Rotation und der Wurf stärke die Wurfrichtung ausrechnen 
Stein aus der Hand nehmen
Stein einen Kick geben

Wir fangen aber ganz am Anfang an.

Wenn du jetzt denkst: „Och ich les mir das hier mal „Schnell“ durch und dann man ich SOO eine geile Mod!!“.
Muss ich dich enttäuschen. Es ist wirklich Arbeit. Du musst dir viel merken können und eine mords Geduld brauchst du auch.
Um dir mal einen Kleinen vorgeschmack zu geben:


Das sind größere Mods, die ich allein geschrieben hab (Nur allein geschrieben, nicht gemappt. Das war/ist Unrealer2 )

Tre – The Spreading hat etwa 120 DinA4 Seiten Code.
Tre – Last Life hat etwa 500 DinA4 Seiten Code.

Unser aktuelles Projekt [W]RPG hat jetzt schon fast 150 DinA4 Seiten Code. (Und ist nicht mal ansatzweise fertig!)


Aber vor allem:
Nur nicht aufgeben Wenn man's kann macht es echt Spaß! Ich finde es faszinierend ein ganzes Spiel nach seinen eigenen Vorstellungen zu schreiben!



Viel Spaß mit diesen (genau) 36 Seiten (DIN A4)
Sorry, aber ist leider nix mit vielen Bildern Du schaffst das schon




Der Anfang

Da du jetzt weißt, wie ein Script aussieht und wozu man es benutzt, können wir anfangen.

Zuerst musst du die vorbereiten. Was jetzt kommt, musst du nur ein mal machen.

NUR FALLS DU DEN UT3-EDITOR BENUTZT: (UDK Nutzer lesen unter dem Strich weiter)
Wenn du den Editor von UT3 benutzt, musst du dieses Source-Package runterladen:
http://udn.epicgames.com/Three/UT3Mods.html

Das heruntergeladene Zip wird hier hin entpackt:
ICH\Dokumente\Mygames\Unreal tournament 3\UTGame\Src

ACHTUNG: In dem Zip sind ein paar mehr Ordner. Irgendwann kommt man zu ziemlich vielen Ordnern. DIE müssen da rein! Nichts anderes!
-----------------------------------


Um dich nicht mit dem ollen Texteditor von Windoof herum plagen zu müssen, gibt’s WOTGreal.
2 Sachen brauchst du:
Das hier: http://www.wotgreal.com/wotgreal/fil...taller3005.exe
Und außerdem das hier: http://www.wotgreal.com/wotgreal/fil...lDeveloper.zip

Nach dem Installieren musst du die Dateien im Installationsordner mit denen aus dem 2ten zip überschreiben.

Das ist nur eine Testversion, aber
keine die nach 30 Tagen nicht mehr läuft! Die haben das anders gemacht:

Pro Start wartet WOT immer eine Millisekunde länger. Wenn du das Programm
also zum 10ten mal aufmachst, musst du 1 Sek. warten. Bei 100 mal 10 sek. usw.
Damit kann man aber leben

Beim allerersten Start wirst du gefragt, ob du die Pfade einstellen möchtest. Drücke dort "Ja" und wechsle in dem sich daraufhin öffnenden Fenster zum Punkt "Game Information":

user1480_pic1507_1254502675_1.jpg
(Bild: WOT1)

Dort oben bei GameType sollte UDK/UT3/DeinSpiel hin. Falls das nicht in der Liste ist, kannst du es per EditGameTypes-Button hinzufügen, du musst aber nicht.

Du kannst sonst alle Boxen freilassen, bis auf zwei:

UCC.exe File:
Source Root Dir(s):

Bei "UCC.exe File:" kommt die .exe-Datei des UDKs hinein. Die findet man in seinem UDK-Ordner im Binaries-Ordner, etwa hier: "C:\UDK\Binaries\UDK.exe"
Natürlich kann der Pfad bei dir etwas abweichen.

Nun zu "Source Root Dir(s):"
Bei UDK-Nutzern muss dort dieser Pfad hin: UDK\Development\Src
Komplett könnte das so aussehen: C:\UDK\Development\Src

Bei UT3-Nutzern muss dort der Pfad zu den oben heruntergeladenen Dateien hin.
Das wäre also: ICH\Dokumente\Mygames\Unreal tournament 3\UTGame\Src


Danach auf Apply klicken und WOT laden lassen. Dauert ein wenig.

Jetzt kanns immer noch nicht losgehen

Links in dem kleinen Fenster ist der Class-Tree (Da wo „Classes“ drüber steht!)
Nun in Unreal ist es so. Jede Klasse erweitert eine andere. Eine Klasse ist ein Script.

So wirst du ganz oben das „Object“ finden. Dort gibt’s die Basic-Sachen. Eben +,-,* und / oder auch komplexeres wie Sinus und Kosinus. Auch
Configs und und und.

Tipp:
Mit einem Doppelklick öffnest du die Klasse!


Wenn du jetzt auf das + vor Object klickst, wirst du eine weitere Flut von sachen sehen, die du vielleicht nicht aus dem ACB (Actor Class Browser) im UnrealEditor kennst.
All diese Klassen die jetzt dort sind können alles was das Object kann, und haben auch eigene Funktionen.

Interessant für uns ist erstmal nur der „Actor“. Der ist ganz oben in der Liste. Ab hier kennst sicherlich einige Actoren. Aber nicht alle

Jetzt aber wieder ans Werk!

Rechtsklick auf „Actor“. Das hier erscheint:

user1480_pic1508_1254502675_2.jpg
(Bild: WOT2)


Jetzt wird ein neues, fast leeres Script erstellt (Pass auf, dass dieser Harken dort bei „Use Extends instead of...“ an ist!) . Aber loslegen könne wir immer noch nicht!

Das was jetzt kommt, musst du immer dann machen, wenn du ein neues Package erstellt hast! (Also nicht sooo oft)

Tipp:
Packages kennst du schon aus dem ED. Dort werden Staticmeshes, Texturen und Materials in innen gespeichert. Diese PCKs haben die Endung „.upk“.
In Script-Packages werden halt Scripts gespeichert. Die haben die Endung „.u“.


Damit der Editor weiß, welche Pakete es durchsehen soll, musst du es ihm sagen.
So wirds fürs UDK gemacht:

Man öffne die Datei /UDK/UTGame/Config/DefaultEngine.ini mit einem Texteditor. In dieser muss man nun nach „+EditPackages=“ suchen (STRG+F drücken!). Es sollten nun ein paar Einträge gefunden werden. Du musst deinen ans Ende der Liste mit den EditPackages schreiben, also direkt unter den letzten „+EditPackages“ Eintrag.
Der könnte so aussehen:
Code:

+EditPackages=MyFirstPackage

Abspeichern und schließen. Danach musst du ALLE Dateien des Config-Ordners löschen, bei denen nicht „default“ vor steht! (Keine sorge, sie werden beim nächsten Start neu erstellt)

Beachte, dass du zum abspeichern den Schreibschutz entfernen musst! (Rechtsklick->Eigenschaften auf die Datei)

Eine Sache wäre da noch. Seit einem Update des UDKs werden keine ScriptLogs mehr im Editor angezeigt. Ich weiß leider auch nicht wie man sie dort wieder sichtbar macht. Deswegen benutzen wir einen kleinen Workaround um das Problem zu beheben:

- Falls du noch keine hast, erstelle dir eine Verknüpfung zum UDK auf deinem Desktop.
- Rechtsklicke diese und wähle "Eigenschaften" aus.
- Suche die Box neben der "Ziel:" steht und schreibe folgendes hinter alles was dort drin steht:
Code:
-log
Das könnte wenn es fertig ist etwa so aussehen:
Code:
"C:\UDK\Binaries\udk.exe" -log
Bei dir könnte im Pfad einiges anders heißen, wichtig ist, dass du -log hinten stehen hast.

Wenn sich beim starten des UDKs über diese Verknüpfung nun ein schwarzes Fenster mit einer menge Text öffnet hast du alles richtig gemacht.
------------------------------------------------------------------

So wirds für UT3 gemacht:

Im Dokumente\Mygames\UT3\UTGame\Config Ordner gibt es die Datei „UTEditor.ini“. Aufmachen und nach [ModPackages] suchen. Ja, mit den [ ].
Dazu kannst du den Windows – Editor nehmen.
Die suche ist auf STRG+F.

Füge in dem Gefundenen Block diese Zeile hinzu!
Code:

ModPackages=MyFirstPackage
das sieht dann etwa so aus:

Code:

[ModPackages]
ModPackagesInPath=..\UTGame\Src
ModOutputDir=..\UTGame\Unpublished\CookedPC\Script
ModPackages=MyFirstPackage

Speichern, fertig.
------------------------------------------------------------------

Jetzt aber zurück zu unserem leeren Script, das darauf wartet gefüllt zu werden


Die ersten Schritte

Jetzt geht’s endlich los

Noch ein Tipp von mir: Ziehe deine Verknüpfung vom UnrealED neben deinen Windows-Start-Knopf. Du wirst sie SEHR oft brauchen...

Also. Los geht’s!

Das ist das Script:

Code:
//-----------------------------------------------------------
// MyFirstScript – Coded by [Wutz]! Blabla loool
//-----------------------------------------------------------
class MyFirstScript extends Actor;
DefaultProperties
Diese // bedeuten einen Kommentar. Alles, was dahinter ist, wird von UT ignoriert. Das gleiche geht auch mit /* und */
nur, das diese beiden Dinger über mehrere Zeilen funktionieren.

Dieses

Code:
class MyFirstScript extends Actor;
nennt man „Class-Scope“. Dort stehen sachen über das Script.
Also zuerst der Name des Scriptes und von welcher klasse es abstammt.

Tipp:
Du musst immer eine neue klasse machen. Versuche nicht die originalen UT-Klassen zu verändern! Das klappt nicht


Wir müssen da noch etwas reinschreiben. So muss das aussehen:

Code:
class MyFirstScript extends Actor
placeable;
Tipp: Benutze die TAB-Taste, damit der Code übersichtlich bleibt!

Damit sagen wir UT: Ich will den Actor aus dem ACB auswählbar machen und ihn ins Level stellen können!

Jetzt weiß ich gar nicht wo ich weitermachen soll

Öhm... Ersetze mal den DefaultProperties-Block mit diesem hier. Das sieht danach so aus:

Code:
//-----------------------------------------------------------
// MyFirstScript – Coded by [Wutz]! Blabla loool
//-----------------------------------------------------------
class MyFirstScript extends Actor;
DefaultProperties
Tipp:
Groß- und Kleinschreibung ist in UnrealScript völlig egal


Musst du nicht verstehen. Dann hat unser Actor diesen Adler-Kopf im Editor. Sonst wäre er unsichtbar...
Zu Components komm ich später.

Jetzt machen wir mal etwas ganz einfaches: Wir schreiben etwas ins Log! (Im GenericBrowser(GB) ganz rechts. Falls du es nicht kennst...)

Dazu brauchen wir eine Funktion. Es gibt bestimmte Funktionen, die zu bestimmten Zeiten aufgerufen werden.

Das hier nennt man Funktion:

Code:
Function TuWas()
Alles, was du an Code in dein Script schreibst, kommt IMMER zwischen dem Class-Scope und dem DefProp-Block! Sonst gibt’s nen Fehler...


Jede Funktion hat diese . Sie sagen wo der „Anfang“ und das „Ende“ der Funktion ist.
Außerhalb dieser Klammern kann man nichts schreiben. Wäre ja auch unsinnig Wann sollte das aufgerufen werden?

Wenn man eine leere Funktion hat, die sowieso nie aufgerufen wird, bringt das einem ziemlich wenig. Also nichts.
Gibt man dieser Funktion allerdings einen bestimmten Namen, wird sie sehr wohl aufgerufen. Hier ist eine Liste mit solch ein paar Namen:

PreBeginPlay: Wird vor Beginn des Spiels aufgerufen
PostBeginPlay: Wird nach dem Beginn des Spiels aufgerufen
Tick: Wird jede Sekunde so an die 1000 mal aufgerufen

Jetzt kommt Action ins Script!
Füge diese Funktionen hinzu:

Code:
Function PreBeginPlay()
Function PostBeginPlay()
Function MachWas()
Die `log Funktion ist etwas besonderes. Es ist ein „Makro“. Das erkennt man an diesem `. Der MUSS da hin! Aber NUR bei `Log! Wirklich nur da!
Es ist auch egal wenn WOTGreal das ` rot hinterlegt. 
 
vielleicht fallen die diese () auf. Mach sie erstmal einfach so immer hinter den Namen einer Funktion. Das sagt UT:

Ich will keine Parameter!

Oder eben, das die Funktion keine hat. Auf jeden Fall müssen da klammern hin


Eine Funktion rufst du auf, indem du ihren Namen, gefolgt von einer (, den Parametern, eine ) und ein ; schreibst.
Also so:

DerName(DieParameter);

Die Parameter kannst du durch Kommas trennen. Dazu sag ich später noch was.



Die `log Funktion ist etwas besonderes. Es ist ein „Makro“. Das erkennt man an diesem `. Der MUSS da hin! Aber NUR bei `Log! Wirklich nur da!
Machen tust du ihn mit *Shift+Die-Taste-Neben-?*. Nicht wundern! Da kommt erst was, wenn du auf die Leertaste drückst! Windows wartet nämlich
auf ein Zeichen. Wenn man statt der Leertaste das a Drückt, kommt das hier: à oder hier: ò.

Tipp: Statt die Leertaste zu drücken kannst du auch einfach weiter schreiben. Beim L macht er das nicht da drauf. So siehts aus: `L

Jetzt kommen die Klammern. Da ist platz für die Parameter. Einen Text, eine Zahl, und und und...

Hier siehst du auch, wo ein Semikolon also ein ; hinkommt. Nämlich immer am Ende eines Funktion Aufrufs. Auch nach dem
setzen einer Variable (Später). UT wird dir schon sagen, wo die (nicht) hin müssen

Und du siehst auch, dass man nur bei `log das ` macht. Bei der Funktion MachWas brauchst du es nicht.


Tipp:
Text wird immer mit Anführungszeichen geschrieben.


Da wir jetzt ein funktionstüchtiges Script haben können wir es „Kompilieren“. Also übersetzt UT den Text in
etwas, mit dem es was anfangen kann. Du merkst davon nur, das du danach ein .u Packard hast

Da wir die Features dazu, die WOTGreal mitbringt, für UT3 nicht nutzen können, musst du oben links auf
den „Save-All“-Button drücken. Das ist der mit den drei Disketten. Das darfst du nicht vergessen

Weiter geht’s:


Das Kompilieren

Zum „Compen“ einfach nur den Editor starten, und HUCH??? Was ist das?
.
Scripts are outdated... Na klar wollen wir einen Rebuild!

So sieht das aus:
user1480_pic1501_1254502558_3.jpg
(Bild: Compen)

Diese Warnungen hab ich nur, weil ich den patch2.0 ohne Titan-Pack hab. Die sind egal
Wichtig ist, das dein Script fehlerfrei ist. Jetzt nur noch das Fenster da schließen.

Falls ein Fehler drin ist, sagt UT schon wo er ist. Und wenn du eine Warnung hast, nimm sie ernst! Dein Package wird zwar gespeichert, aber
meistens Funktioniert es nicht, wenn eine Warnung drin ist!


Tipp:
Du verstehst den Fehler nicht? Ganz unten hab ich eine kleine Fehlerbeschreibung gemacht!



Klick aufs X...

Windows wird sagen: Es ist ABGESTÜRTZT! Das ist aber völlig egal Einfach auf „Programm schließen“ drücken und fertig.
Ist nichts schlimmes. Passiert immer Aber das Package wurde ja gespeichert.

Nun musst du nochmal den ED starten. Diesmal öffnet sich aber der „richtige“ Editor.


Dein erstes Script in Action!

Ich gehe jetzt einfach mal davon aus, dass du weißt, wie man eine kleine Test-Map baut.
Ich mach da immer ein schönes Terrain mit nem Himmel drüber Aber jetzt reicht auch ein Kasten mit
nem Licht drin. (Terrain ist trotzdem schicker Denk immer dran: Du wirst die Map öfter brauchen. Also Bau was kleines tolles, wenn du willst )

Wenn du fertig damit bist, kannst du den ACB öffnen und deinen Actor raus suchen, ihn ins Level stellen. Guck:

user1480_pic1506_1254502675_4.jpg
(Bild: Wohoo!)

Jetzt gibt’s noch eine Anomalie: Nachdem du deine Scripts gecompt hast, und die Testmap geöffnet hast,

MUSST DU SIE ALS ERSTES SPEICHERN!!! SONST STÜRTZT DER ED BEIM SPIELEN AB!!!

Tipp:
Speichere die Map als Deathmatch Map! Also zb. DM-MeineMap.


Auf dem Bild kannst du sehen, dass es WIRKLICH dein Script ist. Jetzt nur noch auf „Spielen“ drücken, und den das „In Editor game“ auch gleich
wieder mit der ESC-Taste schließen. Was das gebracht hat? Naja. Du hast dem Script gesagt, es soll beim Levelstart etwas ins log schreiben. Also musst du
nun auch ins log gucken

user1480_pic1503_1254502558_5.jpg
(Bild: Log)

Das rote zeug sind Fehler, die nichts mit deinem Script zu tun haben. Ich hab sie weg gemacht, damit sie dich nicht stören.

Wenn du genau hin guckst, siehst du die Logs.

Jetzt könnte die frage kommen:
„Was hat das für einen Sinn, wenn was in diesem komischen Log steht??? Da guckt doch eh keiner rein!“

Logs sind sehr nützlich. Durch sie kannst du feststellen, ob dein Script funktioniert. Du siehst also, wo der Fehler liegen könnte.
Darauf könnte wieder ne frage kommen:
„Aber UT sagte doch: „Success! - Errors: 0 Warnings: 0“. Dann sind doch keine Fehler mehr drin, oder?“

Das kann stimmen, aber stell dir mal vor, du möchtest ein Script schreiben, dass 2*5 rechnet. Ist klar, kommt 10 raus.
Aber was, wenn du dich vertippst? Und stattdessen 2+5 schreibst? Da kommt 7 raus. Also nicht 10. Für UT ist da
trotzdem kein Fehler drin, weil man ja alles richtig geschrieben hat. Dieses Problem gibt es auch in Word oder OpenOffice:
Man schreibt zb.

Ich sagte, das wir das so machen!

Da ist ein Fehler drin: „ , dass“ müsste hier mit Doppel S geschrieben werden. Ist aber keine rote Linie drunter, weil es das Wort „Das“ ja
auch nur mit einem S gibt.

Jetzt wollen wir uns den Variablen widmen.


Variablen

Als „Variable“ bezeichnet man etwas, in dem man Daten speichern kann. Also zahlen, Buchstaben und so weiter.

Erstelle eine neue Klasse, die du „MyFirstVariables“ nennst. Pass aber auf, dass du den richtigen Package Namen einträgst!
Den UnrealEditor, ich nenne ihn ihn ab jetzt ED, kannst du wieder schließen. Den brauchen wir erstmal nicht. Mit offenem ED
kann man nämlich keine Scripts compen.

Schreibe in dieses neue Script wieder „Placeable“ und das, was du oben schon in die DefaultProperties schreiben solltest rein.

Jetzt wollen wir ein bisschen rechnen

Erstelle eine Leere PreBeginPlay() Funktion. Also so was:

Code:
Function PreBeginPlay()
Und nun schreibst du direkt unter den Class-Scope das hier:

Code:
Var int Zahl;
So sieht das Script jetzt aus:


Code:
//-----------------------------------------------------------
// MyFirstVariables - Coded by [Wutz]!
//-----------------------------------------------------------
class MyFirstVariables extends Actor
placeable;
var() int zahl;	
var() string Text;
var int NochNeZahl;
function PreBeginPlay()
DefaultProperties
Mit dem Wörtchen „Var“ sagt man: Jetzt kommt eine Variable! Schreibt man noch () dahinter, kann man die Variable im ED einstellen.
Also in den Properties (Ich nenn die ab jetzt Props) des Actors. Ohne die klammern sieht man sie dort nicht. Man kann aber beide Typen gleich benutzen.

Hinter Var kommt der Typ der Variable. Also Text, Zahl oder was auch immer. Und da hinter kommt der Name. Gefolgt von einem ;

Tipp:
Schreibt man Var(Hallo) int Zahl; Wird die variable in den Props in der Gruppe „Hallo“ angezeigt. Probiers mal aus Nur keine Leerzeichen...
Ohne einen Namen sind die Variablen in einer Gruppe, die so heißt wie die klasse.


Du könntest das Script jetzt compen und die Props im ED verstellen. Nur um zu sehen, was das ist

Hier ist eine Liste mit den meist gebrauchten Variablen Typen:

Int → Zahl
Byte → zahl von 0 bis 255
float → Zahl mit Komma. Also 2.5 oder 0.543 (Int und Byte können das nicht!)
Bool → Eine Art Schalter. Kann nur True oder False sein.
String → Ein ganz normaler Text. Benutz ihn nur, wenn du ihn wirklich brauchst!
Name → Ein Spezieller Text: Keine Leerzeichen oder Sonderzeichen. Braucht weniger Speicher als ein String. Du solltest alles Script interne, was mit
Texten zu tun hat, die man nicht sehen wird hiermit machen.
Class<KlassenName> → Hält eine klasse

Die Object-Variablen kommen später noch. Erstmal zeig ich dir, was du hiermit machen kannst.

Fangen wir mit int an:


function PreBeginPlay()



Der Variable NochNeZahl, die man nicht im ED einstellen kann (Das ist völlig egal und geht auch mit im ED einstellbaren), wird der wert 5-2 zugewiesen.
Also 3. Das macht man mit dem = Operator.

Hier ist eine Liste mit ein paar Operatoren:

= → Weißt etwas zu
+= → Addiert etwas hinzu
-= → zieht etwas ab
*= → Multipliziert
/= → Dividiert

Warum +=?

Zahl+NochNeZahl geht nicht!!

Zahl+=NochNeZahl schon.

Zahl=NochNeZahl+5; geht auch.


+= hat den gleichen Effekt wie
Zahl=Zahl+5

Ist nur schneller zu schreiben, außerdem sind die Prozessoren heutzutage für so was optimiert. Dann geht’s schneller

Dann gibt’s noch 2 Stück:

++ → Fügt 1 hinzu
-- → Zieht 1 ab

Auch hierfür sind Prozessoren optimiert. Außerdem kann man das noch schneller schreiben


Jetzt ist noch das Log übrig:

`log("Der Text ist: "$Text$". Die erste Zahl ist: "$Zahl$". Die zweite Zahl ist: "$NochNeZahl);

Alles, was mit " geschrieben wird ist eine String-Variable. Also ein Text. Also hat die Log-Funktion einen String-Parameter.
Auch Strings kann man mit = zuweisen. Und noch was können sie:

Man kann Variablen in sie hinein packen! So was ist sehr nützlich, wenn man etwa sagen möchte:

Du hast 47 Leben!

In Code-Form würde das etwa so aussehen:

Text="Du hast “$Health$“ Leben!";

Also um eine Variable da rein zu packen schreibst du mitten im string "$EineVariable$". Wenn die Variable am Anfang oder Ende steht musst du
das an der richtigen Seite weglassen:

Text=Health$“ ist ganz schön wenig...";

oder

Text=“Leben: “$Health;

Nichts anders hab ich in die Log-Funktion geschrieben. Nur ohne =, da es ein Parameter ist. Kommt noch

Hier ist eine Liste mit Beispielen für Variablen Zuweisungen:

Zahl=5;
bTod=true;
bTod=false;
Name='HeyHey';
PI=3.1415926535897932;

Bool variablen (Die Schalter) schreibt man normalerweise mit einem b vor dem Namen.
So weiß man sofort, dass es ein Bool ist. Du musst das nicht machen. Kannst aber


Funktionen mit Parametern

Du hast sie ja schon gesehen. Aber hier nochmal genauer:

Code:
function PreBeginPlay()
function TuWasTolles(String Msg)
Das kann man auch noch erweitern:

Code:
function GanzVieleSachen(int a,int b, byte Hallo, bool bLol)
Die kann man alle benutzen, als wären es ganz normale variablen.
Sie gelten allerdings nur in dieser Funktion. Und sie sind beim Funktions-Start auf die werte gesetzt, die man eben eingetragen hat.

Gute Gelegenheit um einen kleinen Abstecher zu den Local variablen zu machen:

Code:
function WasTolles(int i)
Diese Locals kommen immer ganz oben in die Funktion. Auch diese Variablen kannst du benutzen, wie jede andere auch. Allerdings
eben nur in dieser Funktion. So muss man nicht den Arbeitsspeicher mit tausenden variablen zumüllen, die man nur ein mal kurz braucht.

Tipp:
Gebe nur Locals einen Namen der nur einen Buchstaben lang ist! Das verwirrt nicht so.


Tipp:
Findest du eine Local variable die i heißt ist es fast immer ein int!


Object Variables (Pointer)

Zeit um dir mal die Funktionsweise von Unreal zu erklären:

Wie du schon weißt, ist dein Script im ED in einem „Actor“ untergebracht. Hast du 100 von diesen
Actoren in der Map, existiert dein Script auch 100 mal. Sie machen alles für sich alleine. Alle Variablen sind
ebenfalls voneinander getrennt. Die haben rein gar nichts miteinander zu tun.

Allerdings müssen die ja irgendwie miteinander „reden“ können. Dazu gibt es so genannte Pointer. Das sind variablen (Jep, die kannst du in Funktionen, hinter Var oder hinter Local benutzen) Die auf einen anderen Actor „zeigen“.

Schau dir das mal an:

user1480_pic1504_1254502558_6.jpg
(Bild: Pointer)

Die Kreise sollen hier Variablen darstellen. Würde ich etwas anhand einer Float-Variable zeigen wollen, wären da zwei Kreise. Du kannst so viele
Pointer machen, wie du willst.

Wie die jetzt wohin zeigen, und wie viele Verbindungen die haben ist vollkommen egal. Aber entscheidend ist, dass man Funktionen über diese Verbindung aufrufen kann. Auch Variablen kann man umsetzen. Man hat vollen Zugriff auf den anderen Actor. (Ausnahmen gibt es, ist erstmal egal, sind sehr wenige)

Um so einen Pointer anzulegen musst du nur

var() Actor DerAndere;

zu den Variablen schreiben.

Var() bedeutet wie gewohnt, dass eine Variable deklariert wird. Danach kommt eben der Typ der Variable, wie zb. Ind oder Float. Hier ist es eben
der Name einer Klasse. Sie sagt, welche Klassen in den Pointer rein können. Also eine Art Filter. Außerdem lässt sich einfacher mit ihnen arbeiten, wenn
man nicht extra einen Cast (Erkläre ich später) durchführen muss. Und man sieht gleich für was die Variable gedacht sein könnte.

Statt Actor kannst du jede andere klasse nehmen. Wenn du dort zb. Trigger hin schreibst, kann man nur Trigger „anzeigen“.
Dieses mal bitte var MIT (). Ich will dir nämlich was zeigen. → Compen und den ED aufmachen.

user1480_pic1505_1254502558_7.jpg
(Bild: PointerED)

1.: Den MyFirstVariables Actor auswählen und die Props aufmachen
2.: Das Prop Fenster auf „Locked“ stellen. Nun ändert es sich nicht mehr, wenn du einen anderen Actor auswählst.
3.: Irgendeinen anderen Actor auswählen (Zb. Den PlayerStart)
4.: Zuweisen

Fertig
So was hast du bestimmt schon man gesehen. Mit einem Material oder so geht das genau so. In einem Content-Package funktioniert das nämlich ähnlich.

Jetzt weißt du, wie man eine Pointer-Prop im ED zu weißt. Also ED zumachen und zurück zu Script

Im Script ist die Variable zwar noch leer, also sie zeigt auf nichts, aber wir können davon ausgehen, dass du sie beim nächsten
Test setzt. Man kann immer nur davon ausgehen, das die nicht leer sind. Deshalb muss man sicherstellen, das sie auf etwas zeigen,
bevor man sie benutzt. Sonst gibt’s ne Log-Warnung. „Accesed none blabla“ Steht dann da. Das sollte eigentlich keine Warnung sein. Betrachte es als einen
Fehler! Denn sonst wird nichts funktionieren!

Dazu noch ein Beispiel:

Du bist auf einem Klo mit 3 Kabinen. In alle drei setzt du Leute. Von jedem Notierst du den nahmen (Packst sie in einen Pointer).
Nur vom 3. nicht.

Im Code sähe das so aus:

Var() UTPawn KloMensch1;
Var() UTPawn KloMensch2;
Var() UTPawn KloMensch3;

Tipp:
Du kannst Vars und locals (Keine Parameter) mit Kommas trennen! Also zb.: Var int Huhu,Hallo,LOL;


(UTPawn ist die Klasse der „Spielfiguren“, die man steuert.)

Jetzt sagst du KloMensch1: „Spülen!“ Und er spült.
KloMensch2 sagst du „Aufstehen!“ Und er steht auf.
KloMensch3 willst du sagen „Leg dich hin!“ Aber du hast den Namen nicht, weißt nicht wen du rufen sollst, hast keine Ahnung ob da überhaupt jemand drin ist,
du weißt gar nichts! Aber du sagst trotzdem „Leg dich hin!“. Keiner Legt sich hin, und UT Loggt den Fehler: „KloMensch3 zeigt nirgendwo hin!“.

Pointer können so lange auf „none“ stehen, bis sie benutzt werden sollen. Es ist also nicht zwingend notwendig, dass sie IMMER auf etwas zeigen.
Aber wenn man sie benutzen möchte muss man erst sicher gehen, dass dort wirklich etwas drin ist. Sonst funktioniert das Script ja nicht

Damit keine Fehler entstehen gibt es ein nützliches Werkzeug:

If

Mit If kann man Dinge checken. Also ist meine Variable=2? Oder ist bTod=true? Oder ist KloMensch3=none?

So wird es benutzt:

Code:
var() Actor DerActor;
var() int Nummer;
function EinIf()
If(Nummer>2)
else
If(DerActor!=none)
if(Nummer<=5 && DerActor!=none)
}
An diesen Beispielen solltest du sehen können, wie es geht. Hier ist eine List mit If-Operatoren:

== Ist gleich (Nicht verwechseln mit = , da dieses nur zum zuweisen einer variable ist!)
< Kleiner als
<= Kleiner als oder gleich
> Größer als
>= Größer als oder Gleich
!= Ungleich

Im letzten Beispiel Steht &&. Das heißt „Und“. Also Wenn „Nummer kleiner als oder gleich 5 ist UND DerActor ist nicht none“: TU WAS!!!
Das gleiche geht auch mit || Das heißt „Oder“.

Tipp:
Dieses Symbol: | Macht man mit Alt-Gr + <


Klammern gehen auch!

if(Nummer==5 && (bTod==false && DerActor!=none))



Also, wenn du nicht 100%ig sicher bist, dass der Pointer auf etwas zeigt, benutz if(DerActor!=none).


Wie du Pointer im ED zu weißt weißt du jetzt.
Du musst noch lernen, wie man so was im Script macht.
Das ist nicht einfach (Eigentlich schon, aber du kennst die ganzen Klassen und Variablen noch nicht auswendig).

Wir wollen uns jetzt mal die GameInfo angeln. In der GameInfo Klasse stehen die Spielregeln für zb. Deathmatch oder CTF. Das sind auch Actoren.
Es gibt immer eine Möglichkeit an die GameInfo (Kurz GI) ran zukommen: Die WorldInfo. Da stehen sachen über die Map drin. Der Autor, usw.
Und eben die GameInfo!

Da unsere kleine Klasse alles kann, was die klasse „Actor“ kann, haben wir schon die Variable „Worldinfo“. Diese zeigt direkt auf die Worldinfo.

Du siehst keine Variable, die „Worldinfo“ heißt in deinem Script? Schau mal in die Klasse Actor bei Zeile 218.


Jetzt lernst du, wie man auf variablen durch einen Pointer zugreift.

In der Actor-Klasse sieht die Variable Worldinfo so aus:

var const transient WorldInfo WorldInfo;

Denke dir den ersten Kram einfach weg. Also so:

var WorldInfo WorldInfo;

Lass dich nicht verwirren! Es gibt eine Klasse, die Worldinfo heißt! Die von Epic haben die Variable halt genau so genannt.


Dann wollen wir uns mal die GI holen:


Code:
var() float NewSpeed;
function PreBeginPlay()
In der Klasse Worldinfo gibt es einen Pointer, der „Game“ heißt und direkt auf die GameInfo zeigt.
Pointer weist du natürlich wie ganz normale Variablen mit dem = zu.

Tipp:
Wenn du STRG gedrückt hältst und auf eine Variable, Funktion oder den Namen einer Klasse Klickst, springt WOT direkt dorthin oder
öffnet die Klasse. Praktisch praktisch



Wenn du den . Hinter Worldinfo machst, öffnen WOT ein kleines Fenster, mit allen sachen, die die klasse Worldinfo kann.
Musst nur Game eingeben und Enter drücken.

Sobald du die ( machst, kommt ein kleines gelbes Fensterchen. Es zeigt alle Props der Funktion. Ein cooles Feature von WOTGreal.

Mit dem Punkt sagst du: Ich will eine variable haben oder eine Funktion aufrufen! Und zwar aus dem Actor, auf den der Pointer zeigt.

Nun zeigt die variable GI auf die GameInfo. Und wir können mit ihr arbeiten. Und zwar mit der Funktion SetGameSpeed.
Dort kommt die variable NewSpeed hinein. (Die du natürlich im ED einstellst, sie hat zwei klammern ).

Für so was braucht man eigentlich keine eigene Variable. Man kann so oft „weiter verbunden“ werden, wie man will.

Code:
Worldinfo.Game.SetGameSpeed(NewSpeed);
Würde es also auch tun.

Variablen kannst du so auch ganz bequem zuweisen. Etwa so;

Code:
Zahl=EinActor.EineZahl;
Das geht auch anders herum:

Code:
EinActor.EineZahl=Zahl;
Jetzt weißt du, wie man von einem Actor auf den Anderen zugreift!


Funktionen überschreiben

Das, was wir jetzt machen wollen, ist etwas komplexer. Funktionen werden ja irgendwann aufgerufen.
Pre und PostBeginPlay() kennst du ja schon. Aber es gibt noch tausende mehr! Du musst dir nur mal eine der längeren Klassen
von UT anschauen. Bevor wir anfangen können, brauchen wir noch einen kleinen Actor, der die Controller-Klasse, die für alle
Spieler benutzt werden soll umstellt. (Nur zum Testen! Nicht Online kompatibel(Glaub ich)! Mach das später in einen Mutator!)

Controller sind Actoren die alles was der Spieler kann verwalten. Durch sie kann man schießen, laufen, sich um gucken und so weiter.
Dazu braucht man noch einen „Pawn“. Pawn bedeutet auf Deutsch so viel wie „Spielfigur“. Es ist also der Typ, den man Steuert,

Wir brauchen hier nur den Controller. Wie du eine neue Pawn und ein neues Hud machst sag ich dir aber gleich trotzdem.


Ein Controller ist unsichtbar. Man sieht ihn nicht. Dazu ist der Pawn da. Damit UT weiß, dass es deinen Controller statt dem Standard Controller benutzen soll,
musst du es ihm sagen. Ist ja klar

Dazu musst du jetzt eine neue Klasse unter Actor erstellen. Nenn sie wie du willst (Ich nenn die teile immer GameModificator). Mach sie Placeable und
pack den Kram von oben wieder in die DefProps. Nun musst du noch die PreBeginPlay() Funktion hinzufügen. So:


Schreib es nicht ab, sondern versuche es aus den Texten zu machen! Vergleiche es nur mit dem hier! Du musst üben, bzw. fähig dazu sein das selber zu schreiben

Code:
//-----------------------------------------------------------
// MyGameModificator - Coded by [WuTz]!
//-----------------------------------------------------------
class MyGameModificator extends Actor
placeable;
function PreBeginPlay()
DefaultProperties
Da wir jetzt wieder einen Grundstein haben, könne wir anfangen. Dieser Actor kann dir später wirklich noch von nutzen sein.
In dem Modificator (Dem Modi ), den ich für Tre – Last Life gemacht habe sind mehr als 250 variablen, mit denen man das Spiel verändern und
anpassen kann

So was wollen wir auch machen. Aber nicht so groß Hier reicht nur eine Variable. Und zwar eine vom Typ „Class<PlayerController>“.
Nenne sie MyControllerClass.

Code:
var() class<PlayerController> MyControllerClass;
Und damit etwas passiert musst du die variable PlayerControllerClass aus der GameInfo in der PreBeginPlay() Funktion mit der
MyControllerClass variable überschreiben.

Code:
function PreBeginPlay()
Wenn du das nun Compst, und den Actor in ein Level stellst, kannst du die Controller klasse verändern. Da du aber nur die Standard Controller (Also 2 Stück) von
UT hast bringt das noch nicht viel. Also musst du dir einen eigenen machen.

Erstelle nun einen Neue klasse unter UTPlayerController. Du findest den UTController unter Object->Actor->Controller->PlayerController->UTPlayerController.

Nenn sie MyController oder so.

Da man diesen Actor nicht in die Map packen muss, brauchst du ihn nicht Placeable zu machen. Er kann auch unsichtbar bleiben. Also reicht das leere Script.

Bis jetzt:

Schreibe die Funktion StartFire hinzu! Dort sind EINGIGE neu sachen dran.

So sieht sie aus (Leer in der MyController klasse):

Code:
exec function StartFire( optional byte FireModeNum )
1.Exec: Wenn du einmal ein Exec vor der Funktion sehen solltest, kannst du sie aus der Console aufrufen.
Du kannst also die Console mit der TAB-Taste öffnen und den Namen eintippen. Gefolgt von den Parametern.
Also für StartFire müsstest du das hier eintippen:

StartFire <FeuerModusNummer>

Mehr nicht. <FeuerModusNummer> kannst du durch die nummern 0 oder 1 ersetzen, oder du lässt es weg...
Du kannst Exec Funktionen natürlich, wie jede andere Funktion auch, durchs Script aufrufen. Sind aber nützlich zum testen,
und außerdem kann man sie auf Tasten legen.

2.Optional: Vor der Variable steht Optional. Das heißt, man kann einen Parameter eintragen, man muss aber nicht.
Ob man nun StartFire(); Oder StartFire(0); Schreibt ist völlig egal. Ohne Optional würde UT bei der ersten Version einen
Fehler ausspucken.


Tipp:
Du kannst Optionalen Parametern einen Standardwert zuweisen! Der wird automatisch benutzt, wenn der Parameter weg gelassen wurde:
Function MachWas(optional int Zahl=5)


Hätten wir das auch geklärt.

Die Funktion StartFire gibt es erst seit der PlayerController klasse. In Actor gibt es sie noch nicht. Man kann sie deshalb dort auch noch nicht aufrufen.
Da wir jetzt aber eine Controller klasse haben können wir sie benutzen. Allerdings wurde sie ja schon in der Controller klasse von UT benutzt...

Egal. Wenn du sie in eine Neue klasse schreibst, und auch diese klasse des Actors benutzt wird, werden auch alle alten Funktionen der übergeordneten Klassen
mit den Neuen aus deiner Klasse ersetzt! Wenn UT also von irgendwo aus StartFire() aufruft, wird nicht mehr die UT-Version benutzt, sondern deine! Dadurch, dass
du sie in deine Klasse geschrieben hast, hast du sie überschrieben! Das gleiche hast du übrigens schon mit PreBeginPlay() gemacht. Die stammt nämlich aus der Actor Klasse.

Das geht übrigens mit fast allen Funktionen.

Ausnahmen sind:

Funktionen vor denen Native steht.
Funktionen vor denen Final steht.

In der Regel ist es aber nicht wichtig diese Funktionen zu überschreiben.

Da diese Funktion in deiner Klasse leer ist, wird man nicht mehr Schießen können. Du hast sie ja überschrieben. Das ist erstmal egal. Später sag ich dir,
wie man das umgehen kann.

Eine recht einfache Methode, dir das ganze zu demonstrieren ist, etwas mit den Leben des Spielers anzustellen. Jeder Controller hat einen Pawn.
Und damit man ihn benutzen kann, gibt es einen Pointer zu diesem Pawn. Nicht verwirrt sein, aber die Variable heißt wie die Klasse „Pawn“. Nämlich auch
Pawn. Ist das gleiche, wie mit Worldinfo.

Die Leben des Spielers werden in der Variable „Health“ im Pawn gespeichert. Mit Pawn.Health erhält man also den Zugriff.

Jetzt kannst du in der StartFire Funktion die Leben des Spielers mit zb. 2 multiplizieren. Oder auch andere tolle sachen machen

Pawn.Health*=2;

Und fertig. Compen und Ab in den ED!
Du darfst nicht vergessen deinen Modi in die Map zu packen und deine Controller klasse aus der List auszuwählen.

(Speichern nicht vergessen! Sonst könnte es abstürzen...)

Jetzt werden sich deine Leben bei jedem Aufruf von StartFire() verdoppeln Und diese Exec Funktion wurde auf zwei tasten gelegen...
Nämlich auf die Maus tasten! Immer wenn du eine davon drückst, wird StartFire(0); Oder StartFire(1); aufgerufen! Also bekommst
du bei jedem klick mehr leben

user1480_pic1502_1254502558_8.jpg
(Bild: Health)

3200 Leben Toll sowas!


Nachteil: Du hast die Funktion überschrieben. Der Code, der dafür sorgt, dass man schießen kann ist also weg. Aber das ist kein Problem!

→ ED Zumachen und zurück zu WOTGreal.

Es gibt den Befehl „Super“, was auf Deutsch soviel wie „Über“ heißt (Nicht „todschick“ oder „echt geil“, wie mein Englisch-Übersetzer meint , es kommt aus dem Lateinischen.(Obs in Englisch auch so ist bin ich mir nicht sicher)).
Damit kann man Funktionen aus der Übergeordneten klasse aufrufen. Also welche in denen der fehlende Code noch vorhanden ist.


Tipp:
Die übergeordnete Klasse nennt man „Parent-Class“. Alle Untergeordneten Klassen nennt man „Sub-Class“ oder „Child-class“.


Super kann man wie einen Pointer benutzen.

Super.MeineFunktion(DieParameter);

Schreib das in deine StartFire Funktion.


Tipp:
Manchmal ist es wichtig, wo du es hinschreibst. Möchtest du mit etwas arbeiten, was in der „Alten“ Funktion ausgerechnet wurde, so muss es am Anfang stehen.
Soll erst zb. Einer der Parameter geändert werden muss es ans Ende. Hier ist es aber egal.



Damit alles richtig funktioniert muss die StartFire Funktion aus der Parent-Class noch den Feuermodus wissen. Gib ihr einfach den FireModeNum-Parameter.
So sieht das aus:

Super.StartFire( FireModeNum);

Wenn du das jetzt Compst kannst du schießen, und deine Leben füllen sich dabei auf.

Casting

Wie du vielleicht gesehen hast, ist die Variable „Pawn“ ein Pointer der Klasse „Pawn“. Drück mal STRG und klicke auf das Wort „Pawn“ (In WOTgreal), und
wähle „Class: Pawn, Package: Engine“-> OK.
Die Klasse „Pawn“ öffnet sich. Diese hat ein paar SubClasses. Mitunter den UTPawn. Dieser wird von UT benutzt. Und er hat viele Funktionen, die der
„normale“ Pawn nicht hat! Zb.

exec simulated function FeignDeath()

Das gibt’s erst im UTPawn.


Tipp:
Die Klassen, die ein UT vorne im Namen haben, sind die Unreal Tournamet 3 Klassen. Alle anderen sind Engine-Klassen, die immer in der UnrealEngine3 dabei sind.
Auch bei anderen spielen, wie Bioshock oder Mirrors Edge gibt’s die.



Tipp:
„Simulated“ hat was mit Online-Coding zu tun, was weiß ich aber auch nicht! Ignoriere es erstmal.
Ich hab eben bis jetzt nur Singleplayer Mods gemacht...


Da der Pointer „Pawn“ nur die Funkionen aufrufen kann, die die klasse „Pawn“ kann, kann man FeignDeath() von dort aus nicht auf den Normalen weg aufrufen,
da sie schon in der neueren UTPawn-Klasse ist.


Tipp:
Du kannst in einen Pointer der auch alle SubClasses des erwarteten Typs eintragen. Bei einem Pawn-Pointer kannst du also auch einen UTPawn hinein tun.


Wie macht man das denn jetzt? Ganz einfach! Man kann UT Sagen, Konvertiere die Variable vom Typ Pawn in eine Variable vom Typ UTPawn! So kann man dessen
Funktionen aufrufen.

So wird’s gemacht:

Code:
UTPawn(Pawn).FeignDeath();
Zuerst den Namen der Klasse, die man wünscht, dann in Klammern der Pointer, von dem man Konvertieren möchte, gefolgt vom Punkt Und der Funktion oder Variable. So wird der Pointer der Klasse „Pawn“ wie ein Pointer der Klasse „