Пример #1
0
class App(Frame):
    def __init__(self, master=Tk(), width=500, height=500, x_axis_scale=100, y_axis_scale=100, zoom=100, drag_scale=0.01):

        #App and windows settings
        Frame.__init__(self, master)
        self.master = master
        master.title("3D viewer - tkinter and numpy")
        self.width = width
        self.height = height

        #Bind mouse to Camera Angle
        self.master.bind('<Key>', lambda e: self.keyPress(e))#KeyRelease
        self.master.bind('<KeyRelease>', lambda e: self.keyRelease(e))  # KeyRelease
        self.master.bind('<Button-1>', lambda e :self.clickScreen(e))
        self.master.bind('<B1-Motion>', lambda e: self.dragScreen(e))
        self.game_canvas = Canvas(master, height=self.height, width=self.width, bg='grey')
        self.all_vectors = []

        #3d person viewing settings
        self.x_axis_scale = x_axis_scale #How much to scale the screen X axis
        self.y_axis_scale = y_axis_scale #How much to scale the screen Y axis
        self.zoom = zoom
        self.root_point = np.array([self.width / 2, self.height / 2]) #Where the (0,0) of the screen X and Y axis is located
        self.drag_scale = drag_scale #How Sensitive the changes to the mouse drag

        #Where camera is located in the game world
        self.camera_vector = Vector([0,0,0],[0,0,1], display_on_screen=False, color='Blue')
        self.camera_moving_vel = 1 #When the player wants to move the camera
        self.view_angle = 2 * np.pi / 3 #Equals 2*theta

        #Where player clicks on the screen canvas
        self.screen_x = 0
        self.screen_y = 0
        self.camera_distance_from_character = 10 #In pixals

        #What the X and Y vectors on the screen represent in the game
        self.screen_x_vector = Vector([0,0,0],[1,0,0], display_on_screen=False, color='red') #What the X axis of the monitor represents
        self.screen_y_vector = Vector([0,0,0],[0,1,0], display_on_screen=False, color='green') #What the Y axis of the monitor represents

    def clickScreen(self, e):
        self.screen_x = e.x
        self.screen_y = e.y

    def dragScreen(self, e):
        #Update vector according to drag
        self.camera_vector.updateVector()
        self.camera_vector.normalizeVector()
        diff_x = e.x - self.screen_x
        diff_y = e.y - self.screen_y

        #The camera vector rotates around the screen_x_vector with diff_y and around the screen_y_vector with diff_x

        #The camera is perpendicular to the XY plane
        self.camera_vector.vector = np.cross(self.screen_x_vector.vector, self.screen_y_vector.vector)

        # Unitize the vectors
        self.screen_x_vector.normalizeVector()
        self.screen_y_vector.normalizeVector()

        #Modify all vectors according to the screen drage
        self.modifyVectors(diff_x, diff_y)

        #Assign current x, y to where the player last clicked
        self.screen_x = e.x
        self.screen_y = e.y

    def keyPress(self, e):
        print (e.char, 'Press')
        #Walk forward
        if e.char == 'w' or e.char == 'W':
            self.modifyVectors(move_y=1)

        #Walk backwards
        elif e.char == 's' or e.char == 'S':
            self.modifyVectors(move_y=-1)

        #Walk left
        elif e.char == 'a' or e.char == 'A':
            self.modifyVectors(move_x=1)

        #Walk right
        elif e.char == 'd' or e.char == 'D':
            self.modifyVectors(move_x=-1)

    def keyRelease(self, e):
        print (e.char, 'KeyRelease')

    def updateObjects(self):
        pass

    def packObjects(self):
        self.game_canvas.pack(fill="both", expand=True)

    def modifyVectors(self, diff_x=0, diff_y=0, move_x=0, move_y=0, move_z=0):
        screen_vectors = [self.screen_x_vector, self.screen_y_vector, self.camera_vector]

        #Start with screen_vectors
        for v in screen_vectors:
            self.modifySingleVector(v=v, diff_x=diff_x, diff_y=diff_y, move_x=move_x, move_y=move_y, move_z=move_z,screen_vectors=screen_vectors)

        #Then on to all other vectors
        for v in self.all_vectors:
            if v not in screen_vectors:
                self.modifySingleVector(v=v, diff_x=diff_x, diff_y=diff_y, move_x=move_x, move_y=move_y, move_z=move_z, screen_vectors=screen_vectors)


    def modifySingleVector(self, v=Vector([0,0,0], [0,0,0]), diff_x=0, diff_y=0, move_x=0, move_y=0, move_z=0, screen_vectors=[]):
        # Rotate Vector according to the current screen_x/y axis
        if diff_x != 0:
            v.rotateAroundAnotherVector(axis_vector=self.screen_y_vector, angle_of_rotation=diff_x)
        if diff_y != 0:
            v.rotateAroundAnotherVector(axis_vector=self.screen_x_vector, angle_of_rotation=diff_y)

        if v not in screen_vectors:
            #If objects are moving
            if move_x != 0:
                v.start_point += self.screen_x_vector.vector * move_x
                v.end_point += self.screen_x_vector.vector * move_x

            if move_y != 0:
                v.start_point += self.screen_y_vector.vector * move_y
                v.end_point += self.screen_y_vector.vector * move_y

            #Create a 2d of a vector in a 3d space

            #Set start point and end point Vectors
            start_point_vector = Vector(end_point=v.start_point)
            end_point_vector = Vector(end_point=v.end_point)

            #Get 2d coordinates of the start and the end of the 2d vector on that plane
            v.screen_start_point = start_point_vector.get2dCoordinates(self.screen_x_vector, self.screen_y_vector)
            v.screen_end_point = end_point_vector.get2dCoordinates(self.screen_x_vector, self.screen_y_vector)

            scale_x = self.x_axis_scale
            scale_y = self.y_axis_scale
            root_point_x = self.root_point[0]
            root_point_y = self.root_point[1]
            x1 = v.screen_start_point [0]
            y1 = v.screen_start_point[1]
            x2 = v.screen_end_point[0]
            y2 = v.screen_end_point[1]
            self.game_canvas.coords(v.canvas_object,
                    #X1, Y1
                    root_point_x - x1 * scale_x, root_point_y - y1 * scale_y,

                    #X2, Y2
                    root_point_x - x2 * scale_x, root_point_y - y2 * scale_y
                                    )


    def generateVectors(self):
        for v in Vector.all_vectors:
            if v.display_on_screen == True:
                scale_x = self.x_axis_scale
                scale_y = self.y_axis_scale
                root_point_x = self.root_point[0]
                root_point_y = self.root_point[1]

                x1 = v.screen_start_point[0]
                y1 = v.screen_start_point[1]
                x2 = v.screen_end_point[0]
                y2 = v.screen_end_point[1]
                #If the vector on this plane equals 0 create a little line
                if (x2 != x1 or y2 != y2):
                    v.canvas_object = self.game_canvas.create_line(
                        # X1, Y1
                        root_point_x - x1 * scale_x, root_point_y - y1 * scale_y,

                        # X2, Y2
                        root_point_x - x2 * scale_x, root_point_y - y2 * scale_y,

                        fill=v.color
                    )

                else:
                    v.canvas_object = self.game_canvas.create_line(0, 0, 1, 1, fill=v.color)

                self.all_vectors.append(v)