Part of pictures, articles, images on this page are copyrighted by Mojang AB.
Dies ist ein Projekt zur Reproduktion des weltberühmten Sandbox-Spiels "Minecraft" in der Programmiersprache "Python".
** Vorheriger Artikel: "[# 1] Minecraft mit Python erstellen. Vorläufige Forschung und Design-" **
** Nächster Artikel: "[# 3] Minecraft mit Python erstellen. - Spielerbewegung (Konzept der Trägheit) und Kollisionsbeurteilung verbessern-" ** ** **
Vielen Dank für Ihre Geduld. Dies ist der zweite!
Ich konnte keine 3D-Game-Engine von Grund auf neu erstellen und suchte nach einer 3D-Game-Engine (Bibliothek), die auch Python unterstützt.
Unter diesen haben wir diejenigen ausgewählt, die relativ einfach zu bedienen sind und wahrscheinlich schöne Zeichnungen produzieren.
Panda3D Engine
Es ist eine 3D-Spiel-Engine namens "Panda3D". Plattformen sind Python und C ++.
Ich werde es tatsächlich bewegen.
▼ Installation
pip install --pre --extra-index-url https://archive.panda3d.org/ panda3d
▼ Quellcode
main.py
from Renderer import engine
def main():
_render = engine.Renderer()
_render.run()
if __name__ == "__main__":
main()
engine.py
from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from panda3d.core import TextNode
from pandac.PandaModules import WindowProperties
class Renderer(ShowBase):
def __init__(self):
ShowBase.__init__(self)
props = WindowProperties()
props.setTitle('PyCraft')
props.setSize(1280, 720)
self.win.requestProperties(props)
OnscreenText(text="PyCraft ScreenText",
parent=None, align=TextNode.ARight,
fg=(1, 1, 1, 1), pos=(-0.1, 0.1), scale=.08,
shadow=(0, 0, 0, 0.5))
Es wurde so gezeichnet.
engine.py
from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from panda3d.core import TextNode
from pandac.PandaModules import WindowProperties
from direct.showbase.Loader import Loader
class Renderer(ShowBase):
def __init__(self):
ShowBase.__init__(self)
props = WindowProperties()
props.setTitle('PyCraft')
props.setSize(1280, 720)
self.win.requestProperties(props)
OnscreenText(text="PyCraft ScreenText",
parent=None, align=TextNode.ARight,
fg=(1, 1, 1, 1), pos=(-0.1, 0.1), scale=.08,
shadow=(0, 0, 0, 0.5))
self.scene = self.loader.loadModel("models/environment")
self.scene.reparentTo(self.render)
self.scene.setScale(1, 1, 1)
self.scene.setPos(0, 0, 0)
self.cube = self.loader.loadModel("models/misc/rgbCube")
self.cube.reparentTo(self.render)
self.cube.setScale(1, 1, 1)
self.cube.setPos(0, 20, 0)
Es stellte sich heraus, dass es so etwas war. Es scheint, dass Sie es mit einer Maus bedienen können. Der Würfel sieht so aus.
Referenz: 6 Sekunden Video mit gif @ panda3D
▼ Quellcode Da es lang sein wird, wird nur der Kernteil beschrieben.
engine.py
self.world = BulletWorld()
self.world.setGravity(Vec3(0, 0, -9.81))
self.worldPath = self.render.attachNewNode("")
debugNode = BulletDebugNode()
nodePath = self.worldPath.attachNewNode(debugNode)
nodePath.show()
self.world.setDebugNode(debugNode)
bodyGround = BulletRigidBodyNode()
bodyGround.addShape(BulletBoxShape((3, 3, 0.001)))
nodePath = self.worldPath.attachNewNode(bodyGround)
nodePath.setPos(0, 0, -2)
nodePath.setHpr(0, 12, 0)
self.world.attachRigidBody(bodyGround)
self.boxes = []
for i in range(30):
bodyBox = BulletRigidBodyNode()
bodyBox.setMass(1.0)
bodyBox.addShape(BulletBoxShape((0.5, 0.5, 0.5)))
nodePath = self.worldPath.attachNewNode(bodyBox)
nodePath.setPos(0, 0, 2 + i * 2)
self.boxes.append(nodePath)
self.world.attachRigidBody(bodyBox)
Ogre3D "Ogre3D" ist eine der Spiel-Engines, die Hardwarebeschleunigung verwenden. Es scheint, dass es nicht nur C ++, sondern auch Python und .NET unterstützt. Die Realisierung von 3D-Spielen in .NET ist ziemlich schwierig, daher möchte ich Ogre.NET verwenden, um zu erkennen, dass "ich versucht habe, Minecraft mit C # zu reproduzieren!".
Schauen Sie sich [Showcase] an (https://www.ogre3d.org/showcase).
Dies scheint ein Spiel zu sein "X-Morph: Defense". Natürlich wird der Ogre-Motor verwendet. Das ist eine großartige Grafik.
Zusätzlich zu anderen als den oben genannten Spiel-Engines habe ich mich für "Pyglet" entschieden, das die meisten Informationen zu enthalten scheint, da es plattformübergreifend ist. Es hängt nicht von anderen Bibliotheken ab. ・ Es ist perfekt, dass es Multi-Display und Multi-Monitor unterstützt.
Von hier aus machen wir eine einfache Zeichnung mit Pyglet.
▼ Installation
pip install pyglet
▼ Installation (für PyCharm)
Menüleiste
▶ Datei
▶ Einstellungen
▼ Beispielcode
main.py
#Modul importieren
from pyglet.gl import *
#Fenster zum Anzeigen
#Breite ist die Breite und Höhe ist die Höhe.
#Die Beschriftung ist der Fenstertitel und die Größe ändert, ob die Größe geändert werden soll.
pyglet.window.Window(width=700, height=400, caption='Hello Pyglet!', resizable=True)
pyglet.app.run()
Wenn es so angezeigt wird, ist es OK.
OpenGL wird in Pyglet verwendet.
▼ Beispielcode
main.py
#Modul importieren
from pyglet.gl import *
#Fenster
window = pyglet.window.Window(width=700, height=400, caption='Hello Pyglet!', resizable=True)
#Fensterzeichnungsereignis
@window.event
def on_draw():
#Klare Zeichnung
window.clear()
glBegin(GL_LINES) #Beginnen Sie mit dem Zeichnen einer Linie
glColor3f(1, 0, 0) # R,G,B ÷ 255
glVertex2f(0, 0) # x, y(0, 0)Von
glVertex2f(100, 100) # x, y(100, 100)Bis
glEnd() #Beenden Sie das Zeichnen der Linie
pyglet.app.run()
Bei der Ausführung wird die Linie wie folgt gezeichnet.
Im obigen Quellcode wird die Zeichenereignisfunktion von "Fenster" definiert und die Linie wird mit OpenGL gezeichnet. Es scheint, dass OpenGL die untere linke Ecke des Bildschirms als Nullkoordinaten erkennt.
** 1. Deklarieren Sie den Beginn der Strichzeichnung mit glBegin (GL_LINES)
**
** 2. Deklariere Farbe mit glColor3f (1, 0, 0)
**
Die Farbe hier ist RGB (Rot, Grün, Blau).
Jedes ist normalerweise 0 bis 255, aber hier wird es mit "Float" deklariert, wie es "3f" sagt. Übergeben Sie also die durch "255.f" geteilte Zahl als Argument.
3f
bedeutet , 3
-Nummern in f
loat zu übergeben.
** 2. Deklarieren Sie den Startpunkt der Linie mit glVertex2f (x, y)
**
Übergeben Sie die Koordinaten des Startpunkts der Linie.
"2f" bedeutet, die Koordinaten der "2" -Dimension mit "f" loat zu übergeben.
** 3. Deklarieren Sie den Endpunkt der Linie mit glVertex2f (x, y)
**
Übergeben Sie die Koordinaten des Endpunkts der Linie.
Es ist in Ordnung, hier eine Zahl zu übergeben, die größer als das Fenster ist, aber sie wird nicht vom Bildschirm gezeichnet.
** 4. Deklarieren Sie das Ende der Strichzeichnung mit glEnd ()
**
Endlich das Hauptthema.
Es ist ein ** großer Fehler **, zu versuchen, alles auf einmal zu implementieren, um das Projekt zu realisieren.
Angenommen, Sie möchten "Funktion A", "Funktion B" und "Funktion C" implementieren. Wenn diese auf einmal implementiert werden und ein Fehler oder Defekt auftritt, ist es schwierig zu identifizieren, welche Funktion (welcher Teil) den Fehler oder Defekt verursacht, oder es dauert länger als gewöhnlich, die Ursache zu finden. Ich werde das machen.
Das richtige Verfahren ist
Implementierung von Funktion A
▶ ** Funktionsprüfung ** ▶ Implementierung von Funktion B
▶ ** Funktionsprüfung ** ▶ Implementierung von Funktion C
ist.
In dem unwahrscheinlichen Fall, dass ein Problem auftritt, nachdem die "Funktion C" implementiert wurde, besteht ein Problem zwischen der "Funktion B" und der "Funktion C". Kann als gedacht werden. Es ist effizienter.
Lassen Sie uns zunächst den Vorgang mit der Mindestkonfiguration überprüfen. Die Einführung ist lang.
Vorerst werden wir es probeweise verwenden, daher haben wir diese Textur vorbereitet, die Minecraft vertraut ist. ▼ Textur
Lassen Sie uns tatsächlich mit der vorbereiteten Textur zeichnen! Der Quellcode wird lang sein, also habe ich ihn auf Gist gepostet.
▼ Quellcode Gist: main.py
Bei der Ausführung wird es wie folgt gezeichnet. * Normaler Zustand. </ font>
Vorerst konnte ich nur auf einer Seite zeichnen.
Ich werde beim Extrahieren von Teilen erklären.
Definiert einen sogenannten Stapel, der den zu zeichnenden Scheitelpunkt enthält.
self.batch = pyglet.graphics.Batch()
Definieren Sie dann die dreidimensionalen Koordinaten, die der Schlüssel sind. Wenn hier "0" eingestellt ist, wird es vom Bildschirm gezeichnet ** und kann aufgrund der Position der ursprünglichen Kamera nicht bestätigt werden **, sodass es mit einer leichten Verschiebung definiert wird.
#Definieren Sie 3D-Weltkoordinaten
x = 0.5
y = 0
z = -2
Zum Laden von Texturen steht eine Funktion zur Verfügung. Verwenden Sie den nativen Pyglet-Lader. Geben Sie den Image-Patch für "Pfad" an.
#Funktion zum Laden der Textur
def load_texture(self, path):
texture = pyglet.image.load(path).get_texture()#Verwenden Sie den Texturlader von pyglet
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
return pyglet.graphics.TextureGroup(texture)
Als nächstes kommt die Fensterklasse.
Diese Klasse erbt von der Klasse pyglet.window.Window
.
Die Initialisierungsfunktion initialisiert die Instanz der zuvor definierten Klasse "World".
super
ähnelt Java.
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
#Weltklasse-Initialisierung
self.world = World()
Definieren Sie dann die Funktion, die die wesentliche Zeichnung ausführt.
def on_draw(self):
#Löschen Sie den Bildschirm
self.clear()
#Da die Welt 3D ist, stellen Sie den 3D-Zeichenmodus ein
self.render_mode_3d()
#Zeichne die Welt
self.world.draw()
Hier ist die Funktion render_mode_3d ()
,
Beim Ausführen von 3D-Zeichnungen und 2D-Zeichnungen muss der Matrixmodus eingestellt werden.
Es verfügt über ** Projektion
** und Feldkonvertierungsmodus (Modellansicht)
, der standardmäßig den Feldkonvertierungsmodus verwendet.
Wir werden diese Matrixmodi später diskutieren.
Hinweis: Verwenden Sie glLoadIdentity ()
, um den Konvertierungsprozess für den kumulativen Modus zu löschen (zu initialisieren). </ font>
def render_mode_3d(self):
self.render_mode_projection()
#Sichtfeld einstellen
gluPerspective(70, self.width / self.height, 0.05, 1000)
self.render_mode_modelview()
def render_mode_2d(self):
self.render_mode_projection()
#Zeichenbereich 0 zum Fenster_Breite, 0 zum Fenster_height
gluOrtho2D(0, self.width, 0, self.height)
self.render_mode_modelview()
def render_mode_projection(self):
glMatrixMode(GL_PROJECTION)#Projektionskonvertierungsmodus
glLoadIdentity()#Beseitigen Sie den kumulativen Konvertierungsprozess
def render_mode_modelview(self):
glMatrixMode(GL_MODELVIEW)#Modellierungskonvertierungsmodus(Feldkonvertierung)
glLoadIdentity()#Beseitigen Sie den kumulativen Konvertierungsprozess
gluOrtho2D
führt eine Projektionskonvertierung durch, bei der es sich um eine Parallelprojektion in 2D handelt.
gluOrtho2D(left, right, top, bottom)
Dann legt gluPerspective ()
das Sichtfeld fest.
gluPerspective(fovY, aspect, zNear, zFar)
Der Betrachtungswinkel der Y-Achse, der Aspekt (horizontaler Betrachtungswinkel), der Z-kürzeste Abstand bzw. der Z-Längste Abstand.
Außerdem ändern zNear
und zFar
das Erscheinungsbild auf dem Bildschirm nicht.
Dies kann als ** angesehen werden, unabhängig davon, ob Sie 1 m näher am Bildschirm oder 1 m näher am Bildschirm sind **.
Ab hier wird der Inhalt spezialisiert. Wenn Sie nicht interessiert sind, können Sie ihn überspringen.
Zu den Matrixmodi gehören ** visuelle Transformation (GL_PROJECTION)
** und ** Modellierungstransformation (GL_MODELVIEW)
**.
* Um genau zu sein, gibt es auch GL_TEXTURE
, aber es wird in dieser Quelle nicht behandelt, daher wird es übersprungen. </ font>
Auch 3D ▶ 2D-Konvertierung ist "Geometriekonvertierung" "Affin-Konvertierung" zur Konvertierung beim Skalieren / Verschieben Wird genannt.
Es wird super lang und ich denke, einige Leute sind interessiert, also werde ich es in einen externen Artikel werfen. Es tut uns leid.
Ich konnte keinen japanischen Artikel finden, der die Geometriekonvertierung ausführlich erklärt.
Ich möchte den gesamten Block zeichnen, aber es ist unpraktisch, weil ich den Ansichtspunkt nicht so verschieben kann, wie er ist. Daher werde ich die Ansichtspunktbewegung vorerst genauso wie den Spieler implementieren. Ich habe auch "PyImGui" verwendet, um die Debug-Informationen anzuzeigen.
▼ Quellcode Gist: main.py
▼ So.
Nachdem Sie den Ansichtspunkt und die Koordinaten frei bewegen können, zeichnen wir den gesamten Block. Der Quellcode lautet wie folgt. Es tut mir leid, wenn ich einen Fehler in der Richtung gemacht habe. ~~ Ich habe Angst, also entschuldige ich mich im Voraus. ~~
▼ Quellcode Gist: main.py
#Es tut mir leid, wenn ich einen Fehler mache
#Vorderseite
self.batch.add(4, GL_QUADS, self.loaded_texture, ('v3f', (x, y, z, x, y, z+1, x, y+1, z+1, x, y+1, z,)), texture_coordinates)
#Rückseite
self.batch.add(4, GL_QUADS, self.loaded_texture, ('v3f', (x+1, y, z+1, x+1, y, z, x+1, y+1, z, x+1, y+1, z+1,)), texture_coordinates)
#Bodenfläche
self.batch.add(4, GL_QUADS, self.loaded_texture, ('v3f', (x, y, z, x+1, y, z, x+1, y, z+1, x, y, z+1,)), texture_coordinates)
#Obere Oberfläche
self.batch.add(4, GL_QUADS, self.loaded_texture, ('v3f', (x, y+1, z+1, x+1, y+1, z+1, x+1, y+1, z, x, y+1, z,)), texture_coordinates)
#Rechte Seite
self.batch.add(4, GL_QUADS, self.loaded_texture, ('v3f', (x+1, y, z, x, y, z, x, y+1, z, x+1, y+1, z,)), texture_coordinates)
#links
self.batch.add(4, GL_QUADS, self.loaded_texture, ('v3f', (x, y, z+1, x+1, y, z+1, x+1, y+1, z+1, x, y+1, z+1,)), texture_coordinates)
▼ Es sieht so aus
Wie Sie dem Video entnehmen können, weist die Zeichnung übrigens einige Auffälligkeiten auf.
Dies liegt daran, dass * zusätzliche Teile * wie der normalerweise unsichtbare Teil (Rückseite) gezeichnet werden.
Um dies zu verhindern, setzen Sie glEnable (GL_DEPTH_TEST)
.
Dies ist eine bequeme Möglichkeit, unnötige Oberflächenzeichnungen auf der OpenGL-Seite auszuwählen / zu eliminieren.
▼ Nach dem Einstellen wurde es wunderschön gezeichnet!
Dieses Mal haben wir die Spiel-Engine ausgewählt, das Modell gezeichnet und den Spieler implementiert. Das nächste Mal möchte ich eine Welt aufbauen und ein Hit-Urteil umsetzen.
Danke, dass du bis zum Ende zugesehen hast.
Recommended Posts