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 BattleTank(object): BULLET_SPEED = 400 SPEED = 40 TURN_SPEED = 25 BULLET_INDEX = 0 def __init__(self, framework, *args, **kwargs): self.bullets = [] self.environment = {} self.colliders = {} self.task_manager = [] self.bullet_colliders = [] self.remove_bullet_indices = [] super().__init__(*args, **kwargs) self.f = framework self.controller = Controller(self.f.accept, self) self.f.set_background_color(0.2, 0.2, 0.2, 0.6) if settings.ALLOW_FILTERS: self.filter = CommonFilters(self.f.win, self.f.cam) self.filter.set_bloom(mintrigger=0.99, size="small") # self.filter.set_blur_sharpen(amount=0.99) self.base_node = NodePath("base") self.base_node.reparent_to(self.f.render) # floor self.plane = self.create_model(settings.egg / "plane", self.base_node, "ground-zero", color=(1, 1, 1, 1)) self.create_model(settings.egg / "house_01", self.base_node, "house-01", position=(20, 50, 0), scale=1.5) self.create_model(settings.egg / "house_02", self.base_node, "house-02", position=(-50, 10, 0), scale=1.5) self.sun_light_model = self.create_model("models/misc/sphere", self.base_node, "sun", position=(0, -150, 250), scale=5.0, color=(1, 1, 1, 1), _store=False) tank = self.create_model(settings.egg / "tank", self.base_node, "player", scale=3.0, position=(0.0, 0.0, 1e-3)) gun = self.create_model("models/misc/sphere", tank, "player-gun", position=(0.0, 4.5, 1.755), scale=0.1, _store=False) self.tank = Tank(tank, gun, framework=self.f) self._tank = self.tank.tank enemy = self.create_model(settings.egg / "enemy", self.base_node, "enemy", scale=0.8, position=(-80.0, 80.0, 1e-3)) self.enemy = EnemyTank(enemy, None, framework=self.f) # point light for shadows sun_light = PointLight("sun-light") sun_light.set_color((0.4, 0.4, 0.4, 1)) self.sun_light_node = self.base_node.attach_new_node(sun_light) self.sun_light_node.reparent_to(self.sun_light_model) self.redistribute_light(self.sun_light_node) self.plane.set_light(self.sun_light_node) # daylight if settings.ALLOW_DAYLIGHT: day_light = DirectionalLight("day-light") day_light.set_color((1, 1, 1, 1)) self.daylight_node = self.f.render.attach_new_node(day_light) self.daylight_node.set_p(-20) self.daylight_node.set_h(10) self.daylight_node.reparent_to(self.sun_light_model) self.redistribute_light(self.daylight_node) # shadows if settings.ALLOW_SHADOWS: sun_light.set_shadow_caster(True, 2048, 2048) self.f.render.set_shader_auto() # 3rd person camera lock if settings.TRD_PERSON_CAM: self.f.camera.reparent_to(self.tank.tank) self.f.cam.set_pos(0, -25, 10) self.f.cam.lookAt(self.tank.tank) self.f.cam.setP(self.f.camera.getP() - 20) if settings.ALLOW_AMBIENT: amblight = AmbientLight("ambient-light") amblight.set_color((0.2, 0.2, 0.2, 1)) self.amblight_node = self.f.render.attach_new_node(amblight) self.redistribute_light(self.amblight_node) # colliders tank_collider = self.environment["player"].attachNewNode( CollisionNode('player-collider')) tank_collider.node().addSolid( CollisionBox(Point3(-1.5, -3, 0), Point3(1.5, 3, 2.25))) self.colliders['player-collider'] = tank_collider enemy_collider = self.environment["enemy"].attachNewNode( CollisionNode('enemy-collider')) enemy_collider.node().addSolid( CollisionBox(Point3(-6.5, -13.5, 0), Point3(6.5, 13, 10))) self.colliders['enemy-collider'] = enemy_collider house_01_collider = self.environment["house-01"].attachNewNode( CollisionNode('house-01-collider')) house_01_collider.node().addSolid( CollisionBox(Point3(0, 2, 0), Point3(14.5, 16, 17))) self.colliders['house-01'] = house_01_collider house_02_collider = self.environment["house-02"].attachNewNode( CollisionNode('house-02-collider')) house_02_collider.node().addSolid( CollisionBox(Point3(0, 0, 0), Point3(21, 27, 37))) self.colliders['house-02'] = house_02_collider floor_collider = self.environment["ground-zero"].attachNewNode( CollisionNode('ground-zero-collider')) floor_collider.node().addSolid( CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))) self.colliders['ground-zero-collider'] = floor_collider self.f.pusher.addCollider(tank_collider, self.environment["player"]) self.f.cTrav.addCollider(tank_collider, self.f.pusher) # show.hide all colliders if settings.SHOW_COLLIDERS: for key, value in self.colliders.items(): logger.info(f"collider for {key} is visible") value.show() self.f.cTrav.showCollisions(self.f.render) # uppdate self.f.cHandler.addInPattern('%fn') self.f.accept('bullet-collider', self.handle_collision) self.task_manager.append(self.f.task_mgr.add(self.update)) self.task_manager.append(self.f.task_mgr.add(self.update_bullets)) def create_model(self, from_path, reparent_to, uid, name=None, position=None, scale=None, color=None, _store=True): if uid in self.environment and _store: raise KeyError(f"Value {uid} of uid already exists.") position = position or (0, 0, 0) obj = self.f.loader.loadModel(from_path) obj.reparent_to(reparent_to) name = name or uid obj.set_name(name) if scale: obj.set_scale(scale) if color: obj.set_color(color) obj.set_pos(*position) if _store: self.environment[uid] = obj return obj def redistribute_light(self, light_node): for key, value in self.environment.items(): logger.info(f"seting light {light_node} for model {key}") value.set_light(light_node) def object_ids_to_indices(self): return [ _ for _, b_collider in enumerate(self.bullet_colliders) if b_collider.node().this in self.remove_bullet_indices ] def update_bullets(self, task: Task): if settings.SHOW_COLLIDERS: for b_collider in self.bullet_colliders: b_collider.show() dt = globalClock.getDt() rmi = [] + self.object_ids_to_indices() for idx, entry in enumerate(self.bullets): bullet, heading = entry bullet_pos = bullet.get_pos() if abs(np.sqrt(bullet_pos.y**2 + bullet_pos.x**2)) > 300: rmi.append(idx) continue dx = (self.BULLET_SPEED * dt) * np.cos(np.radians(heading)) dy = (self.BULLET_SPEED * dt) * np.sin(np.radians(heading)) bullet_pos.y += dy bullet_pos.x += dx bullet.set_fluid_pos(bullet_pos) for idx in rmi: self.bullets[idx][0].removeNode() self.bullet_colliders[idx].node().clearSolids() self.f.cTrav.removeCollider(self.bullet_colliders[idx]) pass self.bullet_colliders = [ b for i, b in enumerate(self.bullet_colliders) if i not in rmi ] self.bullets = [b for i, b in enumerate(self.bullets) if i not in rmi] # print(f"available {len(self.bullet_colliders)} colliders and {len(self.bullets)} bullets") return task.cont def handle_collision(self, entry): if entry.into_node.name == "enemy-collider": self.enemy.hit() self.remove_bullet_indices.append(entry.from_node.this) def update(self, task: Task): if self.f.state == settings.IN_MENU_STATE: return task.cont dt, ft = globalClock.getDt(), globalClock.getFrameTime() tank_heading, tank_position = self.tank.tank.get_h( ), self.tank.tank.get_pos() # # self.sun.set_p(self.sun.get_p() - (dt * 40)) # # self.sun.set_h(self.sun.get_h() - (dt * 20)) # self.tank.hit() z_pos = 0.01 if settings.DISABLE_Z_MOV else tank_position.z self.tank.tank.set_fluid_pos(tank_position.x, tank_position.y, z_pos) self.tank.handle_sfx() if self.enemy.hp <= 0 and self.enemy.is_alive: self.enemy.tank.removeNode() del self.environment["enemy"] self.enemy.is_alive = False print("defeated") if KEY_MAP["up"]: tank_position.z += self.SPEED * dt self._tank.set_fluid_pos(tank_position) if KEY_MAP["down"]: tank_position.z -= self.SPEED * dt self._tank.set_fluid_pos(tank_position) if KEY_MAP["q"]: tank_position.x -= self.SPEED * dt self._tank.set_fluid_pos(tank_position) if KEY_MAP["e"]: tank_position.x += self.SPEED * dt self._tank.set_fluid_pos(tank_position) if KEY_MAP["w"]: dx = (self.SPEED * dt) * np.cos(np.radians(tank_heading + 90)) dy = (self.SPEED * dt) * np.sin(np.radians(tank_heading + 90)) tank_position.y, tank_position.x = tank_position.y + dy, tank_position.x + dx self._tank.set_fluid_pos(tank_position) if KEY_MAP["s"]: dx = -(self.SPEED * dt) * np.cos(np.radians(tank_heading + 90)) dy = -(self.SPEED * dt) * np.sin(np.radians(tank_heading + 90)) tank_position.y, tank_position.x = tank_position.y + dy, tank_position.x + dx self._tank.set_fluid_pos(tank_position) if KEY_MAP["d"] and not KEY_MAP["s"]: tank_heading -= self.TURN_SPEED * dt * 2 self._tank.set_h(tank_heading) if KEY_MAP["a"] and not KEY_MAP["s"]: tank_heading += self.TURN_SPEED * dt * 2 self._tank.set_h(tank_heading) if KEY_MAP["d"] and KEY_MAP["s"]: tank_heading += self.TURN_SPEED * dt * 2 self._tank.set_h(tank_heading) if KEY_MAP["a"] and KEY_MAP["s"]: tank_heading -= self.TURN_SPEED * dt * 2 self._tank.set_h(tank_heading) return task.cont def stop(self): pass def __del__(self): logger.info("game session destroyed")
def __init__(self): load_prc_file_data( "", """ win-size 1680 1050 window-title P3D Space Tech Demo Skybox Test 1 show-frame-rate-meter #t framebuffer-multisample 1 multisamples 4 view-frustum-cull 0 textures-power-2 none hardware-animated-vertices #t gl-depth-zero-to-one true clock-frame-rate 60 interpolate-frames 1 cursor-hidden #t fullscreen #f """) # Initialize the showbase super().__init__() gltf.patch_loader(self.loader) props = WindowProperties() props.set_mouse_mode(WindowProperties.M_relative) base.win.request_properties(props) base.set_background_color(0.5, 0.5, 0.8) self.camLens.set_fov(80) self.camLens.set_near_far(0.01, 90000) self.camLens.set_focal_length(7) self.camera.set_pos(-300, -300, 0) # ConfigVariableManager.getGlobalPtr().listVariables() # point light generator for x in range(0, 3): plight_1 = PointLight('plight') # add plight props here plight_1_node = self.render.attach_new_node(plight_1) # group the lights close to each other to create a sun effect plight_1_node.set_pos(random.uniform(-21, -20), random.uniform(-21, -20), random.uniform(20, 21)) self.render.set_light(plight_1_node) # point light for volumetric lighting filter plight_1 = PointLight('plight') # add plight props here plight_1_node = self.render.attach_new_node(plight_1) # group the lights close to each other to create a sun effect plight_1_node.set_pos(random.uniform(-21, -20), random.uniform(-21, -20), random.uniform(20, 21)) self.render.set_light(plight_1_node) scene_filters = CommonFilters(base.win, base.cam) scene_filters.set_bloom() scene_filters.set_high_dynamic_range() scene_filters.set_exposure_adjust(0.6) scene_filters.set_gamma_adjust(1.1) # scene_filters.set_volumetric_lighting(plight_1_node, 32, 0.5, 0.7, 0.1) # scene_filters.set_blur_sharpen(0.9) # scene_filters.set_ambient_occlusion(32, 0.05, 2.0, 0.01, 0.000002) self.accept("f3", self.toggle_wireframe) self.accept("escape", sys.exit, [0]) exponential_fog = Fog('world_fog') exponential_fog.set_color(0.6, 0.7, 0.7) # this is a very low fog value, set it higher for a greater effect exponential_fog.set_exp_density(0.00009) # self.render.set_fog(exponential_fog) self.game_start = 0 skybox = self.loader.load_model('skyboxes/40k_test.gltf') skybox.reparent_to(self.camera) skybox.setCompass() skybox.setBin("background", 1) skybox.setDepthWrite(False) aster_bool = False # add some asteroids for x in range(100): ran_pos = Vec3(random.uniform(-300, 300), random.uniform(-300, 300), random.uniform(-300, 300)) if not aster_bool: asteroid = self.loader.load_model('models/asteroid_1.gltf') aster_bool = True if aster_bool: asteroid = self.loader.load_model('models/asteroid_2.gltf') aster_bool = False asteroid.reparent_to(self.render) asteroid.set_pos(ran_pos) asteroid.set_scale(random.uniform(0.1, 10)) a_pos = asteroid.get_pos() ran_inter = random.uniform(-20, 20) ran_h = random.uniform(-180, 180) asteroid.set_h(ran_h) a_rotate = LerpPosHprInterval(asteroid, 100, (a_pos[0] + ran_inter, a_pos[1] + ran_inter, a_pos[2] + ran_inter), (360, 360, 0)).loop() # load the scene shader scene_shader = Shader.load(Shader.SL_GLSL, "shaders/simplepbr_vert_mod_1.vert", "shaders/simplepbr_frag_mod_1.frag") self.render.set_shader(scene_shader) self.render.set_antialias(AntialiasAttrib.MMultisample) scene_shader = ShaderAttrib.make(scene_shader) scene_shader = scene_shader.setFlag(ShaderAttrib.F_hardware_skinning, True) # directly make a text node to display text text_2 = TextNode('text_2_node') text_2.set_text("P3D Space Tech Demo Skybox Test") text_2_node = self.aspect2d.attach_new_node(text_2) text_2_node.set_scale(0.04) text_2_node.set_pos(-1.4, 0, 0.8) # import font and set pixels per unit font quality nunito_font = self.loader.load_font('fonts/Nunito/Nunito-Light.ttf') nunito_font.set_pixels_per_unit(100) nunito_font.set_page_size(512, 512) # apply font text_2.set_font(nunito_font) text_2.set_text_color(0.1, 0.1, 0.1, 1) # 3D player movement system begins self.keyMap = { "left": 0, "right": 0, "forward": 0, "backward": 0, "run": 0, "jump": 0, "up": 0, "down": 0 } def setKey(key, value): self.keyMap[key] = value # define button map self.accept("a", setKey, ["left", 1]) self.accept("a-up", setKey, ["left", 0]) self.accept("d", setKey, ["right", 1]) self.accept("d-up", setKey, ["right", 0]) self.accept("w", setKey, ["forward", 1]) self.accept("w-up", setKey, ["forward", 0]) self.accept("s", setKey, ["backward", 1]) self.accept("s-up", setKey, ["backward", 0]) self.accept("lshift", setKey, ["up", 1]) self.accept("lshift-up", setKey, ["up", 0]) self.accept("lcontrol", setKey, ["down", 1]) self.accept("lcontrol-up", setKey, ["down", 0]) self.accept("space", setKey, ["jump", 1]) self.accept("space-up", setKey, ["jump", 0]) # disable mouse self.disable_mouse() # the player movement speed self.inc_var = 1 self.max_speed_inc = 0.02 self.max_abs_speed = 0.2 self.inertia_x = 0 self.inertia_y = 0 self.inertia_z = 0 def move(Task): if self.game_start > 0: # get mouse data mouse_watch = base.mouseWatcherNode if mouse_watch.has_mouse(): pointer = base.win.get_pointer(0) mouseX = pointer.get_x() mouseY = pointer.get_y() # screen sizes window_Xcoord_halved = base.win.get_x_size() // 2 window_Ycoord_halved = base.win.get_y_size() // 2 # mouse speed mouseSpeedX = 0.2 mouseSpeedY = 0.2 # maximum and minimum pitch maxPitch = 90 minPitch = -50 # cam view target initialization camViewTarget = LVecBase3f() # clock dt = globalClock.get_dt() if base.win.movePointer(0, window_Xcoord_halved, window_Ycoord_halved): p = 0 if mouse_watch.has_mouse(): # calculate the pitch of camera p = self.camera.get_p() - ( mouseY - window_Ycoord_halved) * mouseSpeedY # sanity checking if p < minPitch: p = minPitch elif p > maxPitch: p = maxPitch if mouse_watch.has_mouse(): # directly set the camera pitch self.camera.set_p(p) camViewTarget.set_y(p) # rotate the self.player's heading according to the mouse x-axis movement if mouse_watch.has_mouse(): h = self.camera.get_h() - ( mouseX - window_Xcoord_halved) * mouseSpeedX if mouse_watch.has_mouse(): # sanity checking if h < -360: h += 360 elif h > 360: h -= 360 self.camera.set_h(h) camViewTarget.set_x(h) if self.inertia_x > self.max_abs_speed: self.inertia_x = self.max_abs_speed if self.inertia_y > self.max_abs_speed: self.inertia_y = self.max_abs_speed if self.inertia_z > self.max_abs_speed: self.inertia_z = self.max_abs_speed if self.keyMap["right"]: if self.inertia_x > 0: self.inertia_x += self.inc_var * dt else: self.inertia_x = self.max_speed_inc self.camera.set_x(self.camera, self.inertia_x) if self.keyMap["left"]: if self.inertia_x < 0: self.inertia_x -= self.inc_var * dt else: self.inertia_x = -self.max_speed_inc self.camera.set_x(self.camera, self.inertia_x) if self.keyMap["forward"]: # print(self.inertia_y) if self.inertia_y > 0: self.inertia_y += self.inc_var * dt else: self.inertia_y = self.max_speed_inc self.camera.set_y(self.camera, self.inertia_y) if self.keyMap["backward"]: if self.inertia_y < 0: self.inertia_y -= self.inc_var * dt else: self.inertia_y = -self.max_speed_inc self.camera.set_y(self.camera, self.inertia_y) if self.keyMap["up"]: if self.inertia_z > 0: self.inertia_z += self.inc_var * dt else: self.inertia_z = self.max_speed_inc self.camera.set_z(self.camera, self.inertia_z) if self.keyMap["down"]: if self.inertia_z < 0: self.inertia_z -= self.inc_var * dt else: self.inertia_z = -self.max_speed_inc self.camera.set_z(self.camera, self.inertia_z) else: self.camera.set_x(self.camera, self.inertia_x) self.camera.set_y(self.camera, self.inertia_y) self.camera.set_z(self.camera, self.inertia_z) return Task.cont def update(Task): if self.game_start < 1: self.game_start = 1 return Task.cont self.task_mgr.add(move) self.task_mgr.add(update)
def __init__(self): load_prc_file_data( "", """ win-size 1920 1080 window-title Panda3D Arena Sample FPS Bullet Auto Colliders PBR HW Skinning show-frame-rate-meter #t framebuffer-srgb #t framebuffer-multisample 1 multisamples 4 view-frustum-cull 0 textures-power-2 none hardware-animated-vertices #t gl-depth-zero-to-one true clock-frame-rate 60 interpolate-frames 1 cursor-hidden #t fullscreen #f """) # Initialize the showbase super().__init__() gltf.patch_loader(self.loader) props = WindowProperties() props.set_mouse_mode(WindowProperties.M_relative) base.win.request_properties(props) base.set_background_color(0.5, 0.5, 0.8) self.camLens.set_fov(80) self.camLens.set_near_far(0.01, 90000) self.camLens.set_focal_length(7) # self.camera.set_pos(0, 0, 2) # ConfigVariableManager.getGlobalPtr().listVariables() # point light generator for x in range(0, 3): plight_1 = PointLight('plight') # add plight props here plight_1_node = self.render.attach_new_node(plight_1) # group the lights close to each other to create a sun effect plight_1_node.set_pos(random.uniform(-21, -20), random.uniform(-21, -20), random.uniform(20, 21)) self.render.set_light(plight_1_node) # point light for volumetric lighting filter plight_1 = PointLight('plight') # add plight props here plight_1_node = self.render.attach_new_node(plight_1) # group the lights close to each other to create a sun effect plight_1_node.set_pos(random.uniform(-21, -20), random.uniform(-21, -20), random.uniform(20, 21)) self.render.set_light(plight_1_node) scene_filters = CommonFilters(base.win, base.cam) scene_filters.set_bloom() scene_filters.set_high_dynamic_range() scene_filters.set_exposure_adjust(0.6) scene_filters.set_gamma_adjust(1.1) # scene_filters.set_volumetric_lighting(plight_1_node, 32, 0.5, 0.7, 0.1) # scene_filters.set_blur_sharpen(0.9) # scene_filters.set_ambient_occlusion(32, 0.05, 2.0, 0.01, 0.000002) self.accept("f3", self.toggle_wireframe) self.accept("escape", sys.exit, [0]) exponential_fog = Fog('world_fog') exponential_fog.set_color(0.6, 0.7, 0.7) # this is a very low fog value, set it higher for a greater effect exponential_fog.set_exp_density(0.00009) self.render.set_fog(exponential_fog) self.game_start = 0 from panda3d.bullet import BulletWorld from panda3d.bullet import BulletCharacterControllerNode from panda3d.bullet import ZUp from panda3d.bullet import BulletCapsuleShape from panda3d.bullet import BulletTriangleMesh from panda3d.bullet import BulletTriangleMeshShape from panda3d.bullet import BulletBoxShape from panda3d.bullet import BulletGhostNode from panda3d.bullet import BulletRigidBodyNode from panda3d.bullet import BulletPlaneShape self.world = BulletWorld() self.world.set_gravity(Vec3(0, 0, -9.81)) arena_1 = self.loader.load_model('models/arena_1.gltf') arena_1.reparent_to(self.render) arena_1.set_pos(0, 0, 0) def make_collision_from_model(input_model, node_number, mass, world, target_pos, h_adj): # tristrip generation from static models # generic tri-strip collision generator begins geom_nodes = input_model.find_all_matches('**/+GeomNode') geom_nodes = geom_nodes.get_path(node_number).node() # print(geom_nodes) geom_target = geom_nodes.get_geom(0) # print(geom_target) output_bullet_mesh = BulletTriangleMesh() output_bullet_mesh.add_geom(geom_target) tri_shape = BulletTriangleMeshShape(output_bullet_mesh, dynamic=False) print(output_bullet_mesh) body = BulletRigidBodyNode('input_model_tri_mesh') np = self.render.attach_new_node(body) np.node().add_shape(tri_shape) np.node().set_mass(mass) np.node().set_friction(0.01) np.set_pos(target_pos) np.set_scale(1) np.set_h(h_adj) # np.set_p(180) # np.set_r(180) np.set_collide_mask(BitMask32.allOn()) world.attach_rigid_body(np.node()) make_collision_from_model(arena_1, 0, 0, self.world, (arena_1.get_pos()), 0) # load the scene shader scene_shader = Shader.load(Shader.SL_GLSL, "shaders/simplepbr_vert_mod_1.vert", "shaders/simplepbr_frag_mod_1.frag") self.render.set_shader(scene_shader) self.render.set_antialias(AntialiasAttrib.MMultisample) scene_shader_attrib = ShaderAttrib.make(scene_shader) scene_shader_attrib = scene_shader_attrib.setFlag( ShaderAttrib.F_hardware_skinning, True) # initialize player character physics the Bullet way shape_1 = BulletCapsuleShape(0.75, 0.5, ZUp) player_node = BulletCharacterControllerNode( shape_1, 0.1, 'Player') # (shape, mass, player name) # player_node.set_max_slope(0.1) # player_node.set_linear_movement(1, True) player_np = self.render.attach_new_node(player_node) player_np.set_pos(-20, -10, 10) player_np.set_collide_mask(BitMask32.allOn()) self.world.attach_character(player_np.node()) # cast player_np to self.player self.player = player_np # reparent player character to render node fp_character = actor_data.player_character fp_character.reparent_to(self.render) fp_character.set_scale(1) # set the actor skinning hardware shader fp_character.set_attrib(scene_shader_attrib) self.camera.reparent_to(self.player) # reparent character to FPS cam fp_character.reparent_to(self.player) fp_character.set_pos(0, 0, -0.95) # self.camera.set_x(self.player, 1) self.camera.set_y(self.player, 0.03) self.camera.set_z(self.player, 0.5) # player gun begins self.player_gun = actor_data.arm_handgun self.player_gun.reparent_to(self.render) self.player_gun.reparent_to(self.camera) self.player_gun.set_x(self.camera, 0.1) self.player_gun.set_y(self.camera, 0.4) self.player_gun.set_z(self.camera, -0.1) # directly make a text node to display text text_1 = TextNode('text_1_node') text_1.set_text("") text_1_node = self.aspect2d.attach_new_node(text_1) text_1_node.set_scale(0.05) text_1_node.set_pos(-1.4, 0, 0.92) # import font and set pixels per unit font quality nunito_font = loader.load_font('fonts/Nunito/Nunito-Light.ttf') nunito_font.set_pixels_per_unit(100) nunito_font.set_page_size(512, 512) # apply font text_1.set_font(nunito_font) # small caps # text_1.set_small_caps(True) # on-screen target dot for aiming target_dot = TextNode('target_dot_node') target_dot.set_text(".") target_dot_node = self.aspect2d.attach_new_node(target_dot) target_dot_node.set_scale(0.075) target_dot_node.set_pos(0, 0, 0) # target_dot_node.hide() # apply font target_dot.set_font(nunito_font) target_dot.set_align(TextNode.ACenter) # see the Task section for relevant dot update logic # directly make a text node to display text text_2 = TextNode('text_2_node') text_2.set_text("Neutralize the NPC by shooting the head." + '\n' + "Press 'f' to toggle the flashlight.") text_2_node = self.aspect2d.attach_new_node(text_2) text_2_node.set_scale(0.04) text_2_node.set_pos(-1.4, 0, 0.8) # import font and set pixels per unit font quality nunito_font = self.loader.load_font('fonts/Nunito/Nunito-Light.ttf') nunito_font.set_pixels_per_unit(100) nunito_font.set_page_size(512, 512) # apply font text_2.set_font(nunito_font) text_2.set_text_color(0, 0.3, 1, 1) # print player position on mouse click def print_player_pos(): print(self.player.get_pos()) self.player.node().do_jump() self.accept('mouse3', print_player_pos) self.flashlight_state = 0 def toggle_flashlight(): current_flashlight = self.render.find_all_matches("**/flashlight") if self.flashlight_state == 0: if len(current_flashlight) == 0: self.slight = 0 self.slight = Spotlight('flashlight') self.slight.set_shadow_caster(True, 1024, 1024) self.slight.set_color(VBase4(0.5, 0.6, 0.6, 1)) # slightly bluish lens = PerspectiveLens() lens.set_near_far(0.5, 5000) self.slight.set_lens(lens) self.slight.set_attenuation((0.5, 0, 0.0000005)) self.slight = self.render.attach_new_node(self.slight) self.slight.set_pos(-0.1, 0.3, -0.4) self.slight.reparent_to(self.camera) self.flashlight_state = 1 self.render.set_light(self.slight) elif len(current_flashlight) > 0: self.render.set_light(self.slight) self.flashlight_state = 1 elif self.flashlight_state > 0: self.render.set_light_off(self.slight) self.flashlight_state = 0 self.accept('f', toggle_flashlight) # add a few random physics boxes for x in range(0, 40): # dynamic collision random_vec = Vec3(1, 1, 1) special_shape = BulletBoxShape(random_vec) # rigidbody body = BulletRigidBodyNode('random_prisms') d_coll = self.render.attach_new_node(body) d_coll.node().add_shape(special_shape) d_coll.node().set_mass(0.9) d_coll.node().set_friction(0.5) d_coll.set_collide_mask(BitMask32.allOn()) # turn on Continuous Collision Detection d_coll.node().set_ccd_motion_threshold(0.000000007) d_coll.node().set_ccd_swept_sphere_radius(0.30) d_coll.node().set_deactivation_enabled(False) d_coll.set_pos(random.uniform(-60, -20), random.uniform(-60, -20), random.uniform(5, 10)) box_model = self.loader.load_model('models/1m_cube.gltf') box_model.reparent_to(self.render) box_model.reparent_to(d_coll) box_model.set_color(random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1), 1) self.world.attach_rigid_body(d_coll.node()) # portal #1 begins # make a new texture buffer, render node, and attach a camera mirror_buffer = self.win.make_texture_buffer("mirror_buff", 4096, 4096) mirror_render = NodePath("mirror_render") mirror_render.set_shader(scene_shader) self.mirror_cam = self.make_camera(mirror_buffer) self.mirror_cam.reparent_to(mirror_render) self.mirror_cam.set_pos(0, -60, 5) self.mirror_cam.set_hpr(0, 25, 0) self.mirror_cam.node().get_lens().set_focal_length(10) self.mirror_cam.node().get_lens().set_fov(90) mirror_filters = CommonFilters(mirror_buffer, self.mirror_cam) # mirror_filters.set_high_dynamic_range() mirror_filters.set_exposure_adjust(1.1) # mirror_filters.set_gamma_adjust(1.3) # load in a mirror/display object model in normal render space self.mirror_model = self.loader.loadModel( 'models/wide_screen_video_display.egg') self.mirror_model.reparent_to(self.render) self.mirror_model.set_pos(-20, 0, 1) self.mirror_model.set_sz(3) # self.mirror_model.flatten_strong() # mirror scene model load-in # reparent to mirror render node house_uv = self.loader.load_model('models/hangar_1.gltf') house_uv.reparent_to(mirror_render) windows = house_uv.find('**/clear_arches') windows.hide() house_uv.set_pos(0, 0, 0) house_uv.set_scale(1) # the portal ramp house_uv = self.loader.load_model('models/ramp_1.gltf') house_uv.reparent_to(mirror_render) house_uv.set_h(180) house_uv.set_scale(1.5) house_uv.set_pos(0, -50, 0) # mirror scene lighting # point light generator for x in range(0, 1): plight_1 = PointLight('plight') # add plight props here plight_1_node = mirror_render.attach_new_node(plight_1) # group the lights close to each other to create a sun effect plight_1_node.set_pos(random.uniform(-21, -20), random.uniform(-21, -20), random.uniform(20, 21)) mirror_render.set_light(plight_1_node) # set the live buffer texture to the mirror/display model in normal render space self.mirror_model.set_texture(mirror_buffer.get_texture()) # secret hangar far off somewhere on the graph house_uv = self.loader.load_model('models/hangar_1.gltf') house_uv.reparent_to(self.render) windows = house_uv.find('**/clear_arches') windows.hide() house_uv.set_pos(400, 400, -1) # the portal ring house_uv = self.loader.load_model('models/ring_1.gltf') house_uv.reparent_to(self.render) house_uv.set_h(90) house_uv.set_pos(-20, 0, -2) # the portal ramp house_uv = self.loader.load_model('models/ramp_1.gltf') house_uv.reparent_to(self.render) house_uv.set_h(0) house_uv.set_pos(-20, -5.5, 0) r_pos = house_uv.get_pos() make_collision_from_model(house_uv, 0, 0, self.world, (r_pos[0], r_pos[1], r_pos[2] + 1), 0) self.count_frames_1 = 0 self.screen_cap_num = 1 def make_screenshot(): # Ensure the frame is rendered. base.graphicsEngine.render_frame() # Grab the screenshot into a big image full = PNMImage() base.win.get_screenshot(full) # Now reduce it reduced = PNMImage(500, 300) reduced.gaussianFilterFrom(1, full) # And write it out. reduced.write( Filename('screen_cap_' + str(self.screen_cap_num) + '.jpg')) self.screen_cap_num += 1 def update_portal_cam(Task): if self.count_frames_1 < 30: self.count_frames_1 += 1 if self.count_frames_1 == 15: pass # make_screenshot() if self.count_frames_1 == 29: self.count_frames_1 = 0 p_dist = (self.player.get_pos() - self.mirror_model.get_pos(base.render)).length() target_fov = 115 if p_dist < 2.25: target_fov = 145 self.player.set_pos(400, 400, 3) # adjust the ground plane self.ground_plane.set_pos(0, 0, 0) # move the normal point lights lights = self.render.find_all_matches('**/plight*') for l in lights: l.set_pos(400, 400, 21) player_h = self.player.get_h() self.mirror_cam.set_h(player_h) self.mirror_cam.node().get_lens().set_fov(target_fov) return Task.cont self.task_mgr.add(update_portal_cam) # portal #2 begins # the portal ring house_uv = self.loader.load_model('models/ring_1.gltf') house_uv.reparent_to(self.render) house_uv.set_h(90) house_uv.set_pos(400, 400, -2) # the portal ramp house_uv = self.loader.load_model('models/ramp_1.gltf') house_uv.reparent_to(self.render) house_uv.set_h(180) house_uv.set_pos(400, 405.5, 0) r_pos = house_uv.get_pos() make_collision_from_model(house_uv, 0, 0, self.world, (r_pos[0], r_pos[1], r_pos[2] + 1), 180) # NPC_1 load-in comp_shape_1 = BulletCapsuleShape(0.05, 0.01, ZUp) npc_1_node = BulletCharacterControllerNode( comp_shape_1, 0.2, 'NPC_A_node') # (shape, mass, character name) np = self.render.attach_new_node(npc_1_node) np.set_pos(-40, -40, 5) np.set_collide_mask(BitMask32.allOn()) self.world.attach_character(np.node()) np.set_h(random.randint(0, 180)) npc_model_1 = actor_data.NPC_1 npc_model_1.reparent_to(np) # set the actor skinning hardware shader npc_model_1.set_attrib(scene_shader_attrib) # get the separate head model npc_1_head = self.loader.load_model('models/npc_1_head.gltf') npc_1_head.reparent_to(actor_data.NPC_1.get_parent()) # npc base animation loop npc_1_control = actor_data.NPC_1.get_anim_control('walking') if not npc_1_control.is_playing(): actor_data.NPC_1.stop() actor_data.NPC_1.loop("walking", fromFrame=60, toFrame=180) actor_data.NPC_1.set_play_rate(6.0, 'walking') # create special hit areas # use Task section for npc collision movement logic # special head node size special_shape = BulletBoxShape(Vec3(0.1, 0.1, 0.1)) # ghost npc node body = BulletGhostNode('special_node_A') special_node = self.render.attach_new_node(body) special_node.node().add_shape( special_shape, TransformState.makePos(Point3(0, 0, 0.4))) # special_node.node().set_mass(0) # special_node.node().set_friction(0.5) special_node.set_collide_mask(BitMask32(0x0f)) # turn on Continuous Collision Detection special_node.node().set_deactivation_enabled(False) special_node.node().set_ccd_motion_threshold(0.000000007) special_node.node().set_ccd_swept_sphere_radius(0.30) self.world.attach_ghost(special_node.node()) # dynamic collision special_shape = BulletBoxShape(Vec3(0.3, 0.15, 0.6)) # rigidbody npc node body = BulletRigidBodyNode('d_coll_A') d_coll = self.render.attach_new_node(body) d_coll.node().add_shape(special_shape, TransformState.makePos(Point3(0, 0, 0.7))) # d_coll.node().set_mass(0) d_coll.node().set_friction(0.5) d_coll.set_collide_mask(BitMask32.allOn()) # turn on Continuous Collision Detection d_coll.node().set_deactivation_enabled(False) d_coll.node().set_ccd_motion_threshold(0.000000007) d_coll.node().set_ccd_swept_sphere_radius(0.30) self.world.attach_rigid_body(d_coll.node()) # npc state variables self.npc_1_is_dead = False self.npc_1_move_increment = Vec3(0, 0, 0) self.gun_anim_is_playing = False # npc movement timer def npc_1_move_gen(): while not self.npc_1_is_dead: m_incs = [] for x in range(0, 2): m_incs.append(random.uniform(2, 5)) print('NPC_1 movement increments this cycle: ' + str(m_incs)) self.npc_1_move_increment[0] = m_incs[0] self.npc_1_move_increment[1] = m_incs[1] time.sleep(3) self.npc_1_move_increment[0] = m_incs[0] self.npc_1_move_increment[1] = m_incs[1] time.sleep(3) self.npc_1_move_increment[0] = (-1 * m_incs[0]) * 2 self.npc_1_move_increment[1] = (-1 * m_incs[1]) * 2 time.sleep(3) self.npc_1_move_increment[0] = 0 self.npc_1_move_increment[1] = 0 # activate the movement timer in a dedicated thread to prevent lockup with .sleep() threading2._start_new_thread(npc_1_move_gen, ()) def is_npc_1_shot(): # animate the gun gun_ctrl = actor_data.arm_handgun.get_anim_control('shoot') if not gun_ctrl.is_playing(): actor_data.arm_handgun.stop() actor_data.arm_handgun.play("shoot") actor_data.arm_handgun.set_play_rate(15.0, 'shoot') # target dot ray test # get mouse data mouse_watch = base.mouseWatcherNode if mouse_watch.has_mouse(): posMouse = base.mouseWatcherNode.get_mouse() posFrom = Point3() posTo = Point3() base.camLens.extrude(posMouse, posFrom, posTo) posFrom = self.render.get_relative_point(base.cam, posFrom) posTo = self.render.get_relative_point(base.cam, posTo) rayTest = self.world.ray_test_closest(posFrom, posTo) target = rayTest.get_node() target_dot = self.aspect2d.find_all_matches( "**/target_dot_node") if 'special_node_A' in str(target): def npc_cleanup(): # the head is hit, the npc is dead self.npc_1_is_dead = True text_2.set_text('Congrats, you have won!') npc_1_control = actor_data.NPC_1.get_anim_control( 'walking') if npc_1_control.is_playing(): actor_data.NPC_1.stop() npc_1_control = actor_data.NPC_1.get_anim_control( 'death') if not npc_1_control.is_playing(): actor_data.NPC_1.play('death') # Bullet node removals self.world.remove(target) rigid_target = self.render.find('**/d_coll_A') self.world.remove(rigid_target.node()) threading2._start_new_thread(npc_cleanup, ()) self.accept('mouse1', is_npc_1_shot) def smooth_load_physics(): # this is a patch to speed up the cold start hitch on success condition # Bullet node removals self.world.remove(special_node.node()) rigid_target = self.render.find('**/d_coll_A') self.world.remove(rigid_target.node()) print('NPC physics init removed.') smooth_load_physics() # repeat the NPC physics initialization after smooth_load_physics # create special hit areas # use Task section for npc collision movement logic # special head node size special_shape = BulletBoxShape(Vec3(0.1, 0.1, 0.1)) # ghost npc node body = BulletGhostNode('special_node_A') special_node = self.render.attach_new_node(body) special_node.node().add_shape( special_shape, TransformState.makePos(Point3(0, 0, 0.4))) # special_node.node().set_mass(0) # special_node.node().set_friction(0.5) special_node.set_collide_mask(BitMask32(0x0f)) # turn on Continuous Collision Detection special_node.node().set_deactivation_enabled(False) special_node.node().set_ccd_motion_threshold(0.000000007) special_node.node().set_ccd_swept_sphere_radius(0.30) self.world.attach_ghost(special_node.node()) # dynamic collision special_shape = BulletBoxShape(Vec3(0.3, 0.15, 0.6)) # rigidbody npc node body = BulletRigidBodyNode('d_coll_A') d_coll = self.render.attach_new_node(body) d_coll.node().add_shape(special_shape, TransformState.makePos(Point3(0, 0, 0.7))) # d_coll.node().set_mass(0) d_coll.node().set_friction(0.5) d_coll.set_collide_mask(BitMask32.allOn()) # turn on Continuous Collision Detection d_coll.node().set_deactivation_enabled(False) d_coll.node().set_ccd_motion_threshold(0.000000007) d_coll.node().set_ccd_swept_sphere_radius(0.30) self.world.attach_rigid_body(d_coll.node()) # 3D player movement system begins self.keyMap = { "left": 0, "right": 0, "forward": 0, "backward": 0, "run": 0, "jump": 0 } def setKey(key, value): self.keyMap[key] = value # define button map self.accept("a", setKey, ["left", 1]) self.accept("a-up", setKey, ["left", 0]) self.accept("d", setKey, ["right", 1]) self.accept("d-up", setKey, ["right", 0]) self.accept("w", setKey, ["forward", 1]) self.accept("w-up", setKey, ["forward", 0]) self.accept("s", setKey, ["backward", 1]) self.accept("s-up", setKey, ["backward", 0]) self.accept("shift", setKey, ["run", 1]) self.accept("shift-up", setKey, ["run", 0]) self.accept("space", setKey, ["jump", 1]) self.accept("space-up", setKey, ["jump", 0]) # disable mouse self.disable_mouse() # the player movement speed self.movementSpeedForward = 5 self.movementSpeedBackward = 5 self.dropSpeed = -0.2 self.striveSpeed = 6 self.ease = -10.0 self.static_pos_bool = False self.static_pos = Vec3() def move(Task): if self.game_start > 0: if not self.npc_1_is_dead: npc_pos_1 = actor_data.NPC_1.get_parent().get_pos() # place head hit box special_node.set_pos(npc_pos_1[0], npc_pos_1[1], npc_pos_1[2] + 1) special_node.set_h(actor_data.NPC_1.get_h()) # dynamic collision node d_coll.set_pos(npc_pos_1[0], npc_pos_1[1], npc_pos_1[2]) d_coll.set_h(actor_data.NPC_1.get_h()) # make the npc look at the player continuously actor_data.NPC_1.look_at(self.player) npc_1_head.look_at(self.player) if actor_data.NPC_1.get_p() > 3: actor_data.NPC_1.set_p(3) if npc_1_head.get_p() > 3: npc_1_head.set_p(3) m_inst = self.npc_1_move_increment t_inst = globalClock.get_dt() actor_data.NPC_1.get_parent().set_pos( npc_pos_1[0] + (m_inst[0] * t_inst), npc_pos_1[1] + (m_inst[1] * t_inst), npc_pos_1[2]) if self.npc_1_is_dead: npc_1_head.hide() inst_h = actor_data.NPC_1.get_h() inst_p = actor_data.NPC_1.get_p() actor_data.NPC_1.set_hpr(inst_h, inst_p, 0) # target dot ray test # turns the target dot red # get mouse data mouse_watch = base.mouseWatcherNode if mouse_watch.has_mouse(): posMouse = base.mouseWatcherNode.get_mouse() posFrom = Point3() posTo = Point3() base.camLens.extrude(posMouse, posFrom, posTo) posFrom = self.render.get_relative_point(base.cam, posFrom) posTo = self.render.get_relative_point(base.cam, posTo) rayTest = self.world.ray_test_closest(posFrom, posTo) target = rayTest.get_node() target_dot = self.aspect2d.find_all_matches( "**/target_dot_node") if 'special_node_A' in str(target): # the npc is recognized, make the dot red for dot in target_dot: dot.node().set_text_color(0.9, 0.1, 0.1, 1) if 'd_coll_A' in str(target): # the npc is recognized, make the dot red for dot in target_dot: dot.node().set_text_color(0.9, 0.1, 0.1, 1) if 'special_node_A' not in str(target): # no npc recognized, make the dot white if 'd_coll_A' not in str(target): for dot in target_dot: dot.node().set_text_color(1, 1, 1, 1) # get mouse data mouse_watch = base.mouseWatcherNode if mouse_watch.has_mouse(): pointer = base.win.get_pointer(0) mouseX = pointer.get_x() mouseY = pointer.get_y() # screen sizes window_Xcoord_halved = base.win.get_x_size() // 2 window_Ycoord_halved = base.win.get_y_size() // 2 # mouse speed mouseSpeedX = 0.2 mouseSpeedY = 0.2 # maximum and minimum pitch maxPitch = 90 minPitch = -50 # cam view target initialization camViewTarget = LVecBase3f() if base.win.movePointer(0, window_Xcoord_halved, window_Ycoord_halved): p = 0 if mouse_watch.has_mouse(): # calculate the pitch of camera p = self.camera.get_p() - ( mouseY - window_Ycoord_halved) * mouseSpeedY # sanity checking if p < minPitch: p = minPitch elif p > maxPitch: p = maxPitch if mouse_watch.has_mouse(): # directly set the camera pitch self.camera.set_p(p) camViewTarget.set_y(p) # rotate the self.player's heading according to the mouse x-axis movement if mouse_watch.has_mouse(): h = self.player.get_h() - ( mouseX - window_Xcoord_halved) * mouseSpeedX if mouse_watch.has_mouse(): # sanity checking if h < -360: h += 360 elif h > 360: h -= 360 self.player.set_h(h) camViewTarget.set_x(h) # hide the gun if looking straight down if p < -30: self.player_gun.hide() if p > -30: self.player_gun.show() if self.keyMap["left"]: if self.static_pos_bool: self.static_pos_bool = False self.player.set_x(self.player, -self.striveSpeed * globalClock.get_dt()) myAnimControl = actor_data.player_character.get_anim_control( 'walking') if not myAnimControl.isPlaying(): actor_data.player_character.play("walking") actor_data.player_character.set_play_rate( 4.0, 'walking') if not self.keyMap["left"]: if not self.static_pos_bool: self.static_pos_bool = True self.static_pos = self.player.get_pos() self.player.set_x(self.static_pos[0]) self.player.set_y(self.static_pos[1]) self.player.set_z(self.player, self.dropSpeed * globalClock.get_dt()) if self.keyMap["right"]: if self.static_pos_bool: self.static_pos_bool = False self.player.set_x(self.player, self.striveSpeed * globalClock.get_dt()) myAnimControl = actor_data.player_character.get_anim_control( 'walking') if not myAnimControl.isPlaying(): actor_data.player_character.play("walking") actor_data.player_character.set_play_rate( 4.0, 'walking') if not self.keyMap["right"]: if not self.static_pos_bool: self.static_pos_bool = True self.static_pos = self.player.get_pos() self.player.set_x(self.static_pos[0]) self.player.set_y(self.static_pos[1]) self.player.set_z(self.player, self.dropSpeed * globalClock.get_dt()) if self.keyMap["forward"]: if self.static_pos_bool: self.static_pos_bool = False self.player.set_y( self.player, self.movementSpeedForward * globalClock.get_dt()) myAnimControl = actor_data.player_character.get_anim_control( 'walking') if not myAnimControl.isPlaying(): actor_data.player_character.play("walking") actor_data.player_character.set_play_rate( 4.0, 'walking') if self.keyMap["forward"] != 1: if not self.static_pos_bool: self.static_pos_bool = True self.static_pos = self.player.get_pos() self.player.set_x(self.static_pos[0]) self.player.set_y(self.static_pos[1]) self.player.set_z(self.player, self.dropSpeed * globalClock.get_dt()) if self.keyMap["backward"]: if self.static_pos_bool: self.static_pos_bool = False self.player.set_y( self.player, -self.movementSpeedBackward * globalClock.get_dt()) myBackControl = actor_data.player_character.get_anim_control( 'walking') if not myBackControl.isPlaying(): myBackControl.stop() actor_data.player_character.play('walking') actor_data.player_character.set_play_rate( -4.0, 'walking') return Task.cont # infinite ground plane # the effective world-Z limit ground_plane = BulletPlaneShape(Vec3(0, 0, 1), 0) node = BulletRigidBodyNode('ground') node.add_shape(ground_plane) node.set_friction(0.1) self.ground_plane = self.render.attach_new_node(node) self.ground_plane.set_pos(0, 0, -1) self.world.attach_rigid_body(node) # Bullet debugger from panda3d.bullet import BulletDebugNode debugNode = BulletDebugNode('Debug') debugNode.show_wireframe(True) debugNode.show_constraints(True) debugNode.show_bounding_boxes(False) debugNode.show_normals(False) debugNP = self.render.attach_new_node(debugNode) self.world.set_debug_node(debugNP.node()) # debug toggle function def toggle_debug(): if debugNP.is_hidden(): debugNP.show() else: debugNP.hide() self.accept('f1', toggle_debug) def update(Task): if self.game_start < 1: self.game_start = 1 return Task.cont def physics_update(Task): dt = globalClock.get_dt() self.world.do_physics(dt) return Task.cont self.task_mgr.add(move) self.task_mgr.add(update) self.task_mgr.add(physics_update)
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 TheGameWindow(ShowBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.speed = 50 self.set_background_color(0, 0, 0, 0.6) # disables the default mouse camera control # self.disable_mouse() self.cam.set_pos(0, -100, 0) self.floor = self.loader.loadModel(str(settings.egg / "floor.egg")) self.bc304 = self.loader.loadModel(str(settings.egg / "bc304.egg")) self.floor.set_color((0.5, 0.5, 0.5, 1)) self.floor.reparent_to(self.render) self.sphere = self.loader.loadModel("models/misc/sphere") self.sphere.reparent_to(self.render) self.sphere.set_pos(10, 10, 10) self.sphere.set_scale(2.0) self.amblight = AmbientLight("ambl") self.amblight.set_color((0.1, 0.1, 0.1, 1)) self.ambnp = self.render.attach_new_node(self.amblight) self.plight = PointLight("pl") self.plight.set_shadow_caster(True, 2048, 2048) self.render.set_shader_auto() self.plight.set_color((1, 1, 1, 1)) self.plight.set_attenuation((1, 0, 0)) self.plnp = self.sphere.attach_new_node(self.plight) self.bc304.set_light(self.plnp) self.floor.set_light(self.plnp) self.bc304.set_light(self.ambnp) self.floor.set_light(self.ambnp) self.filter = CommonFilters(self.win, self.cam) self.filter.set_bloom(mintrigger=0.9, size="large") # left-rigth, far-from-camera, vertical-movement # x, y, z self.bc304.set_pos(0, 0, 50) self.bc304.set_scale(0.1) self.bc304.reparent_to(self.render) # heading, pitch,, roll self.bc304.set_hpr(280, 10, 0) self.x, self.y, self.z = 0.0, 0.0, 0.0 self.h, self.p = 0.0, 0.0 self.task_mgr.add(self.update) # self.accept("mouse1", self.to_pegasus) self.accept("mouse1-up", self.to_pegasus) # self.accept("mouse2", self.to_pegasus) self.accept("mouse2-up", self.to_pegasus) # self.accept("mouse3", self.to_pegasus) self.accept("mouse3-up", self.to_pegasus) self.accept("arrow_left", update_key_map, ["left", True]) self.accept("arrow_left-up", update_key_map, ["left", False]) self.accept("arrow_right", update_key_map, ["right", True]) self.accept("arrow_right-up", update_key_map, ["right", False]) self.accept("arrow_up", update_key_map, ["up", True]) self.accept("arrow_up-up", update_key_map, ["up", False]) self.accept("arrow_down", update_key_map, ["down", True]) self.accept("arrow_down-up", update_key_map, ["down", False]) self.accept("space", update_key_map, ["space", True]) self.accept("space-up", update_key_map, ["space", False]) self.accept("w", update_key_map, ["w", True]) self.accept("w-up", update_key_map, ["w", False]) self.accept("s", update_key_map, ["s", True]) self.accept("s-up", update_key_map, ["s", False]) self.accept("a", update_key_map, ["a", True]) self.accept("a-up", update_key_map, ["a", False]) self.accept("d", update_key_map, ["d", True]) self.accept("d-up", update_key_map, ["d", False]) self.accept("e", update_key_map, ["e", True]) self.accept("e-up", update_key_map, ["e", False]) self.accept("q", update_key_map, ["q", True]) self.accept("q-up", update_key_map, ["q", False]) def to_pegasus(self): # mouse_pos = self.mouseWatcherNode.getMouse() # mouse_pos_3d = (mouse_pos[0], 0, mouse_pos[1]) # mouse_pos_button = self.button.getRelativePoint(render, mouse_pos_3d) # print(mouse_pos_3d) # pointer = self.win.get_pointer(0) # self.z = -(pointer.get_y() - (720 / 2)) / 10 # print(self.z) # self.bc304.set_pos(pointer.get_x(), 0, self.z) pass def update(self, task: Task): dt, ft = globalClock.getDt(), globalClock.getFrameTime() if KEY_MAP["up"]: self.bc304.set_pos(self.x, self.y, self.z) self.z += self.speed * dt if KEY_MAP["down"]: self.bc304.set_pos(self.x, self.y, self.z) self.z -= self.speed * dt if KEY_MAP["right"]: self.bc304.set_pos(self.x, self.y, self.z) self.x += self.speed * dt if KEY_MAP["left"]: self.bc304.set_pos(self.x, self.y, self.z) self.x -= self.speed * dt if KEY_MAP["e"]: pos = self.sphere.get_pos() pos.z += self.speed * dt self.sphere.set_pos(pos) if KEY_MAP["q"]: pos = self.sphere.get_pos() pos.z -= self.speed * dt self.sphere.set_pos(pos) if KEY_MAP["a"]: pos = self.sphere.get_pos() pos.x -= self.speed * dt self.sphere.set_pos(pos) if KEY_MAP["d"]: pos = self.sphere.get_pos() pos.x += self.speed * dt self.sphere.set_pos(pos) if KEY_MAP["w"]: pos = self.sphere.get_pos() pos.y += self.speed * dt self.sphere.set_pos(pos) if KEY_MAP["s"]: pos = self.sphere.get_pos() pos.y -= self.speed * dt self.sphere.set_pos(pos) # self.sphere.set_pos(float(np.cos(ft) * 4), float(np.sin(ft) * 4), float(np.sin(ft) * 10)) # self.z -= 0.5 * dt # self.bc304.set_hpr(self.h, self.p, 0) # self.h += 0.1 # self.p += 0.1 return task.cont