diff --git a/functions.py b/functions.py index 747c6db..d6b91c0 100644 --- a/functions.py +++ b/functions.py @@ -47,20 +47,19 @@ ry = math.radians(ry) rz = math.radians(rz) - new_points3d = [] - for i in range(len(points3d)): - new_points3d.append([0, 0, 0]) - new_points3d[i][0] = ((math.cos(rz))*points3d[i][0] + - (-math.sin(rz))*points3d[i][1]) + new_point3d = [0, 0, 0] + # new_points3d.append([0, 0, 0]) + new_point3d[0] = ((math.cos(rz))*points3d[0] + + (-math.sin(rz))*points3d[1]) - new_points3d[i][1] = ((math.sin(rz)*math.cos(rx))*points3d[i][0] + - (math.cos(rz)*math.cos(rx))*points3d[i][1] + - (-math.sin(rx)) * points3d[i][2]) + new_point3d[1] = ((math.sin(rz)*math.cos(rx))*points3d[0] + + (math.cos(rz)*math.cos(rx))*points3d[1] + + (-math.sin(rx)) * points3d[2]) - new_points3d[i][2] = ((math.sin(rz)*math.sin(rx))*points3d[i][0] + - (math.cos(rz)*math.sin(rx))*points3d[i][1] + - (math.cos(rx))*points3d[i][2]) - return new_points3d + new_point3d[2] = ((math.sin(rz)*math.sin(rx))*points3d[0] + + (math.cos(rz)*math.sin(rx))*points3d[1] + + (math.cos(rx))*points3d[2]) + return new_point3d def reverse_rotate(points3d, ry, rx, rz): @@ -87,7 +86,7 @@ def translate(points3d, t_vec): - new_points3d = copy.deepcopy(points3d) + new_points3d = list(points3d) for i in range(len(points3d)): new_points3d[i][0] += t_vec[0] new_points3d[i][1] += t_vec[1] @@ -104,7 +103,7 @@ # function that returns the angle of a face to the camera def face_angle(points3d, fp_distance, distance): # calculate cross product: - vec1 = points3d[0][0], points3d[0][1]-(distance), points3d[0][2] + vec1 = points3d[0][0], points3d[0][1] - (distance), points3d[0][2] vec2 = cross_product(sub_l(points3d[0], points3d[1]), sub_l(points3d[1], points3d[2])) return math.degrees(_2vec_angle(vec1, vec2)) @@ -175,26 +174,33 @@ # new functions -def generate_cam_matrix(rx: int, ry: int, rz: int, player_pos): +def generate_cam_matrix(rx_D: int, ry_D: int, rz_D: int, player_pos): + #rx = math.radians(rx_D) + rx = 0 + ry = math.radians(rx_D) + rz = math.radians(rz_D) + rotation_matrix = numpy.array( - [[[math.cos(ry)*math.cos(rz)], [math.sin(rx)*math.sin(ry)*math.cos(rz) - math.cos(rx)*math.sin(rz)], [math.cos(rx)*math.sin(ry)*math.cos(rz) + math.sin(rx)*math.sin(rz)], [0]], - [[math.cos(ry)*math.sin(rz)], [math.sin(rx)*math.sin(ry)*math.sin(rz) + math.cos(rx)*math.cos(rz)], [math.cos(rx)*math.sin(ry)*math.sin(rz) - math.sin(rx)*math.sin(rz)], [0]], - [[-math.sin(ry)], [math.sin(rx)*math.cos(ry)], [math.cos(rx)*math.cos(ry)], [0]], - [[0], [0], [0], [1]]] + [[math.cos(ry)*math.cos(rz), math.sin(rx)*math.sin(ry)*math.cos(rz) - math.cos(rx)*math.sin(rz), math.cos(rx)*math.sin(ry)*math.cos(rz) + math.sin(rx)*math.sin(rz), 0], + [math.cos(ry)*math.sin(rz), math.sin(rx)*math.sin(ry)*math.sin(rz) + math.cos(rx)*math.cos(rz), math.cos(rx)*math.sin(ry)*math.sin(rz) - math.sin(rx)*math.sin(rz), 0], + [-math.sin(ry), math.sin(rx)*math.cos(ry), math.cos(rx)*math.cos(ry), 0], + [0, 0, 0, 1]] ) translation_matrix = numpy.array( - [[[1], [0], [0], [player_pos.x]], - [[0], [1], [0], [player_pos.y]], - [[0], [0], [1], [player_pos.z]], - [[0], [0], [0], [1]]] + [[1, 0, 0, player_pos.x], + [0, 1, 0, player_pos.y], + [0, 0, 1, player_pos.z], + [0, 0, 0, 1]] ) # todo # make this thing # generates a transformation matrix for the current camera # should only be run once per frame (hopefully a performance improvement?) - - return numpy.multiply(translation_matrix, rotation_matrix) + # return translation_matrix.dot(rotation_matrix) + # return numpy.matmul(translation_matrix, rotation_matrix) + return numpy.matmul(translation_matrix, rotation_matrix) + # return numpy.multiply(translation_matrix, rotation_matrix) def draw_face(face: Face, cam_matrix: numpy.array, fp_dis): diff --git a/main.py b/main.py index 7845eb4..cc4585b 100644 --- a/main.py +++ b/main.py @@ -16,8 +16,8 @@ scrWidth = 3.2 # player information -playerPos: Point3D = Point3D([0, 10, 0]) -playerSpeed: Point3D = Point3D([0, 0, 0]) +playerPos: Point3D = Point3D(0, 10, 0) +playerSpeed: Point3D = Point3D(0, 0, 0) # todo implement these variables into the code acc = 20 # units per second per second @@ -50,8 +50,8 @@ # create cubes cubes: list[Cube] = [] -for x in [[-12, 3, 4], [2, 2, 2], [2, 0, 0], [0, 2, 0], [0, 0, 0], [6, -8, 4]]: - cubes.append(Cube(Point3D(x), [Colour([255, 0, 0]) for x in range(6)], True, True)) +for x in [[5, 0, 0]]: #[[-12, 3, 4], [2, 2, 2], [2, 0, 0], [0, 2, 0], [0, 0, 0], [6, -8, 4]]: + cubes.append(Cube(Point3D(x[0], x[1], x[2]), [Colour([255, 0, 0]) for x in range(6)], True, True)) # todo update or remove # axes points @@ -90,7 +90,7 @@ # initial values for variables so pycharm doesn't get mad keys = pygame.key.get_pressed() -newCubePos: Point3D = Point3D([0, 0, 0]) +newCubePos: Point3D = Point3D(0, 0, 0) # settings pygame.mouse.set_visible(True) @@ -164,7 +164,8 @@ # add faces for placeable cube if placing: # generate the position for the new cube ('ray cast' out of camera and do weird things) - newCubePos = Point3D(reverse_rotate([[blockDistance, 0, 0]], rotX, rotY, -rotZ + 90)[0]) # todo change this to a .applymatrix + newCubePos = Point3D._make([reverse_rotate([[blockDistance, 0, 0]], rotX, rotY, -rotZ + 90)[0]][0]) + # todo change this to a .applymatrix newCubePos.inv_translate(playerPos) newCubePos.snap() @@ -184,30 +185,25 @@ # ______draw all faces______ # apply camMatrix to allFaces for face in allFaces: - # newpoints: list[Point3D] = [] - for point in face.points: - point.apply_matrix(camMatrix) - # newpoints.append(Point3D([0, 0, 0])) - # point = Point3D(rotate(translate([point.xyz()], playerPos.xyz()), rotX, rotY, rotZ)[0]) - # face.points = newpoints + for i, point in enumerate(face.points): + # face.points[i] = point.apply_matrix(camMatrix) + face.points[i] = Point3D._make(rotate(point.translate(playerPos), rotX, rotY, rotZ)) # fix points behind the camera face.fix_points_behind_camera() - # if len(face.points) < 3: - # allFaces.remove(face) # sort the list of allFaces # iterates through all faces - iterates through each point axis - iterates through points within faces # (strange order) allFaces_sort = [] for face in allFaces: - average = Point3D([0, 0, 0]) + average = [0, 0, 0] for index in range(3): for point in face.points: - average.xyz()[index] += point.xyz()[index] - average.xyz()[index] = average.xyz()[index] / 3 + average[index] += point.xyz()[index] + average[index] = average[index] / 3 # 3d pythagoras to find the distance to the camera - allFaces_sort.append(-(average.x ** 2 + average.y ** 2 + average.z ** 2)) + allFaces_sort.append(-(average[0] ** 2 + average[1] ** 2 + average[2] ** 2)) allFaces = [x for _, x in sorted(zip(allFaces_sort, allFaces), key=lambda item: item[0])] # draw allFaces @@ -255,14 +251,15 @@ magnitude = 0 vectoredDirection = [x * magnitude for x in pressedKeys] - rotatedVector = rotate([vectoredDirection], 0, 0, -rotZ)[0] + rotatedVector = rotate(vectoredDirection, 0, 0, -rotZ) - playerSpeed = Point3D([(speed + ((acc / frameRate) * kPress)) * (1 - (((acc-1) / maxSpeed)/frameRate)) - for speed, kPress in zip(playerSpeed.xyz(), rotatedVector)]) + playerSpeed = Point3D._make( + [(speed + ((acc / frameRate) * kPress)) * (1 - (((acc-1) / maxSpeed)/frameRate)) + for speed, kPress in zip(playerSpeed.xyz(), rotatedVector)]) # handle speed and movement in that direction - move = Point3D([x / frameRate for x in playerSpeed.xyz()]) - playerPos.translate(move) + move = Point3D._make([x / frameRate for x in playerSpeed.xyz()]) + playerPos = playerPos.translate(move) screen.blit(mainSurface, (0, 0)) pygame.display.update() diff --git a/model.py b/model.py index 0dd350d..e718057 100644 --- a/model.py +++ b/model.py @@ -48,11 +48,6 @@ return False -class WindowSize(NamedTuple): - height: int - width: int - - class Point2D(NamedTuple): x: float y: float @@ -64,6 +59,12 @@ return Point2D((self.x * scale) + size[0]/2, (self.y * scale) + size[1]/2) +class AbstractPoint3D(NamedTuple): + x: float + y: float + z: float + + class Point3D(NamedTuple): # todo: # check if i have missed anything obvious @@ -72,31 +73,24 @@ z: float def xyz(self): - xyz: list[float] = [self.x, self.y, self.z] - return xyz - - def translate(self, t_vec): # but whyy - self.x += t_vec.x - self.y += t_vec.y - self.z += t_vec.z - return self - def inv_translate(self, t_vec): # but whyy - self.x -= t_vec.x - self.y -= t_vec.y - self.z -= t_vec.z + def translate(self, t_vec): + return Point3D(self.x + t_vec.x, self.y + t_vec.y, self.z + t_vec.z) - return self + def inv_translate(self, t_vec): + return Point3D(self.x - t_vec.x, + self.y - t_vec.y, + self.z - t_vec.z,) def snap(self): # sets x y z to the nearest integer - self.x = round(self.x) - self.y = round(self.y) - self.z = round(self.z) + return Point3D(round(self.x), round(self.y), round(self.z)) def apply_matrix(self, rot_matrix: numpy.array): - point = numpy.array([self.x, self.y, self.z]) - numpy.multiply(point, rot_matrix) + # point: numpy.array = numpy.multiply(rot_matrix, numpy.array([self.x, self.y, self.z, 0])) + point = rot_matrix.dot(numpy.array([self.x, self.y, self.z, 1])) + point = numpy.delete(point, 3) + return Point3D._make(point) def get_2d_point(self, fp_distance): # converts a 3d point into a 2d point (replacement for the projection function) @@ -162,9 +156,11 @@ return self.points def fix_points_behind_camera(self): + new_points: list[Point3D] = [] for point in self.points: - if point.y <= 0.5: - self.points.remove(point) + if not(point.y <= .5): + new_points.append(point) + self.points = new_points class TexturedFace(Face): @@ -191,15 +187,15 @@ faces: list[Face] # ordered top - north - east - south - west - bottom - cubePoints = [Point3D([.5, .5, .5]), Point3D([.5, .5, -.5]), Point3D([.5, -.5, .5]), Point3D([.5, -.5, -.5]), - Point3D([-.5, .5, .5]), Point3D([-.5, .5, -.5]), Point3D([-.5, -.5, .5]), Point3D([-.5, -.5, -.5])] + cubePoints = [Point3D(.5, .5, .5), Point3D(.5, .5, -.5), Point3D(.5, -.5, .5), Point3D(.5, -.5, -.5), + Point3D(-.5, .5, .5), Point3D(-.5, .5, -.5), Point3D(-.5, -.5, .5), Point3D(-.5, -.5, -.5)] # same as the dictionary, but no longer used. not sure why it still exists. # cubeSides = [[3, 7, 5, 1], [2, 6, 7, 3], [4, 5, 7, 6], [0, 1, 5, 4], [0, 2, 3, 1], [6, 2, 0, 4]] # hardcoded dict for the relative positions of cube faces cubeFaces: list[list[Point3D]] = [ - [cubePoints[3], cubePoints[5], cubePoints[7], cubePoints[1]], # top + [cubePoints[3], cubePoints[7], cubePoints[5], cubePoints[1]], # top [cubePoints[2], cubePoints[6], cubePoints[7], cubePoints[3]], # north [cubePoints[4], cubePoints[5], cubePoints[7], cubePoints[6]], # east [cubePoints[0], cubePoints[1], cubePoints[5], cubePoints[4]], # south @@ -208,7 +204,7 @@ def __init__(self, position: Point3D, texture : list[Colour], has_faces, has_edges): self.faces = [] - self.position = Point3D([0, 0, 0]) + self.position = Point3D(0, 0, 0) # todo # implement texture self.position = position @@ -222,7 +218,6 @@ new_points = 0 self.faces.append(Face([point.translate(self.position) for point in copy.deepcopy(self.cubeFaces[i])], self.colours[i], self.has_edges, self.has_faces)) - print(self.position.xyz()) def get_faces(self): - return copy.deepcopy(self.faces) \ No newline at end of file + return copy.deepcopy(self.faces)