マイクラのブロックを作ってみた

processingは3Dも扱えるので、試しにマイクラのブロックを作ってみた。

当初テクスチャのサイズを原寸の16×16にしていたが、processingの場合、引き延ばすと汚くなってしまうので1600%の256pxにして使用することにした。

from MouseCamera import MouseCamera
from TextureBox import TextureBox

mouseCamera = None
blocks = list()

def square(r=5, y=0, tname="cobblestone"):
    if r % 2 == 0:
        return

    herf = (r - 1) / 2

    for x in range(-herf, herf+1):
        blocks.append(TextureBox(tname, x, y, -herf))
        blocks.append(TextureBox(tname, x, y, herf))

    for z in range(-(herf-1), herf):
        blocks.append(TextureBox(tname, -herf, y, z))
        blocks.append(TextureBox(tname, herf, y, z))

def setup():
    global mouseCamera, blocks
    size(800,800, P3D)
    textureMode(NORMAL)
    mouseCamera = MouseCamera()

    blocks.append(TextureBox("cobblestone", 0, -20, 0))

    for x in range(-10, 11):
        for z in range(-10, 11):
            blocks.append(TextureBox("grass_block", x, 1, z))

    y=0
    for i in range(19, 0, -4):
        square(i, y, "tnt")
        y-=2


def draw():
    background(200)
    mouseCamera.update()
    for block in blocks:
        block.draw()
    if blocks[0].y < 0:
        blocks[0].y += 0.01

def mousePressed():
    mouseCamera.mousePressed()
def mouseDragged():
    mouseCamera.mouseDragged()
def mouseWheel(event):
    mouseCamera.mouseWheel(event)
# coding: utf-8

import copy

class MouseCamera(object):
    def __init__(self):
        self.radius = 800.0 # 仮想的な球の半径
        self.eyeX = 0.0
        self.eyeY = 0.0
        self.eyeZ = (height / 2.0)/tan(PI*30.0/180.0)
        self.centerX = 0.0
        self.centerY = 0.0
        self.centerZ = 0.0
        self.upX = 0.0
        self.upY = 1.0
        self.upZ = 0.0
        self.matrix = self.getIdentityMatrix() # 行列
        self.preVector = PVector()

    # def setView(self, radius, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ):
    #     self.radius = radius
    #     self.eyeX = eyeX
    #     self.eyeY = eyeY
    #     self.eyeZ = eyeZ
    #     self.centerX = centerX
    #     self.centerY = centerY
    #     self.centerZ = centerZ
    #     self.upX = upX
    #     self.upY = upY
    #     self.upZ = upZ
    #     self.matrix = self.getIdentityMatrix()

    # 毎フレーム処理
    def update(self):
        beginCamera()
        camera(self.eyeX, self.eyeY, self.eyeZ, self.centerX, self.centerY, self.centerZ, self.upX, self.upY, self.upZ)
        applyMatrix(self.matrix[0][0], self.matrix[0][1], self.matrix[0][2], self.matrix[0][3],
                    self.matrix[1][0], self.matrix[1][1], self.matrix[1][2], self.matrix[1][3],
                    self.matrix[2][0], self.matrix[2][1], self.matrix[2][2], self.matrix[2][3],
                    self.matrix[3][0], self.matrix[3][1], self.matrix[3][2], self.matrix[3][3])
        endCamera()

    # クリックしたときに呼び出す関数
    def mousePressed(self):
        # 右ボタンをクリックをしたときの処理
        if mouseButton == RIGHT:
            matrix = self.getIdentityMatrix()
        # 左ボタンをクリックをしたときの処理
        elif mouseButton == LEFT:
            self.preVector = self.mouseOnSphere(mouseX-width / 2.0, mouseY-height / 2.0)
        # 中ボタンをクリックしたときの処理
        elif mouseButton == CENTER:
            self.preVector = PVector(mouseX-width / 2.0, mouseY-height / 2.0)

    # ドラッグしたときに呼び出す関数
    def mouseDragged(self):
        # 左ボタンをドラッグしたときの処理
        if mouseButton == LEFT:
            v = self.mouseOnSphere(mouseX-width / 2.0, mouseY-height / 2.0)
            self.matrix = self.mult(self.getRotationMatrix(self.preVector, v), self.matrix)
            self.preVector = v

        # 中ボタンをドラッグしたときの処理
        elif mouseButton == CENTER:
            v = PVector(mouseX-width / 2.0, mouseY-height / 2.0)
            self.matrix = self.mult(self.getTranslationMatrix(self.preVector, v), self.matrix)
            self.preVector = v

    # マウスホイールを動かしたときに呼び出す関数
    def mouseWheel(self, event):
        self.matrix = self.mult(self.getScaleMatrix(event.getCount()), self.matrix)

    # 単位行列の取得
    def getIdentityMatrix(self):
        return [[1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]]

    # 回転行列の取得
    def getRotationMatrix(self, v1, v2):
        v1tmp = copy.copy(v1) # 保護するためにコピーして使う(normalizeの挙動がjavaと違うのか、値渡しができない影響か、オブジェクトの生成の挙動の違いかわからん)
        v = v1tmp.cross(v2).normalize() # 回転軸
        c = v1.dot(v2) # cos
        s = v1.cross(v2).mag() # sin
        return [[c + v.x*v.x*(1.0-c), v.x*v.y*(1.0-c) - v.z*s, v.x*v.z*(1.0-c) + v.y*s, 0.0],
                [v.y*v.x*(1.0-c) + v.z*s, c + v.y*v.y*(1.0-c), v.y*v.z*(1.0-c) - v.x*s, 0.0],
                [v.z*v.x*(1.0-c) - v.y*s, v.z*v.y*(1.0-c) + v.x*s, c + v.z*v.z*(1.0-c), 0.0],
                [0.0, 0.0, 0.0, 1.0]]

    # 平行移動行列の取得
    def getTranslationMatrix(self, v1, v2):
        return [[1.0, 0.0, 0.0, v2.x-v1.x],
                [0.0, 1.0, 0.0, v2.y-v1.y],
                [0.0, 0.0, 1.0, v2.z-v1.z],
                [0.0, 0.0, 0.0, 1.0]]

    # 拡大縮小行列の取得
    def getScaleMatrix(self, wheelCount):
        temp = 10.0 # wheelCountの値が大きいので定数で割る
        return [[exp(-wheelCount/temp), 0.0, 0.0, 0.0],
                [0.0, exp(-wheelCount/temp), 0.0, 0.0],
                [0.0, 0.0, exp(-wheelCount/temp), 0.0],
                [0.0, 0.0, 0.0, 1.0]]

    # マウスの座標から球面上の位置ベクトルを取得する
    def mouseOnSphere(self, x, y):
        _x = x / self.radius
        _y = y / self.radius
        res = PVector(_x, _y, 0.0)
        if _x * _x + _y * _y > 1.0:
            res.normalize()
        else:
            res.z = sqrt(1.0 - _x * _x - _y * _y)
        return res

    # 行列の積 (m1 * m2)
    def mult(self, m1, m2):
        assert(len(m1[0]) == len(m2))
        res = [[0 for i in range(len(m1))] for j in range(len(m2[0]))]
        for i in range(len(m1)):
            for j in range(len(m2[0])):
                sum = 0.0
                for k in range(len(m1[0])):
                    sum += m1[i][k] * m2[k][j]
                res[i][j] = sum
        return res
# coding: utf-8

import os

class TextureBox:
    NAME = list()
    NAME.append("grass_block")
    NAME.append("tnt")
    NAME.append("cobblestone")
    IMG = dict()
    TEXTURE_LOADED = False

    def __init__(self, textureName="tnt", x=0, y=0, z=0):
        self.loadTexture()
        imgs = TextureBox.IMG[textureName]
        self.tex_top = imgs[0]
        self.tex_side = imgs[0]
        self.tex_bottom = imgs[0]
        if len(imgs) >= 2:
            self.tex_top = imgs[1]
        if len(imgs) >= 3:
            self.tex_bottom = imgs[2]
        self.box_size = 50
        self.x = x
        self.y = y
        self.z = z

    def loadTexture(self):
        if TextureBox.TEXTURE_LOADED == False:
            for name in TextureBox.NAME:
                imgs = list()
                for i in range(3):
                    fname = name + str(i) + ".png"
                    path = os.getcwd() + "\\data\\" + fname
                    if os.path.isfile(path):
                        imgs.append(loadImage(fname))
                TextureBox.IMG[name] = imgs
            TextureBox.TEXTURE_LOADED = True

    def draw(self):
        noFill()
        noStroke()

        beginShape(QUADS)
        pushMatrix()
        scale(self.box_size, self.box_size, self.box_size)
        translate(self.x - 0.5, self.y + 0.5, self.z + 0.5)
        # +Z "front" face
        texture(self.tex_side)
        vertex(0, -1, -1, 0, 0)
        vertex(1, -1, -1, 1, 0)
        vertex(1, 0, -1, 1, 1)
        vertex(0, 0, -1, 0, 1)
        # -Z "back" face
        vertex(0, -1, 0, 0, 0)
        vertex(1, -1, 0, 1, 0)
        vertex(1, 0, 0, 1, 1)
        vertex(0, 0, 0, 0, 1)
        # +X "right" face
        vertex(1, -1, 0, 0, 0)
        vertex(1, -1, -1, 1, 0)
        vertex(1, 0, -1, 1, 1)
        vertex(1, 0, 0, 0, 1)
        # -X "left" face
        vertex(0, -1, 0, 0, 0)
        vertex(0, -1, -1, 1, 0)
        vertex(0, 0, -1, 1, 1)
        vertex(0, 0, 0, 0, 1)
        endShape()

        beginShape(QUADS)
        # -Y "top" face
        texture(self.tex_top)
        vertex(1, -1, 0, 0, 0)
        vertex(1, -1, -1, 1, 0)
        vertex(0, -1, -1, 1, 1)
        vertex(0, -1, 0, 0, 1)
        endShape()

        beginShape(QUADS)
        # +Y "bottom" face
        texture(self.tex_bottom)
        vertex(1, 0, 0, 0, 0)
        vertex(1, 0, -1, 1, 0)
        vertex(0, 0, -1, 1, 1)
        vertex(0, 0, 0, 0, 1)
        endShape()

        popMatrix()

コメントする