# TODO # make todo list # import import copy import pygame from functions import * # variables # screen size in pixels size = (1000, 1000) # screen with in units scrWidth = 3.2 # player information 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 maxSpeed = 4 # units per second sensitivity = 0.05 frameRate = 60 # measures the frame-rate (if this decreases then other things are sped up) # program variables running = True triggerDraw = True placing = True blockDistance = 3 lastMillis = [0, 0, 0] scale = size[1] / scrWidth allFaces: list[Face] = [] # colours bgColour: Colour = Colour([0, 0, 0]) fgColour: Colour = Colour([255, 255, 255]) # placing colours is to be replaced with placingTextures placingColours: list[list[Colour]] = [[Colour([100, 100, 100]), Colour([100, 100, 100]), Colour([100, 100, 100]), Colour([100, 100, 100]), Colour([100, 100, 100]), Colour([100, 100, 100])], [Colour([162, 84, 57]), Colour([162, 84, 57]), Colour([162, 84, 57]), Colour([162, 84, 57]), Colour([162, 84, 57]), Colour([162, 84, 57])], [Colour([50, 255, 50]), Colour([100, 255, 100]), Colour([100, 255, 100]), Colour([100, 255, 100]), Colour([100, 255, 100]), Colour([162, 84, 57])]] currentTexture: int = 0 # 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)) # todo update or remove # axes points axesPoints = [[1000, 0, 0], [-1000, 0, 0], [0, 1000, 0], [0, -1000, 0], [0, 0, 1000], [0, 0, -1000]] axesEdges = [[0, 1], [2, 3], [4, 5]] axesColours = [(0, .8, .8), (.2, .8, 1), (.8, .8, .8)] i = 0 for c in axesColours: axesColours[i] = colorsys.hsv_to_rgb(c[0], c[1], c[2]) axesColours[i] = tuple(255 * x for x in axesColours[i]) i += 1 # rendering variables # rotation rotY = 0 rotX = 0 rotZ = 0 # distance camDistance = 0 # fov camFOV = 120 # matrices camMatrix: numpy.array = generate_cam_matrix(rotX, rotY, rotZ, playerPos) FPDis = fov_calc(camFOV, scrWidth) # start pygame.init() lastMillis[1] = pygame.time.get_ticks() + 1000 lastMillis[2] = pygame.time.get_ticks() + 1000 timerOffset = 0 screen = pygame.display.set_mode(size) screen.fill(bgColour.get_rgb()) # initial values for variables so pycharm doesn't get mad keys = pygame.key.get_pressed() newCubePos: Point3D = Point3D([0, 0, 0]) # settings pygame.mouse.set_visible(True) grabbed = False pygame.event.set_grab(False) # create surfaces mainSurface = pygame.Surface(size) while running: # every tick: if lastMillis[1] + 16.6 <= pygame.time.get_ticks() or triggerDraw: frameRate = 1 / ((pygame.time.get_ticks() - lastMillis[1]) / 1000) # change colours and apply rotation from mouse if grabbed: # rotate camera if mouse moves dZ, dX = pygame.mouse.get_rel() rotX -= dX * sensitivity rotZ += dZ * sensitivity # fix camera within movement bounds rotZ = rotZ % 360 if rotX > 90: rotX = 90 elif rotX < -90: rotX = -90 if not triggerDraw: lastMillis[1] = pygame.time.get_ticks() triggerDraw = False # reset surface area mainSurface.fill(fgColour.get_rgb()) # save currently pressed keys keys = pygame.key.get_pressed() # generate matrices camMatrix = generate_cam_matrix(rotX, rotY, rotZ, playerPos) # __draw cubes__ # calculate 3d and project 3d point locations for cube in cubes: for face in cube.get_faces(): allFaces.append(face) # if cube.has_texture(): # texturedFaces = cube.get_textured_faces(playerPos) # for texturedFace in texturedFaces: # newSubFaces = [] # try: # faces = texturedFace.get_sub_faces() # for face in faces: # newPoints = fix_points_behind_camera(rotate(face.points, rotX, rotY, rotZ), camDistance) # if len(newPoints) > 2: # face.points = newPoints # newSubFaces.append(face) # except AttributeError: # pass # texturedFace.set_sub_faces(newSubFaces) # allFaces.append(texturedFace) # faces = cube.get_faces(playerPos) # # fix points behind camera and remove faces with two or fewer remaining points # for face in faces: # newPoints = fix_points_behind_camera(rotate(face.points, rotX, rotY, rotZ), camDistance) # if len(newPoints) > 2: # face.points = newPoints # allFaces.append(face) # whyyyy # 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.inv_translate(playerPos) newCubePos.snap() # generate cube object with position of newCubePos newCube = Cube(newCubePos, placingColours[currentTexture], True, keys[pygame.K_LCTRL]) # take faces out of cube object and never speak of it again for face in newCube.get_faces(): allFaces.append(face) # # fix points behind camera and remove faces with two or fewer remaining points # for face in faces: # newPoints = fix_points_behind_camera(rotate(face.points, rotX, rotY, rotZ), camDistance) # if len(newPoints) > 2: # face.points = newPoints # allFaces.append(face) # ______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 # 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]) for index in range(3): for point in face.points: average.xyz()[index] += point.xyz()[index] average.xyz()[index] = average.xyz()[index] / 3 # 3d pythagoras to find the distance to the camera allFaces_sort.append(-(average.x ** 2 + average.y ** 2 + average.z ** 2)) allFaces = [x for _, x in sorted(zip(allFaces_sort, allFaces), key=lambda item: item[0])] # draw allFaces i = 0 for i, face in enumerate(allFaces): _2dPoints = [point.get_2d_point(FPDis) for point in face.points] [point.conv_coord(size, scale) for point in _2dPoints] # this seems really illegal try: if True: # face_angle([face.points[0], face.points[1], face.points[2]], FPDis, camDistance) > 90: if face.hasFaces and len(face.points) > 2: pygame.draw.polygon(mainSurface, tuple(face.colour.get_rgb()), [point.get() for point in _2dPoints], 0) if face.hasEdges: for i2 in range(len(_2dPoints)): pygame.draw.aaline(mainSurface, (0, 0, 0), _2dPoints[i2].get(), _2dPoints[(i2 + 1) % len(_2dPoints)].get()) except IndexError: print("found face with only 2 points (This error occurring here indicates a bug in the code somewhere)") allFaces.clear() # _____end face drawing_____ # draw axes # _3dPoints = rotate(translate(axesPoints, playerPos), rotX, rotY, rotZ) # for i in range(len(axesEdges)): # if not (_3dPoints[axesEdges[i][0]][1] <= camDistance and _3dPoints[axesEdges[i][1]][1] <= camDistance): # _new3dPoints = fix_points_behind_camera_edge(_3dPoints[axesEdges[i][0]], _3dPoints[axesEdges[i][1]], # camDistance) # _2dPoints = conv_coord(project(_new3dPoints, FPDis, camDistance), size, scale) # player movement # speed increase with key press if keys[pygame.K_LCTRL] == 1: sprint = 5 else: sprint = 1 # calculate the key presses, figure out a force direction, then rotate it, then apply a magnitude, # then apply that to the player speed, subtract the drag (value proportional to the speed) from the vector. pressedKeys = [(keys[pygame.K_a] - keys[pygame.K_d]), (keys[pygame.K_s] - keys[pygame.K_w]), (keys[pygame.K_SPACE] - keys[pygame.K_LSHIFT])] try: magnitude = 1 / math.sqrt(pressedKeys[0] ** 2 + pressedKeys[1] ** 2 + pressedKeys[2] ** 2) except ZeroDivisionError: magnitude = 0 vectoredDirection = [x * magnitude for x in pressedKeys] rotatedVector = rotate([vectoredDirection], 0, 0, -rotZ)[0] playerSpeed = Point3D([(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) screen.blit(mainSurface, (0, 0)) pygame.display.update() # END EVERY FRAME # handle events for event in pygame.event.get(): if event.type == pygame.QUIT: running = False pygame.display.quit() # keyboard elif event.type == pygame.KEYDOWN: if event.key == pygame.K_BACKSPACE: running = False elif event.key == pygame.K_ESCAPE: grabbed = False pygame.event.set_grab(False) pygame.mouse.set_visible(True) elif event.key == pygame.K_0: placing = False elif event.key == pygame.K_1: placing = True # mouse elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == pygame.BUTTON_MIDDLE: pygame.mouse.get_rel() pygame.event.set_grab(True) pygame.mouse.set_visible(False) grabbed = True elif event.button == pygame.BUTTON_RIGHT: if placing: cubes.append(Cube(newCubePos, placingColours[currentTexture], True, keys[pygame.K_LCTRL])) elif event.button == pygame.BUTTON_LEFT: if placing: try: for x, cube in enumerate(cubes): if cube.position == newCubePos: cubes.pop(x) except ValueError: continue elif event.type == pygame.MOUSEWHEEL: if keys[pygame.K_LCTRL]: currentTexture = (currentTexture + 1) % len(placingColours) else: blockDistance += event.y