見出し画像

Pythonでマイクラを作る ④プログラミングで自動建築

Processing でマイクラを作る 第4回目はクリエイティブモードでの建築を行います。Pythonプログラミングによる自動建築で壁、円柱、円錐、サインカーブを作り、最後にそれらを組み合わせてお城を作成します。

壁の建築

"""04_01_wall.py"""
from direct.showbase.ShowBase import ShowBase
from panda3d.core import *


class App(ShowBase):
    # コンストラクタ
    def __init__(self):
        # ShowBaseを継承する
        ShowBase.__init__(self)

        # ウインドウの設定
        self.properties = WindowProperties()
        self.properties.setTitle('wall sample')
        self.properties.setSize(1200, 800)
        self.win.requestProperties(self.properties)
        self.setBackgroundColor(0, 0, 0)

        # マウス操作を禁止
        self.disableMouse()
        # カメラの設定
        self.camera.setPos(50, -50, 30)
        self.camera.lookAt(0, 0, 0)

        # 座標軸
        self.axis = self.loader.loadModel('models/zup-axis')
        self.axis.setPos(0, 0, 0)
        self.axis.setScale(1.5)
        self.axis.reparentTo(self.render)

        # グラウンド
        for i in range(64):
            for j in range(64):
                grass_block = self.loader.loadModel('models/grass_block')
                grass_block.setPos(i - 32, j - 32, -1)
                grass_block.reparentTo(self.render)

        # 壁
        for i in range(12):
            for j in range(12):
                for k in range(12):
                    if i == 0 or i == 11 or j == 0 or j == 11:
                        gold_block = self.loader.loadModel('models/gold_block')
                        gold_block.setPos(i - 6, j - 6, k)
                        gold_block.reparentTo(self.render)


app = App()
app.run()
04_01_wall.py

金ブロックで壁を作成しました。このような簡単な建築でも、一つひとつブロックを置いていくと時間がかかるのはマイクラ経験者ならわかっていただけることでしょう。プログラムなら一瞬で完成します。複雑な建築ほど自動化の恩恵が感じられます。

04_01_wall.py の説明をします。
壁作成部分は、for文を3重にしてブロックを並べただけですが、中身をくり抜くには一工夫必要になります。それが条件式 if i == 0 or i == 11 or j == 0 or j == 11:  であり、4辺のブロックのみ設置するようにしています。

(課題1)
縦横高さ = (40, 30, 20) の壁を作ってみよう。天井と床は作らなくて良い。ブロックの種類は好きなものを選んでください。

シリンダー(円柱)の建築

"""04_02_cylinder.py"""
from direct.showbase.ShowBase import ShowBase
from panda3d.core import *


class App(ShowBase):
    # コンストラクタ
    def __init__(self):
        # ShowBaseを継承する
        ShowBase.__init__(self)

        # ウインドウの設定
        self.properties = WindowProperties()
        self.properties.setTitle('cylinder sample')
        self.properties.setSize(1200, 800)
        self.win.requestProperties(self.properties)
        self.setBackgroundColor(0, 0, 0)

        # マウス操作を禁止
        self.disableMouse()
        # カメラの設定
        self.camera.setPos(50, -50, 30)
        self.camera.lookAt(0, 0, 0)

        # 座標軸
        self.axis = self.loader.loadModel('models/zup-axis')
        self.axis.setPos(0, 0, 0)
        self.axis.setScale(1.5)
        self.axis.reparentTo(self.render)

        # グラウンド
        for i in range(64):
            for j in range(64):
                grass_block = self.loader.loadModel('models/grass_block')
                grass_block.setPos(i - 32, j - 32, -1)
                grass_block.reparentTo(self.render)

        # シリンダー
        for i in range(25):
            for j in range(25):
                for k in range(5):
                    if 11**2 < (i - 12)**2 + (j - 12)**2 <= 12**2:
                        bricks = self.loader.loadModel('models/bricks')
                        bricks.setPos(i - 12, j - 12, k)
                        bricks.reparentTo(self.render)


app = App()
app.run()
04_02_cylinder.py

マイクラ建築で直線的な構造物は(手間はかかるにしても)簡単に作ることができます。しかし曲線が入ってくると難易度が急激に上がってしまいます。プログラミングの自動建築なら円柱の作成も簡単です。

04_02_cylinder.py の説明をします。
先ほどの壁建築とほとんど同じなのですが、違う部分はブロックを置く条件を計算する部分です。


                    if 11**2 < (i - 12)**2 + (j - 12)**2 <= 12**2:
                        bricks = self.loader.loadModel('models/bricks')
                        bricks.setPos(i - 12, j - 12, k)
                        bricks.reparentTo(self.render)
半径11 の円と半径12 の円

$$
x^2 + y^2 = r^2  (r は円の半径)
$$

この条件式は、半径11 より大きく、半径12以下の部分にブロックを設置することを規定しています。そうすることで半径12 の円を描くことができるのです。x = i - 12、y = j - 12 として円の中心とグラウンドの中心を合わせている点にも注意が必要です。

(課題2)
半径6、高さ20の円柱を作ってください。ブロックの種類は好きなものを選んでください。天井は作らなくてかまいません。

コーン(円錐)の建築

"""04_03_corn.py"""
from direct.showbase.ShowBase import ShowBase
from panda3d.core import *


class App(ShowBase):
    # コンストラクタ
    def __init__(self):
        # ShowBaseを継承する
        ShowBase.__init__(self)

        # ウインドウの設定
        self.properties = WindowProperties()
        self.properties.setTitle('corn sample')
        self.properties.setSize(1200, 800)
        self.win.requestProperties(self.properties)
        self.setBackgroundColor(0, 0, 0)

        # マウス操作を禁止
        self.disableMouse()
        # カメラの設定
        self.camera.setPos(50, -50, 30)
        self.camera.lookAt(0, 0, 0)

        # 座標軸
        self.axis = self.loader.loadModel('models/zup-axis')
        self.axis.setPos(0, 0, 0)
        self.axis.setScale(1.5)
        self.axis.reparentTo(self.render)

        # グラウンド
        for i in range(64):
            for j in range(64):
                grass_block = self.loader.loadModel('models/grass_block')
                grass_block.setPos(i - 32, j - 32, -1)
                grass_block.reparentTo(self.render)

        # コーン(円錐)
        for i in range(25):
            for j in range(25):
                for k in range(13):
                    r = 12 - k
                    if ((r - 1)**2 < (i - 12)**2 + (j - 12)**2 <= r**2) or (i == 12 and j == 12 and k == 12):
                        blue_wool = self.loader.loadModel('models/blue_wool')
                        blue_wool.setPos(i - 12, j - 12, k)
                        blue_wool.reparentTo(self.render)


app = App()
app.run()
04_03_corn.py

丸い塔の先端に屋根をつけたい時があります。その時コーン(円錐)を作る必要がありますが、この形状も建築が難しいです。プログラミングでサクッと作ってしまいましょう。

04_03_corn.py の説明をします。
ほとんど円柱と同じですが、ブロックを置く条件式のところが違います。


    r = 12 - k
    if ((r - 1)**2 < (i - 12)**2 + (j - 12)**2 <= r**2) or (i == 12 and j == 12 and k == 12):

変数r はその高さでの円の半径を表します。高さが上がるにつれてどんどん細くなっていることをコードで表現しています。if条件式には一工夫してあり、(i == 12 and j == 12 and k == 12) は頂点の一個を決め打ちして設置しています。 少しカッコ悪いですが、数式でうまく表現できない部分は個別に指定するしかありません。

サインカーブの建築

"""04_04_sin_wave.py"""
from math import sin, pi
from direct.showbase.ShowBase import ShowBase
from panda3d.core import *


class App(ShowBase):
    # コンストラクタ
    def __init__(self):
        # ShowBaseを継承する
        ShowBase.__init__(self)

        # ウインドウの設定
        self.properties = WindowProperties()
        self.properties.setTitle('sin_wave sample')
        self.properties.setSize(1200, 800)
        self.win.requestProperties(self.properties)
        self.setBackgroundColor(0, 0, 0)

        # マウス操作を禁止
        self.disableMouse()
        # カメラの設定
        self.camera.setPos(50, -50, 30)
        self.camera.lookAt(0, 0, 0)

        # 座標軸
        self.axis = self.loader.loadModel('models/zup-axis')
        self.axis.setPos(0, 0, 0)
        self.axis.setScale(1.5)
        self.axis.reparentTo(self.render)

        # グラウンド
        for i in range(64):
            for j in range(64):
                grass_block = self.loader.loadModel('models/grass_block')
                grass_block.setPos(i - 32, j - 32, -1)
                grass_block.reparentTo(self.render)

        # サイン波
        for i in range(64):
            for j in range(10):
                x = i - 32
                y = sin(pi * x / 32) * 5
                z = j
                red_wool = self.loader.loadModel('models/red_wool')
                red_wool.setPos(x, y, z)
                red_wool.reparentTo(self.render)


app = App()
app.run()
04_04_sin_wave.py

サインカーブでなだらかな曲線を作成できます。サインカーブは、はためく旗などに使うことができます。

04_04_sin_wave.py の説明をします。
標準ライブラリmath からsin(サイン関数)と pi(円周率3.14)をインポートしてください。

from math import sin, pi

グラウンドに対して中心を合わせるために、変数x = i -32 を代入しました。 
X軸に対して周期64のサインカーブを描画しています。1サイクルで2 * pi ですからサイン関数の引数は pi * x / 32 になります。振幅は5に設定しました。波が一番大きくなった時に振れ幅が5になるということです。つまり y = sin(pi * x / 32) * 5 がサインカーブの式になります。

$$
x = i -32\\
y = 5 \sin \frac{\pi x}{32}
$$

(課題4)
縦横 3 X 6 のはためく旗を作成してください。サインカーブの半周期を使います。

お城の建築

"""04_05_castle.py"""
from math import sin, pi
from direct.showbase.ShowBase import ShowBase
from panda3d.core import *


class App(ShowBase):
    # コンストラクタ
    def __init__(self):
        # ShowBaseを継承する
        ShowBase.__init__(self)

        # ウインドウの設定
        self.properties = WindowProperties()
        self.properties.setTitle('castle sample')
        self.properties.setSize(1200, 800)
        self.win.requestProperties(self.properties)
        self.setBackgroundColor(0, 0, 0)

        # マウス操作を禁止
        self.disableMouse()
        # カメラの設定
        self.camera.setPos(120, -120, 90)
        self.camera.lookAt(0, 0, 0)

        # 座標軸
        self.axis = self.loader.loadModel('models/zup-axis')
        self.axis.setPos(0, 0, 0)
        self.axis.setScale(1.5)
        self.axis.reparentTo(self.render)

        # グラウンド
        for i in range(128):
            for j in range(128):
                grass_block = self.loader.loadModel('models/grass_block')
                grass_block.setPos(i - 64, j - 64, -1)
                grass_block.reparentTo(self.render)

        # 壁
        for i in range(60):
            for j in range(40):
                for k in range(12):
                    if i == 0 or i == 59 or j == 0 or j == 39:
                        gold_block = self.loader.loadModel('models/gold_block')
                        gold_block.setPos(i - 30, j - 20, k)
                        gold_block.reparentTo(self.render)

        # 尖塔
        for x0, y0 in ((0, 0), (-30, -20), (-30, 20), (30, 20), (30, -20)):
            # シリンダー
            for i in range(13):
                for j in range(13):
                    for k in range(20):
                        if 5**2 < (i - 6)**2 + (j - 6)**2 <= 6**2:
                            bricks = self.loader.loadModel('models/bricks')
                            bricks.setPos(x0 + i - 6, y0 + j - 6, k)
                            bricks.reparentTo(self.render)

            # コーン(円錐)
            for i in range(13):
                for j in range(13):
                    for k in range(12):
                        r = 6 - k / 2
                        if ((r - 1) ** 2 < (i - 6) ** 2 + (j - 6) ** 2 <= r ** 2) or (i == 6 and j == 6 and k == 11):
                            blue_wool = self.loader.loadModel('models/blue_wool')
                            blue_wool.setPos(x0 + i - 6, y0 + j - 6, k + 20)
                            blue_wool.reparentTo(self.render)

            # サイン波
            for i in range(6):
                for j in range(3):
                    x = i
                    y = sin(pi * x / 6) * 2
                    z = j
                    red_wool = self.loader.loadModel('models/red_wool')
                    red_wool.setPos(x0 + x, y0 + y, z + 32)
                    red_wool.reparentTo(self.render)


app = App()
app.run()
04_05_castle.py

壁、円柱、円錐、そしてサインカーブを使ってお城を作ってみました。簡単なコードで複雑な建築が可能であることがわかっていただけたかと思います。中央の尖塔を太く高くしたい。壁は厚みを持たせたい。など思い通りに改造して遊んでください。

04_05_castle.py の説明をします。
パーツは全て作成済みですから、それを正しい位置に置いているだけです。5箇所に尖塔を建てるため、for文を使いました。

for x0, y0 in ((0, 0), (-30, -20), (-30, 20), (30, 20), (30, -20)):

5つの座標 ((0, 0), (-30, -20), (-30, 20), (30, 20), (30, -20)) から一つずつ取り出して、変数x0, y0 に代入します。尖塔の基準点を(x0, y0) にすることで5つの塔を建築できました。

今回はプログラミングによるマイクラ建築を学びました。筆者は面倒なことが苦手です。こういった自動化ができると、すごく楽しくなってくるのですね。読者の皆様も楽しんでいただければ幸いです。今回の内容はプログラミング初心者の練習用に最適かと思います。

次回は、Blockクラスを作成し、ブロックの設置と破壊が簡単にできるようにします。お楽しみに!


前の記事
Pythonでマイクラを作る ③ブロックのモデルを作成する
次の記事
Pythonでマイクラを作る ⑤ブロックの設置と破壊

その他のタイトルはこちら


この記事が気に入ったらサポートをしてみませんか?