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)
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 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
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)
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
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)
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())
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)
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
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