Schwierigkeit: Fortgeschrittene
Blender 2.33
pat | 08.06.2004

Blendertutorium: Egoshooter

Blender 2.0 war die erste Version von Blender, die die GameEngine eingebaut hatte. Nach und nach kamen weitere Funktionen dazu, um dem Benutzer das Leben und Spielen leichter zu machen. Das ging so weiter, bis mit 2.25 der letzte GameBlender veröffentlicht wurde und die Firma NAN Pleite ging. Seither benutzen spielfreudige Blenderfans den etwas veralteten Blender 2.25, um weiter ihre Ideen umzusetzen. Bis heute...
Mit Blender 2.33 wurde die GameEngine wieder eingeführt, zuerst auf dem Stand von 2.25, aber weitere Funktionen sind zu erwarten. Um diese neuen Möglichkeiten sinnvoll nutzen zu können, ist ein grundlegendes Verständnis der GameEngine notwendig. Um alle Funktionen voll auszuschöpfen, werden wir auch etwas mit der Programmiersprache Python arbeiten müssen, aber keine Angst, ihr müsst jetzt nicht programmieren lernen :)
Nachdem ihr eine kleine Umgebung gebaut habt, in der ihr euren Spieler herumsteuern könnt, werde ich euch zeigen wie ihr einen Spieler in der typischen 'Ich'-Perspektive erzeugt. Dann kümmern wir uns noch um Einschusslöcher, damit ihr seht was ihr getroffen habt.

Die Umgebung

Hier solltet ihr eigentlich eure eigenen Ideen verwirklichen. Da ich nicht vorhabe, gegnerische Spieler zu erzeugen, habe ich einfach eine Art Schießstand gebaut.
Zuerst braucht ihr natürlich das Mesh, die Geometrie eures Levels. Ich denke, dass kann ich euch selbst überlassen. Ich habe hier einfach mal das Konzept meines Levels abgebildet, falls ihr genauso wenig eigene Ideen habt wie ich :)
Dann braucht euer Level natürlich Texturen, davon geistern im Internet genug kostenlose rum, und wer ne Digicam hat, kann sich selbst gute Texturen erzeugen.
Mit ALT + Z wechselt ihr in die texturierte Ansicht, falls noch nicht geschehen, und gebt wie gewohnt Texturen. Achtet aber darauf, dass die Flächennormale in die richtige Richtung zeigt. Im Gegensatz zum normalen Rendern wird in der GameEngine nur eine Seite der Fläche gerendert, welche das ist könnt ihr im EditMode sehen, wenn Draw Normals (EditButtons, Mesh Tools 1) aktiviert ist. Der blaue Strich kommt dann auf der Seite der Fläche raus, die gerendert wird. In der texturiertern Ansicht könnt ihr kontrollieren ob die Normalen in die richtige Richtung zeigen: wenn ihr eine Stelle entdeckt die durchsichtig ist aber nicht sein soll, dann müsst ihr die entsprechenden Normalen drehen. Dazu müsst ihr die Fläche im EditMode auswählen und drückt W >> Flip Normals.
Blender kann die Normalen auch automatisch berechnen (Strg [+ Shift] + N im EditMode, ohne Shift werden die Normalen nach außen gedreht, mit Shift nach innen), das Ergebnis muss aber manchmal manuell korrigiert werden.

Der Spieler

Bevor ihr hier anfangt, kontrolliert erst einmal, ob bei den WorldButtons (F8) eine Physikengine eingestellt ist. Der Button links neben dem Grav Button darf nicht 'None' anzeigen. Im Moment gibt es nur die Sumo-Engine, also wechselt auf Sumo sofern das noch nicht eingestellt ist.
In der Oberansicht erzeugt ihr zuerst ein Empty, dann gleich noch eine Kamera in der Vorderansicht. Die Kamera bewegt ihr etwas nach oben.
Danach wählt ihr wieder das Empty. Um den Überblick nicht zu verlieren nennen wir es ab jetzt Spielerempty. Wechselt mit F4 in den Logic Kontext und klickt auf Actor und dann auf den neuen Dynamic Button. Jetzt wird das Spielerempty von der Engine beachtet.
Um das gleich zu testen, klickt ihr in der Sensor Gruppe (links) auf Add und macht aus dem Always ein Keyboard. Dann klickt ihr in das Key Feld und drückt eine Taste. Als nächstes erzeugt ihr einen Controller und zieht mit der Maus eine Verbindung zwischen den gelben Kreisen bei Sensor und Controller. Ihr erzeugt auch noch einen Actuator, den ihr mit dem Controller verbindet. Diese Verbindungen könnt ihr übrigens löschen, indem ihr mit der Maus darüberfahrt so dass sie weiß werden, und dann X drückt.
Im zweiten linV-Feld des Aktuators, das heißt in Y Richtung, gebt ihr dann den Wert 5 ein und aktiviert den kleinen L Button rechts daneben, damit wir unabhängig von der Drehung immer nach vorne laufen.
Um das Ganze auch zu sehen, erzeugt ihr einen Würfel an der Position des Spieleremptys, wählt den Würfel und als zweites zusätzlich das Empty und drückt Strg + P, damit der Würfel dem Empty folgt. Wenn ihr jetzt in der Seitenansicht P drückt, könnt ihr euren Spieler mit der Taste bewegen und seht, wie sich der Würfel mitbewegt.
Da das aber ein Egoshooter werden soll, könnt ihr den Würfel wieder löschen. Bindet jetzt die Kamera an das Spielerempty (Strg + P), dabei muss das Empty wieder als letztes ausgewählt werden. Jetzt könnt ihr euch in der Kameraansicht durch das Level bewegen, aber immer nur geradeaus ist langweilig, oder?! Deshalb kommt jetzt das erste Pythonscript. Das wird uns das Spielerempty drehen, wenn wir die Maus bewegen, so wie wir es aus anderen Spielen kennen.
Zuerst brauchen wir für unser Spielerempty einen Mouse Sensor, der auf Movement reagiert. Den verbindet ihr mit einem Python Controller und einem normalen Motion Actuator. Gebt dem Actuator einen eindeutigen Namen, z.B. 'linksrechts'.
Außerdem kriegt unser Empty eine bestimmte Eigenschaft zur leichteren Einstellung: klickt auf ADD property und ändert das Namensfeld auf 'move'. Als Wert für diese Float Eigenschaft stellt ihr 180 ein. Mit der Maus über einem 3D-Fenster drückt ihr Shift + F11, um ein Textfenster zu öffnen. Da hinein kopiert ihr dann diesen Code:
from GameLogic import *
from Rasterizer import *

Cont = getCurrentController()
Own = Cont.getOwner()
Sens = Cont.getSensors()
Sensor = Sens[0]

Height = getWindowHeight()/2
Width = getWindowWidth()/2

#aktuelle mausposition holen
Xpos = Sensor.getXPosition()

#actuator holen
linksrechts = Cont.getActuator('linksrechts')

#mausposition relativ zur bildschirmmitte messen
XDiff = Xpos - Width

#den actuator einstellen
linksrechts.setDRot(0,0,(XDiff/Own.move),1)

#und einmal kurz aktivieren
addActiveActuator(linksrechts,1)
addActiveActuator(linksrechts,0)

#dann die maus wieder in die bildschirmmitte setzen
setMousePosition(Width,Height)
Diesem Text gebt ihr dann einen Namen, ich habe wieder 'linksrechts' genommen, und tragt diesen Namen im Python Controller unter Script ein (Bild oben). Wenn ihr eurem Actuator einen anderen Namen gegeben habt, müsst ihr das Script ändern, da wo 'getActuator' steht. Achtung, wenn ihr irgendwelche Namen ändert: Blender und Python achten auf Groß- und Kleinschreibung!
Jetzt solltet ihr in der Kameraansicht sehen, dass ihr euch seitlich drehen könnt. Die Drehgeschwindigkeit könnt ihr mit der 'move' Eigenschaft des Emtys einstellen.
Da wir die Kamera auch nach oben oder unten kippen wollen, machen wir das Ganze jetzt für die Kamera: Mouse-Movement Sensor, Pythoncontroller, Actuator 'hochrunter' und 'move' Eigenschaft. Dazu gehört dieses Script:
from GameLogic import *
from Rasterizer import *

Cont = getCurrentController()
Own = Cont.getOwner()
Sens = Cont.getSensors()
Sensor = Sens[0]

Height = getWindowHeight()/2
Width = getWindowWidth()/2

Ypos = Sensor.getYPosition()

hochrunter = Cont.getActuator('hochrunter')

YDiff = Ypos - Height
hochrunter.setDRot((YDiff/Own.move),0,0,1)

addActiveActuator(hochrunter,1)
addActiveActuator(hochrunter,0)

setMousePosition(Width,Height)
Jetzt könnt ihr euch in jede Richtung drehen, geradeaus laufen und dabei an die Decke schauen, wenn ihr wollt.

Die Löcher

Zum Zielen braucht man einen Zieler, also erzeugt ihr eine einzelne Fläche und bewegt sie direkt vor die Kamera. Macht sie nicht zu groß; je nachdem welche Art von Zieler ihr verwendet soll der ja nicht das ganze Bild ausfüllen. Dann gebt ihr eine Textur von einem Zielerkreuz, am Besten weiß auf schwarzem Hintergrund. Ihr könnt den Zieler später mit Vertexfarben einfärben. Außerdem bindet ihr das Zielermesh mit Strg + P an die Kamera.
Wenn ihr im FaceSelect Modus seid, geht ihr zu den EditButtons, in der Gruppe Texture face klickt ihr dann auf Add, um den Modus für die Textur umzustellen. Falls ihr eine Textur mit Alphakanal verwendet, könnt ihr auch Alpha wählen. Damit wird dann der (schwarze) Hintergrund ausgeblendet, nur der weiße Vordergrund bleibt sichtbar. Wenn ihr mein Bild verwendet (Format PNG), könnt ihr Alpha aktivieren, ich hab einen Alphakanal drin.
Damit wir sehen, wo wir getroffen haben, erstellen wir jetzt die Einschusslöcher:
Wir brauchen eine weitere kleine Fläche mit der Textur des Lochs (wieder die gleichen Einstellungen für den Texturmodus, dazu noch Halo), die ihr in der Oberansicht (wichtig!) erzeugt und im EditMode so dreht, dass die Normale in die negative X-Richtung zeigt (Oberansicht: nach links). Dadurch ist sichergestellt dass die Fläche nachher auch zur Kamera zeigt. Dieses Objekt heißt Lochmesh. Wichtig: dieses Objekt muss auf ein Layer verschoben werden welches im Spiel nicht zu sehen ist, sonst werden die Löcher von Blender gar nicht erst erzeugt. Also drückt M und wählt eine Ebene aus die ihr später nicht anzeigen lasst. Ich verwende dafür meist eine aus der unteren Reihe, z.B. die Zwanzigste (Alt 0).
Außerdem noch ein Empty (Zielerempty), das ihr aus der Sicht der Kamera etwas hinter dem Zielerobjekt platziert und auch an die Kamera bindet. Für dieses Zielerempty erzeugt ihr einen Ray Sensor mit großer Reichweite (Range); 20 oder so sollte genug sein, kann aber von euerm Level abhängen. Im Feld rechts daneben stellt ihr die Achse des Zieleremptys ein, die von Kamera und Zielermesh weg zeigt. (Bei mir -Z, ich hab das Zielerempty in der Vorderansicht erzeugt.) Außerdem aktiviert ihr den Button Inv rechts oben und den Button links oben mit den drei Punkten (True Pulse Mode). Der Ray Sensor heißt 'raySen'.
Dann braucht ihr noch ein Empty (es wird langsam richtig voll :) mit einem Edit Object Actuator namens 'loch_setzen'. Im OB: Feld tragt ihr den Namen eures Lochmeshes ein. Wenn ihr bei Time einen Wert größer als null einstellt, verschwindet das Loch nach einer Weile wieder. Das war unser Lochempty.
Unser Zielerempty von gerade eben bekommt jetzt noch einen Mouse : Left Button Sensor 'mouseSen'. Dann wählt ihr zusätzlich zum Zielerempty noch das Lochempty aus, erzeugt einen Python Controller für das Lochempty, der mit dem Ray Sensor, dem Mouse Sensor und dem EditObject Actuator verbunden wird. Bei Unklarheiten sollte das Bild helfen. Und hier kommt das Script 'loch.py':
import GameLogic

con = GameLogic.getCurrentController()

mouse = con.getSensor('mouseSen')
if mouse.isPositive():
  own = con.getOwner()

  raySen = con.getSensor('raySen')
  pos = raySen.getHitPosition()

  own.setPosition(pos)

  addHole = con.getActuator('loch_setzen')
  GameLogic.addActiveActuator(addHole, 1)
  GameLogic.addActiveActuator(addHole, 0)
Ihr müsst noch den Scriptnamen im Python Controller eintragen und solltet dann die Einschusslöcher sehen.
Um noch einmal zusammenzufassen: die Kamera ist parent vom Zielermesh und dem Zielerempty; das Lochmesh und das Lochempty sind völlig frei. Zwischen dem Lochempty und dem Zielerempty besteht eine direkte Verbindung per Logic Bricks.
Jetzt könnt ihr noch eine Zielscheibe oder etwas ähliches aufstellen, und dann viel Spass beim ballern.
[www.psycho3d.de - überarbeitet 31.08.06]