Ejemplo n.º 1
0
class ShadowCreator:
    def __init__(self):
        self.shadowBuffer = base.win.makeTextureBuffer('Shadow Buffer', 2048,
                                                       2048)
        self.shadowBuffer.setClearColorActive(True)
        self.shadowBuffer.setClearColor((0, 0, 0, 1))
        self.shadowCamera = base.makeCamera(self.shadowBuffer)
        self.shadowCamera.reparentTo(render)
        self.lens = base.camLens
        self.lens.setAspectRatio(1 / 1)
        self.shadowCamera.node().setLens(self.lens)
        self.shadowCamera.node().setCameraMask(BitMask32.bit(1))
        self.initial = NodePath('initial')
        self.initial.setColor(0.75, 0.75, 0.75, 1, 1)
        self.initial.setTextureOff(2)
        self.initial.setMaterialOff(2)
        self.initial.setLightOff(2)
        self.shadowCamera.node().setInitialState(self.initial.getState())
        self.shadowCamera.setPos(-10, 0, 20)
        self.shadowCamera.lookAt(0, 0, 0)
        self.filters = CommonFilters(self.shadowBuffer, self.shadowCamera)
        self.filters.setBlurSharpen(0.1)
        self.shadowTexture = self.shadowBuffer.getTexture()
        self.imageObject = OnscreenImage(image=self.shadowTexture,
                                         pos=(-0.75, 0, 0.75),
                                         scale=0.2)
class ShadowCreator:
    def __init__(self):
        #Create a buffer for storing the shadow texture,
        #the higher the buffer size the better quality the shadow.
        self.shadowBuffer = base.win.makeTextureBuffer("Shadow Buffer", 2048,
                                                       2048)
        self.shadowBuffer.setClearColorActive(True)
        self.shadowBuffer.setClearColor((0, 0, 0, 1))

        self.shadowCamera = base.makeCamera(self.shadowBuffer)
        self.shadowCamera.reparentTo(render)

        self.lens = base.camLens
        self.lens.setAspectRatio(1 / 1)
        self.shadowCamera.node().setLens(self.lens)
        self.shadowCamera.node().setCameraMask(BitMask32.bit(1))

        #Make everything rendered by the shadow camera grey:
        self.initial = NodePath('initial')
        self.initial.setColor(.75, .75, .75, 1, 1)
        self.initial.setTextureOff(2)
        self.initial.setMaterialOff(2)
        self.initial.setLightOff(2)
        self.shadowCamera.node().setInitialState(self.initial.getState())

        #The cameras pos effects the shadows dirrection:
        self.shadowCamera.setPos(-10, 0, 20)
        self.shadowCamera.lookAt(0, 0, 0)

        #Make the shadows soft by bluring the screen:
        self.filters = CommonFilters(self.shadowBuffer, self.shadowCamera)
        self.filters.setBlurSharpen(.1)

        self.shadowTexture = self.shadowBuffer.getTexture()

        #Draw the shadowTexture on sceen:
        self.imageObject = OnscreenImage(image=self.shadowTexture,
                                         pos=(-.75, 0, .75),
                                         scale=.2)
Ejemplo n.º 3
0
class ShadowCreator:

    def __init__(self):
        self.shadowBuffer = base.win.makeTextureBuffer('Shadow Buffer', 2048, 2048)
        self.shadowBuffer.setClearColorActive(True)
        self.shadowBuffer.setClearColor((0, 0, 0, 1))
        self.shadowCamera = base.makeCamera(self.shadowBuffer)
        self.shadowCamera.reparentTo(render)
        self.lens = base.camLens
        self.lens.setAspectRatio(1 / 1)
        self.shadowCamera.node().setLens(self.lens)
        self.shadowCamera.node().setCameraMask(BitMask32.bit(1))
        self.initial = NodePath('initial')
        self.initial.setColor(0.75, 0.75, 0.75, 1, 1)
        self.initial.setTextureOff(2)
        self.initial.setMaterialOff(2)
        self.initial.setLightOff(2)
        self.shadowCamera.node().setInitialState(self.initial.getState())
        self.shadowCamera.setPos(-10, 0, 20)
        self.shadowCamera.lookAt(0, 0, 0)
        self.filters = CommonFilters(self.shadowBuffer, self.shadowCamera)
        self.filters.setBlurSharpen(0.1)
        self.shadowTexture = self.shadowBuffer.getTexture()
        self.imageObject = OnscreenImage(image=self.shadowTexture, pos=(-0.75, 0, 0.75), scale=0.2)
Ejemplo n.º 4
0
class world(ShowBase):
    def __init__(self):
        try:
            ShowBase.__init__(self)
        except:
            sys.exit("something went wrong: error while loading OpenGL")

        # ------------------------------- Begin of parameter variables (pretty messy actually) ------------------------------------
        #debug
        self.debug = False  #REMEMBER TO TURN THIS OFF WHEN COMMITTING THIS TO GITHUB YOU GODDAM MORRON !!!
        #debug
        self.dir = Filename.fromOsSpecific(os.getcwd())
        self.timescale = 5
        self.worldscale = 0.1  # currently unused

        self.camera_delta = 0.5  # camera delta displacement
        self.sensitivity_x, self.sensitivity_y = 20, 20
        self.watched = None  # watched object (object focused by the cursor)

        self.state = [
            'paused', 'free', None
        ]  # state of things: [simulation paused/running,camera following object/free,followed object/None]
        print('free mode on')
        self.iteration = 0  #iteration for the menu to be drawn once
        self.collision_status = False  # Keep this on False, that's definitely not a setting # currently unused

        self.u_constant = 6.67408 * 10**(-11)  #just a quick reminder
        self.u_radius = 5.25  #just what I said earlier
        self.u_radius_margin = 0.1  #a margin added to the generic radius as a safety feature (mountains and stuff, atmosphere)

        # ------------------------------- End of parameter variables (sry for the mess) --------------------------------------------

        # Mouse parameters
        self.hidden_mouse = True
        wp = WindowProperties()
        wp.setCursorHidden(self.hidden_mouse)
        self.win.requestProperties(wp)

        # preparing the menu text list:
        self.menu_text = []
        self.menu_text.append(
            self.showsimpletext('The PyOS project V0.10', (0, 0.4),
                                (0.07, 0.07), None, (1, 1, 1, True)))
        self.menu_text.append(
            self.showsimpletext('Resume', (0, 0.3), (0.06, 0.06), None,
                                (1, 1, 1, True)))
        self.menu_text.append(
            self.showsimpletext('Quit', (0, 0.2), (0.06, 0.06), None,
                                (1, 1, 1, True)))

        # btw I found something about energy transmition through thermal radiation. I think it uses some Boltzmann formula stuff. Link here:
        # https://fr.wikibooks.org/wiki/Plan%C3%A9tologie/La_temp%C3%A9rature_de_surface_des_plan%C3%A8tes#Puissance_re%C3%A7ue_par_la_Terre

        # Defining important data lists
        self.sounds = [
            self.loader.loadSfx(self.dir + "/Sound/001.mp3"),
            self.loader.loadSfx(self.dir + "/Sound/002.mp3"),
            self.loader.loadSfx(self.dir + "/Sound/003.mp3"),
            self.loader.loadSfx(self.dir + "/Sound/004.mp3"),
            self.loader.loadSfx(self.dir + "/Sound/005.mp3")
        ]  #buggy
        self.collision_solids = [
        ]  #collision related stuff - comments are useless - just RTFM
        self.light_Mngr = []
        self.data = [
            [
                0, 0, 0, 0, 0.003, 0, 0.15, 0.15, 0.15, 100000.00, True,
                [
                    self.loader.loadModel(self.dir +
                                          "/Engine/lp_planet_0.egg"),
                    (0.1, 0, 0),
                    self.loader.loadModel(self.dir +
                                          "/Engine/lp_planet_1.egg"),
                    (0.14, 0, 0)
                ], "lp_planet", False, 0.1
            ],
            [
                40, 0, 0, 0, 0.003, 0, 0.05, 0.05, 0.05, 20.00, True,
                [
                    self.loader.loadModel(self.dir + "/Engine/Icy.egg"),
                    (0.05, 0, 0)
                ], "Ottilia", False, 0.1
            ],
            [
                0, 70, 10, 0, 0.005, 0, 0.1, 0.1, 0.1, 40.00, True,
                [
                    self.loader.loadModel(self.dir + "/Engine/asteroid_1.egg"),
                    (0, 0, 0.2)
                ], "Selena", False, 1
            ],
            [
                100, 0, 10, 0, 0, 0, 5, 5, 5, 1000000, True,
                [
                    self.loader.loadModel(self.dir + "/Engine/sun1.egg"),
                    (0.01, 0, 0),
                    self.loader.loadModel(self.dir + "/Engine/sun1_atm.egg"),
                    (0.01, 0, 0)
                ], "Sun", True, 0.1
            ],
            [
                -100, 50, 70, 0, 0, 0.002, 0.15, 0.15, 0.15, 1000.00, True,
                [
                    self.loader.loadModel(self.dir + "/Engine/Earth2.egg"),
                    (-0.1, 0, 0),
                    self.loader.loadModel(self.dir + "/Engine/Earth2_atm.egg"),
                    (-0.15, 0, 0)
                ], "Julius_planet", False, 0.1
            ]
            # insert your 3d models here, following the syntax
        ]
        # the correct reading syntax is [x,y,z,l,m,n,scale1,scale2,scale3,mass,static,[file,(H,p,r),file,(H,p,r)...],id,lightsource,brakeforce] for each body - x,y,z: position - l,m,n: speed - scale1,scale2,scale3: obvious (x,y,z) - mass: kg - static: boolean - [files]: panda3d readfiles list - id: str - lightsource: boolean -
        #if you want the hitbox to be correctly scaled, and your body to have reasonable proportions, your 3d model must be a 5*5 sphere, or at least have these proportions

        # create the real data list, the one used by the program
        self.bodies = []

        for c in self.data:
            temp = body()
            temp.fill_entries(c)
            self.bodies.append(temp)
            temp = None
        #self.bodies.reverse()

        # Quick presetting
        self.setBackgroundColor(0, 0, 0, True)

        # non-body type structures loading
        if SKYBOX == 'sky':
            self.isphere = self.loader.loadModel(
                self.dir +
                "/Engine/InvertedSphere.egg")  #loading skybox structure
            self.tex = loader.loadCubeMap(self.dir +
                                          '/Engine/Skybox4/skybox_#.png')
        elif SKYBOX == 'arena':
            self.box = self.loader.loadModel(self.dir + "/Engine/arena.egg")

        #load shaders (optionnal)
        '''
        sun_shader=Shader.load(Shader.SLGLSL,self.dir+'/Engine/Shaders/flare_v.glsl',self.dir+'/Engine/Shaders/flare_f.glsl')
        '''
        self.orbit_lines = []  #under developement

        # see https://www.panda3d.org/manual/?title=Collision_Solids for further collision interaction informations
        base.graphicsEngine.openWindows()
        try:
            # filters predefining
            self.filters = CommonFilters(base.win, base.cam)
            '''
            self.filters.setBlurSharpen(amount=0) # just messing around
            '''
            if not self.debug:
                self.filters.set_gamma_adjust(1.0)  # can be usefull
                self.filters.set_bloom(intensity=1, size="medium")
                render.setAntialias(AntialiasAttrib.MAuto)

            for c in self.bodies:  # loading and displaying the preloaded planets and bodies

                if c.is_lightSource and not self.debug:
                    # VM filtering
                    self.filters.setVolumetricLighting(c.filelist[u],
                                                       numsamples=50,
                                                       density=0.5,
                                                       decay=0.95,
                                                       exposure=0.035)
                    #c.filelist[u].set_shader(sun_shader)
                    if BLUR: self.filters.setCartoonInk()

                for u in range(0, len(c.filelist), 2):  # loading each sub-file
                    c.filelist[u].reparentTo(self.render)
                    c.filelist[u].setScale(tuple(c.scale))
                    c.filelist[u].setPos(tuple(c.position))
                    #setting the collision solid up
                temp = hitbox()
                temp.Volume = CollisionSphere(0, 0, 0, self.u_radius)
                temp.NodePath = c.filelist[0].attachNewNode(CollisionNode(
                    c.id))
                temp.CollisionNode = temp.NodePath.node()
                self.collision_solids.append(
                    temp
                )  #the radius is calculated by using the average scale + the u_radius
                # the structure of the collision_solids list will be: [temp1,temp2,...]
                # asteroids and irregular shapes must be slightly bigger than their hitbox in order to avoid visual glitches
                self.collision_solids[
                    len(self.collision_solids) - 1].CollisionNode.addSolid(
                        self.collision_solids[
                            len(self.collision_solids) -
                            1].Volume)  #I am definitely not explaining that
                temp = None
                if self.debug:
                    loadPrcFileData('', 'show-frame-rate-meter true')
                    self.collision_solids[
                        len(self.collision_solids) -
                        1].NodePath.show()  # debugging purposes only

                print("collision: ok")
                print("placing body: done")
                if c.is_lightSource:
                    self.light_Mngr.append([PointLight(c.id + "_other")])
                    self.light_Mngr[len(self.light_Mngr) - 1].append(
                        render.attachNewNode(
                            self.light_Mngr[len(self.light_Mngr) - 1][0]))
                    self.light_Mngr[len(self.light_Mngr) - 1][1].setPos(
                        tuple(c.position))
                    render.setLight(self.light_Mngr[len(self.light_Mngr) -
                                                    1][1])

                    self.light_Mngr.append([AmbientLight(c.id + "_self")])
                    self.light_Mngr[len(self.light_Mngr) -
                                    1][0].setColorTemperature(3000)
                    self.light_Mngr[len(self.light_Mngr) - 1].append(
                        render.attachNewNode(
                            self.light_Mngr[len(self.light_Mngr) - 1][0]))
                    for u in range(0, len(c.filelist), 2):
                        c.filelist[u].setLight(
                            self.light_Mngr[len(self.light_Mngr) - 1][1])
                    print("lights: done")

                print("loaded new body, out: done")
            if SKYBOX == 'sky':
                self.isphere.setTexGen(
                    TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap
                )  # *takes a deep breath* cubemap stuff !
                self.isphere.setTexProjector(TextureStage.getDefault(), render,
                                             self.isphere)
                self.isphere.setTexPos(TextureStage.getDefault(), 0, 0, 0)
                self.isphere.setTexScale(TextureStage.getDefault(),
                                         .5)  # that's a thing...
                self.isphere.setTexture(
                    self.tex
                )  # Create some 3D texture coordinates on the sphere. For more info on this, check the Panda3D manual.
                self.isphere.setLightOff()
                self.isphere.setScale(10000)  #hope this is enough
                self.isphere.reparentTo(self.render)
            elif SKYBOX == 'arena':
                self.box.setPos(0, 0, 0)
                self.box.setScale(100)
                self.box.reparentTo(self.render)
            # collision traverser and other collision stuff # that's super important, and super tricky to explain so just check the wiki
            self.ctrav = CollisionTraverser()
            self.queue = CollisionHandlerQueue()
            for n in self.collision_solids:
                self.ctrav.add_collider(n.NodePath, self.queue)
            # the traverser will be automatically updated, no need to repeat this every frame
            # debugging only
            if self.debug:
                self.ctrav.showCollisions(render)
            # play a random music
            self.current_playing = random.randint(0, len(self.sounds) - 1)
            self.sounds[self.current_playing].play()

            # task manager stuff comes here
            self.taskMgr.add(self.intro_loop, 'showIntroPic')
        except:
            sys.exit(":( something went wrong: files could not be loaded")
        '''
        self.showsimpletext("All modules loaded, simulation running",(-1.42,0.95),(0.04,0.04),None,(1,1,1,True))
        self.showsimpletext("PyOS build V0.10",(-1.5,0.90),(0.04,0.04),None,(1,1,1,True))
        self.showsimpletext("By l3alr0g",(-1.68,0.85),(0.04,0.04),None,(1,1,1,True))
        '''

        # key bindings
        self.accept('backspace', self.system_break)
        self.accept('escape', self.toggle_pause)
        self.accept('mouse1', self.handle_select, [True])
        self.accept('wheel_up', self.handle_scrolling,
                    [True])  # center button (just a quick test)
        self.accept('wheel_down', self.handle_scrolling, [False])
        self.accept('z', self.move_camera, [0, True])
        self.accept('q', self.move_camera, [1, True])
        self.accept('s', self.move_camera, [2, True])
        self.accept('d', self.move_camera, [3, True])
        self.accept('a', self.move_camera, [4, True])
        self.accept('e', self.move_camera, [5, True])

        self.accept('z-up', self.move_camera, [0, False])
        self.accept('q-up', self.move_camera, [1, False])
        self.accept('s-up', self.move_camera, [2, False])
        self.accept('d-up', self.move_camera, [3, False])
        self.accept('a-up', self.move_camera, [4, False])
        self.accept('e-up', self.move_camera, [5, False])
        self.keymap = [
            'z', 0, 'q', 0, 's', 0, 'd', 0, 'a', 0, 'e', 0, 'mouse1', 0
        ]

        self.disable_mouse()

        if self.debug:
            # draw axis
            coord = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
            axis = []
            for c in range(3):
                axis.append(LineSegs())
                axis[c].moveTo(0, 0, 0)
                axis[c].drawTo(coord[c])
                axis[c].setThickness(3)
                axis[c].setColor(
                    tuple([coord[c][u] * 255
                           for u in range(len(coord[c]))] + [True]))
                NodePath(axis[c].create()).reparent_to(render)

        # camera positionning -------
        self.focus_point = [
            0, 0, 0
        ]  # point focused: can become a body's coordinates if the user tells the program to do so
        self.zoom_distance = 30  # distance to the focus point in common 3D units (can be modified by scrolling)
        self.cam_Hpr = [0, 0, 0]  # phi, alpha, theta - aka yaw, pitch, roll
        self.cam_Hpr = [
            self.cam_Hpr[n] * pi / 180 for n in range(len(self.cam_Hpr))
        ]  # convert to rad
        phi, alpha, theta, zoom, object = self.cam_Hpr[
            0] * pi / 180, self.cam_Hpr[1] * pi / 180, self.cam_Hpr[
                2] * pi / 180, self.zoom_distance, self.state[
                    2]  # temporary vars
        if self.state[1] == 'free':
            self.camera_pos = [0, 0, 0]
            self.camera.setPos(tuple(self.camera_pos))
        elif self.state[1] == 'linked':
            # find the object (self.state[2]) in the data list
            list_pos = [
                self.bodies[n].filelist[0] for n in range(len(self.bodies))
            ].index(object.getParent())
            self.focus_point = self.bodies[
                list_pos].position  # take the focused object's coordinates
            self.camera_pos = [
                self.focus_point[0] + sin(phi) * cos(-alpha) * zoom,
                self.focus_point[1] - cos(phi) * cos(-alpha) * zoom,
                self.focus_point[2] + sin(-alpha) * zoom
            ]  #keep it up to date so that it's not hard to find whend switching modes
            self.camera.setPos(tuple(self.camera_pos))
            self.camera.setHpr(self.cam_Hpr)

        # cursor
        self.cursor = self.showsimpletext('.', (0, 0), (0.08, 0.08), None, (
            1, 1, 1,
            True))  # yeah, you can laugh, but this still works so I don't care
        self.pointerNode = CollisionNode('cursor')
        self.pointerNP = camera.attachNewNode(self.pointerNode)
        self.pointerNode.setFromCollideMask(
            BitMask32.bit(1)
        )  # separate collisions (in order to avoid mistakes during physical calculations)
        self.cursor_ray = CollisionRay()  # create the mouse control ray
        self.pointerNode.addSolid(self.cursor_ray)
        self.ctrav.add_collider(self.pointerNP, self.queue)

        return None

    def showsimpletext(
        self, content, pos, scale, bg, fg
    ):  #shows a predefined, basic text on the screen (variable output only)
        return OnscreenText(text=content, pos=pos, scale=scale, bg=bg, fg=fg)

    def intro_loop(self, task):
        if not (task.time):
            self.screen_fill = OnscreenImage(image=str(self.dir) +
                                             "/Engine/main_page.png",
                                             pos=(0, 0, 0),
                                             scale=(1.77777778, 1, 1))
        elif task.time > 3:
            self.screen_fill.destroy()
            self.taskMgr.add(self.mouse_check, 'mousePositionTask')
            self.taskMgr.add(self.placement_Mngr, 'frameUpdateTask')
            self.taskMgr.add(self.Sound_Mngr, 'MusicHandle')
            self.taskMgr.add(self.camera_update, 'cameraPosition')
            self.taskMgr.remove('showIntroPic')
            return None
        return task.cont

    def placement_Mngr(
        self, task
    ):  # main game mechanics, frame updating function (kinda, all pausing and menu functions must be applied here
        if self.state[0] == 'running' or not task.time:
            self.ctrav.traverse(render)
            #self.queue = CollisionHandlerQueue() # update the collision queue
            brakeforce = [0 for n in range(len(self.bodies))
                          ]  # create an empty brakeforce list
            if self.queue.getNumEntries():
                if self.debug:
                    print(self.queue.getNumEntries())  # debug
                # now we have to create a temp list containing only the Entries that refer to collisions between bodies,
                # not cursor-type collisions:
                temp1, temp2 = [], []
                for count in range(len(self.queue.getEntries())):
                    if self.queue.getEntries()[count].getFromNodePath(
                    ) != self.pointerNP:
                        temp1.append(self.queue.getEntries()[count])
                    else:
                        temp2.append(self.queue.getEntries()[count])
                # the temp1 and temp2 lists have been created
                # run the check for the body-with-body collisions
                for c in range(0, len(temp1), 2):
                    entry = temp1[c]
                    brakeforce = self.collision_log(entry, brakeforce)
                # run the check for the cursor-with-body collisions
                for c in range(len(temp2)):
                    entry = temp2[c]
                    self.watched = entry.getIntoNodePath()
                # print "out"

                # update the collider list
                self.ctrav.clear_colliders()
                self.queue = CollisionHandlerQueue()
                for n in self.collision_solids:
                    self.ctrav.add_collider(n.NodePath, self.queue)
                self.ctrav.add_collider(self.pointerNP,
                                        self.queue)  # add the cursor ray again
            else:
                self.watched = None

            # collision events are now under constant surveillance
            acceleration = []
            for c in range(len(self.bodies)):  #selects the analysed body
                var = self.bodies[c]
                Bdf = [
                    0, 0, 0
                ]  #Bdf stands for 'bilan des forces' in french, it's the resulting acceleration
                for d in self.bodies[0:c] + self.bodies[c + 1:len(
                        self.bodies
                ) - 1]:  #selects the body which action on the analysed body we're studying...not sure about that english sentence though
                    S, M = [d.mass] + d.position, [var.mass] + var.position
                    temp = self.dual_a(S, M)
                    Bdf = [Bdf[x] + temp[x] for x in range(3)]  # list sum
                # add the result to the global save list
                acceleration.append(Bdf)
            #update the bodies' position
            self.speed_update(acceleration, brakeforce)
            self.pos_update()
            self.apply_update()
        elif self.state[0] == 'paused':
            self.handle_menu(self.iteration)
            self.iteration += 1
        return task.cont

    def speed_update(self, a, brakeforce):
        for c in range(len(self.bodies)
                       ):  #the function updates the speed tuple accordingly
            self.bodies[c].speed[0] += self.timescale * a[c][0]
            #self.bodies[c].speed[0]/=brakeforce[c]+1 # aero/lytho braking has to be applied to the colliding object
            # actually, speed isn't applied that way
            self.bodies[c].speed[1] += self.timescale * a[c][1]
            #self.bodies[c].speed[1]/=brakeforce[c]+1
            self.bodies[c].speed[2] += self.timescale * a[c][2]
            #self.bodies[c].speed[2]/=brakeforce[c]+1
        return 0

    def pos_update(self):  #updates the positional coordinates
        for c in range(len(self.bodies)):
            self.bodies[c].position[
                0] += self.timescale * self.bodies[c].speed[0]
            self.bodies[c].position[
                1] += self.timescale * self.bodies[c].speed[1]
            self.bodies[c].position[
                2] += self.timescale * self.bodies[c].speed[2]
        return 0

    def apply_update(self):  #actually moves the hole 3d stuff around
        count = 0  #local counter
        for c in self.bodies:
            for u in range(len(c.filelist)):
                if u % 2 != 0:
                    c.filelist[u - 1].setHpr(c.filelist[u - 1], c.filelist[u])
                else:
                    c.filelist[u].setPos(tuple(c.position))
            if c.is_lightSource:
                self.light_Mngr[count][1].setPos(tuple(c.position))
                count += 2  #we have to change the position of the pointlight, not the ambientlight
        return 0

    def camera_update(self, task):
        phi, alpha, theta, zoom, object = self.cam_Hpr[
            0] * pi / 180, self.cam_Hpr[1] * pi / 180, self.cam_Hpr[
                2] * pi / 180, self.zoom_distance, self.state[2]
        if self.state[1] == 'free':
            self.camera.setPos(tuple(self.camera_pos))
        elif self.state[1] == 'linked':
            # find the object (self.state[2]) in the data list
            list_pos = [
                self.bodies[n].filelist[0] for n in range(len(self.bodies))
            ].index(object.getParent())
            self.focus_point = self.bodies[
                list_pos].position  # take the focused object's coordinates
            self.camera_pos = [
                self.focus_point[0] + sin(phi) * cos(-alpha) * zoom,
                self.focus_point[1] - cos(phi) * cos(-alpha) * zoom,
                self.focus_point[2] + sin(-alpha) * zoom
            ]
            self.camera.setPos(tuple(self.camera_pos))
            self.camera.setHpr(tuple(self.cam_Hpr))
        ''' # not finished yet
        self.camera.setPos(self.focus_point[0]+cos(self.cam_Hpr[0])*self.zoom_distance,self.focus_point[1]+sin(self.cam_Hpr[0])*self.zoom_distance,self.focus_point[2]+sin(self.cam_Hpr[1])*self.zoom_distance)
        self.camera.lookAt(self.focus_point[0],self.focus_point[1],self.focus_point[2])
        '''
        # collision cursor stuff goes here:
        self.cursor_ray.setFromLens(self.camNode, 0, 0)
        # relatively to the camera, the cursor position will always be 0,0 which is the position of the
        # white point on the screen

        if self.keymap != ['z', 0, 'q', 0, 's', 0, 'd', 0]:
            for x in range(1, len(self.keymap), 2):
                if self.keymap[x]:
                    self.move_camera(
                        int((x - 1) / 2), True
                    )  # why (x-1)/2 ? because we have to make the tow readable as a key number, like 0,1,2,3
        return task.cont

    def dual_a(
        self, S, M
    ):  #S is the "static object", the one that applies the force to the "moving" object M
        O = []  #This will be the list with the accelerations for an object
        d = sqrt((S[1] - M[1])**2 + (S[2] - M[2])**2 + (S[3] - M[3])**2)
        x = (self.u_constant * S[0] * (S[1] - M[1])) / d**2
        y = (self.u_constant * S[0] * (S[2] - M[2])) / d**2
        z = (self.u_constant * S[0] * (S[3] - M[3])) / d**2
        O.append(x)
        O.append(y)
        O.append(z)
        return O

    def collision_log(self, entry, brakeforce):
        from_pos = [
            self.bodies[n].filelist[0] for n in range(len(self.bodies))
        ].index(entry.getFromNodePath().getParent())
        into_pos = [
            self.bodies[n].filelist[0] for n in range(len(self.bodies))
        ].index(entry.getIntoNodePath().getParent()
                )  #find the nodepath in the list
        f_radius = sum(self.bodies[from_pos].scale) * self.u_radius / 3
        i_radius = sum(self.bodies[into_pos].scale) * self.u_radius / 3
        if max(f_radius, i_radius) == f_radius:
            inverted = True
            into_pos, from_pos = from_pos, into_pos
        else:
            inverted = False  # currently unused
        brakeforce[from_pos] = self.bodies[
            from_pos].brakeforce  # get the force given in the data list
        # those are the two positions of the nodepaths, now we need to know which one is bigger, in order to obtain the fusion effect
        # from_pos is the smaller body, into_pos is the bigger one
        self.collision_gfx(
            self.momentum_transfer(from_pos, into_pos, entry, inverted),
            f_radius, i_radius)
        return brakeforce

    def momentum_transfer(self, f_pos, i_pos, entry, inverted):
        if self.debug:
            print("colliding")  # debug, makes the game laggy
        interior = entry.getInteriorPoint(entry.getIntoNodePath())  # default
        surface = entry.getSurfacePoint(entry.getIntoNodePath())
        print((interior - surface).length())  # debug
        if (interior - surface).length() >= 2 * sum(
                self.bodies[f_pos].scale) * self.u_radius / 3:
            if self.state[2] == self.collision_solids[f_pos].NodePath:
                self.state[1] = 'free'
                self.state[2] = None
            self.ctrav.remove_collider(self.collision_solids[f_pos].NodePath)
            self.bodies[f_pos].delete_body()

            self.bodies[i_pos].scale[0] *= (
                self.bodies[i_pos].mass +
                self.bodies[f_pos].mass) / self.bodies[i_pos].mass
            self.bodies[i_pos].scale[1] *= (
                self.bodies[i_pos].mass +
                self.bodies[f_pos].mass) / self.bodies[i_pos].mass
            self.bodies[i_pos].scale[2] *= (
                self.bodies[i_pos].mass +
                self.bodies[f_pos].mass) / self.bodies[i_pos].mass
            self.bodies[i_pos].mass += self.bodies[f_pos].mass
            # scale updating ()
            ''' temporarly removed
            for c in range(0,len(self.bodies[i_pos].filelist),2):
                self.bodies[i_pos].filelist[c].setScale(tuple(self.bodies[i_pos].scale))
            '''
            # deleting the destroyed planet's data
            self.bodies = self.bodies[:f_pos] + self.bodies[f_pos +
                                                            1:len(self.bodies)]
            self.collision_solids = self.collision_solids[:f_pos] + self.collision_solids[
                f_pos + 1:len(self.collision_solids)]
            # just a quick test
            if self.debug:
                self.ctrav.showCollisions(render)
            if self.debug:
                print("planet destroyed")
        return interior, surface  # used for the collision gfx calculations

    def printScene(self):  #debug
        file = open("scenegraph.txt", "a")
        ls = LineStream()
        render.ls(ls)
        while ls.isTextAvailable():
            file.write(ls.getLine())
            file.write("\n")
        file.write("\n")
        file.write("END\n")
        file.write("\n")
        file.close()

    def Sound_Mngr(self, task):
        if self.sounds[self.current_playing].length() - self.sounds[
                self.current_playing].getTime(
                ) == 0:  #could have just used not()
            self.current_playing = random.choice(
                list(range(0, self.current_playing)) +
                list(range(self.current_playing + 1, len(self.sounds))))
            self.sounds[self.current_playing].play()
        return task.cont

    def collision_gfx(self, points, Rf,
                      Ri):  # collision animation calculations
        # section size calculation
        # we know the depth of penetration (no silly jokes please), which allows us, knowing the radius of each body,
        # to calculate the radius of the section (I've got no idea how to say that in correct english)
        # the display of the particles all over this circle will be a piece of cake (at least I hope so)
        # see documents in the screenshot folder for more informations about the maths
        interior, surface = points[0], points[1]
        p = (interior - surface).length()
        p2 = (p**2 - 2 * Ri * p) / (2 * Ri - 2 * p - 2 * Rf)
        p1 = p - p2
        # now we know everything about our impact section (the circle that defines the contact between the two bodies)
        # we just have to find the coord of the circle's center

        return 0

    def create_crater(self):  # see project for more informations
        return None

    def toggle_pause(self):
        temp = ['paused', 'running']
        self.state[0] = temp[self.state[0] ==
                             temp[0]]  # switches between paused and running
        self.iteration = 0
        if self.state[0] == 'paused':
            self.handle_menu(self.iteration)
        else:
            self.filters.del_blur_sharpen()
            # make the mouse invisible
            self.hidden_mouse = True
            wp = WindowProperties()
            wp.setCursorHidden(self.hidden_mouse)
            # set the mouse pos to 0
            self.center_mouse()

            self.win.requestProperties(wp)
            for u in self.menu_text:
                u.hide()
        return None

    def handle_menu(self, iteration):
        if not iteration:
            self.accept('escape', self.toggle_pause)
            self.draw_menu()
            # make the mouse visible
            self.hidden_mouse = False
            wp = WindowProperties()
            wp.setCursorHidden(self.hidden_mouse)
            self.win.requestProperties(wp)
        else:
            a = 1  # indentation (temporary)
            #put your mouse detection stuff here
        return None

    def draw_menu(self):
        self.filters.setBlurSharpen(amount=0)
        for u in self.menu_text:
            u.show()
        return None

    def show_credits(self):
        print(
            "created by l3alr0g (at least this part, I'll do something better at the end)"
        )
        return None

    def system_break(self):
        # place your data saving routines here
        print("system exit successful, data saved")
        print("executing sys.exit()")
        print("out: done")
        sys.exit(0)
        return None

    def handle_scrolling(
            self,
            up):  # up is a boolean: up=True means up, up=False means down
        if up and self.state[0] == 'running':
            if self.state[1] == 'linked':
                self.zoom_distance *= 0.95
            else:
                self.camera_delta *= 1.1
        elif not up and self.state[0] == 'running':
            if self.state[1] == 'linked':
                self.zoom_distance /= 0.95
            else:
                self.camera_delta /= 1.1
        return None

    def rotate_camera(self):
        self.camera.setHpr(tuple(self.cam_Hpr))
        return None

    def move_camera(
        self, tow, pressed
    ):  # tow stands for towards, pressed is a boolean which indicates the state of the key
        if pressed:
            self.keymap[2 * tow + 1] = 1
            self.state[1] = 'free'
            #print('free mode on')
            self.state[2] = None
        else:
            self.keymap[2 * tow + 1] = 0

        if self.keymap[2 * tow + 1]:
            phi, alpha, theta, delta, zoom = self.cam_Hpr[
                0] * pi / 180, self.cam_Hpr[1] * pi / 180, self.cam_Hpr[
                    2] * pi / 180, self.camera_delta, self.zoom_distance
            if self.keymap[2 * tow] == 'q':
                if self.state[1] == 'free':
                    self.camera_pos = [
                        self.camera_pos[0] - cos(phi) * cos(theta) * delta,
                        self.camera_pos[1] - sin(phi) * cos(theta) * delta,
                        self.camera_pos[2] + sin(theta) * delta
                    ]  # moving the camera
            if self.keymap[2 * tow] == 'z':
                if self.state[1] == 'free':
                    self.camera_pos = [
                        self.camera_pos[0] - sin(phi) * cos(alpha) * delta,
                        self.camera_pos[1] + cos(phi) * cos(alpha) * delta,
                        self.camera_pos[2] + sin(alpha) * delta
                    ]
            if self.keymap[2 * tow] == 's':
                if self.state[1] == 'free':
                    self.camera_pos = [
                        self.camera_pos[0] + sin(phi) * cos(alpha) * delta,
                        self.camera_pos[1] - cos(phi) * cos(alpha) * delta,
                        self.camera_pos[2] - sin(alpha) * delta
                    ]
            if self.keymap[2 * tow] == 'd':
                if self.state[1] == 'free':
                    self.camera_pos = [
                        self.camera_pos[0] + cos(phi) * cos(theta) * delta,
                        self.camera_pos[1] + sin(phi) * cos(theta) * delta,
                        self.camera_pos[2] - sin(theta) * delta
                    ]
            if self.keymap[2 * tow] == 'a':
                self.cam_Hpr[2] -= 1
            if self.keymap[2 * tow] == 'e':
                self.cam_Hpr[2] += 1
        return None

    def mouse_check(self, task):  # gets the mouse's coordinates
        mwn = self.mouseWatcherNode
        if mwn.hasMouse():
            x, y = mwn.getMouseX(), mwn.getMouseY()
            #print(x,y) # debug
            # focus_point coordinates modifier code here:
            if self.state == ['running', 'free', None]:
                self.cam_Hpr[
                    0] -= x * self.sensitivity_x  # the - fixes a bug I can't solve
                self.cam_Hpr[
                    1] += y * self.sensitivity_y  # those formulas do not work when theta (self.cam_Hpr[2]) changes
                self.rotate_camera()
                self.center_mouse()
            elif self.state[0] == 'running' and self.state[1] == 'linked':
                self.cam_Hpr[0] -= x * self.sensitivity_x
                self.cam_Hpr[1] -= y * self.sensitivity_y
                self.rotate_camera()
                self.center_mouse()
            '''
            if self.debug:
                print(self.cam_Hpr,self.camera_pos) # debug
        '''
        return task.cont

    def center_mouse(self):
        self.win.movePointer(
            0, int(self.win.getProperties().getXSize() / 2),
            int(self.win.getProperties().getYSize() / 2)
        )  # move mouse back to center --> careful ! this makes the delta calculation code buggy

    def handle_select(self, is_clicked):
        if is_clicked and self.watched != None:
            self.state[1] = 'linked'  # toggle following mode
            self.state[2] = self.watched
            print('linked mode on, focusing: ', self.watched)
        #else: # do nothing actually
        return None

    def easter_egg(self):
        return "please be patient, our hens are working on it"
class ShadowCaster(DirectObject):
    def __init__(self, shadowAngle):
        DirectObject.__init__(self)
        self.shadowAngle = shadowAngle
        self.shadowCamArm = None
        self.casterState = None
        self.shadowBuffer = None
        self.shadowColor = 0.5
        self.shadowColorIndex = 0
        self.shadowsEnabled = 0
        self.clearColor = VBase4(1, 1, 1, 1)
        self.setupTask = None
        self.shadowsHidden = False
        self.shadowImage = None

    def enable(self, fMoreShadows=True):
        self.fMoreShadows = fMoreShadows
        self.disable()
        self.shadowsEnabled = 1
        camNode = Camera('shadowCam')
        camNode.setCameraMask(CIGlobals.ShadowCameraBitmask)
        self.shadowLens = OrthographicLens()
        if fMoreShadows:
            more = 2
            self.shadowLens.setFilmSize(60 * more, 60 * more)
        else:
            self.shadowLens.setFilmSize(60, 60)
        camNode.setLens(self.shadowLens)
        #smiley = loader.loadModel("models/smiley.egg.pz")
        self.shadowCamArm = base.camera.attachNewNode('shadowCamArm')
        #smiley.reparentTo(self.shadowCamArm)
        self.shadowCam = self.shadowCamArm.attachNewNode(camNode)
        self.shadowCamArm.setPos(0, 40, 0)
        self.shadowCam.setPos(0, -40, 0)
        #smiley.copyTo(self.shadowCam)
        taskName = 'shadowCamCompass'
        taskMgr.remove(taskName)

        def applyCompassEffect(task, self=self):
            self.shadowCamArm.setHpr(render, self.shadowAngle)
            self.shadowCamArm.setScale(1)
            return Task.cont

        taskMgr.add(applyCompassEffect, taskName, sort=-100)
        self.shadowTex = Texture('shadow')
        self.shadowTex.setBorderColor(self.clearColor)
        self.shadowTex.setWrapU(Texture.WMBorderColor)
        self.shadowTex.setWrapV(Texture.WMBorderColor)
        if self.shadowImage:
            self.shadowImage.destroy()
            self.shadowImage = None
        #self.shadowImage = OnscreenImage(image = self.shadowTex, scale = 0.3, pos = (0, 0, 0.7))
        self.casterState = NodePath('temp')
        self.casterState.setColorScaleOff(10)
        self.casterState.setColor(self.shadowColor, self.shadowColor,
                                  self.shadowColor, 1, 10)
        self.casterState.setTextureOff(10)
        self.casterState.setLightOff(10)
        self.casterState.setFogOff(10)
        camNode.setInitialState(self.casterState.getState())
        render.hide(CIGlobals.ShadowCameraBitmask)
        self.shadowStage = TextureStage('shadow')
        self.shadowStage.setSort(-100)

        #self.turnOnShadows()

    def hideShadows(self):
        if self.shadowsHidden:
            return None

        self.shadowsHidden = True
        self.turnOffShadows()

    def showShadows(self):
        if not self.shadowsHidden:
            return None

        self.shadowsHidden = False
        self.turnOnShadows()

    def projectShadows(self):
        for gmnp in render.findAllMatches("**/+GeomNode"):
            if gmnp.getBinName() == 'ground':
                # The ground bin is directly on the node.
                gmnp.projectTexture(self.shadowStage, self.shadowTex,
                                    self.shadowCam)
                continue

            # Check the individual geoms for the ground bin
            for state in gmnp.node().getGeomStates():
                if state.hasAttrib(CullBinAttrib.getClassType()):
                    attr = state.getAttrib(CullBinAttrib.getClassType())
                    if attr.getBinName() == "ground":
                        gmnp.projectTexture(self.shadowStage, self.shadowTex,
                                            self.shadowCam)

    def turnOnShadows(self):
        if self.shadowsHidden or not (self.shadowsEnabled):
            return None

        self.turnOffShadows()
        self.__createBuffer()
        self.accept('close_main_window', self.__destroyBuffer)
        self.accept('open_main_window', self.__createBuffer)
        self.accept('texture_state_changed', self.__createBuffer)

    def turnOffShadows(self):
        for gmnp in render.findAllMatches("**/+GeomNode"):
            if gmnp.getBinName() == "ground":
                gmnp.clearProjectTexture(self.shadowStage)
        self.__destroyBuffer()
        self.ignore('close_main_window')
        self.ignore('open_main_window')
        self.ignore('texture_state_changed')

    def disable(self):
        if not self.shadowsEnabled:
            return None

        if self.shadowImage:
            self.shadowImage.destroy()
            self.shadowImage = None

        #base.oobe()

        self.shadowsEnabled = 0
        taskName = 'shadowCamCompass'
        taskMgr.remove(taskName)
        self.shadowCamArm.removeNode()
        self.shadowCam.removeNode()
        base.camNode.clearTagState('caster')
        self.turnOffShadows()
        self.shadowTex = None
        self.shadowStage = None
        #ShadowCaster.setGlobalDropShadowFlag(1)

    def setShadowAngle(self, light):
        self.shadowAngle = light

    def updateShadows(self, h):
        """
        while h < TODGlobals.ShadowColorTable[self.shadowColorIndex][0]:
            self.shadowColorIndex -= 1
        while h > TODGlobals.ShadowColorTable[self.shadowColorIndex + 1][0]:
            self.shadowColorIndex += 1
        (prevH, prevColor) = TODGlobals.ShadowColorTable[self.shadowColorIndex]
        (nextH, nextColor) = TODGlobals.ShadowColorTable[self.shadowColorIndex + 1]
        dt = (h - prevH) / (nextH - prevH)
        grayLevel = dt * (nextColor - prevColor) + prevColor
        if h == 0:
            self.hideShadows()
        else:
            self.showShadows()
        if self.shadowColor != grayLevel:
            self.shadowColor = grayLevel
            ShadowCaster.setGlobalDropShadowGrayLevel(1.0 - grayLevel)
            if self.shadowsEnabled:
                self.casterState.setColor(grayLevel, grayLevel, grayLevel, 1, 10)
                self.shadowCam.node().setInitialState(self.casterState.getState())
        """

        pass

    def updateShadowAmount(self, amount):
        grayLevel = amount
        if self.shadowColor != grayLevel:
            self.shadowColor = grayLevel
            #ShadowCaster.setGlobalDropShadowGrayLevel(1.0 - grayLevel)
            if self.shadowsEnabled:
                self.casterState.setColor(grayLevel, grayLevel, grayLevel, 1,
                                          10)
                self.shadowCam.node().setInitialState(
                    self.casterState.getState())

    def __createBuffer(self):
        if self.shadowsHidden or not (self.shadowsEnabled):
            return None

        self.__destroyBuffer()
        if not base.win.getGsg():
            return None

        if self.fMoreShadows and False:
            self.shadowBuffer = base.win.makeTextureBuffer('shadow',
                                                           1024 * 4,
                                                           1024 * 4,
                                                           tex=self.shadowTex)
        else:
            self.shadowBuffer = base.win.makeTextureBuffer('shadow',
                                                           1024,
                                                           1024,
                                                           tex=self.shadowTex)
        #self.shadowBuffer.setSort(30)
        self.shadowBuffer.setClearColor(self.clearColor)
        dr = self.shadowBuffer.makeDisplayRegion()
        dr.setCamera(self.shadowCam)
        #self.setupTask = taskMgr.doMethodLater(0, self.__setupCamera, 'setupCamera')

        self.filters = CommonFilters(self.shadowBuffer, self.shadowCam)
        self.filters.setBlurSharpen(.5)

    def __setupCamera(self, task):
        groundState = NodePath('temp')
        #groundState.projectTexture(self.shadowStage, self.shadowTex, self.shadowCamArm)
        #groundState.setTexGen(self.shadowStage, TexGenAttrib.MWorldPosition)
        base.camNode.setTagStateKey('cam')
        base.camNode.setTagState('shground', groundState.getState())

        self.setupTask = None
        return task.done

    def __destroyBuffer(self):
        if self.shadowBuffer:
            base.graphicsEngine.removeWindow(self.shadowBuffer)
            self.shadowBuffer = None

        if self.setupTask:
            taskMgr.remove(self.setupTask)
            self.setupTask = None
Ejemplo n.º 6
0
class Engine(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.disableMouse()

        props = WindowProperties()
        props.setTitle('Test')
        self.win.requestProperties(props)

        # self.render.setAntiAlias(AntialiasAttrib.MAuto)

        self.transitions = Transitions(self.loader)
        self.transitions.setFadeColor(0, 0, 0)

        self.filters = CommonFilters(self.win, self.cam)
        # self.filters.setCartoonInk()
        self.filters.setBlurSharpen(1)
        # self.filters.setVolumetricLighting(self.render)

        # self.buffer = self.win.makeTextureBuffer("Post-processing buffer", self.win.getXSize(), self.win.getXSize())
        # print self.buffer.getYSize()
        # self.texture = self.buffer.getTexture()
        # self.buffer.setSort(-100)
        #
        # self.originalCamera = self.camera
        # self.offScreenCamera = self.makeCamera(self.buffer)
        # self.camera = self.offScreenCamera
        #
        # self.img = OnscreenImage(image=self.texture, pos=(0, 0, 0.5))

        self.scene = None
        self.channel = Channel()

    def set_scene(self, scene_module):
        # self.transitions.fadeOut(0.2)
        args = []

        if self.scene:
            args.append(
                Parallel(Func(self.fade_out),
                         LerpFunc(self.blur_out, duration=0.2)))
            args.append(Wait(0.2))

        args.append(Func(self._set_scene, scene_module))
        args.append(
            Parallel(Func(self.fade_in), LerpFunc(self.blur_in, duration=0.4)))

        Sequence(*args).start()

    def blur_out(self, t):
        # index = int(t)
        # self.filters.delBlurSharpen()
        self.filters.setBlurSharpen(1 - t)
        self.filters.setBloom(intensity=t)

    def blur_in(self, t):
        # index = int(t)
        # self.filters.delBlurSharpen()
        self.filters.setBlurSharpen(t)
        self.filters.setBloom(intensity=-t)

    def fade_out(self):
        self.transitions.fadeOut(0.2)

    def fade_in(self):
        self.transitions.fadeIn(0.2)

    def _set_scene(self, scene_module):
        group, class_ = scene_module.split('.')
        module = importlib.import_module('game.scenes.{}'.format(group))
        scene_class = getattr(module, class_)
        if self.scene:
            self.scene.destroy()
            del self.scene
        self.scene = scene_class(self)
        # self.transitions.fadeIn(0.2)

    def start(self):
        self.channel = Channel()
        self.channel.connect()

        self.set_scene('auth.AuthScene')

        while True:
            self.taskMgr.step()
            if self.channel.can_read():
                for packet in self.channel.read_packets():
                    self.scene.on_packet(packet)
Ejemplo n.º 7
0
class Application(ShowBase):

	def __init__(self):
		ShowBase.__init__(self)

		self.useAdvancedVisualEffects =\
			ConfigVariableBool("use-advanced-visual-effects", True) and\
			base.win.getGsg().getSupportsBasicShaders() and\
			base.win.getGsg().getSupportsGlsl() and\
			base.win.getGsg().getSupportsDepthTexture()

		self.game = Game(scriptPath)

		self.phoneState = PhoneState(self)
		self.setupFilters()
		self.setupModels()
		self.setupLighting()
		self.setupKeyboardControl()
		self.camera.setPos(0.0, 0.0, 1.7)
		self.setupMouseControl()
		self.phoneState.request("Hidden")
		blockSize = 10.0
		self.maxX = self.game.getCityBlueprint().getSizeWE() * blockSize / 2.0
		self.maxY = self.game.getCityBlueprint().getSizeNS() * blockSize / 2.0
		self.setBackgroundColor(0.2, 0.4, 1.0, 1.0)

	def setupFilters(self):
		if (self.useAdvancedVisualEffects):
			self.filters = CommonFilters(self.win, self.cam)
			self.filters.setBloom()

	def setupKeyboardControl(self):
		self.accept("escape", sys.exit)

	def setupMouseControl(self):
		self.disableMouse()

		self.mousex = 0
		self.mousey = 0
		self.last = 0
		self.mousebtn = [0,0,0]

		self.accept("mouse1", self.setMouseBtn, [0, 1])
		self.accept("mouse1-up", self.setMouseBtn, [0, 0])

		self.taskMgr.add(self.controlCamera, "cameraTask")

	def setupLights(self):
		self.sunLight = self.render.attachNewNode(DirectionalLight("sunLight"))
		self.sunLight.setColor(Vec4(0.8, 0.8, 0.8, 1))
		self.sunLight.node().getLens().setFilmSize(128, 64)
		self.sunLight.node().getLens().setNearFar(20,2000)
		self.sunLight.setPos(60, 30, 50)
		self.sunLight.lookAt(0, 0, 0)
		self.render.setLight(self.sunLight)
#		self.sunLight.node().showFrustum()
		if self.useAdvancedVisualEffects:
			self.sunLight.node().setShadowCaster(True, 256, 256)
			self.render.setShaderAuto()

		self.ambientLight = self.render.attachNewNode(AmbientLight("ambientLight"))
		self.ambientLight.node().setColor(Vec4(0.2, 0.2, 0.2, 1))
		self.render.setLight(self.ambientLight)

	def setupModels(self):
		self.city = self.loader.loadModel("models/city")
		self.city.reparentTo(self.render)
		self.phoneState.setupPhone()
		self.cityOutline = self.loader.loadModel("models/city_outline")
		self.cityOutline.reparentTo(self.phoneState.minimap)

	def setupLighting(self):
		self.ambientLight = self.render.attachNewNode(AmbientLight("ambientLight"))
		self.ambientLight.node().setColor(Vec4(1, 1, 1, 1))
		self.render.setLight(self.ambientLight)

	def setMouseBtn(self, btn, value):
		self.mousebtn[btn] = value

		if (btn == 0 and value == 1 and self.phoneState.state == "Center"):
			phoneDisplayRegionCenterX = self.win.getXSize() * (self.phoneState.phoneDisplayRegion.getLeft() + self.phoneState.phoneDisplayRegion.getRight()) / 2.0
			phoneDisplayRegionCenterY = self.win.getYSize() * (1.0 - (self.phoneState.phoneDisplayRegion.getBottom() + self.phoneState.phoneDisplayRegion.getTop()) / 2.0)
			mouse = self.win.getPointer(0)
			s = 2 ** self.phoneState.minimapZoom
			x = clamp(self.camera.getX() + (mouse.getX() - phoneDisplayRegionCenterX) / s, -self.maxX, self.maxX)
			y = clamp(self.camera.getY() + (phoneDisplayRegionCenterY - mouse.getY()) / s, -self.maxY, self.maxY)
			previousHeading = self.camera.getH() % 360.0
			heading = (rad2Deg(atan2(y - self.camera.getY(), x - camera.getX())) - 90.0) % 360.0

			if (180.0 < abs(heading - previousHeading)):
				if (previousHeading < heading):
					heading -= 360.0
				else:
					heading += 360.0

			self.camera.setH(previousHeading)
			self.phoneState.orientationTriangle.setH(previousHeading)

			Parallel(
				self.camera.posInterval(0.5, Vec3(x, y, self.camera.getZ())),
				self.phoneState.minimapCamera.posInterval(0.5, Vec3(x, y, self.phoneState.minimapCamera.getZ())),
				self.phoneState.orientationTriangle.posInterval(0.5, Vec3(x, y, self.phoneState.orientationTriangle.getZ())),
				self.camera.hprInterval(0.5, Vec3(heading, self.camera.getP(), self.camera.getR())),
				self.phoneState.orientationTriangle.hprInterval(0.5, Vec3(heading, self.phoneState.orientationTriangle.getP(), self.phoneState.orientationTriangle.getR()))
			).start()
	
	def setBlurSharpen(self, amount):
		if (not self.useAdvancedVisualEffects):
			return

		if (amount == 1.0):
			self.filters.delBlurSharpen()
		else:
			self.filters.setBlurSharpen(amount=amount)

	def controlCamera(self, task):
		if (self.phoneState.state == "Center"):
			return Task.cont

		# figure out how much the mouse has moved (in pixels)
		mouse = self.win.getPointer(0)
		x = mouse.getX()
		y = mouse.getY()
		windowCenterX = self.win.getXSize() / 2
		windowCenterY = self.win.getYSize() / 2
		heading = self.camera.getH()
		pitch = self.camera.getP()

		if self.win.movePointer(0, windowCenterX, windowCenterY):
			heading -= (x - windowCenterX) * 0.2
			pitch = clamp(pitch - (y - windowCenterY) * 0.2, -45, 45)

		self.camera.setHpr(heading, pitch, 0)

		elapsed = task.time - self.last

		if (self.last == 0):
			elapsed = 0

		if (self.mousebtn[0]):
			direction = self.camera.getMat().getRow3(1)
			self.camera.setPos(self.camera.getPos() + direction * elapsed*30)

		clampX(self.camera, -self.maxX, self.maxX)
		clampY(self.camera, -self.maxY, self.maxY)
		self.camera.setZ(2)

		self.phoneState.minimapCamera.setX(self.camera.getX())
		self.phoneState.minimapCamera.setY(self.camera.getY())

		self.phoneState.orientationTriangle.setX(self.camera.getX())
		self.phoneState.orientationTriangle.setY(self.camera.getY())
		self.phoneState.orientationTriangle.setHpr(heading, -90, 0)

		self.last = task.time

		return Task.cont
Ejemplo n.º 8
0
class ToonBase(OTPBase.OTPBase):
    notify = DirectNotifyGlobal.directNotify.newCategory('ToonBase')

    def __init__(self):
        OTPBase.OTPBase.__init__(self)
        self.disableShowbaseMouse()
        self.addCullBins()
        self.debugRunningMultiplier /= OTPGlobals.ToonSpeedFactor
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)
        self.toonChatSounds = self.config.GetBool('toon-chat-sounds', 1)
        self.placeBeforeObjects = self.config.GetBool('place-before-objects', 1)
        self.endlessQuietZone = False
        self.wantDynamicShadows = 0
        self.exitErrorCode = 0
        camera.setPosHpr(0, 0, 0, 0, 0, 0)
        self.camLens.setMinFov(settings['fov']/(4./3.))
        self.camLens.setNearFar(ToontownGlobals.DefaultCameraNear, ToontownGlobals.DefaultCameraFar)
        self.musicManager.setVolume(0.65)
        self.setBackgroundColor(ToontownGlobals.DefaultBackgroundColor)
        tpm = TextPropertiesManager.getGlobalPtr()
        candidateActive = TextProperties()
        candidateActive.setTextColor(0, 0, 1, 1)
        tpm.setProperties('candidate_active', candidateActive)
        candidateInactive = TextProperties()
        candidateInactive.setTextColor(0.3, 0.3, 0.7, 1)
        tpm.setProperties('candidate_inactive', candidateInactive)
        self.transitions.IrisModelName = 'phase_3/models/misc/iris'
        self.transitions.FadeModelName = 'phase_3/models/misc/fade'
        self.exitFunc = self.userExit
        globalClock.setMaxDt(0.2)
        if self.config.GetBool('want-particles', 1) == 1:
            self.notify.debug('Enabling particles')
            self.enableParticles()

        self.accept(ToontownGlobals.ScreenshotHotkey, self.takeScreenShot)

        # OS X Specific Actions
        if platform == "darwin":
            self.acceptOnce(ToontownGlobals.QuitGameHotKeyOSX, self.exitOSX)
            self.accept(ToontownGlobals.QuitGameHotKeyRepeatOSX, self.exitOSX)
            self.acceptOnce(ToontownGlobals.HideGameHotKeyOSX, self.hideGame)
            self.accept(ToontownGlobals.HideGameHotKeyRepeatOSX, self.hideGame)
            self.acceptOnce(ToontownGlobals.MinimizeGameHotKeyOSX, self.minimizeGame)
            self.accept(ToontownGlobals.MinimizeGameHotKeyRepeatOSX, self.minimizeGame)

        self.accept('f3', self.toggleGui)
        self.accept('f4', self.oobe)
        self.accept('panda3d-render-error', self.panda3dRenderError)
        oldLoader = self.loader
        self.loader = ToontownLoader.ToontownLoader(self)
        __builtins__['loader'] = self.loader
        oldLoader.destroy()
        self.accept('PandaPaused', self.disableAllAudio)
        self.accept('PandaRestarted', self.enableAllAudio)
        self.wantPets = self.config.GetBool('want-pets', 1)
        self.wantBingo = self.config.GetBool('want-fish-bingo', 1)
        self.wantKarts = self.config.GetBool('want-karts', 1)
        self.inactivityTimeout = self.config.GetFloat('inactivity-timeout', ToontownGlobals.KeyboardTimeout)
        if self.inactivityTimeout:
            self.notify.debug('Enabling Panda timeout: %s' % self.inactivityTimeout)
            self.mouseWatcherNode.setInactivityTimeout(self.inactivityTimeout)
        self.mouseWatcherNode.setEnterPattern('mouse-enter-%r')
        self.mouseWatcherNode.setLeavePattern('mouse-leave-%r')
        self.mouseWatcherNode.setButtonDownPattern('button-down-%r')
        self.mouseWatcherNode.setButtonUpPattern('button-up-%r')
        self.randomMinigameAbort = self.config.GetBool('random-minigame-abort', 0)
        self.randomMinigameDisconnect = self.config.GetBool('random-minigame-disconnect', 0)
        self.randomMinigameNetworkPlugPull = self.config.GetBool('random-minigame-netplugpull', 0)
        self.autoPlayAgain = self.config.GetBool('auto-play-again', 0)
        self.skipMinigameReward = self.config.GetBool('skip-minigame-reward', 0)
        self.wantMinigameDifficulty = self.config.GetBool('want-minigame-difficulty', 0)
        self.minigameDifficulty = self.config.GetFloat('minigame-difficulty', -1.0)
        if self.minigameDifficulty == -1.0:
            del self.minigameDifficulty
        self.minigameSafezoneId = self.config.GetInt('minigame-safezone-id', -1)
        if self.minigameSafezoneId == -1:
            del self.minigameSafezoneId
        cogdoGameSafezoneId = self.config.GetInt('cogdo-game-safezone-id', -1)
        cogdoGameDifficulty = self.config.GetFloat('cogdo-game-difficulty', -1)
        if cogdoGameDifficulty != -1:
            self.cogdoGameDifficulty = cogdoGameDifficulty
        if cogdoGameSafezoneId != -1:
            self.cogdoGameSafezoneId = cogdoGameSafezoneId
        ToontownBattleGlobals.SkipMovie = self.config.GetBool('skip-battle-movies', 0)
        self.housingEnabled = self.config.GetBool('want-housing', 1)
        self.cannonsEnabled = self.config.GetBool('estate-cannons', 0)
        self.fireworksEnabled = self.config.GetBool('estate-fireworks', 0)
        self.dayNightEnabled = self.config.GetBool('estate-day-night', 0)
        self.cloudPlatformsEnabled = self.config.GetBool('estate-clouds', 0)
        self.greySpacing = self.config.GetBool('allow-greyspacing', 0)
        self.slowQuietZone = self.config.GetBool('slow-quiet-zone', 0)
        self.slowQuietZoneDelay = self.config.GetFloat('slow-quiet-zone-delay', 5)
        self.killInterestResponse = self.config.GetBool('kill-interest-response', 0)
        tpMgr = TextPropertiesManager.getGlobalPtr()
        WLDisplay = TextProperties()
        WLDisplay.setSlant(0.3)
        tpMgr.setProperties('WLDisplay', WLDisplay)
        WLRed = tpMgr.getProperties('red')
        WLRed.setTextColor(1.0, 0.0, 0.0, 1)
        tpMgr.setProperties('WLRed', WLRed)
        del tpMgr
        self.lastScreenShotTime = globalClock.getRealTime()
        self.accept('InputState-forward', self.__walking)
        self.canScreenShot = 1
        self.glitchCount = 0
        self.walking = 0
        self.oldX = max(1, base.win.getXSize())
        self.oldY = max(1, base.win.getYSize())
        self.aspectRatio = float(self.oldX) / self.oldY
        self.localAvatarStyle = None

        self.filters = CommonFilters(self.win, self.cam)
        self.filters.setBlurSharpen(1.1)

        self.wantCogInterface = settings.get('cogInterface', True)
        self.wantWASD = settings.get('want-WASD', False)
        self.wantNews = settings.get('want-News', True)

        self.Move_Up = 'arrow_up'
        self.Move_Left = 'arrow_left'       
        self.Move_Down = 'arrow_down'
        self.Move_Right = 'arrow_right'
        self.JUMP = 'control'
        
        if self.wantWASD:
            self.Move_Up = 'w'
            self.Move_Left = 'a'            
            self.Move_Down = 's'
            self.Move_Right = 'd'
            self.JUMP = 'shift'

    def openMainWindow(self, *args, **kw):
        result = OTPBase.OTPBase.openMainWindow(self, *args, **kw)
        self.setCursorAndIcon()
        return result

    def setCursorAndIcon(self):
        atexit.register(shutil.rmtree, tempdir)

        wp = WindowProperties()
        wp.setCursorFilename(Filename.fromOsSpecific(os.path.join(tempdir, 'toonmono.cur')))
        wp.setIconFilename(Filename.fromOsSpecific(os.path.join(tempdir, 'icon.ico')))
        self.win.requestProperties(wp)

    def addCullBins(self):
        cbm = CullBinManager.getGlobalPtr()
        cbm.addBin('ground', CullBinManager.BTUnsorted, 18)
        cbm.addBin('shadow', CullBinManager.BTBackToFront, 19)
        cbm.addBin('gui-popup', CullBinManager.BTUnsorted, 60)

    def disableShowbaseMouse(self):
        self.useDrive()
        self.disableMouse()
        if self.mouseInterface: self.mouseInterface.detachNode()
        if self.mouse2cam: self.mouse2cam.detachNode()

    def __walking(self, pressed):
        self.walking = pressed

    def toggleGui(self):
        if aspect2d.isHidden():
            aspect2d.show()
        else:
            aspect2d.hide()

    def takeScreenShot(self):
        if not os.path.exists(TTLocalizer.ScreenshotPath):
            os.mkdir(TTLocalizer.ScreenshotPath)
            self.notify.info('Made new directory to save screenshots.')

        namePrefix = TTLocalizer.ScreenshotPath + launcher.logPrefix + 'screenshot'
        timedif = globalClock.getRealTime() - self.lastScreenShotTime
        if self.glitchCount > 10 and self.walking:
            return
        if timedif < 1.0 and self.walking:
            self.glitchCount += 1
            return
        if not hasattr(self, 'localAvatar'):
            self.screenshot(namePrefix=namePrefix)
            self.lastScreenShotTime = globalClock.getRealTime()
            return
        coordOnScreen = self.config.GetBool('screenshot-coords', 0)
        self.localAvatar.stopThisFrame = 1
        ctext = self.localAvatar.getAvPosStr()
        self.screenshotStr = ''
        messenger.send('takingScreenshot')
        if coordOnScreen:
            coordTextLabel = DirectLabel(pos=(-0.81, 0.001, -0.87), text=ctext, text_scale=0.05, text_fg=VBase4(1.0, 1.0, 1.0, 1.0), text_bg=(0, 0, 0, 0), text_shadow=(0, 0, 0, 1), relief=None)
            coordTextLabel.setBin('gui-popup', 0)
            strTextLabel = None
            if len(self.screenshotStr):
                strTextLabel = DirectLabel(pos=(0.0, 0.001, 0.9), text=self.screenshotStr, text_scale=0.05, text_fg=VBase4(1.0, 1.0, 1.0, 1.0), text_bg=(0, 0, 0, 0), text_shadow=(0, 0, 0, 1), relief=None)
                strTextLabel.setBin('gui-popup', 0)
        self.graphicsEngine.renderFrame()
        self.screenshot(namePrefix=namePrefix, imageComment=ctext + ' ' + self.screenshotStr)
        self.lastScreenShotTime = globalClock.getRealTime()
        self.snapshotSfx = base.loadSfx('phase_4/audio/sfx/Photo_shutter.ogg')
        base.playSfx(self.snapshotSfx)
        if coordOnScreen:
            if strTextLabel is not None:
                strTextLabel.destroy()
            coordTextLabel.destroy()
        return

    def addScreenshotString(self, str):
        if len(self.screenshotStr):
            self.screenshotStr += '\n'
        self.screenshotStr += str

    def initNametagGlobals(self):
        arrow = loader.loadModel('phase_3/models/props/arrow')
        card = loader.loadModel('phase_3/models/props/panel')
        speech3d = ChatBalloon(loader.loadModel('phase_3/models/props/chatbox'))
        thought3d = ChatBalloon(loader.loadModel('phase_3/models/props/chatbox_thought_cutout'))
        speech2d = ChatBalloon(loader.loadModel('phase_3/models/props/chatbox_noarrow'))
        chatButtonGui = loader.loadModel('phase_3/models/gui/chat_button_gui')
        NametagGlobals.setCamera(self.cam)
        NametagGlobals.setArrowModel(arrow)
        NametagGlobals.setNametagCard(card, VBase4(-0.5, 0.5, -0.5, 0.5))
        if self.mouseWatcherNode:
            NametagGlobals.setMouseWatcher(self.mouseWatcherNode)
        NametagGlobals.setSpeechBalloon3d(speech3d)
        NametagGlobals.setThoughtBalloon3d(thought3d)
        NametagGlobals.setSpeechBalloon2d(speech2d)
        NametagGlobals.setThoughtBalloon2d(thought3d)
        NametagGlobals.setPageButton(PGButton.SReady, chatButtonGui.find('**/Horiz_Arrow_UP'))
        NametagGlobals.setPageButton(PGButton.SDepressed, chatButtonGui.find('**/Horiz_Arrow_DN'))
        NametagGlobals.setPageButton(PGButton.SRollover, chatButtonGui.find('**/Horiz_Arrow_Rllvr'))
        NametagGlobals.setQuitButton(PGButton.SReady, chatButtonGui.find('**/CloseBtn_UP'))
        NametagGlobals.setQuitButton(PGButton.SDepressed, chatButtonGui.find('**/CloseBtn_DN'))
        NametagGlobals.setQuitButton(PGButton.SRollover, chatButtonGui.find('**/CloseBtn_Rllvr'))
        rolloverSound = DirectGuiGlobals.getDefaultRolloverSound()
        if rolloverSound:
            NametagGlobals.setRolloverSound(rolloverSound)
        clickSound = DirectGuiGlobals.getDefaultClickSound()
        if clickSound:
            NametagGlobals.setClickSound(clickSound)
        NametagGlobals.setToon(self.cam)

        self.marginManager = MarginManager()
        self.margins = self.aspect2d.attachNewNode(self.marginManager, DirectGuiGlobals.MIDGROUND_SORT_INDEX + 1)
        mm = self.marginManager

        # TODO: Dynamicaly add more and reposition cells
        padding = 0.0225

        # Order: Top to bottom
        self.leftCells = [
            mm.addGridCell(0.2 + padding, -0.45, base.a2dTopLeft), # Above boarding groups
            mm.addGridCell(0.2 + padding, -0.9, base.a2dTopLeft),  # 1
            mm.addGridCell(0.2 + padding, -1.35, base.a2dTopLeft)  # Below Boarding Groups
        ]

        # Order: Left to right
        self.bottomCells = [
            mm.addGridCell(-0.87, 0.2 + padding, base.a2dBottomCenter), # To the right of the laff meter
            mm.addGridCell(-0.43, 0.2 + padding, base.a2dBottomCenter), # 1
            mm.addGridCell(0.01, 0.2 + padding, base.a2dBottomCenter),  # 2
            mm.addGridCell(0.45, 0.2 + padding, base.a2dBottomCenter),  # 3
            mm.addGridCell(0.89, 0.2 + padding, base.a2dBottomCenter)   # To the left of the shtiker book
        ]

        # Order: Bottom to top
        self.rightCells = [
            mm.addGridCell(-0.2 - padding, -1.35, base.a2dTopRight), # Above the street map
            mm.addGridCell(-0.2 - padding, -0.9, base.a2dTopRight),  # Below the friends list
            mm.addGridCell(-0.2 - padding, -0.45, base.a2dTopRight)  # Behind the friends list
        ]

    def hideFriendMargins(self):
        middleCell = self.rightCells[1]
        topCell = self.rightCells[2]

        self.setCellsAvailable([middleCell, topCell], False)

    def showFriendMargins(self):
        middleCell = self.rightCells[1]
        topCell = self.rightCells[2]

        self.setCellsAvailable([middleCell, topCell], True)

    def setCellsAvailable(self, cell_list, available):
        for cell in cell_list:
            self.marginManager.setCellAvailable(cell, available)

    def startShow(self, cr):
        self.cr = cr
        base.graphicsEngine.renderFrame()
        # Get the base port.
        serverPort = base.config.GetInt('server-port', 7199)

        # Get the number of client-agents.
        clientagents = base.config.GetInt('client-agents', 1) - 1

        # Get a new port.
        serverPort += (random.randint(0, clientagents) * 100)

        serverList = []
        for name in launcher.getGameServer().split(';'):
            url = URLSpec(name, 1)
            if base.config.GetBool('server-force-ssl', False):
                url.setScheme('s')
            if not url.hasPort():
                url.setPort(serverPort)
            serverList.append(url)

        if len(serverList) == 1:
            failover = base.config.GetString('server-failover', '')
            serverURL = serverList[0]
            for arg in failover.split():
                try:
                    port = int(arg)
                    url = URLSpec(serverURL)
                    url.setPort(port)
                except:
                    url = URLSpec(arg, 1)

                if url != serverURL:
                    serverList.append(url)

        cr.loginFSM.request('connect', [serverList])

        # Start detecting speed hacks:
        self.lastSpeedHackCheck = time.time()
        self.lastTrueClockTime = TrueClock.getGlobalPtr().getLongTime()
        taskMgr.add(self.__speedHackCheckTick, 'speedHackCheck-tick')

    def __speedHackCheckTick(self, task):
        elapsed = time.time() - self.lastSpeedHackCheck
        tcElapsed = TrueClock.getGlobalPtr().getLongTime() - self.lastTrueClockTime

        if tcElapsed > (elapsed + 0.05):
            # The TrueClock is running faster than it should. This means the
            # player may have sped up the process. Disconnect them:
            self.cr.stopReaderPollTask()
            self.cr.lostConnection()
            return task.done

        self.lastSpeedHackCheck = time.time()
        self.lastTrueClockTime = TrueClock.getGlobalPtr().getLongTime()

        return task.cont

    def removeGlitchMessage(self):
        self.ignore('InputState-forward')

    def exitShow(self, errorCode = None):
        self.notify.info('Exiting Toontown: errorCode = %s' % errorCode)
        sys.exit()

    def setExitErrorCode(self, code):
        self.exitErrorCode = code

    def getExitErrorCode(self):
        return self.exitErrorCode

    def userExit(self):
        try:
            self.localAvatar.d_setAnimState('TeleportOut', 1)
        except:
            pass

        if self.cr.timeManager:
            self.cr.timeManager.setDisconnectReason(ToontownGlobals.DisconnectCloseWindow)
        base.cr._userLoggingOut = False
        try:
            localAvatar
        except:
            pass
        else:
            messenger.send('clientLogout')
            self.cr.dumpAllSubShardObjects()

        self.cr.loginFSM.request('shutdown')
        self.notify.warning('Could not request shutdown; exiting anyway.')
        self.ignore(ToontownGlobals.QuitGameHotKeyOSX)
        self.ignore(ToontownGlobals.QuitGameHotKeyRepeatOSX)
        self.ignore(ToontownGlobals.HideGameHotKeyOSX)
        self.ignore(ToontownGlobals.HideGameHotKeyRepeatOSX)
        self.ignore(ToontownGlobals.MinimizeGameHotKeyOSX)
        self.ignore(ToontownGlobals.MinimizeGameHotKeyRepeatOSX)
        self.exitShow()

    def panda3dRenderError(self):
        if self.cr.timeManager:
            self.cr.timeManager.setDisconnectReason(ToontownGlobals.DisconnectGraphicsError)
        self.cr.sendDisconnect()
        sys.exit()

    def playMusic(self, music, looping = 0, interrupt = 1, volume = None, time = 0.0):
        OTPBase.OTPBase.playMusic(self, music, looping, interrupt, volume, time)

    # OS X Specific Actions
    def exitOSX(self):
        self.confirm = TTDialog.TTGlobalDialog(doneEvent='confirmDone', message=TTLocalizer.OptionsPageExitConfirm, style=TTDialog.TwoChoice)
        self.confirm.show()
        self.accept('confirmDone', self.handleConfirm)

    def handleConfirm(self):
        status = self.confirm.doneStatus
        self.ignore('confirmDone')
        self.confirm.cleanup()
        del self.confirm
        if status == 'ok':
            self.userExit()

    def hideGame(self):
        # Hacky, I know, but it works
        hideCommand = """osascript -e 'tell application "System Events"
                                            set frontProcess to first process whose frontmost is true
                                            set visible of frontProcess to false
                                       end tell'"""
        os.system(hideCommand)

    def minimizeGame(self):
        wp = WindowProperties()
        wp.setMinimized(True)
        base.win.requestProperties(wp)
Ejemplo n.º 9
0
class ToontownShaderManager(DirectFrame):
    def __init__(self, parent):
        self._parent = parent
        DirectFrame.__init__(self,
                             parent=self._parent,
                             relief=None,
                             pos=(0.0, 0.0, 0.0),
                             scale=(1.0, 1.0, 1.0))
        self.filter = CommonFilters(base.win,
                                    base.cam)  # Only affects primary window

        # Ambient Occlusion
        self.samples = 0
        self.radius = 0.0
        self.amount = 0.0
        self.strength = 0.0

        # Blur/Sharpen
        self.blur = 1.0  # this is normal value, 0.0 blurs it

        # Cartoon Ink
        self.cartoonSep = 0.0
        self.cartoonR = 0.0
        self.cartoonB = 0.0
        self.cartoonG = 0.0

        # todo: Add bloom

        # Boolean Filters
        self.HDREnabled = False
        self.invertedEnabled = False
        self.sRGBEnabled = False
        self.halfPixelShiftEnabled = False
        self.viewGlowEnabled = False

        # Other Filters
        self.exposure = 0.0

        self.SAMPLES_MAX = 128
        self.RAD_MAX = 1.0
        self.AMT_MAX = 64.0
        self.STR_MAX = 0.01
        self.INCREMENT = 1
        self.numSamples = None
        self.numRadius = None

        self.circleModel = loader.loadModel(
            'phase_3/models/gui/tt_m_gui_mat_nameShop')
        self.barTexture = loader.loadTexture('phase_3/maps/slider.png')
        self.loadGUI()
        # self.newWindow() # Disabled for now

    def loadGUI(self):
        self.textRowHeight = 0.2
        self.buttonbase_xcoord = 1.4
        self.buttonbase_ycoord = 0.45
        self.loadAmbientOcclusionGUI()
        self.loadBlurGUI()
        self.loadExposureGUI()
        self.loadCartoonInkGUI()
        self.loadHotkeys()

    def loadHotkeys(self):
        # for now instead of gui buttons i'ma just put the bool filters as hotkeys
        self.accept('4', self.__toggleHDR)
        self.accept('5', self.__toggleInverted)
        self.accept('6', self.__toggleSRGB)
        self.accept('7', self.__toggleHalfPixelShift)
        self.accept('8', self.__toggleViewGlow)

    def loadAmbientOcclusionGUI(self):
        self.numSamples = DirectSlider(
            parent=self,
            value=self.samples,
            pos=(self.buttonbase_xcoord + 0.1, 0.0,
                 self.buttonbase_ycoord - self.textRowHeight * 3.5),
            thumb_relief=None,
            range=(0, 32),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeAOValue)
        # command=self.__changeAOValue(self.samples, self.radius, self.amount, self.strength))
        self.numSamples.setScale(0.5)
        self.numSamples.setTransparency(True)
        self.numSamplesText = OnscreenText(
            pos=(self.buttonbase_xcoord + 0.1,
                 self.buttonbase_ycoord - self.textRowHeight * 3.2),
            scale=0.05,
            text="AO Sample Count = {}".format(self.samples),
            style=5,
            mayChange=True)

        self.numRadius = DirectSlider(
            parent=self,
            value=self.radius,
            pos=(self.buttonbase_xcoord + 0.1, 0.0,
                 (self.buttonbase_ycoord - self.textRowHeight * 4.5)),
            thumb_relief=None,
            range=(0, 1),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeAOValue)

        self.numRadius.setScale(0.5)
        self.numRadius.setTransparency(True)
        self.numRadiusText = OnscreenText(
            pos=(self.buttonbase_xcoord + 0.1,
                 self.buttonbase_ycoord - self.textRowHeight * 4.2),
            scale=0.05,
            text="AO Radius = {}".format(str(self.radius)),
            style=5,
            mayChange=True)

        self.numAmount = DirectSlider(
            parent=self,
            value=self.amount,
            pos=(self.buttonbase_xcoord + 0.1, 0.0,
                 (self.buttonbase_ycoord - self.textRowHeight * 5.5)),
            thumb_relief=None,
            range=(0, 64),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeAOValue)

        self.numAmount.setScale(0.5)
        self.numAmount.setTransparency(True)
        self.numAmountText = OnscreenText(
            pos=(self.buttonbase_xcoord + 0.1,
                 self.buttonbase_ycoord - self.textRowHeight * 5.2),
            scale=0.05,
            text="AO Amount = {}".format(self.amount),
            style=5,
            mayChange=True)

        self.numStrength = DirectSlider(
            parent=self,
            value=self.strength,
            pos=(self.buttonbase_xcoord + 0.1, 0.0,
                 (self.buttonbase_ycoord - self.textRowHeight * 6.5)),
            thumb_relief=None,
            range=(0, 0.1),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeAOValue)

        self.numStrength.setScale(0.5)
        self.numStrength.setTransparency(True)
        self.numStrengthText = OnscreenText(
            pos=(self.buttonbase_xcoord + 0.1,
                 self.buttonbase_ycoord - self.textRowHeight * 6.2),
            scale=0.05,
            text="AO Strength = {}".format(self.strength),
            style=5,
            mayChange=True)

    def loadCartoonInkGUI(self):
        self.cSep = DirectSlider(
            parent=self,
            value=self.cartoonSep,
            pos=(-self.buttonbase_xcoord + 0.1, 0.0,
                 self.buttonbase_ycoord - self.textRowHeight * 2.5),
            thumb_relief=None,
            range=(0, 32),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeCartoon)
        # command=self.__changeAOValue(self.samples, self.radius, self.amount, self.strength))
        self.cSep.setScale(0.5)
        self.cSep.setTransparency(True)

        self.cRed = DirectSlider(
            parent=self,
            value=self.cartoonR,
            pos=(-self.buttonbase_xcoord + 0.1, 0.0,
                 self.buttonbase_ycoord - self.textRowHeight * 3.5),
            thumb_relief=None,
            range=(0, 1),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeCartoon)
        # command=self.__changeAOValue(self.samples, self.radius, self.amount, self.strength))
        self.cRed.setScale(0.5)
        self.cRed.setTransparency(True)

        self.cBlue = DirectSlider(
            parent=self,
            value=self.cartoonB,
            pos=(-self.buttonbase_xcoord + 0.1, 0.0,
                 self.buttonbase_ycoord - self.textRowHeight * 4.5),
            thumb_relief=None,
            range=(0, 1),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeCartoon)
        # command=self.__changeAOValue(self.samples, self.radius, self.amount, self.strength))
        self.cBlue.setScale(0.5)
        self.cBlue.setTransparency(True)

        self.cGreen = DirectSlider(
            parent=self,
            value=self.cartoonG,
            pos=(-self.buttonbase_xcoord + 0.1, 0.0,
                 self.buttonbase_ycoord - self.textRowHeight * 5.5),
            thumb_relief=None,
            range=(0, 1),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeCartoon)
        # command=self.__changeAOValue(self.samples, self.radius, self.amount, self.strength))
        self.cGreen.setScale(0.5)
        self.cGreen.setTransparency(True)

    def loadBlurGUI(self):
        self.numBlur = DirectSlider(
            parent=self,
            value=self.blur,
            # pos=(0.0, 0.0, 0.0), # for new window
            pos=(self.buttonbase_xcoord + 0.1, 0.0,
                 (self.buttonbase_ycoord - self.textRowHeight * 0.5)),
            thumb_relief=None,
            range=(-10, 10),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeBlur)
        self.numBlur.setScale(0.5)
        self.numBlur.setTransparency(True)
        self.numBlurText = OnscreenText(
            pos=(self.buttonbase_xcoord + 0.1,
                 self.buttonbase_ycoord - self.textRowHeight * 0.2),
            scale=0.05,
            text="Blur Amount = {}".format(self.blur),
            style=5,
            mayChange=True)

    def loadExposureGUI(self):
        self.numExposure = DirectSlider(
            parent=self,
            value=self.exposure,
            pos=(self.buttonbase_xcoord + 0.1, 0.0,
                 (self.buttonbase_ycoord - self.textRowHeight * 2.2)),
            thumb_relief=None,
            range=(0, 5),  # self.SAMPLES_MAX
            thumb_geom=self.circleModel.find(
                '**/tt_t_gui_mat_namePanelCircle'),
            frameTexture=self.barTexture,
            frameSize=(-0.5, 0.5, -0.08, 0.08),
            command=self.__changeExposure)
        self.numExposure.setScale(0.5)
        self.numExposure.setTransparency(True)
        self.numExposureText = OnscreenText(
            pos=(self.buttonbase_xcoord + 0.1,
                 self.buttonbase_ycoord - self.textRowHeight * 1.9),
            scale=0.05,
            text="Exposure Amount = {}".format(self.blur),
            style=5,
            mayChange=True)

    def printValue(self):
        print(self.numSamples['value'])

    def __changeCartoon(self):
        self.filter.delCartoonInk()
        s = self.cSep['value']
        self.cartoonSep = s
        r = self.cRed['value']
        self.cartoonR = r
        b = self.cBlue['value']
        self.cartoonB = b
        g = self.cGreen['value']
        self.cartoonG = g
        self.filter.setCartoonInk(s, (r, g, b, 1))  # a doesn't change

    def __changeBlur(self):
        self.filter.delBlurSharpen()
        b = self.numBlur['value']
        self.blur = b
        self.numBlurText.setText("Blur amount = {}".format(b))
        self.filter.setBlurSharpen(b)

    def __changeAOValue(self):
        if self.numSamples is None:
            print("NONE")
            return
        self.filter.delAmbientOcclusion()

        s = self.numSamples['value']
        self.samples = s
        self.numSamplesText.setText("AO Sample Count = {}".format(s))
        if (s == 0):
            return

        r = self.numRadius['value']
        self.radius = r
        self.numRadiusText.setText("AO Radius = {}".format(r))
        if (r == 0):
            return

        a = self.numAmount['value']
        self.amount = a
        self.numAmountText.setText("AO Amount = {}".format(a))
        if (a == 0):
            return

        st = self.numStrength['value']
        self.strength = st
        self.numStrengthText.setText("AO Strength = {}".format(st))
        if (st == 0):
            return

        self.filter.setAmbientOcclusion(numsamples=s,
                                        radius=r,
                                        amount=a,
                                        strength=st)
        print(
            "sample count: {} | radius count: {} | amount count: {} | strength count: {}"
            .format(self.samples, self.radius, self.amount, self.strength))

    # WARNING: Won't work with relatively older Panda versions because this is new
    def __changeExposure(self):
        self.filter.delExposureAdjust()
        e = self.numExposure['value']
        self.exposure = e
        self.numExposureText.setText("Exposure amount = {}".format(e))
        self.filter.setExposureAdjust(e)

    def __toggleInverted(self):
        if not self.invertedEnabled:
            self.filter.setInverted()
            self.invertedEnabled = True
        else:
            self.filter.delInverted()
            self.invertedEnabled = False

    def __toggleHDR(self):
        if not self.HDREnabled:
            self.filter.setHighDynamicRange()
            self.HDREnabled = True
        else:
            self.filter.delHighDynamicRange()
            self.HDREnabled = False

    def __toggleSRGB(self):
        if not self.sRGBEnabled:
            self.filter.setSrgbEncode(True)
            self.sRGBEnabled = True
        else:
            self.filter.delSrgbEncode()
            self.sRGBEnabled = False

    def __toggleHalfPixelShift(self):
        if not self.halfPixelShiftEnabled:
            self.filter.setHalfPixelShift()
            self.halfPixelShiftEnabled = True
        else:
            self.filter.delHalfPixelShift()
            self.halfPixelShiftEnabled = False

    def __toggleViewGlow(self):
        if not self.viewGlowEnabled:
            self.filter.setViewGlow()
            self.viewGlowEnabled = True
        else:
            self.filter.delViewGlow()
            self.viewGlowEnabled = False

    def getValue(self, item, item_MAX):
        return item / item_MAX

    # Not gonna use this feature since it makes it very laggy. I will have to figure out
    # a better way to layout UI some other time.
    # https://discourse.panda3d.org/t/how-to-open-a-new-window/23929/4
    def newWindow(self):
        self.wp = WindowProperties()
        self.wp.setSize(700, 500)
        self.wp.setRawMice(True)
        print(self.wp.getMouseMode())
        win2mouseWatcher = MouseWatcher()
        ar = 1
        self.win2 = base.openWindow(props=self.wp, aspectRatio=ar)
        self.window2render2d = NodePath('window2render2d')
        self.window2render2d.setDepthTest(0)
        self.window2render2d.setDepthWrite(0)

        self.window2camera2d = base.makeCamera2d(self.win2)
        self.window2camera2d.reparentTo(self.window2render2d)

        # Parent gui to this
        self.window2aspect2d = self.window2render2d.attachNewNode(
            PGTop('window2aspect2d'))
        self.window2aspect2d.setScale(1.0 / ar, 1.0, 1.0)

        name = self.win2.getInputDeviceName(0)
        mk = base.dataRoot.attachNewNode(MouseAndKeyboard(self.win2, 0, name))
        mw = mk.attachNewNode(MouseWatcher(name))
        self.window2aspect2d.node().setMouseWatcher(mw.node())
Ejemplo n.º 10
0
class Engine(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.disableMouse()

        props = WindowProperties()
        props.setTitle('Test')
        self.win.requestProperties(props)

        # self.render.setAntiAlias(AntialiasAttrib.MAuto)

        self.transitions = Transitions(self.loader)
        self.transitions.setFadeColor(0, 0, 0)

        self.filters = CommonFilters(self.win, self.cam)
        # self.filters.setCartoonInk()
        self.filters.setBlurSharpen(1)
        # self.filters.setVolumetricLighting(self.render)

        # self.buffer = self.win.makeTextureBuffer("Post-processing buffer", self.win.getXSize(), self.win.getXSize())
        # print self.buffer.getYSize()
        # self.texture = self.buffer.getTexture()
        # self.buffer.setSort(-100)
        #
        # self.originalCamera = self.camera
        # self.offScreenCamera = self.makeCamera(self.buffer)
        # self.camera = self.offScreenCamera
        #
        # self.img = OnscreenImage(image=self.texture, pos=(0, 0, 0.5))

        self.scene = None
        self.channel = Channel()

    def set_scene(self, scene_module):
        # self.transitions.fadeOut(0.2)
        args = []

        if self.scene:
            args.append(Parallel(Func(self.fade_out), LerpFunc(self.blur_out, duration=0.2)))
            args.append(Wait(0.2))

        args.append(Func(self._set_scene, scene_module))
        args.append(Parallel(Func(self.fade_in), LerpFunc(self.blur_in, duration=0.4)))

        Sequence(*args).start()

    def blur_out(self, t):
        # index = int(t)
        # self.filters.delBlurSharpen()
        self.filters.setBlurSharpen(1 - t)
        self.filters.setBloom(intensity=t)

    def blur_in(self, t):
        # index = int(t)
        # self.filters.delBlurSharpen()
        self.filters.setBlurSharpen(t)
        self.filters.setBloom(intensity=-t)

    def fade_out(self):
        self.transitions.fadeOut(0.2)

    def fade_in(self):
        self.transitions.fadeIn(0.2)

    def _set_scene(self, scene_module):
        group, class_ = scene_module.split('.')
        module = importlib.import_module('game.scenes.{}'.format(group))
        scene_class = getattr(module, class_)
        if self.scene:
            self.scene.destroy()
            del self.scene
        self.scene = scene_class(self)
        # self.transitions.fadeIn(0.2)

    def start(self):
        self.channel = Channel()
        self.channel.connect()

        self.set_scene('auth.AuthScene')

        while True:
            self.taskMgr.step()
            if self.channel.can_read():
                for packet in self.channel.read_packets():
                    self.scene.on_packet(packet)
Ejemplo n.º 11
0
class world(ShowBase):
    def __init__(self):
        try:
            ShowBase.__init__(self)
        except:
            sys.exit("[WARNING]: unknown error: Showbase initialisation failed")
        
        
        # ------------------------------- Begin of parameter variables (pretty messy actually) ------------------------------------
        #debug ------
        self.debug=False #[ /!\ IMPORTANT /!\ ] do not leave this value to True when you commit the code to github, as it is impossible to change once ingame, and modifies quite a lot of graphical parameters 
        #debug ------

        self.stored_collisions=[] # this counts the amount of collisions and allows us to detect the income of a new collision in order to create a new particle effect when it appears
        
        self.timescale=5 # this can be changed at any moment, it represents the speed of the ingame time
        self.worldscale=0.1 # currently useless
        
        self.camera_delta=0.5 # camera delta displacement
        self.sensitivity_x,self.sensitivity_y=20,20
        self.watched=None # watched object (object focused by the cursor)
        
        self.state=['paused','free',None] # state of things: [simulation paused/running,camera following object/free,followed object/None]
        print('free mode on')
        self.iteration=0 #iteration for the menu to be drawn once
        self.collision_status=False # Keep this on False, that's definitely not a setting # currently useless

        self.u_constant=6.67408*10**(-11) #just a quick reminder
        self.u_radius=5 #just what I said earlier 
        
        # ------------------------------- End of parameter variables (sry for the mess) --------------------------------------------
        

        self.Game_state=state()
        self.Game_state.cleanup() # better safe than sorry
        self.taskMgr.add(self.wait,'wait_task')
        self.setBackgroundColor(0,0,0)
        
    def wait(self,task):
        if not(task.time):
            self.screen_fill=OnscreenImage(image=str(MAINDIR)+"/Engine/main_page.png",pos = (0, 0, 0),scale=(1.77777778,1,1))
        elif task.time>4:
            self.taskMgr.remove('wait_task')
            self.screen_fill.destroy()
            self.menu()
            return None
        return task.cont


    def menu(self):
        # loading time
        # music
        self.menu_music=self.loader.loadSfx(str(MAINDIR)+'/Sound/deadmau5-cabin.mp3')
        self.menu_music.setLoop(True)
        self.menu_music.play()
        # filters
        try:
            self.filters = CommonFilters(self.win, self.cam)
        except: pass
        self.Game_state.root_node.setAntialias(AntialiasAttrib.MAuto)
        def quit():
            sys.exit(0)
        

        button_block_pos=(-1.2,0.35,0.25)
        maps_start=loader.loadModel(str(MAINDIR)+'/Engine/start.egg')
        maps_quit=loader.loadModel(str(MAINDIR)+'/Engine/quit.egg')
        maps_set=loader.loadModel(str(MAINDIR)+'/Engine/set.egg')
        self.start_button=DirectButton(pos=button_block_pos,frameColor=(0,0,0,0),scale=(0.717,0.4,0.221),geom=(maps_start.find('**/Start'),maps_start.find('**/Start_push'),maps_start.find('**/Start_on'),maps_start.find('**/Start')),command=self.loadgame)
        self.quit_button=DirectButton(pos=(button_block_pos[0]+0.135,button_block_pos[1],button_block_pos[2]-0.4),frameColor=(0,0,0,0),scale=(1,0.4,0.221),geom=(maps_quit.find('**/Quit'),maps_quit.find('**/Quit_push'),maps_quit.find('**/Quit_on'),maps_quit.find('**/Quit')),command=quit)
        self.settings_button=DirectButton(pos=(button_block_pos[0]-0.075,button_block_pos[1],button_block_pos[2]-0.2),frameColor=(0,0,0,0),scale=(0.56,0.4,0.221),geom=(maps_set.find('**/Set'),maps_set.find('**/Set_push'),maps_set.find('**/Set_on'),maps_set.find('**/Set')),command=self.not_implemented_yet) # settings not implemented yet
        self.title_pic=OnscreenImage(image=str(MAINDIR)+'/Engine/title.png',pos=(0,0.35,0), scale=(0.51,1,0.5))
        self.title_pic.setTransparency(TransparencyAttrib.MAlpha)
        
        pannel_pos_x=1.25
        self.activity_log=OnscreenImage(image=str(MAINDIR)+'/Engine/activity_log.png',pos=(pannel_pos_x,0.35,0.30),scale=(0.375,0.75,0.086775))
        self.activity_log.setTransparency(TransparencyAttrib.MAlpha)
        #self.activity_log_bg=OnscreenImage(image=str(MAINDIR)+'/Engine/activity_log_bg.png',pos=(pannel_pos_x,-0.35,-0.3),scale=(0.5,0.4,0.675))
        #self.activity_log_bg.setTransparency(TransparencyAttrib.MAlpha)
        #spaces compensate the center text effect
        self.logs=OnscreenText(text='   PyOS v0.11       \n\n                              Added main menu in last update\n                                             Particle support has now become reality\n                                  but still needs some improvement\n\n\n          Feature in progress:\n      collision animation\n\n\nRelease date >>',pos=(pannel_pos_x-0.3,0.11,0.2), scale=(0.05,0.05,0.05),fg=(1,1,1,1))
        self.shrug=OnscreenImage(image=str(MAINDIR)+'/Engine/shrug.png',pos=(pannel_pos_x-0.35,0.35,-0.48),scale=(0.1,1,0.0317))
        self.shrug.setTransparency(TransparencyAttrib.MAlpha)

        self.backgrnd=OnscreenImage(image=str(MAINDIR)+'/Engine/Stars.png',scale=(85.44,1,48),pos=(0,60,0))
        self.backgrnd.reparentTo(self.Game_state.root_node)
        

        #self.filters.set_gamma_adjust(0.9)
        self.moon=self.loader.loadModel(str(MAINDIR)+"/Engine/Icy.egg")
        self.moon.setScale(0.2,0.2,0.2)
        self.moon.setPos(0,50,0) # radius of orbit equals 50 units
        self.moon.reparentTo(self.Game_state.root_node)
        self.intro_planet=self.loader.loadModel(str(MAINDIR)+"/Engine/tessena.egg")
        self.intro_planet_atm=self.loader.loadModel(str(MAINDIR)+"/Engine/tessena_atm.egg")
        self.intro_planet.setPos(0,-35,0)
        self.intro_planet_atm.setPos(0,-35,0)
        self.intro_planet.reparentTo(self.Game_state.root_node)
        self.intro_planet_atm.reparentTo(self.Game_state.root_node)
        self.intro_planet.setHpr(-110,0,0)
        self.intro_planet_atm.setHpr(-110,0,0)
        self.cam.setPos(0,-70,0)

        self.disable_mouse()
        # lighting
        d=DirectionalLight('menu_dlight')
        d.setColor(VBase4(0.631,0.369,1,1))
        dlight=self.Game_state.root_node.attachNewNode(d)
        dlight.setHpr(60,-30,0)

        e=DirectionalLight('menu_dlight2')
        e.setColor(VBase4(1,1,1,1))
        elight=self.Game_state.root_node.attachNewNode(e)
        elight.setHpr(60,-30,0)

        self.moon.setLight(elight)
        self.intro_planet.setLight(dlight)
        self.intro_planet_atm.setLight(dlight)

        self.task_mgr.add(self.rotate,'rotationtask') # penser a l'enlever

        
    
    def rotate(self,task):
        self.intro_planet.setHpr(self.intro_planet,(0.1,0,0))
        self.intro_planet_atm.setHpr(self.intro_planet_atm,(0.07,0,0))
        self.moon.setHpr(self.moon,(0.2,0,0))
        self.moon.setPos(50*sin(task.time*0.02),50*cos(task.time*0.02),0)
        return task.cont
    
    # end of menu subfunctions


    def loadgame(self):
        # transition phase
        self.menu_music.setLoop(False)
        self.menu_music.stop()
        
        
        self.taskMgr.remove('rotationtask')
        self.cam.setPos(0,0,0)
        self.Game_state.cleanup()
        self.activity_log.hide()
        #self.activity_log_bg.hide()
        self.logs.hide()
        self.shrug.hide()
        self.start_button.hide()
        self.quit_button.hide()
        self.settings_button.hide()
        self.title_pic.hide()
        
        

        # end of transition phase

        # Mouse parameters 
        self.hidden_mouse=True
        wp = WindowProperties()
        wp.setCursorHidden(self.hidden_mouse)
        self.win.requestProperties(wp)

        # preparing the menu text list:
        quit_to_desk=self.loader.loadModel(str(MAINDIR)+"/Engine/quit_to_desktop.egg")
        quit_to_menu=self.loader.loadModel(str(MAINDIR)+"/Engine/quit_to_menu.egg")
        resume=self.loader.loadModel(str(MAINDIR)+"/Engine/resume.egg")
        self.paused_menu_text=[]
        global_tempPosx=-1
        self.paused_menu_text.append(DirectButton(pos=(global_tempPosx-0.065,0,-0.2),frameColor=(0,0,0,0),scale=(1,0.4,0.211),geom=(quit_to_desk.find('**/quit_to_desktop'),quit_to_desk.find('**/quit_to_desktop_push'),quit_to_desk.find('**/quit_to_desktop_on'),quit_to_desk.find('**/quit_to_desktop')),command=self.system_break))
        self.paused_menu_text.append(DirectButton(pos=(global_tempPosx,0,0),frameColor=(0,0,0,0),scale=(1.12,0.4,0.211),geom=(quit_to_menu.find('**/quit_to_menu'),quit_to_menu.find('**/quit_to_menu_push'),quit_to_menu.find('**/quit_to_menu_on'),quit_to_menu.find('**/quit_to_menu')),command=self.ingame_back_to_menu))
        self.paused_menu_text.append(DirectButton(pos=(global_tempPosx-0.325,0,0.2),frameColor=(0,0,0,0),scale=(0.47,0.4,0.211),geom=(resume.find('**/resume'),resume.find('**/resume_push'),resume.find('**/resume_on'),resume.find('**/resume')),command=self.toggle_pause))

        # btw I found something about energy transmission through thermal radiation. I think it uses some Boltzmann formula stuff. Link here:
        # https://fr.wikibooks.org/wiki/Plan%C3%A9tologie/La_temp%C3%A9rature_de_surface_des_plan%C3%A8tes#Puissance_re%C3%A7ue_par_la_Terre

        # Defining important data lists
        # music imports (paths)
        self.sounds=[str(MAINDIR)+"/Sound/001.mp3",
        str(MAINDIR)+"/Sound/Blazing-Stars.mp3",
        str(MAINDIR)+"/Sound/Cold-Moon.mp3",
        str(MAINDIR)+"/Sound/Light-Years_v001.mp3",
        str(MAINDIR)+"/Sound/The-Darkness-Below.mp3",
        str(MAINDIR)+"/Sound/Retro-Sci-Fi-Planet.mp3",
        str(MAINDIR)+"/Sound/droid-bishop-nightland.mp3",
        str(MAINDIR)+"/Sound/interstellar-ost-03-dust-by-hans-zimmer.mp3",
        str(MAINDIR)+"/Sound/interstellar-ost-04-day-one-by-hans-zimmer.mp3",
        str(MAINDIR)+"/Sound/ascendant-remains-2015.mp3",
        str(MAINDIR)+"/Sound/droid-bishop-nightland.mp3",
        str(MAINDIR)+"/Sound/john-carpenter-utopian-facade-official-music-video.mp3",
        str(MAINDIR)+"/Sound/stranger-things-2-eulogy.mp3",
        str(MAINDIR)+"/Sound/interstellar-ost-07-the-wormhole-by-hans-zimmer.mp3"] 
        
        self.collision_solids=[] #collision related stuff - comments are useless - just RTFM
        self.light_Mngr=[]
        self.data=[
        [0,0,0,-0.00,0.003,0,0.30,0.30,0.30,100000.00,True,[self.loader.loadModel(str(MAINDIR)+"/Engine/lp_planet_0.egg"),(0.1,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/lp_planet_1.egg"),(0.14,0,0)],"low_poly_planet01",False,0.1]
        ,[10,0,0,0,0.003,0,0.05,0.05,0.05,20.00,True,[self.loader.loadModel(str(MAINDIR)+"/Engine/Icy.egg"),(0.05,0,0)],"Ottilia_modified",False,0.1]
        ,[0,70,10,0,0.005,0,0.1,0.1,0.1,40.00,True,[self.loader.loadModel(str(MAINDIR)+"/Engine/asteroid_1.egg"),(0,0,0.2)],"Selena",False,1]
        ,[100,0,10,0,0,0,5,5,5,1000000,True,[self.loader.loadModel(str(MAINDIR)+"/Engine/sun1.egg"),(0.01,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/sun1_atm.egg"),(0.01,0,0)],"Sun",True,0.1]
        ,[-100,50,70,0,0,0.003,0.15,0.15,0.15,1000.00,True,[self.loader.loadModel(str(MAINDIR)+"/Engine/Earth2.egg"),(-0.1,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/Earth2_atm.egg"),(-0.15,0,0)],"big_fucking_planet",False,0.1]
        ,[200,0,0,-0.001,0,0.01,0.1,0.1,0.1,100000,False,[self.loader.loadModel(MAINDIR+"/Engine/realistic_asteroid.egg"),(0,0.01,0)],"spaceship",False,0]
        ,[0,-120,0,0.004,0,0,0.3,0.3,0.3,100000,True,[self.loader.loadModel(str(MAINDIR)+"/Engine/FG1.egg"),(0.01,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/FG2.egg"),(0.01,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/FG3.egg"),(0.01,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/FG4.egg"),(0.01,0,0),self.loader.loadModel(str(MAINDIR)+"/Engine/FG5.egg"),(0.01,0,0)],"Frozen_giant",False,0.1]
        # insert your 3d models here, following the syntax (this is the default scene that will be loaded on startup)
        ] 
        # the correct reading syntax is [x,y,z,l,m,n,scale1,scale2,scale3,mass,static,[file,(H,p,r),file,(H,p,r)...],id,lightsource,brakeforce] for each body - x,y,z: position - l,m,n: speed - scale1,scale2,scale3: obvious (x,y,z) - mass: kg - static: boolean - [files]: panda3d readfiles list (first file must be the ground, the others are atmosphere models)
        #id: str - lightsource: boolean -
        #if you want the hitbox to be correctly scaled,and your body to have reasonable proportions, your 3d model must be a 5*5 sphere, or at least have these proportions
        
        # create the real data list, the one used by the program
        self.bodies=[]
        
        for c in self.data:
            temp=body()
            temp.fill_entries(c)
            self.bodies.append(temp)
            temp=None
        #self.bodies.reverse()
        
        # Quick presetting
        self.setBackgroundColor(0,0,0,True)
        
        # enable particles
        
        self.enableParticles()
        self.toggle_particles() # debug
        # create particle class object
        self.particle=particle()
        # intialize object:
        self.particle.config_path='/Engine/destruction_sphere.ptf' # the MAINDIR is already included inside the class definition

        # non-body type structures loading
        if SKYBOX=='sky':
            self.isphere=self.loader.loadModel(str(MAINDIR)+"/Engine/InvertedSphere.egg") #loading skybox structure
            self.tex=loader.loadCubeMap(str(MAINDIR)+'/Engine/Skybox4/skybox_#.png')
        elif SKYBOX=='arena':
            self.box=self.loader.loadModel(str(MAINDIR)+"/Engine/arena.egg") 
        
        #load shaders (optionnal)
        '''
        sun_shader=Shader.load(Shader.SLGLSL,MAINDIR+'/Engine/Shaders/flare_v.glsl',MAINDIR+'/Engine/Shaders/flare_f.glsl')
        '''
        self.camLens.setNearFar(0.5, 100000)
        
        self.orbit_lines=[] #under developement
        
        # see https://www.panda3d.org/manual/?title=Collision_Solids for further collision interaction informations
        base.graphicsEngine.openWindows()
        try:
            print('\n[Loader manager]:\n')
            '''
            self.filters.setBlurSharpen(amount=0) # just messing around
            '''
            if not self.debug:
                self.filters.set_gamma_adjust(1.0) # can be usefull
                self.filters.set_bloom(intensity=1,size="medium")
            

            for c in self.bodies: # loading and displaying the preloaded planets and bodies
                
                if c.is_lightSource and not self.debug:
                    # VM filtering
                    self.filters.setVolumetricLighting(c.filelist[0],numsamples=50,density=0.5,decay=0.95,exposure=0.035) 
                    #c.filelist[u].set_shader(sun_shader)
                    if BLUR: self.filters.setCartoonInk()
                
                for u in range(0,len(c.filelist),2): # loading each sub-file
                    c.filelist[u].reparentTo(self.Game_state.root_node)
                    c.filelist[u].setScale(tuple(c.scale))
                    c.filelist[u].setPos(tuple(c.position))
                    if u==0 and not(c.is_lightSource):
                        c.filelist[u].setShaderAuto() #activate auto shading for compact, non translucent bodies
                    #setting the collision solid up
                temp=hitbox()
                temp.Volume=CollisionSphere(0,0,0,self.u_radius)
                temp.NodePath=c.filelist[0].attachNewNode(CollisionNode(c.id))
                temp.CollisionNode=temp.NodePath.node()
                self.collision_solids.append(temp) #the radius is calculated by using the average scale + the self.u_radius 
                # the structure of the collision_solids list will be: [temp1,temp2,...]
                # asteroids and irregular shapes must be slightly bigger than their hitbox in order to avoid visual glitches
                self.collision_solids[len(self.collision_solids)-1].CollisionNode.addSolid(self.collision_solids[len(self.collision_solids)-1].Volume) #I am definitely not explaining that
                temp=None
                if self.debug:
                    loadPrcFileData("", "show-frame-rate-meter  1")
                    self.collision_solids[len(self.collision_solids)-1].NodePath.show() # debugging purposes only
                
                print("collision: ok")
                print("placing body: done")
                if c.is_lightSource:
                    self.light_Mngr.append([PointLight(c.id+"_other")])
                    self.light_Mngr[len(self.light_Mngr)-1].append(self.Game_state.root_node.attachNewNode(self.light_Mngr[len(self.light_Mngr)-1][0]))
                    self.light_Mngr[len(self.light_Mngr)-1][1].setPos(tuple(c.position))
                    # shadow stuff
                    
                    self.light_Mngr[len(self.light_Mngr)-1][1].node().setShadowCaster(True)
                    '''
                    self.light_Mngr[len(self.light_Mngr)-1][1].node().getLens().setFov(40)
                    self.light_Mngr[len(self.light_Mngr)-1][1].node().getLens().setNearFar(10, 100)
                    '''
                    self.Game_state.root_node.setLight(self.light_Mngr[len(self.light_Mngr)-1][1]) 

                    self.light_Mngr.append([AmbientLight(c.id+"_self")])
                    self.light_Mngr[len(self.light_Mngr)-1][0].setColorTemperature(3000)
                    self.light_Mngr[len(self.light_Mngr)-1].append(self.Game_state.root_node.attachNewNode(self.light_Mngr[len(self.light_Mngr)-1][0]))
                    for u in range(0,len(c.filelist),2):
                        c.filelist[u].setLight(self.light_Mngr[len(self.light_Mngr)-1][1])
                    print("lights: done")
                else:
                    self.light_Mngr.append([]) #create an empty list, so that the coordinates of the data in the list is the same as in self.bodies (easier for further analysis and potential deletion)
                    self.light_Mngr.append([])
                
                print("loaded new body, out: done")
            if SKYBOX=='sky':
                self.isphere.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap)  # *takes a deep breath* cubemap stuff !
                self.isphere.setTexProjector(TextureStage.getDefault(), self.Game_state.root_node, self.isphere)
                self.isphere.setTexPos(TextureStage.getDefault(), 0, 0, 0)
                self.isphere.setTexScale(TextureStage.getDefault(), .5) # that's a thing...
                self.isphere.setTexture(self.tex)# Create some 3D texture coordinates on the sphere. For more info on this, check the Panda3D manual.
                self.isphere.setLightOff()
                self.isphere.setScale(10000) #hope this is enough
                self.isphere.reparentTo(self.Game_state.root_node)
            elif SKYBOX=='arena':
                self.box.setPos(0,0,0)
                self.box.setScale(100)
                self.box.reparentTo(self.Game_state.root_node)
            # collision traverser and other collision stuff # that's super important, and super tricky to explain so just check the wiki
            self.ctrav = CollisionTraverser()
            self.queue = CollisionHandlerQueue()
            for n in self.collision_solids:
                self.ctrav.add_collider(n.NodePath,self.queue)
            # the traverser will be automatically updated, no need to repeat this every frame
            # debugging only
            if self.debug:
                self.ctrav.showCollisions(self.Game_state.root_node) 
            # play a random music
            self.current_playing=random.randint(0,len(self.sounds)-1)
            self.current_song=self.loader.loadSfx(self.sounds[self.current_playing])
            self.current_song.play()

            # task manager stuff comes here
            self.intro_loop()
        except:
            sys.exit(":( something went wrong: files could not be loaded")
        
        
        # key bindings
        self.accept('escape',self.toggle_pause)
        self.accept('mouse1',self.handle_select,[True])
        self.accept('wheel_up',self.handle_scrolling,[True]) # center button (just a quick test)
        self.accept('wheel_down',self.handle_scrolling,[False])
        self.accept('z',self.move_camera,[0,True])
        self.accept('q',self.move_camera,[1,True])
        self.accept('s',self.move_camera,[2,True])
        self.accept('d',self.move_camera,[3,True])
        self.accept('a',self.move_camera,[4,True])
        self.accept('e',self.move_camera,[5,True])
        self.accept('arrow_right',self.time_change,[True])
        self.accept('arrow_left',self.time_change,[False])
        
        self.accept('z-up',self.move_camera,[0,False])
        self.accept('q-up',self.move_camera,[1,False])
        self.accept('s-up',self.move_camera,[2,False])
        self.accept('d-up',self.move_camera,[3,False])
        self.accept('a-up',self.move_camera,[4,False])
        self.accept('e-up',self.move_camera,[5,False])
        self.keymap=['z',0,'q',0,'s',0,'d',0,'a',0,'e',0,'mouse1',0]
        
        
        if self.debug: 
            # draw axis
            coord=[(1,0,0),(0,1,0),(0,0,1)]
            axis=[]
            for c in range(3): 
                axis.append(LineSegs())
                axis[c].moveTo(0,0,0)
                axis[c].drawTo(coord[c])
                axis[c].setThickness(3)
                axis[c].setColor(tuple([coord[c][u]*255 for u in range(len(coord[c]))] +[True]))
                NodePath(axis[c].create()).reparent_to(self.Game_state.root_node)

        # camera positionning -------
        self.focus_point=[0,0,0] # point focused: can become a body's coordinates if the user tells the program to do so
        self.zoom_distance=30 # distance to the focus point in common 3D units (can be modified by scrolling)
        self.cam_Hpr=[0,0,0] # phi, alpha, theta - aka yaw, pitch, roll
        self.cam_Hpr=[self.cam_Hpr[n]*pi/180 for n in range(len(self.cam_Hpr))] # convert to rad
        phi,alpha,theta,zoom,object=self.cam_Hpr[0]*pi/180,self.cam_Hpr[1]*pi/180,self.cam_Hpr[2]*pi/180,self.zoom_distance,self.state[2] # temporary vars
        if self.state[1]=='free':
            self.camera_pos=[0,0,0]
            self.camera.setPos(tuple(self.camera_pos))
        elif self.state[1]=='linked':
            # find the object (self.state[2]) in the data list
            list_pos=[self.bodies[n].filelist[0] for n in range(len(self.bodies))].index(object.getParent())
            self.focus_point=self.bodies[list_pos].position # take the focused object's coordinates
            self.camera_pos=[self.focus_point[0]+sin(phi)*cos(-alpha)*zoom,self.focus_point[1]-cos(phi)*cos(-alpha)*zoom,self.focus_point[2]+sin(-alpha)*zoom] #keep it up to date so that it's not hard to find whend switching modes
            self.camera.setPos(tuple(self.camera_pos))
            self.camera.setHpr(self.cam_Hpr)

        # cursor
        self.cursor=self.showsimpletext('.',(0,0),(0.08,0.08),None,(1,1,1,True)) # yeah, you can laugh, but this still works so I don't care
        self.pointerNode=CollisionNode('cursor')
        self.pointerNP=camera.attachNewNode(self.pointerNode)
        self.pointerNode.setFromCollideMask(BitMask32.bit(1)) # separate collisions (in order to avoid mistakes during physical calculations)
        self.cursor_ray=CollisionRay() # create the mouse control ray
        self.pointerNode.addSolid(self.cursor_ray)
        self.ctrav.add_collider(self.pointerNP,self.queue)

        #self.screen_fill.destroy() # delete the displayed picture
        return None




    
    def showsimpletext(self,content,pos,scale,bg,fg): #shows a predefined, basic text on the screen (variable output only)
        return OnscreenText(text=content,pos=pos,scale=scale,bg=bg,fg=fg)
    
    def intro_loop(self):
        
        self.taskMgr.add(self.mouse_check,'mousePositionTask')
        self.taskMgr.add(self.placement_Mngr,'frameUpdateTask')
        self.taskMgr.add(self.Sound_Mngr,'MusicHandle')
        self.taskMgr.add(self.camera_update,'cameraPosition')
        self.taskMgr.remove('showIntroPic')
        return None
    
    def placement_Mngr(self,task): # void main = main game mechanics, frame updating function (kinda, all pausing and menu functions must be applied here)
        if self.state[0]=='running' or not task.time:
            self.ctrav.traverse(self.Game_state.root_node)
            #self.queue = CollisionHandlerQueue() # update the collision queue
            brakeforce=[0 for n in range(len(self.bodies))] # create an empty brakeforce list
            if self.queue.getNumEntries():
                if self.debug:
                    print(self.queue.getNumEntries()) # debug, shows only one digit most of the time
                # now we have to create a temp list containing only the Entries that refer to collisions between bodies,
                # not cursor-type collisions:
                temp1,temp2=[],[]
                for count in range(len(self.queue.getEntries())):
                    if self.queue.getEntries()[count].getFromNodePath()!=self.pointerNP: temp1.append(self.queue.getEntries()[count])
                    else: temp2.append(self.queue.getEntries()[count])
                # the temp1 and temp2 lists have been created 

                # run the check for the body-with-body collisions 
                if len(temp1)>len(self.stored_collisions):
                    print('[WARNING]: New collision') # debugging , detects when a collision occurs AND IT F*****G WORKS BITCH !! (actually I created this system so that the particles linked to the collision are only created once)
                    self.particle.add_particle(temp1[len(self.stored_collisions):])
                    #b=len(temp1[self.stored_collisions:len(temp1)])
                    for x in temp1[len(self.stored_collisions):]:
                        self.particle.activate(x.getIntoNodePath().getParent(),self.Game_state.root_node)
                elif len(temp1)<len(self.stored_collisions):
                    print('Collision ended')
                    a=self.stored_collisions[len(temp1):]
                    for x in a:
                        self.particle.deactivate(x.getIntoNodePath().getParent())
                        self.particle.deactivate(x.getFromNodePath().getParent())
                    # at this point we should probably delete the particle object, as if we don't, it might still be updated, even if the collision doesn't exist in the self.queue anymore
                self.stored_collisions=temp1 #else do nothing
                for c in range(0,len(temp1),2): 
                    entry=temp1[c]
                    brakeforce=self.collision_log(entry,brakeforce)
                
                # run the check for the cursor-with-body collisions
                for c in range(len(temp2)):
                    entry=temp2[c]
                    self.watched=entry.getIntoNodePath()
                # print "out"

                # update the collider list
                self.ctrav.clear_colliders()
                self.queue = CollisionHandlerQueue()
                for n in self.collision_solids:
                    self.ctrav.add_collider(n.NodePath,self.queue)
                self.ctrav.add_collider(self.pointerNP,self.queue) # add the cursor ray again
            else:
                self.watched=None
                
            # collision events are now under constant surveillance
            acceleration=[]
            for c in range(len(self.bodies)): #selects the analysed body
                var=self.bodies[c]
                Bdf=[0,0,0] #Bdf stands for 'bilan des forces' in french, it's the resulting acceleration
                for d in self.bodies[0:c]+self.bodies[c+1:len(self.bodies)-1]: #selects the body which action on the analysed body we're studying...not sure about that english sentence though
                    S,M=[d.mass]+d.position,[var.mass]+var.position
                    temp=self.dual_a(S,M)
                    Bdf=[Bdf[x]+temp[x] for x in range(3)] # list sum
                # add the result to the global save list
                acceleration.append(Bdf)
            #update the bodies' position
            self.speed_update(acceleration,brakeforce)
            self.pos_update()
            self.apply_update()
        elif self.state[0]=='paused':
            self.handle_menu(self.iteration)
            self.iteration+=1
        return task.cont
    
    def speed_update(self,a,brakeforce):
        for c in range(len(self.bodies)): #the function updates the speed tuple accordingly
            self.bodies[c].speed[0]+=self.timescale*a[c][0]
            #self.bodies[c].speed[0]/=brakeforce[c]+1 # aero/lytho braking has to be applied to the colliding object
            # actually, speed isn't applied that way
            self.bodies[c].speed[1]+=self.timescale*a[c][1]
            #self.bodies[c].speed[1]/=brakeforce[c]+1
            self.bodies[c].speed[2]+=self.timescale*a[c][2]
            #self.bodies[c].speed[2]/=brakeforce[c]+1 
        return 0
    
    def pos_update(self): #updates the positional coordinates
        for c in range(len(self.bodies)):
            self.bodies[c].position[0]+=self.timescale*self.bodies[c].speed[0]
            self.bodies[c].position[1]+=self.timescale*self.bodies[c].speed[1]
            self.bodies[c].position[2]+=self.timescale*self.bodies[c].speed[2]
        return 0
    
    def apply_update(self): #actually moves the hole 3d stuff around
        count=0 #local counter
        for c in self.bodies:
            for u in range(len(c.filelist)):
                if u%2!=0:
                    c.filelist[u-1].setHpr(c.filelist[u-1],tuple([self.timescale*i for i in c.filelist[u]]))
                else:    
                    c.filelist[u].setPos(tuple(c.position))    
            if c.is_lightSource:
                self.light_Mngr[count][1].setPos(tuple(c.position))
            count+=2
        return 0
    
    def camera_update(self,task):
        phi,alpha,theta,zoom,object=self.cam_Hpr[0]*pi/180,self.cam_Hpr[1]*pi/180,self.cam_Hpr[2]*pi/180,self.zoom_distance,self.state[2]
        if self.state[1]=='free':
            self.camera.setPos(tuple(self.camera_pos))
        elif self.state[1]=='linked':
            # find the object (self.state[2]) in the data list
            list_pos=[self.bodies[n].filelist[0] for n in range(len(self.bodies))].index(object.getParent())
            self.focus_point=self.bodies[list_pos].position # take the focused object's coordinates
            self.camera_pos=[self.focus_point[0]+sin(phi)*cos(-alpha)*zoom,self.focus_point[1]-cos(phi)*cos(-alpha)*zoom,self.focus_point[2]+sin(-alpha)*zoom]
            self.camera.setPos(tuple(self.camera_pos))
            self.camera.setHpr(tuple(self.cam_Hpr))
        
        # collision cursor stuff goes here:
        self.cursor_ray.setFromLens(self.camNode,0,0) 
        # relatively to the camera, the cursor position will always be 0,0 which is the position of the 
        # white point on the screen


        if self.keymap!=['z',0,'q',0,'s',0,'d',0]:
            for x in range(1,len(self.keymap),2):
                if self.keymap[x]:
                    self.move_camera(int((x-1)/2),True) # why (x-1)/2 ? because we have to make the tow readable as a key number, like 0,1,2,3
        return task.cont

    def dual_a(self,S,M): #S is the "static object", the one that applies the force to the "moving" object M
        O=[]  #This will be the list with the accelerations for an object 
        d=sqrt((S[1]-M[1])**2+(S[2]-M[2])**2+(S[3]-M[3])**2)
        x=(self.u_constant*S[0]*(S[1]-M[1]))/d**2
        y=(self.u_constant*S[0]*(S[2]-M[2]))/d**2
        z=(self.u_constant*S[0]*(S[3]-M[3]))/d**2
        O.append(x)
        O.append(y)
        O.append(z)
        return O
    
    def collision_log(self,entry,brakeforce):
        from_pos=[self.bodies[n].filelist[0] for n in range(len(self.bodies))].index(entry.getFromNodePath().getParent())
        into_pos=[self.bodies[n].filelist[0] for n in range(len(self.bodies))].index(entry.getIntoNodePath().getParent()) #find the nodepath in the list
        f_radius=sum(self.bodies[from_pos].scale)*self.u_radius/3
        i_radius=sum(self.bodies[into_pos].scale)*self.u_radius/3
        if max(f_radius,i_radius)==f_radius:
            inverted=True
            into_pos,from_pos=from_pos,into_pos
        else:
            inverted=False # currently useless
        brakeforce[from_pos]=self.bodies[from_pos].brakeforce # get the force given in the data list
        # those are the two positions of the nodepaths, now we need to know which one is bigger, in order to obtain the fusion effect
        # from_pos is the smaller body, into_pos is the bigger one
        self.collision_gfx(self.momentum_transfer(from_pos,into_pos,entry,inverted),f_radius,i_radius) #some useless data remains from version 0.9
        return brakeforce
    
    def momentum_transfer(self,f_pos,i_pos,entry,inverted):
        if self.debug:
            print("colliding") # debug, makes the game laggy (only activated when the self.debug var is on)
        interior = entry.getInteriorPoint(self.Game_state.root_node) # default
        surface = entry.getSurfacePoint(self.Game_state.root_node)
        if self.debug:
            print((interior - surface).length()) # debug, doesn't slow the game down too much so I haven't removed it


        if (interior - surface).length() >= self.u_radius*2*sum(self.bodies[f_pos].scale)/3: # this is the body deletion routine
            if self.state[2]==self.collision_solids[f_pos].NodePath:
                self.state[1]='free'
                self.state[2]=None

            # Lighting
            if self.bodies[f_pos].is_lightSource:
                self.Game_state.root_node.clearLight(self.light_Mngr[2*f_pos][1])
                self.Game_state.root_node.clearLight(self.light_Mngr[2*f_pos][1])
                self.filters.delVolumetricLighting() #temp
            
            self.ctrav.remove_collider(self.collision_solids[f_pos].NodePath)
            self.bodies[f_pos].delete_body()
            
            self.bodies[i_pos].scale[0]*=(self.bodies[i_pos].mass+self.bodies[f_pos].mass)/self.bodies[i_pos].mass
            self.bodies[i_pos].scale[1]*=(self.bodies[i_pos].mass+self.bodies[f_pos].mass)/self.bodies[i_pos].mass
            self.bodies[i_pos].scale[2]*=(self.bodies[i_pos].mass+self.bodies[f_pos].mass)/self.bodies[i_pos].mass
            self.bodies[i_pos].mass+=self.bodies[f_pos].mass
            
            # particle deletion

            self.particle.deactivate(self.collision_solids[f_pos].NodePath.getParent())
            self.particle.deactivate(self.collision_solids[i_pos].NodePath.getParent())
                
            # scale updating ()
            ''' temporarly removed
            for c in range(0,len(self.bodies[i_pos].filelist),2):
                self.bodies[i_pos].filelist[c].setScale(tuple(self.bodies[i_pos].scale))
            '''
            # deleting the destroyed planet's data
            self.bodies=self.bodies[:f_pos]+self.bodies[f_pos+1:len(self.bodies)]
            self.collision_solids=self.collision_solids[:f_pos]+self.collision_solids[f_pos+1:len(self.collision_solids)]
            # update the light list
            self.light_Mngr=self.light_Mngr[:2*f_pos]+self.light_Mngr[2*f_pos+2:len(self.light_Mngr)]
            
            
            # just a quick test
            if self.debug:
                self.ctrav.showCollisions(self.Game_state.root_node) 
            if self.debug:
                print("planet destroyed")
        return interior,surface # used for the collision gfx calculations
    
    def printScene(self):  #debug
        file=open("scenegraph.txt","a")
        ls = LineStream()
        self.Game_state.root_node.ls(ls)
        while ls.isTextAvailable():
            file.write(ls.getLine())
            file.write("\n")
        file.write("\n")
        file.write("END\n")
        file.write("\n")
        file.close()
    
    def Sound_Mngr(self,task):
        if self.current_song.length()-self.current_song.getTime()==0: #could have just used not()
            self.current_playing=random.choice(list(range(0,self.current_playing))+list(range(self.current_playing+1,len(self.sounds))))
            self.current_song=self.loader.loadSfx(self.sounds[self.current_playing])
            self.current_song.play()
            print(self.current_playing)
        return task.cont

    def collision_gfx(self,points,Rf,Ri): # collision animation calculations
        # section size calculation
        # we know the depth of penetration (no silly jokes please), which allows us, knowing the radius of each body, 
        # to calculate the radius of the section (I've got no idea how to say that in correct english)
        # the display of the particles all over this circle will be a piece of cake (at least I hope so)  - edit - it wasn't
        # see documents in the screenshot folder for more informations about the maths
        '''
        interior,surface=points[0],points[1]
        p=(interior - surface).length()
        p2=(p**2-2*Ri*p)/(2*Ri-2*p-2*Rf)
        p1=p-p2
        ''' #currently useless
        self.update_particle_pos()
        # now we know everything about our impact section (the circle that defines the contact between the two bodies)
        # we just have to find the coord of the circle's center: we will take the surfacepoint impact point
         
        return 0

    def create_crater(self): # see project for more informations
        return None

    def toggle_pause(self):
        self.toggle_particles() # pause the particles
        temp=['paused','running']
        self.state[0]=temp[self.state[0]==temp[0]] # switches between paused and running
        self.iteration=0
        if self.state[0]=='paused':
            # discord rpc updating
            try: 
                RPC.update(state="Version: 0.11", details="In the menus",large_image="logo",small_image=None)
            except: pass
            self.handle_menu(self.iteration)
        else:
            # discord RPC updating
            try: 
                RPC.update(state="Version: 0.11", details="In a simulation",large_image="logo",small_image=None)
            except: pass
            
            self.filters.del_blur_sharpen()
            self.filters.set_gamma_adjust(1)
            # make the mouse invisible
            self.hidden_mouse=True
            wp = WindowProperties()
            wp.setCursorHidden(self.hidden_mouse)
            # set the mouse pos to 0 
            self.center_mouse()

            self.win.requestProperties(wp)
            for u in self.paused_menu_text:
                u.hide()
        return None
    
    def handle_menu(self,iteration):
        if not iteration:
            self.accept('escape',self.toggle_pause)
            self.draw_menu()
            # make the mouse visible
            self.hidden_mouse=False
            wp = WindowProperties()
            wp.setCursorHidden(self.hidden_mouse)
            self.win.requestProperties(wp)
        else:
            a=1 # indentation (temporary)
            #put your mouse detection stuff here
            # menu stuff
            # menu stuff
            # please use directGui for that purpose (better rendering performances)
            # the menu doesn't actually work, as the whole clicking reaction routine is not implemented
        return None
    
    def draw_menu(self):
        self.filters.setBlurSharpen(amount=0)
        self.filters.set_gamma_adjust(1.7)
        for u in self.paused_menu_text:
                u.show()
        return None
    
    def show_credits(self):
        print("created by l3alr0g, zudo and Fang (at least this part) --> I'll do something better later")
        return None
        
    def system_break(self):
        # place your data saving routines here
        print("system exit successful, data saved")
        print("executing sys.exit()")
        print("out: done")
        sys.exit(0)
        return None
    
    def handle_scrolling(self,up): # up is a boolean: up=True means up, up=False means down
        if up and self.state[0]=='running':
            if self.state[1]=='linked':
                self.zoom_distance*=0.95
            else:
                self.camera_delta*=1.1
        elif not up and self.state[0]=='running':
            if self.state[1]=='linked':
                self.zoom_distance/=0.95
            else:
                self.camera_delta/=1.1
        return None

    
    def rotate_camera(self):
        self.camera.setHpr(tuple(self.cam_Hpr))
        return None
    
    def move_camera(self,tow,pressed): # tow stands for towards, pressed is a boolean which indicates the state of the key
        if pressed:
            self.keymap[2*tow+1]=1
            self.state[1]='free'
            #print('free mode on')
            self.state[2]=None
        else:
            self.keymap[2*tow+1]=0
        
        if self.keymap[2*tow+1]:
            phi,alpha,theta,delta,zoom=self.cam_Hpr[0]*pi/180,self.cam_Hpr[1]*pi/180,self.cam_Hpr[2]*pi/180,self.camera_delta,self.zoom_distance
            if self.keymap[2*tow]=='q':
                if self.state[1]=='free':
                    self.camera_pos=[self.camera_pos[0]-cos(phi)*cos(theta)*delta,self.camera_pos[1]-sin(phi)*cos(theta)*delta,self.camera_pos[2]+sin(theta)*delta] # moving the camera
            if self.keymap[2*tow]=='z':
                if self.state[1]=='free':
                    self.camera_pos=[self.camera_pos[0]-sin(phi)*cos(alpha)*delta,self.camera_pos[1]+cos(phi)*cos(alpha)*delta,self.camera_pos[2]+sin(alpha)*delta]
            if self.keymap[2*tow]=='s':
                if self.state[1]=='free':
                    self.camera_pos=[self.camera_pos[0]+sin(phi)*cos(alpha)*delta,self.camera_pos[1]-cos(phi)*cos(alpha)*delta,self.camera_pos[2]-sin(alpha)*delta]
            if self.keymap[2*tow]=='d':
                if self.state[1]=='free':
                    self.camera_pos=[self.camera_pos[0]+cos(phi)*cos(theta)*delta,self.camera_pos[1]+sin(phi)*cos(theta)*delta,self.camera_pos[2]-sin(theta)*delta]
            if self.keymap[2*tow]=='a':
                self.cam_Hpr[2]-=1
            if self.keymap[2*tow]=='e':
                self.cam_Hpr[2]+=1
        return None
    
    def mouse_check(self,task): # gets the mouse's coordinates
        mwn = self.mouseWatcherNode
        if mwn.hasMouse():
            x,y=mwn.getMouseX(),mwn.getMouseY()
            #print(x,y) # debug
            # focus_point coordinates modifier code here:
            if self.state==['running','free',None]:
                self.cam_Hpr[0]-=x*self.sensitivity_x # the - fixes a bug I can't solve
                # sensitivity is a coefficient used for mouse displacement routines
                self.cam_Hpr[1]+=y*self.sensitivity_y # those formulas do not work when theta (self.cam_Hpr[2]) changes 
                self.rotate_camera()
                self.center_mouse()
            elif self.state[0]=='running' and self.state[1]=='linked':
                self.cam_Hpr[0]-=x*self.sensitivity_x
                self.cam_Hpr[1]-=y*self.sensitivity_y
                self.rotate_camera()
                self.center_mouse()
            '''
            if self.debug:
                print(self.cam_Hpr,self.camera_pos) # debug
        '''
        return task.cont

    def center_mouse(self):
        self.win.movePointer(0,
          int(self.win.getProperties().getXSize() / 2),
          int(self.win.getProperties().getYSize() / 2)) # move mouse back to center --> careful ! this makes the delta calculation code buggy
    
    def handle_select(self,is_clicked): 
        if is_clicked and self.watched!=None:
            self.state[1]='linked' # toggle following mode
            self.state[2]=self.watched
            print('linked mode on, focusing: ',self.watched)
        #else: # do nothing actually
        return None
    
    def update_particle_pos(self): # harder than I thought
        for x in range(len(self.particle.particle_list)):
            a=[i.getIntoNodePath() for i in self.queue.getEntries()].index(self.particle.particle_list[x][1]) # finding the intonodepath inside self.queue.getEntries()
            self.particle.particle_list[x][0].setPos(self.queue.getEntries()[a].getSurfacePoint(self.Game_state.root_node)) # all particles are being displaced to the position of the surface impact point
            tempvar=self.queue.getEntries()[a].getSurfacePoint(self.Game_state.root_node) - self.queue.getEntries()[a].getIntoNodePath().getParent().getPos()
            H,P,R=-atan(tempvar[0]/tempvar[1])*180/pi+180,(-atan(tempvar[2]/tempvar[1])+pi/2)*180/pi,0
            self.particle.particle_list[x][0].setHpr(H,P,R)
        # self.queue.getEntries()[a].getIntoNodePath().getParent().getPos()
        # +self.queue.getEntries()[a].getSurfacePoint(self.queue.getEntries()[a].getIntoNodePath())  
        
        return None
    
    def time_change(self,income): # income is a boolean, True means speed up, False means speed down
        if income:
            self.timescale*=1.2
        else:
            self.timescale*=0.80
        return None
    
    def not_implemented_yet(self): # comes with self.follow function
        self.sign=OnscreenImage(image=str(MAINDIR)+"/Engine/not_implemented_yet.png",pos=(0,0,0),scale=(0.5,0.5,0.5))  # scale is useless: already at scale (the pic is square shaped)
        self.sign.setTransparency(TransparencyAttrib.MAlpha)
        self.accept("escape",self.follow)
        self.quit_button['state']=DGG.DISABLED
        self.settings_button['state']=DGG.DISABLED
        self.start_button['state']=DGG.DISABLED
        return None
    
    def follow(self): # dependencies of the not_implemented_yet function
        self.ignore("escape")
        self.sign.destroy()
        self.quit_button['state']=DGG.NORMAL
        self.settings_button['state']=DGG.NORMAL
        self.start_button['state']=DGG.NORMAL
        return None

    def easter_egg(self):
        return "please be patient, our hens are working on it" # I am not responsible for the bad quality of my humor
    
    def ingame_back_to_menu(self): # large name, I know, I had no ideas
        self.filters.set_gamma_adjust(1)
        for u in self.paused_menu_text:
            u.hide()
        self.filters.del_blur_sharpen()
        self.Game_state.cleanup()
        # we have to delete all the taskManager routines we implemented during the simulation
        # here comes the whole stuff:
        self.taskMgr.remove('mousePositionTask')
        self.taskMgr.remove('frameUpdateTask')
        self.taskMgr.remove('MusicHandle')
        self.taskMgr.remove('cameraPosition')
        # end of task manager stuff
        self.stored_collisions=[]
        self.watched=None
        self.state=['paused','free',None]
        self.iteration=0

        self.filters.delVolumetricLighting() # temporary, as I have to implement multiple light source handling

        # music 
        self.current_song.stop()
        
        self.menu()
        return None
Ejemplo n.º 12
0
class MyApp(ShowBase):

	def __init__(self):
		ShowBase.__init__(self)

		self.useAdvancedVisualEffects =\
			ConfigVariableBool("use-advanced-visual-effects", True) and\
			base.win.getGsg().getSupportsBasicShaders() and\
			base.win.getGsg().getSupportsGlsl() and\
			base.win.getGsg().getSupportsDepthTexture()

		self.debug = DirectNotify().newCategory("Debug")

		self.phoneState = PhoneState(self)
		self.setupFilters()
		self.setupModels()
		self.setupKeyboardControl()
		self.camera.setPos(0, 0, 2)
		self.setupMouseControl()
		self.phoneState.request("Hidden")

	def setupFilters(self):
		if (self.useAdvancedVisualEffects):
			self.filters = CommonFilters(self.win, self.cam)
			self.filters.setBloom()

	def setupKeyboardControl(self):
		self.accept("escape", sys.exit)

	def setupMouseControl(self):
		self.disableMouse()

		self.mousex = 0
		self.mousey = 0
		self.last = 0
		self.mousebtn = [0,0,0]

		self.accept("mouse1", self.setMouseBtn, [0, 1])
		self.accept("mouse1-up", self.setMouseBtn, [0, 0])

		self.taskMgr.add(self.controlCamera, "cameraTask")

	def setupModels(self):
		self.setupLights()
		self.loadSky()
		self.loadTerrain()
		self.setupBuildings()
		self.phoneState.setupPhone()

	def setupLights(self):
		self.sunLight = self.render.attachNewNode(DirectionalLight("sunLight"))
		self.sunLight.setColor(Vec4(0.8, 0.8, 0.8, 1))
		self.sunLight.node().getLens().setFilmSize(128, 64)
		self.sunLight.node().getLens().setNearFar(20,2000)
		self.sunLight.setPos(60, 30, 50)
		self.sunLight.lookAt(0, 0, 0)
		self.render.setLight(self.sunLight)
#		self.sunLight.node().showFrustum()
		if self.useAdvancedVisualEffects:
			self.sunLight.node().setShadowCaster(True, 256, 256)
			self.render.setShaderAuto()

		self.ambientLight = self.render.attachNewNode(AmbientLight("ambientLight"))
		self.ambientLight.node().setColor(Vec4(0.2, 0.2, 0.2, 1))
		self.render.setLight(self.ambientLight)

	def loadSky(self):
		self.sky = self.loader.loadModel("models/sky")
		self.sky.reparentTo(self.camera)
		self.sky.setScale(base.camLens.getNear() * 1.1)
		self.sky.setBin("background", 0)
		self.sky.setDepthWrite(False)
		self.sky.setCompass()
		self.sky.setLightOff()

	def loadTerrain(self):
		self.terrain = self.loader.loadModel("models/terrain")
		self.terrain.reparentTo(self.render)
		self.teapot = self.loader.loadModel("teapot")

	def setupBuildings(self):
		# Load building prototypes
		self.buildingPadPrototype = self.loader.loadModel("models/building_pad")
		self.policeBuildingPrototype = self.loader.loadModel("models/police_building")
		self.tribunalPrototype = self.loader.loadModel("models/tribunal")
		self.officeBuildingPrototype = self.loader.loadModel("models/office_building")
		self.housePrototype = self.loader.loadModel("models/House/CasaSimples")
		self.housePrototype.setPos(5, 5, 2.1)

		self.buildCity()

	def buildCity(self):
		# Define city blueprint
		city = [
			"PSOSHS_",
			"SSSSSSS",
			"OSHHHHH",
			"_SSSSSS",
			"_SHHHHH",
			"_SSSSSS",
			"_SHHHHH",
			"_SSSSSS",
			"_SHHHHH"
		]
		blockSize = 10
		cityWESize = len(city[0]) * blockSize
		cityNSSize = len(city) * blockSize
		self.maxX = cityWESize / 2.0
		self.maxY = cityNSSize / 2.0
		buildingOutline = LineSegs("building")

		buildingSize = 8
		buildingPadding = 1
		buildingOutline.setColor(0, 0, 0, 1)
		buildingOutline.moveTo(buildingPadding, buildingPadding, 0)
		buildingOutline.drawTo(buildingPadding + buildingSize, buildingPadding, 0)
		buildingOutline.drawTo(buildingPadding + buildingSize, buildingPadding + buildingSize, 0)
		buildingOutline.drawTo(buildingPadding, buildingPadding + buildingSize, 0)
		buildingOutline.drawTo(buildingPadding, buildingPadding, 0)
		buildingOutlinePrototype = NodePath(buildingOutline.create())

		# Create buildings from city blueprint
		for rowIndex, row in enumerate(city):
			for columnIndex, buildingType in enumerate(row):
				# Get building data from city blueprint
				buildingInstanceName, buildingPrototype = self.buildingInstanceNameAndPrototypeFromType(buildingType)

				if (not (buildingInstanceName is None or buildingPrototype is None)):
					# Compute building position
					buildingX, buildingY, buildingZ = columnIndex * blockSize - cityWESize / 2, cityNSSize / 2 - (rowIndex + 1) * blockSize, 0

					# Create building pad
					buildingPadInstance = self.render.attachNewNode("buildingPadInstance")
					buildingPadInstance.setPos(buildingX, buildingY, buildingZ)
					self.buildingPadPrototype.instanceTo(buildingPadInstance)

					# Create building
					buildingInstance = self.render.attachNewNode(buildingInstanceName)
					buildingInstance.setPos(buildingX, buildingY, buildingZ)
					buildingPrototype.instanceTo(buildingInstance)

					# Create building outline in minimap
					buildingOutlineInstance = self.phoneState.minimap.attachNewNode("buildingOutline")
					buildingOutlineInstance.setPos(buildingX, buildingY, buildingZ)
					buildingOutlinePrototype.instanceTo(buildingOutlineInstance)

	def setMouseBtn(self, btn, value):
		self.mousebtn[btn] = value

		if (btn == 0 and value == 1 and self.phoneState.state == "Center"):
			phoneDisplayRegionCenterX = self.win.getXSize() * (self.phoneState.phoneDisplayRegion.getLeft() + self.phoneState.phoneDisplayRegion.getRight()) / 2.0
			phoneDisplayRegionCenterY = self.win.getYSize() * (1.0 - (self.phoneState.phoneDisplayRegion.getBottom() + self.phoneState.phoneDisplayRegion.getTop()) / 2.0)
			mouse = self.win.getPointer(0)
			s = 2 ** self.phoneState.minimapZoom
			x = clamp(self.camera.getX() + (mouse.getX() - phoneDisplayRegionCenterX) / s, -self.maxX, self.maxX)
			y = clamp(self.camera.getY() + (phoneDisplayRegionCenterY - mouse.getY()) / s, -self.maxY, self.maxY)
			previousHeading = self.camera.getH() % 360.0
			heading = (rad2Deg(atan2(y - self.camera.getY(), x - camera.getX())) - 90.0) % 360.0

			if (180.0 < abs(heading - previousHeading)):
				if (previousHeading < heading):
					heading -= 360.0
				else:
					heading += 360.0

			self.camera.setH(previousHeading)
			self.phoneState.orientationTriangle.setH(previousHeading)

			Parallel(
				self.camera.posInterval(0.5, Vec3(x, y, self.camera.getZ())),
				self.phoneState.minimapCamera.posInterval(0.5, Vec3(x, y, self.phoneState.minimapCamera.getZ())),
				self.phoneState.orientationTriangle.posInterval(0.5, Vec3(x, y, self.phoneState.orientationTriangle.getZ())),
				self.camera.hprInterval(0.5, Vec3(heading, self.camera.getP(), self.camera.getR())),
				self.phoneState.orientationTriangle.hprInterval(0.5, Vec3(heading, self.phoneState.orientationTriangle.getP(), self.phoneState.orientationTriangle.getR()))
			).start()

	def buildingInstanceNameAndPrototypeFromType(self, buildingType):
		return {
			'S' : ( None, None ),
			'P' : ( "policeBuildingInstance", self.policeBuildingPrototype ),
			'T' : ( "tribunalInstance", self.tribunalPrototype ),
			'O' : ( "officeBuildingInstance", self.officeBuildingPrototype ),
			'H' : ( "houseInstance", self.housePrototype ),
		}.get(buildingType, ( None, None ))
	
	def setBlurSharpen(self, amount):
		if (not self.useAdvancedVisualEffects):
			return

		if (amount == 1.0):
			self.filters.delBlurSharpen()
		else:
			self.filters.setBlurSharpen(amount=amount)

	def controlCamera(self, task):
		if (self.phoneState.state == "Center"):
			return Task.cont

		# figure out how much the mouse has moved (in pixels)
		mouse = self.win.getPointer(0)
		x = mouse.getX()
		y = mouse.getY()
		windowCenterX = self.win.getXSize() / 2
		windowCenterY = self.win.getYSize() / 2
		heading = self.camera.getH()
		pitch = self.camera.getP()

		if self.win.movePointer(0, windowCenterX, windowCenterY):
			heading -= (x - windowCenterX) * 0.2
			pitch = clamp(pitch - (y - windowCenterY) * 0.2, -45, 45)

		self.camera.setHpr(heading, pitch, 0)

		elapsed = task.time - self.last

		if (self.last == 0):
			elapsed = 0

		if (self.mousebtn[0]):
			direction = self.camera.getMat().getRow3(1)
			self.camera.setPos(self.camera.getPos() + direction * elapsed*30)

		clampX(self.camera, -self.maxX, self.maxX)
		clampY(self.camera, -self.maxY, self.maxY)
		self.camera.setZ(2)

		self.phoneState.minimapCamera.setX(self.camera.getX())
		self.phoneState.minimapCamera.setY(self.camera.getY())

		self.phoneState.orientationTriangle.setX(self.camera.getX())
		self.phoneState.orientationTriangle.setY(self.camera.getY())
		self.phoneState.orientationTriangle.setHpr(heading, -90, 0)

		self.last = task.time

		return Task.cont