Pygame 3D立方体平移和移动
我做了一个3D立方体,现在我想写一个移动的功能,比如用键盘的上箭头键来让立方体在X轴上移动,用Y轴来让它在Y轴上移动,用右箭头键来让它在Z轴上移动。我找到了一个关于2D移动的函数,在这里,但是我有点卡住了,不知道该怎么做。
现在我想请教一下,怎么把这个移动的函数调整到我的代码里,或者有没有人能给我一些建议,告诉我怎么把我的立方体移动到下面代码中的vertices3?
请大家帮帮我。
import sys, math, pygame
class Point3D:
def __init__(self, x = 0, y = 0, z = 0):
self.x, self.y, self.z = float(x), float(y), float(z)
def rotateX(self, angle):
""" Rotates the point around the X axis by the given angle in degrees. """
rad = angle * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
y = self.y * cosa - self.z * sina
z = self.y * sina + self.z * cosa
return Point3D(self.x, y, z)
def rotateY(self, angle):
""" Rotates the point around the Y axis by the given angle in degrees. """
rad = angle * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
z = self.z * cosa - self.x * sina
x = self.z * sina + self.x * cosa
return Point3D(x, self.y, z)
def rotateZ(self, angle):
""" Rotates the point around the Z axis by the given angle in degrees. """
rad = angle * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
x = self.x * cosa - self.y * sina
y = self.x * sina + self.y * cosa
return Point3D(x, y, self.z)
def project(self, win_width, win_height, fov, viewer_distance):
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + self.z)
x = self.x * factor + win_width / 2
y = -self.y * factor + win_height / 2
return Point3D(x, y, 1)
class Simulation:
def __init__(self, win_width = 640, win_height = 480):
pygame.init()
self.screen = pygame.display.set_mode((win_width, win_height))
pygame.display.set_caption("3D Wireframe Cube Simulation (http://codeNtronix.com)")
self.clock = pygame.time.Clock()
self.vertices = [
Point3D(-1,-1,-1),
Point3D(-1,1,-1),
Point3D(1,1,-1),
Point3D(1,-1,-1),
Point3D(-1,1,1),
Point3D(1,1,1),
Point3D(1,-1,1),
Point3D(-1,-1,1)
]
self.vertices2 = [
Point3D(-1,-1,-1),
Point3D(-1,0,-1),
Point3D(0,0,-1),
Point3D(0,-1,-1),
Point3D(-1,0,0),
Point3D(0,0,0),
Point3D(0,-1,0),
Point3D(-1,-1,0)
]
self.vertices3 = [
Point3D(0,-1,-1),
Point3D(0,0,-1),
Point3D(1,0,-1),
Point3D(1,-1,-1),
Point3D(0,0,0),
Point3D(1,0,0),
Point3D(1,-1,0),
Point3D(0,-1,0)
]
# Define the vertices that compose each of the 6 faces. These numbers are
# indices to the vertices list defined above.
self.faces = [(0,1,2,3),(0,1,4,7),(4,5,6,7),(7,6,3,0),(5,6,3,2)]
self.faces2 = [(0,1,2,3),(0,1,4,7),(4,5,6,7),(7,6,3,0),(5,6,3,2)]
self.angleX, self.angleY, self.angleZ = 0, 0, 0
def run(self):
""" Main Loop """
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
self.clock.tick(50)
self.screen.fill((0,0,0))
# Will hold transformed vertices.
t = []
t1 = []
for v in self.vertices:
# Rotate the point around X axis, then around Y axis, and finally around Z axis.
r = v.rotateX(self.angleX).rotateY(self.angleY).rotateZ(self.angleZ)
# Transform the point from 3D to 2D
p = r.project(self.screen.get_width(), self.screen.get_height(), 256, 4)
# Put the point in the list of transformed vertices
t.append(p)
x, y = int(p.x), int(p.y)
self.screen.fill((255,0,0),(x,y,2,2))
for v1 in self.vertices2:
# Rotate the point around X axis, then around Y axis, and finally around Z axis.
r1 = v1.rotateX(self.angleX).rotateY(self.angleY).rotateZ(self.angleZ)
# Transform the point from 3D to 2D
p1 = r1.project(self.screen.get_width(), self.screen.get_height(), 256, 4)
# Put the point in the list of transformed vertices
t1.append(p1)
x, y = int(p1.x), int(p1.y)
self.screen.fill((255,0,0),(x,y,3,3))
for f in self.faces:
pygame.draw.line(self.screen, (255,255,255), (t[f[0]].x, t[f[0]].y), (t[f[1]].x, t[f[1]].y))
pygame.draw.line(self.screen, (255,255,255), (t[f[1]].x, t[f[1]].y), (t[f[2]].x, t[f[2]].y))
pygame.draw.line(self.screen, (255,255,255), (t[f[2]].x, t[f[2]].y), (t[f[3]].x, t[f[3]].y))
pygame.draw.line(self.screen, (255,255,255), (t[f[3]].x, t[f[3]].y), (t[f[0]].x, t[f[0]].y))
for f1 in self.faces2:
pygame.draw.line(self.screen, (255,255,255), (t1[f1[0]].x, t1[f1[0]].y), (t1[f1[1]].x, t1[f1[1]].y))
pygame.draw.line(self.screen, (255,255,255), (t1[f1[1]].x, t1[f1[1]].y), (t1[f1[2]].x, t1[f1[2]].y))
pygame.draw.line(self.screen, (255,255,255), (t1[f1[2]].x, t1[f1[2]].y), (t1[f1[3]].x, t1[f1[3]].y))
pygame.draw.line(self.screen, (255,255,255), (t1[f1[3]].x, t1[f1[3]].y), (t1[f1[0]].x, t1[f1[0]].y))
self.angleX += 1
self.angleY += 1
self.angleZ += 1
pygame.display.flip()
if __name__ == "__main__":
Simulation().run()
2 个回答
0
import pygame
import math
import numpy as np
import sys
'''
Not really sure but I think pygame needs to run under Python 3.6
Here is what I used:
Pycharm - Community Version
Python Ver:3.6
Pygame Ver:2.0.1
Numpy Ver: 1.19.3
Good Luck!
'''
print()
print("Python Ver: " + str(sys.version_info.major) + '.' + str(sys.version_info.minor))
print("Pygame Ver: " + pygame.__version__)
print("Numpy Ver: " + np.__version__)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
GREEN = ( 0, 255, 0)
RED = ( 0, 0, 255)
WDT = 640
HGT = 480
pygame.init() # Set up pygame parameters
pygame.display.set_caption("Rotating 3D Cube Projection in PYGame")
screen = pygame.display.set_mode((WDT, HGT))
points = [n for n in range(8)] # Define 3D cube
points[0] = [[-1], [-1], [1]]
points[1] = [[1], [-1], [1]]
points[2] = [[1], [1], [1]]
points[3] = [[-1], [1], [1]]
points[4] = [[-1], [-1], [-1]]
points[5] = [[1], [-1], [-1]]
points[6] = [[1], [1], [-1]]
points[7] = [[-1], [1], [-1]]
def draw_line(i, j, k): # Draw lines between edges of cube
a = k[i]
b = k[j]
pygame.draw.line(screen, GREEN, (a[0], a[1]), (b[0], b[1]), 2)
angle_x = 0 # starting x position
angle_y = 0 # starting y position
angle_z = 0 # starting z position
cube_size = 600 # 300 = small 900 = large
distance_from_cube = 5 # view point distance - MUST BE GREATER THAN 1
while True:
screen.fill(BLACK)
for event in pygame.event.get():
if event.type == pygame.QUIT: pygame.quit()
if event.type == pygame.KEYDOWN: pygame.quit()
projected_points = [j for j in range(len(points))]
rotation_x = [[1, 0, 0],
[0, math.cos(angle_x), -math.sin(angle_x)],
[0, math.sin(angle_x), math.cos(angle_x)]]
rotation_y = [[math.cos(angle_y), 0, -math.sin(angle_y)],
[0, 1, 0],
[math.sin(angle_y), 0, math.cos(angle_y)]]
rotation_z = [[math.cos(angle_z), -math.sin(angle_z), 0],
[math.sin(angle_z), math.cos(angle_z), 0],
[0, 0, 1]]
index = 0
for point in points:
rotated_y = np.matmul(rotation_y, point) # Cube rotation in y axis
rotated_x = np.matmul(rotation_x, rotated_y) # Cube rotation in yx axis
rotated_xyz = np.matmul(rotation_z, rotated_x) # Cube rotation in yxz axis
z = 1 / (distance_from_cube - rotated_xyz[2][0])
projection_matrix = [[z, 0, 0], [0, z, 0]]
projected_2d = np.matmul(projection_matrix, rotated_xyz)
x = int(projected_2d[0][0] * cube_size) + WDT // 2 # x,y 2D projection
y = int(projected_2d[1][0] * cube_size) + HGT // 2
projected_points[index] = [x, y]
index += 1
pygame.draw.circle(screen, RED, (x, y), 4)
for m in range(4): # Draw lines to connect dots/circles
draw_line(m, (m+1)%4, projected_points)
draw_line(m+4, (m+1)%4 + 4, projected_points)
draw_line(m, m+4, projected_points)
angle_x += 0.00030 # Rotation speed about x axis
angle_y += 0.00020 # Rotation speed about y axis
angle_z += 0.00010 # Rotation speed about z axis
pygame.display.update()
当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。