Advertisement
Guest User

Untitled

a guest
Apr 19th, 2019
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.28 KB | None | 0 0
  1. from math import *
  2. from direct.showbase.ShowBase import ShowBase
  3. from direct.task import Task
  4. from panda3d.core import *
  5. from direct.showbase import DirectObject # event handling
  6. from direct.gui.OnscreenText import OnscreenText
  7. import os,sys,random
  8. import ctypes
  9.  
  10. user32 = ctypes.windll.user32
  11. user32.SetProcessDPIAware() #windows cross platform compatibility, fixes the getsystemmetrics bug
  12.  
  13. loadPrcFileData('', 'fullscreen true')
  14. loadPrcFileData('','win-size '+str(user32.GetSystemMetrics(0))+' '+str(user32.GetSystemMetrics(1))) # fullscreen stuff for one monitor, for multi monitor setup try 78 79
  15. loadPrcFileData('','window-title PyOS')
  16. loadPrcFileData('','load-display pandagl')
  17.  
  18. class world(ShowBase):
  19. def __init__(self):
  20. try:
  21. ShowBase.__init__(self)
  22. except:
  23. raise window_error(":( something went wrong: error while loading OpenGL")
  24. #debug
  25. self.debug=False #REMEMBER TO TURN THIS OFF WHEN COMMITTING THIS TO GITHUB YOU GODDAM MORRON !!!
  26. #debug
  27. self.dir=Filename.fromOsSpecific(os.getcwd())
  28. self.timescale=10
  29. self.worldscale=0.1 # currently unused
  30. self.collision_status=False # Keep this on False, that's definitely not a setting # currently unused
  31. # btw I found something about energy transmition through thermal radiation. I think it uses some Boltzmann formula stuff. Link here:
  32. # 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
  33. 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
  34. self.collision_solids=[] #collision related stuff - comments are useless - just RTFM
  35. self.light_Mngr=[]
  36. self.data=[[0,0,0,0,0.003,0,1,1,1,100000.00,True,[self.loader.loadModel(self.dir+"/Engine/Planete_tellurique.egg"),(0,0,0.1)],"lp_planet",False],
  37. [40,0,0,0,0.003,0,0.5,0.5,0.5,20.00,True,[self.loader.loadModel(self.dir+"/Engine/Icy.egg"),(0.5,0,0)],"Ottilia",False],
  38. [0,70,10,0,0.005,0,0.2,0.2,0.2,40.00,True,[self.loader.loadModel(self.dir+"/Engine/asteroid_1.egg"),(0,0,0.2)],"Selena",False],[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.05)],"Sun",True]]
  39. # the correct reading syntax is [x,y,z,l,m,n,scale1,scale2,scale3,mass,static,[files],id,lightsource,radius] 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 - radius: positive value -
  40. #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
  41. self.u_constant=6.67408*10**(-11) #just a quick reminder
  42. self.u_radius=5.25 #just what I said earlier
  43. self.u_radius_margin=0.1 #a margin added to the generic radius as a safety feature (mountains and stuff, atmosphere)
  44. #currently unused
  45. self.isphere=self.loader.loadModel(self.dir+"/Engine/InvertedSphere.egg") #loading skybox structure
  46. self.tex=loader.loadCubeMap(self.dir+'/Engine/cubemap_#.png')
  47.  
  48. self.orbit_lines=[] #under developement
  49.  
  50. # see https://www.panda3d.org/manual/?title=Collision_Solids for further collision interaction informations
  51. base.graphicsEngine.openWindows()
  52. try:
  53. for c in self.data: # loading and displaying the preloaded planets and bodies
  54. for u in range(0,len(c[11]),2): # loading each sub-file
  55. c[11][u].reparentTo(self.render)
  56. c[11][u].setScale(c[6],c[7],c[8])
  57. c[11][u].setPos(c[0],c[1],c[2])
  58. #setting the collision solid up
  59. self.collision_solids.append([CollisionSphere(0,0,0,self.u_radius)]) #the radius is calculated by using the average scale + the u_radius
  60. # still not working
  61. self.collision_solids[len(self.collision_solids)-1].append(c[11][0].attachNewNode(CollisionNode(c[12])))
  62. # the structure of the collision_solids list will be: [[(0,1,2),1],[(0,1,2),1],[(0,1,2),1],...]
  63. # asteroids and irregular shapes must be slightly bigger than their hitbox in order to avoid visual glitches
  64. self.collision_solids[len(self.collision_solids)-1][1].node().addSolid(self.collision_solids[len(self.collision_solids)-1][0]) #I am definitely not explaining that
  65. if self.debug:
  66. self.collision_solids[len(self.collision_solids)-1][1].show() # debugging purposes only
  67.  
  68. print("collision: ok")
  69. print("placing body: done")
  70. if c[13]:
  71. self.light_Mngr.append([PointLight(c[12]+"_other")])
  72. self.light_Mngr[len(self.light_Mngr)-1].append(render.attachNewNode(self.light_Mngr[len(self.light_Mngr)-1][0]))
  73. self.light_Mngr[len(self.light_Mngr)-1][1].setPos(c[0],c[1],c[2])
  74. render.setLight(self.light_Mngr[len(self.light_Mngr)-1][1])
  75. self.light_Mngr.append([AmbientLight(c[12]+"_self")])
  76. self.light_Mngr[len(self.light_Mngr)-1][0].setColorTemperature(1000)
  77. self.light_Mngr[len(self.light_Mngr)-1].append(render.attachNewNode(self.light_Mngr[len(self.light_Mngr)-1][0]))
  78. for u in range(0,len(c[11]),2):
  79. c[11][u].setLight(self.light_Mngr[len(self.light_Mngr)-1][1])
  80. print("lights: done")
  81. print("loaded new body, out: done")
  82. self.isphere.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap) # *takes a deep breath* cubemap stuff !
  83. self.isphere.setTexProjector(TextureStage.getDefault(), render, self.isphere)
  84. self.isphere.setTexPos(TextureStage.getDefault(), 0, 0, 0)
  85. self.isphere.setTexScale(TextureStage.getDefault(), .5) # that's a thing...
  86. self.isphere.setTexture(self.tex)# Create some 3D texture coordinates on the sphere. For more info on this, check the Panda3D manual.
  87. self.isphere.setLightOff()
  88. self.isphere.setScale(10000) #hope this is enough
  89. self.isphere.reparentTo(self.render)
  90. # collision traverser and other collision stuff # that's super important, and super tricky to explain so just check the wiki
  91. self.ctrav = CollisionTraverser()
  92. self.queue = CollisionHandlerQueue()
  93. for n in self.collision_solids:
  94. self.ctrav.add_collider(n[1],self.queue)
  95. # the traverser will be automatically updated, no need to repeat this every frame
  96. # debugging only
  97. if self.debug:
  98. self.ctrav.showCollisions(render)
  99. # play a random music
  100. self.current_playing=random.randint(0,len(self.sounds)-1)
  101. self.sounds[self.current_playing].play()
  102. self.taskMgr.add(self.placement_Mngr,'frameUpdateTask')
  103. self.taskMgr.add(self.Sound_Mngr,'MusicHandle')
  104. except:
  105. raise loader_error(":( something went wrong: 3d models could not be loaded")
  106.  
  107. def showsimpletext(self,content,pos,scale): #shows a predefined, basic text on the screen (variable output only)
  108. return OnscreenText(text=content,pos=pos,scale=scale)
  109.  
  110. def placement_Mngr(self,task): #main game mechanics, frame updating function (kinda)
  111. self.ctrav.traverse(render)
  112. if self.queue.getNumEntries():
  113. print(self.queue.getNumEntries()) # debug
  114.  
  115. for c in range(0,len(self.queue.getEntries()),2):
  116. # print(entry)#experimental, debugging purposes only
  117. #print(entry.getInteriorPoint(entry.getIntoNodePath()))# we have to run a collision check for each couple
  118. self.collision_log(self.queue.getEntries()[c])
  119. # print "out"
  120. # collision events are now under constant surveillance
  121. acceleration=[]
  122. for c in range(len(self.data)): #selects the analysed body
  123. var=self.data[c]
  124. Bdf=[0,0,0] #Bdf stands for 'bilan des forces' in french, it's the resulting acceleration
  125. for d in self.data[0:c]+self.data[c+1:len(self.data)-1]: #selects the body which action on the analysed body we're studying...not sure about that english sentence though
  126. S,M=[d[9],d[0],d[1],d[2]],[var[9],var[0],var[1],var[2]]
  127. temp=self.dual_a(S,M)
  128. Bdf=[Bdf[x]+temp[x] for x in range(3)] # list sum
  129. # add the result to the global save list
  130. acceleration.append(Bdf)
  131. #update the bodies' position
  132. self.speed_update(acceleration)
  133. self.pos_update()
  134. self.apply_update()
  135. return task.cont
  136.  
  137. def speed_update(self,a):
  138. for c in range(len(self.data)): #the function updates the speed tuple accordingly
  139. self.data[c][3]+=self.timescale*a[c][0]
  140. self.data[c][4]+=self.timescale*a[c][1]
  141. self.data[c][5]+=self.timescale*a[c][2]
  142. #print(self.data[c][3],self.data[c][4],self.data[c][5],"#") # slow (debug phase)
  143. return 0
  144.  
  145. def pos_update(self): #updates the positional coordinates
  146. for c in range(len(self.data)):
  147. self.data[c][0]+=self.timescale*self.data[c][3]
  148. self.data[c][1]+=self.timescale*self.data[c][4]
  149. self.data[c][2]+=self.timescale*self.data[c][5]
  150. return 0
  151.  
  152. def apply_update(self): #actually moves the hole 3d stuff around
  153. count=0 #local counter
  154. for c in self.data:
  155. for u in range(len(c[11])):
  156. if u%2!=0:
  157. c[11][u-1].setHpr(c[11][u-1],c[11][u])
  158. else:
  159. c[11][u].setPos(c[0],c[1],c[2])
  160. if c[13]:
  161. self.light_Mngr[count][1].setPos(c[0],c[1],c[2])
  162. count+=2 #we have to change the position of the pointlight, not the ambientlight
  163. return 0
  164.  
  165. def dual_a(self,S,M): #S is the "static object", the one that applies the force to the "moving" object M
  166. O=[] #This will be the list with the accelerations for an object
  167. d=sqrt((S[1]-M[1])**2+(S[2]-M[2])**2+(S[3]-M[3])**2)
  168. x=(self.u_constant*S[0]*(S[1]-M[1]))/d**2
  169. y=(self.u_constant*S[0]*(S[2]-M[2]))/d**2
  170. z=(self.u_constant*S[0]*(S[3]-M[3]))/d**2
  171. O.append(x)
  172. O.append(y)
  173. O.append(z)
  174. return O
  175.  
  176. def collision_log(self,entry):
  177. from_pos=[self.data[n][11][0] for n in range(len(self.data))].index(entry.getFromNodePath().getParent())
  178. into_pos=[self.data[n][11][0] for n in range(len(self.data))].index(entry.getIntoNodePath().getParent()) #find the nodepath in the list
  179. f_radius=(self.data[from_pos][6]+self.data[from_pos][7]+self.data[from_pos][8])/3
  180. i_radius=(self.data[into_pos][6]+self.data[into_pos][7]+self.data[into_pos][8])/3
  181. if max(f_radius,i_radius)==f_radius:
  182. into_pos,from_pos=from_pos,into_pos
  183. # those are the two positions of the nodepaths, now we need to know which one is bigger, in order to obtain the fusion effect
  184. self.momentum_transfer(from_pos,into_pos,entry) # from_pos is the smaller body, into_pos is the bigger one
  185. self.collision_gfx()
  186. return 0
  187.  
  188. def momentum_transfer(self,f_pos,i_pos,entry):
  189. print("colliding") # debug, makes the game laggy
  190. #that part is completely fucked up
  191. if sqrt((entry.getInteriorPoint(entry.getIntoNodePath())[0]-entry.getSurfacePoint(entry.getIntoNodePath())[0])**2+(entry.getInteriorPoint(entry.getIntoNodePath())[1]-entry.getSurfacePoint(entry.getIntoNodePath())[1])**2+(entry.getInteriorPoint(entry.getIntoNodePath())[2]-entry.getSurfacePoint(entry.getIntoNodePath())[2])**2)>=2*(self.data[f_pos][6]+self.data[f_pos][7]+self.data[f_pos][8])*self.u_radius/3:
  192. #Here's Johny
  193. for c in range(0,len(self.data[f_pos][11]),2):
  194. self.ctrav.remove_collider(self.collision_solids[f_pos][1])
  195. #self.collision_solids[f_pos][1].node().removeSolid()
  196. #self.collision_solids[f_pos][1]=None
  197. self.data[f_pos][11][c].removeNode()
  198. #self.data[f_pos][11][c]=None
  199.  
  200. self.data[i_pos][6],self.data[i_pos][7],self.data[i_pos][8]=self.data[i_pos][6]*(self.data[i_pos][9]+self.data[f_pos][9]),self.data[i_pos][7]*(self.data[i_pos][9]+self.data[f_pos][9]),self.data[i_pos][8]*(self.data[i_pos][9]+self.data[f_pos][9])
  201. self.data[i_pos][9]+=self.data[f_pos][9]
  202. # scale updating
  203. self.data[i_pos][11][0].setScale(self.data[i_pos][6],self.data[i_pos][7],self.data[i_pos][8])
  204. # deleting the destroyed planet's data, it is not fully functionnal as the other models remain intact
  205. self.data=self.data[:f_pos]+self.data[f_pos+1:len(self.data)]
  206. self.collision_solids=self.collision_solids[:f_pos]+self.collision_solids[f_pos+1:len(self.collision_solids)]
  207. # just a quick test
  208. print("planet destroyed")
  209. return 0
  210. def printScene(self): #debug
  211. file=open("scenegraph.txt","a")
  212. ls = LineStream()
  213. render.ls(ls)
  214. while ls.isTextAvailable():
  215. file.write(ls.getLine())
  216. file.write("\n")
  217. file.write("\n")
  218. file.write("END\n")
  219. file.write("\n")
  220. file.close()
  221. def Sound_Mngr(self,task):
  222. if self.sounds[self.current_playing].length()-self.sounds[self.current_playing].getTime()==0: #could have just used not()
  223.  
  224. self.current_playing=random.choice(range(0,self.current_playing)+range(self.current_playing+1,len(self.sounds)))
  225. self.sounds[self.current_playing].play()
  226. return task.cont
  227.  
  228. def collision_gfx(self):
  229. return 0
  230.  
  231. launch=world()
  232. base.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement