15
2024
11

python编程学习-翻滚的方块

学习python编程,在新东方少儿编程官网的自由创作平台做的一些作品。

可以在线运行,效果如下(在新页面中打开链接):

代码如下(用到平台自定义的xdf库):

import math

class Vector3:
    def __init__(self, x = 0.0, y = 0.0, z = 0.0, w = 1.0):
        self.x = x
        self.y = y
        self.z = z
        self.w = w
    
    def setV(self, v):
        self.x = v.x
        self.y = v.y
        self.z = v.z
        
    def copy(self):
        return Vector3(self.x, self.y, self.z)
    
    def length(self):
        return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
    
    def sqrLength(self):
        return self.x * self.x + self.y * self.y + self.z * self.z
    
    def normalize(self):
        inv = 1 / self.length()
        return Vector3(self.x * inv, self.y * inv, self.z * inv)
    
    def cross(self, v):
        return Vector3(-self.x * v.y + self.y * v.z, self.z * v.x - self.x * v.z, -self.y * v.x + self.x * v.y)
    
    def __pow__(self, v):
        return Vector3(-self.x * v.y + self.y * v.z, self.z * v.x - self.x * v.z, -self.y * v.x + self.x * v.y)
    
    def __neg__(self): #重载-(负)
        return Vector3(-self.x, -self.y, -self.z)
    
    def __pos__(self): #重载+(正)
        return Vector3(self.x, self.y, self.z)
    
    def __abs__(self): #重载abs()
        return Vector3(abs(self.x), abs(self.y), abs(self.z))
    
    def __add__(self, v): #重载+
        return Vector3(self.x + v.x, self.y + v.y, self.z + v.z)
    
    def __sub__(self, v): #重载-
        return Vector3(self.x - v.x, self.y - v.y, self.z - v.z)
    
    def __mul__(self, v): #重载*
        if type(v)==type(self):
            return self.x * v.x + self.y * v.y + self.z * v.z
        return Vector3(self.x * v, self.y * v, self.z * v)
    
    def __div__(self, v): # 重载/
        if type(v)==type(self):
            pass
        invf = 1 / v
        return Vector3(self.x * invf, self.y * invf, self.z * invf)
    
    def __iadd__(self, v): #重载+=
        self.x += v.x
        self.y += v.y
        self.z += v.z
        return self
    
    def __isub__(self, v): #重载-=
        self.x -= v.x
        self.y -= v.y
        self.z -= v.z
        return self
    
    def __imul__(self, v): #重载*=
        if type(v)==type(self):
            return self.x * v.x + self.y * v.y + self.z * v.z
        self.x *= v
        self.y *= v
        self.z *= v
        return self
    
    def __idiv__(self, v): # 重载/
        if type(v)==type(self):
            pass
        invf = 1 / v
        self.x *= invf
        self.y *= invf
        self.z *= invf
        return self
    
    def __str__(self):
        return "({},{},{},{})".format(self.x, self.y, self.z, self.w)
    pass
Vector3.zero = Vector3()

class Matrix:
    def __init__(self):
        self.m = [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ]
    def setRotation(self, a, b, c):
        cosa = math.cos(a)
        sina = math.sin(a)
        cosb = math.cos(b)
        sinb = math.sin(b)
        cosc = math.cos(c)
        sinc = math.sin(c)
        m = self.m
        m[0][0] = cosb * cosc
        m[0][1] = sina * sinb * cosc - sinc * cosa
        m[0][2] = sinb * cosa * cosc + sina * sinc
        m[1][0] = cosb * sinc
        m[1][1] = cosa * cosc + sina * sinb * sinc
        m[1][2] = -sina * cosc + sinc * sinb * cosa
        m[2][0] = -sinb
        m[2][1] = sina * cosb
        m[2][2] = cosa * cosb
    def setRotationV(self, v):
        self.setRotation(v.x, v.y, v.z)
    def setTranslate(self, tx = 0.0, ty = 0.0, tz = 0.0):
        m = self.m
        m[0][3] = tx
        m[1][3] = ty
        m[2][3] = tz
    def setTranslateV(self, v):
        self.setTranslate(v.x, v.y, v.z)
    def __mul__(self, v):
        m = self.m
        if type(v)==type(self):
            vm = v.m
            mt = Matrix()
            m0 = mt.m
            for i in range(4):
                for j in range(4):
                    m0[i][j] = 0
                    for k in range(4):
                        m0[i][j] += m[i][k] * vm[k][j]
            return mt
        return Vector3(
            m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w,
            m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w,
            m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w,
            m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w
        )
def ang2rad(ang):
    return math.pi * ang / 180
def rad2ang(rad):
    return 180 * rad / math.pi
class Camera:
    def __init__(self, p, dr, fov, w, h):
        self.p = p
        self.dr = dr
        self.w = w
        self.h = h
        self.n = (h / 2) / math.tan(ang2rad(fov/2))
        self.m = Matrix()
        self.m.setRotation(math.pi/4, 0, 0)
    def mapV(self, v):
        p = self.p
        dr = self.dr
        w = self.w
        h = self.h
        n = self.n
        #
        p0 = v - p
        d = p0 * dr
        d0 = p0.length()
        # n / d = t / d0
        t = d0 * n / d
        p1 = p0.normalize()
        p2 = p + p1 * t
        #
        p3 = p + dr
        p4 = self.m * p2
        return Vector3(p4.x + 768 / 2, p4.y + 1024 / 2)

from xdf import *

ground = stamp("ground001@001j")
SQRT2_2 = 0.7071067811865475
camera = Camera(Vector3(0, 3, 3), Vector3(0, -SQRT2_2, -SQRT2_2), 45, 768, 464)
class Cube:
    def __init__(self):
        psA = [
            Vector3(0, -0.3359375, 0),
            Vector3(-0.234375,0.3125, 0),
            Vector3(0.234375,0.3125, 0),
            Vector3(-0.1640625,0.1171875, 0),
            Vector3(0.1640625,0.1171875, 0)
        ]
        lindA = [
            [0, 1],
            [0, 2],
            [3, 4]
        ]
        psB = [
            Vector3(-0.1484375,-0.234375, 1.0),
            Vector3(0.1484375,-0.1171875, 1.0),
            Vector3(-0.1484375,0.234375, 1.0),
            Vector3(0.1484375,0.1171875, 1.0),
            Vector3(-0.1484375,0, 1.0)
        ]
        lindB = [
            [0, 1],
            [0, 2],
            [1, 4],
            [2, 3],
            [3, 4]
        ]
        psC = [
            Vector3(-0.5,-0.265625,0.1953125 + 0.5),
            Vector3(-0.5,-0.265625,-0.1953125 + 0.5),
            Vector3(-0.5,0.265625,-0.1953125 + 0.5),
            Vector3(-0.5,0.265625,0.1953125 + 0.5),
        ]
        lindC = [
            [0, 1],
            [1, 2],
            [2, 3]
        ]
        psD = [
            Vector3(0.5,-0.265625,0.1953125 + 0.5),
            Vector3(0.5,0.265625,0.1953125 + 0.5),
            Vector3(0.5,0,-0.1953125 + 0.5),
        ]
        lindD = [
            [0, 1],
            [1, 2],
            [2, 0]
        ]
        psE = [
            Vector3(-0.109375,0.5,-0.265625 + 0.5),
            Vector3(-0.109375,0.5,0.265625 + 0.5),
            Vector3(0.15625,0.5,-0.265625 + 0.5),
            Vector3(-0.109375,0.5,0 + 0.5),
            Vector3(0.15625,0.5,0 + 0.5),
            Vector3(0.15625,0.5,0.265625 + 0.5)
        ]
        lindE = [
            [0, 1],
            [0, 2],
            [3, 4],
            [1, 5]
        ]
        psF = [
            Vector3(-0.109375,-0.5,-0.265625 + 0.5),
            Vector3(-0.109375,-0.5,0.265625 + 0.5),
            Vector3(0.15625,-0.5,-0.265625 + 0.5),
            Vector3(-0.109375,-0.5,0 + 0.5),
            Vector3(0.15625,-0.5,0 + 0.5)
        ]
        lindF = [
            [0, 1],
            [0, 2],
            [3, 4]
        ]
        self.arr = [
            [psA, lindA]
            #,[psB, lindB]
            #,[psC, lindC]
            #,[psD, lindD]
            #,[psE, lindE]
            #,[psF, lindF]
        ]
        #
        self.ps0 = [
            Vector3(-0.5, -0.5, 0),
            Vector3(0.5, -0.5, 0),
            Vector3(0.5, 0.5, 0),
            Vector3(-0.5, 0.5, 0),
            Vector3(-0.5, -0.5, 1),
            Vector3(0.5, -0.5, 1),
            Vector3(0.5, 0.5, 1),
            Vector3(-0.5, 0.5, 1)
        ]
        self.linds = [[0, 1],[1, 2],[2, 3],[3, 0],
            [4, 5],[5, 6],[6, 7],[7, 4],
            [0, 4],[1, 5],[2, 6],[3, 7]
        ]
        #
        for a in self.arr:
            n = len(self.ps0)
            ps = a[0]
            inds = a[1]
            for b in inds:
                b[0] += n
                b[1] += n
            self.ps0.extend(ps)
            self.linds.extend(inds)
        #
        self.ps = [Vector3() for v in self.ps0]
        self.ps2 = [Vector3() for v in self.ps]
        self.lines = [line(0, 0, 1, 0) for l in self.linds]
        self.pos = Vector3()
        self.reset()
        
    def reset(self):
        for i in range(len(self.ps0)):
            self.ps[i].setV(self.ps0[i]) 
        self.pos.setV(Vector3.zero)
        
    def isEqual(self, p0, p1, th):
        return (p0 - p1).sqrLength() < th
    
    def success(self):
        th = 0.1 * 0.1
        if self.isEqual(self.pos, Vector3.zero, th):
            for i in range(len(self.ps0)):
                if not self.isEqual(self.ps[i], self.ps0[i], th):
                    return False
            return True
        return False
    
    def update(self):
        for i in range(len(self.ps)):
            self.ps2[i] = camera.mapV(self.ps[i])
        for i in range(len(self.linds)):
            ps = self.linds[i]
            li = self.lines[i]
            p0 = self.ps2[ps[0]]
            p1 = self.ps2[ps[1]]
            dx = p1.x - p0.x
            dy = p1.y - p0.y
            sz = math.sqrt(dx * dx + dy * dy)
            rot = math.atan2(dy, dx)
            li.move(p0.x, p0.y)
            li.rotate(rad2ang(rot) + 90)
            li.size(sz)

class Turn:
    def __init__(self, cube):
        self.angV = Vector3()
        self.transV = Vector3()
        self.cube = cube
        self.isAnim = False
        self.N = 20
        self.n = 0
        
    def reset(self):
        self.isAnim = False
        
    def anim(self, angV, transV, im = False):
        if self.isAnim:
            return
        tp = self.cube.pos + transV * 2
        if tp.x > 1.5 or tp.x < -1.5 or tp.y > 1.5 or tp.y < -1.5:
            return
        self.isAnim = True
        self.n = 0
        self.angV = angV / self.N
        self.transV = self.cube.pos + transV
        self.cube.pos += transV * 2
        if im:
            self.angV = angV
            self.update()
            self.isAnim = False
    
    def update(self):
        if not self.isAnim:
            return
        angV = self.angV
        transV = self.transV
        ps = self.cube.ps
        #
        m = Matrix()
        m0 = Matrix()
        m0.setTranslateV(-transV)
        m1 = Matrix()
        m1.setRotation(angV.x, angV.y, angV.z)
        m2 = Matrix()
        m2.setTranslateV(transV)
        m = m2 * m1 * m0
        for v in ps:
            v.setV(m*v)
        self.n += 1
        if self.n >= self.N:
            self.isAnim = False
            chekSuccess()
isOver = False
cube = Cube()
turn = Turn(cube)
overTf = text("成功了", 768/2, 100, 100, "red", "center")

def chekSuccess():
    global isOver
    if cube.success():
        isOver = True
        overTf.show()
    pass

def loop():
    turn.update()
    cube.update()
    pass

def reset():
    global isOver
    isOver = False
    cube.reset()
    turn.reset()
    overTf.hide()
    aa = [
        [[turnLeft, turnUp, turnRight, turnDown],
        [turnLeft, turnDown, turnRight, turnUp],
        [turnRight, turnDown, turnLeft, turnUp],
        [turnRight, turnUp, turnLeft, turnDown]],
        [[turnUp, turnLeft, turnDown, turnRight],
        [turnUp, turnRight, turnDown, turnLeft],
        [turnDown, turnLeft, turnUp, turnRight],
        [turnDown, turnRight, turnUp, turnLeft]]
    ][random(2)-1]
    while cube.success():
        bb = []
        for i in range(10):
            a = aa[random(len(aa)) - 1]
            bb.append(a)
        for a in bb:
            for b in a:
                b(True)
    
def turnLeft(im = False):
    turn.anim(Vector3(0, -math.pi / 2, 0), Vector3(-0.5, 0, 0), im)
def turnRight(im = False):
    turn.anim(Vector3(0, math.pi / 2, 0), Vector3(0.5, 0, 0), im)
def turnUp(im = False):
    turn.anim(Vector3(math.pi / 2, 0, 0), Vector3(0, -0.5, 0), im)
def turnDown(im = False):
    turn.anim(Vector3(-math.pi / 2, 0, 0), Vector3(0, 0.5, 0), im)
def keyup(code, key):
    global isOver
    if turn.isAnim:
        return
    if isOver:
        if code == 32:
            reset()
        return
    if code == 37:
        turnLeft()
    elif code == 38:
        turnUp()
    elif code == 39:
        turnRight()
    elif code == 40:
        turnDown()
    pass

def tap():
    global isOver
    if isOver:
        reset()
    pass
reset()

btn = text("重新开始", 0, 50, 50)
btn.tap = reset
class MyKeyBoard:
    def __init__(self, x, y, w):
        hw = w / 2
        hhw = w * 0.75
        self.arr = [
            box(x, y - w, w, w, "white", "red"),
            text("↑", x + hw, y - w + hhw, w, "center", "red"),
            box(x, y, w, w, "white", "red"),
            text("↓", x + hw, y + hhw, w, "center", "red"),
            box(x - w, y, w, w, "white", "red"),
            text("←", x - hw, y + hhw, w, "center", "red"),
            box(x + w, y, w, w, "white", "red"),
            text("→", x + w + hw, y + hhw, w, "center", "red"),
        ]
        self.arr[0].tap=self.clickUp
        self.arr[2].tap=self.clickDown
        self.arr[4].tap=self.clickLeft
        self.arr[6].tap=self.clickRight
        delay(self.loop, 100)
        
    def loop(self):
        for i in range(len(self.arr)):
            self.arr[i].front()
        delay(self.loop, 100)
    
    def onKeydown(self, keyCode, key):
        try:
            keyup(keyCode, key)
        except e:
            pass
    def clickUp(self):
        self.onKeydown(38, "ArrowLeft")
    def clickDown(self):
        self.onKeydown(40, "ArrowDown")
    def clickLeft(self):
        self.onKeydown(37, "ArrowLeft")
    def clickRight(self):
        self.onKeydown(39, "ArrowRight")
MyKeyBoard(768-200, 1024-100, 100)

也可以下载代码,本地python环境运行(用pygame封装了xdf库)。



« 上一篇下一篇 »

相关文章:

python编程学习-英雄天梯  (2024-11-15 11:37:35)

python编程学习-玛丽跳跳跳  (2024-11-15 11:36:43)

python编程学习-汉诺塔  (2024-11-15 11:36:16)

python编程学习-模拟键盘按键  (2024-11-15 11:35:50)

python编程学习-显示帧频  (2024-11-15 11:35:26)

python编程学习-收不完的西瓜  (2024-11-15 11:35:0)

python编程学习-推箱子  (2024-11-15 11:34:1)

python编程学习-拼图  (2024-11-15 11:33:25)

python编程学习-扫雷  (2024-11-15 11:32:58)

python编程学习-小学数学加减分解题  (2024-11-15 11:32:29)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。