player.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. ########################################################################
  2. # Hello Worlds - Libre 3D RPG game.
  3. # Copyright (C) 2020 CYBERDEViL
  4. #
  5. # This file is part of Hello Worlds.
  6. #
  7. # Hello Worlds is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Hello Worlds is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ########################################################################
  21. # Panda3d
  22. from panda3d.core import BitMask32
  23. from panda3d.core import Vec3
  24. from panda3d.core import WindowProperties
  25. from panda3d.core import PandaNode, NodePath, TextNode
  26. from panda3d.core import Camera, OrthographicLens, PGTop
  27. from panda3d.bullet import BulletCharacterControllerNode
  28. from panda3d.bullet import BulletCapsuleShape, ZUp
  29. from direct.showbase import DirectObject
  30. from direct.actor.Actor import Actor
  31. from direct.filter.CommonFilters import CommonFilters
  32. # Local
  33. from core.db import Maps, AssetsPath
  34. import os
  35. class MiniMap(DirectObject.DirectObject):
  36. def __init__(self, mapId):
  37. self._mapId = mapId
  38. # Create 2d display stuff
  39. self.dr = base.win.makeDisplayRegion()
  40. self.dr.setSort(20)
  41. self.myCamera2d = NodePath(Camera('myCam2d'))
  42. lens = OrthographicLens()
  43. lens.setFilmSize(2, 2)
  44. lens.setNearFar(-1000, 1000)
  45. self.myCamera2d.node().setLens(lens)
  46. self.myRender2d = NodePath('myRender2d')
  47. self.myRender2d.setDepthTest(False)
  48. self.myRender2d.setDepthWrite(False)
  49. self.myCamera2d.reparentTo(self.myRender2d)
  50. self.dr.setCamera(self.myCamera2d)
  51. self._aspectRatio = base.getAspectRatio()
  52. self.myAspect2d = self.myRender2d.attachNewNode(PGTop('myAspect2d'))
  53. self.myAspect2d.setScale(1.0 / self._aspectRatio, 1.0, 1.0)
  54. # we now get buffer thats going to hold the texture of our new scene
  55. #self.mapWidth = Maps[mapId].width
  56. #self.mapHeight = Maps[mapId].height
  57. self.mapWidth = 100
  58. self.mapHeight = 100 # TODO
  59. self.mapWidthRatio = self.mapWidth / self.mapHeight
  60. self.mapHeightRatio = self.mapHeight / self.mapWidth
  61. if self.mapWidthRatio > 1: self.mapHeightRatio = 1
  62. else: self.mapWidthRatio = 1
  63. self.textureBuffer = base.win.makeTextureBuffer("miniMapBuffer", 256, 256)
  64. # now we have to setup a new scene graph to make this scene
  65. self.miniMapRender = NodePath("miniMapRender")
  66. # this takes care of setting up ther camera properly
  67. self.altCam = base.makeCamera(self.textureBuffer)
  68. self.altCam.reparentTo(self.miniMapRender)
  69. self.altCam.setPos(0, -24, 0)
  70. self._2dMap = loader.loadModel(
  71. Maps[mapId].orthoFilePath
  72. )
  73. self._2dMap.setScale(self.mapWidthRatio, 1, self.mapHeightRatio)
  74. self._2dMap.reparentTo(self.miniMapRender)
  75. self.altCam.lookAt(self._2dMap)
  76. self._model = loader.loadModel(os.path.join(AssetsPath.widgets, "miniMap.egg"))
  77. self._model.reparentTo(self.myAspect2d)
  78. self._model.setPos(-1.50, 0, 0.7)
  79. self.resize()
  80. projectionObj = self._model.find("**/miniMap")
  81. tex = self.textureBuffer.getTexture()
  82. projectionObj.setTexture(tex, 1)
  83. projectionObj.reparentTo(self._model)
  84. # Player head
  85. self._playerHead = self._model.find("**/miniMapHead")
  86. self._playerHead.reparentTo(self._model)
  87. # Zoom buttons
  88. self._zoomInButton = self._model.find("**/miniMapZoomIn")
  89. self._zoomOutButton = self._model.find("**/miniMapZoomOut")
  90. self._zoomInButton.reparentTo(self._model)
  91. self._zoomOutButton.reparentTo(self._model)
  92. self.accept("m", self.zoomIn)
  93. self.accept("n", self.zoomOut)
  94. self.accept("b", self.resize)
  95. self.accept("v", base.bufferViewer.toggleEnable)
  96. base.bufferViewer.setPosition("llcorner")
  97. base.bufferViewer.setCardSize(1.0, 0.0)
  98. base.mouseHandler.connect('mouse1', self._onLeftMouseClick, priority=1)
  99. #base.mouseHandler.connect('wheel_up', self._onLeftMouseClick, priority=1)
  100. #base.mouseHandler.connect('wheel_down', self._onLeftMouseClick, priority=1)
  101. self.accept('playerRotateEvent', self._onPlayerRotateEvent)
  102. self.accept('playerPositionUpdateEvent', self._onPlayerPositionUpdateEvent)
  103. self.accept('WINDOW_RESIZED', self.resize)
  104. def __del__(self):
  105. print("Destroyed MiniMap")
  106. """Events
  107. """
  108. def resize(self):
  109. """ Keep the minimap always the same size.
  110. """
  111. # Size of the miniMap-frame as reference
  112. blenderUnitWidth = 0.5
  113. blenderUnitHeight = 0.5
  114. screenWidth = base.win.getProperties().getXSize()
  115. screenHeight = base.win.getProperties().getYSize()
  116. ratio = base.getAspectRatio()
  117. zeroXPx = screenWidth / 2
  118. zeroZPx = screenHeight / 2
  119. oneUnitPerPixelX = ratio / zeroXPx
  120. oneUnitPerPixelZ = 1 / zeroZPx
  121. wantPixelsWidth = 175
  122. wantPixelsHeight = 175
  123. currentWidthPx = blenderUnitWidth / oneUnitPerPixelX
  124. currentHeightPx = blenderUnitHeight / oneUnitPerPixelZ
  125. widthScale = wantPixelsWidth / currentWidthPx
  126. heightScale = wantPixelsHeight / currentHeightPx
  127. self._model.setScale(widthScale, 1, heightScale)
  128. # Now re-position (TODO re-evaluate this method)
  129. wantPixelsTop = 25
  130. wantPixelsLeft = 15
  131. topPx = 1 - ((wantPixelsTop + (wantPixelsHeight / 2)) * oneUnitPerPixelZ)
  132. leftPx = ratio - ((wantPixelsLeft + (currentWidthPx / 2)) * oneUnitPerPixelX) # move to right
  133. self._model.setPos(leftPx, 0, topPx)
  134. def destroy(self):
  135. self.ignoreAll()
  136. self.removeAllTasks()
  137. loader.unloadModel(self._model)
  138. self._model.removeNode()
  139. del self._model
  140. self._model = None
  141. loader.unloadModel(self._2dMap)
  142. del self._2dMap
  143. self._2dMap = None
  144. self.altCam.removeNode()
  145. self.altCam = None
  146. self.myCamera2d.removeNode()
  147. self.myCamera2d = None
  148. self.myRender2d.removeNode()
  149. self.myRender2d = None
  150. self.myAspect2d.removeNode()
  151. self.myAspect2d = None
  152. self.miniMapRender.removeNode()
  153. self.miniMapRender = None
  154. base.graphicsEngine.removeWindow(self.textureBuffer)
  155. self.textureBuffer = None
  156. self.dr = None
  157. def _onPlayerRotateEvent(self, omega):
  158. self.altCam.setR(self.altCam, -omega)
  159. def _onPlayerPositionUpdateEvent(self, characterPos):
  160. self.altCam.setX(((characterPos[0] / self.mapWidth) * 16) * self.mapWidthRatio) # 2d map == 16x16 blender units
  161. self.altCam.setZ(((characterPos[1] / self.mapHeight) * 16) * self.mapHeightRatio)
  162. def _onLeftMouseClick(self, args=[]):
  163. mpos = base.mouseWatcherNode.getMouse()
  164. mousePos = (mpos.getX() * self._aspectRatio, mpos.getY())
  165. zoomInButtonPos = (
  166. ((self._model.getX() + self._zoomInButton.getX())),
  167. self._model.getZ() + self._zoomInButton.getZ()
  168. );
  169. zoomOutButtonPos = (
  170. ((self._model.getX() + self._zoomOutButton.getX())),
  171. self._model.getZ() + self._zoomOutButton.getZ()
  172. );
  173. margin = 0.03
  174. if (mousePos[0] + margin >= zoomInButtonPos[0]
  175. and mousePos[0] - margin <= zoomInButtonPos[0]
  176. and mousePos[1] + margin >= zoomInButtonPos[1]
  177. and mousePos[1] - margin <= zoomInButtonPos[1]):
  178. self.zoomIn()
  179. return True
  180. elif (mousePos[0] + margin >= zoomOutButtonPos[0]
  181. and mousePos[0] - margin <= zoomOutButtonPos[0]
  182. and mousePos[1] + margin >= zoomOutButtonPos[1]
  183. and mousePos[1] - margin <= zoomOutButtonPos[1]):
  184. self.zoomOut()
  185. return True
  186. else: return False
  187. @property
  188. def camera(self): return self.altCam
  189. # TODO it makes different on how large a map is (-4 * mapRatio?)
  190. def zoomIn(self):
  191. if self.altCam.getY() < (-24):
  192. self.altCam.setY(self.altCam, 1)
  193. return True
  194. return False
  195. # TODO it makes different on how large a map is (-96 * mapRatio?)
  196. def zoomOut(self):
  197. if self.altCam.getY() > (-128):
  198. self.altCam.setY(self.altCam, -1)
  199. return True
  200. return False
  201. class PlayerProto:
  202. """ Bones of player (only what is necesary so client and server can
  203. subclass from this)
  204. """
  205. def __init__(self, world, worldNP, character, mapId):
  206. self._world = world
  207. self._worldNP = worldNP
  208. self._character = character
  209. self._mapId = mapId
  210. self.crouching = False
  211. self.isMoving = False
  212. self._previousCharacterPos = Vec3()
  213. self.keyMap = {
  214. "shuffleLeft": 0,
  215. "shuffleRight": 0,
  216. "forward": 0,
  217. "backward": 0,
  218. "jump": 0
  219. }
  220. @property
  221. def character(self): return self._character
  222. def id(self): return self._id
  223. def setKey(self, key, value):
  224. self.keyMap[key] = value
  225. return True # to base.mouseHandler that we accepted
  226. def destroy(self):
  227. self.characterNP.removeNode()
  228. self._world.remove(self.characterCont) # (BulletWorld.remove())
  229. del self.characterNP
  230. del self.characterCont
  231. self.characterCont = None
  232. self.characterNP = None
  233. def setup(self):
  234. h = 0.6
  235. w = 0.3
  236. # BulletCapsuleShape(float radius, float height, BulletUpAxis up)
  237. shape = BulletCapsuleShape(w, h, ZUp)
  238. # BulletCharacterControllerNode(BulletShape shape, float step_height, str name)
  239. self.characterCont = BulletCharacterControllerNode(shape, 0.5, 'Player')
  240. self.characterCont.setGravity(18.0)
  241. self.characterCont.setMaxSlope(0.5)
  242. self.characterNP = self._worldNP.attachNewNode(self.characterCont)
  243. self.characterNP.setPos(*self.character.spawnData.pos)
  244. self.characterNP.setH(self.character.spawnData.orientation)
  245. self.characterNP.setCollideMask(BitMask32.allOn())
  246. self._world.attach(self.characterCont)
  247. def rotate(self, omega):
  248. self.characterNP.setH(self.characterNP, omega)
  249. def rotateLeft(self, dt):
  250. omega = 120 * dt
  251. self.characterNP.setH(self.characterNP, omega)
  252. return omega
  253. def rotateRight(self, dt):
  254. omega = -120 * dt
  255. self.characterNP.setH(self.characterNP, omega)
  256. return omega
  257. def forward(self, dt, moveVec):
  258. moveVec.setY(6 * dt)
  259. def backward(self, dt, moveVec):
  260. moveVec.setY(-3 * dt)
  261. def shuffleLeft(self, dt, moveVec):
  262. moveVec.setX(-3 * dt)
  263. def shuffleRight(self, dt, moveVec):
  264. moveVec.setX(3 * dt)
  265. def setPos(self, moveVec):
  266. self.characterNP.setPos(self.characterNP, moveVec)
  267. def setGlobalPos(self, moveVec):
  268. self.characterNP.setPos(moveVec)
  269. def setOrientation(self, o):
  270. self.characterNP.setH(o)
  271. def setGlobalX(self, x): self.characterNP.setX(x)
  272. def setGlobalY(self, y): self.characterNP.setY(y)
  273. def setGlobalZ(self, z): self.characterNP.setZ(z)
  274. def getGlobalPos(self): return self.characterNP.getPos()
  275. def getOrientation(self): return self.characterNP.getH()
  276. def updatePreviousPos(self): # TODO find better name for this
  277. characterPos = self.characterNP.getPos()
  278. if characterPos[2] < -10:
  279. # reset pos (character is fallen of the map)
  280. self.characterNP.setPos(*self._pos) # TODO create function for this, it doesnt belong here
  281. if characterPos != self._previousCharacterPos:
  282. self._previousCharacterPos = characterPos
  283. self.isMoving = True
  284. else: self.isMoving = False
  285. def doJump(self):
  286. if self.characterCont.isOnGround() and self.isMoving:
  287. self.characterCont.setMaxJumpHeight(1.25)
  288. self.characterCont.setJumpSpeed(5.6)
  289. self.characterCont.setFallSpeed(16)
  290. self.characterCont.doJump()
  291. self.setKey('jump', False)
  292. def doCrouch(self):
  293. self.crouching = not self.crouching
  294. #sz = self.crouching and 1.2 or 1.0
  295. # eh this does not work
  296. # https://www.panda3d.org/manual/?title=Bullet_Character_Controller#Crouching
  297. #self.characterNP.setScale(Vec3(1, 1, sz))
  298. #self.characterCont.getShape().setLocalScale(Vec3(1, 1, sz))
  299. class InputLocker(DirectObject.DirectObject):
  300. def __init__(self):
  301. self._lockInput = False
  302. self.accept('lockInput', self._setLockInput)
  303. def _setLockInput(self, state):
  304. self._lockInput = state
  305. def locked(self): return self._lockInput
  306. class Player(PlayerProto):
  307. def __init__(self, world, worldNP, character, mapId):
  308. PlayerProto.__init__(self, world, worldNP, character, mapId)
  309. self.keyMap.update({
  310. "walk": 0,
  311. "rotateLeft": 0,
  312. "rotateRight": 0,
  313. "cameraUp": 0,
  314. "cameraDown" : 0,
  315. "leftMouse" : 0,
  316. "rightMouse" : 0
  317. })
  318. self._previousKeyMap = self.keyMap.copy()
  319. base.accept('space', self.setKey, ["jump", True])
  320. base.accept('c', self.doCrouch)
  321. base.accept("a", self.setKey, ["shuffleLeft", True])
  322. base.accept("d", self.setKey, ["shuffleRight", True])
  323. base.accept("w", self.setKey, ["forward", True])
  324. base.accept("W", self.setKey, ["walk", True])
  325. base.accept("shift", self.setKey, ["walk", True])
  326. base.accept("s", self.setKey, ["backward", True])
  327. base.accept("q", self.setKey, ["rotateLeft", True])
  328. base.accept("e", self.setKey, ["rotateRight", True])
  329. base.accept("r", self.setKey, ["cameraUp", True])
  330. base.accept("f", self.setKey, ["cameraDown", True])
  331. base.accept("a-up", self.setKey, ["shuffleLeft", False])
  332. base.accept("d-up", self.setKey, ["shuffleRight", False])
  333. base.accept("w-up", self.setKey, ["forward", False])
  334. base.accept("W-up", self.setKey, ["walk", False])
  335. base.accept("shift-up", self.setKey, ["walk", False])
  336. base.accept("s-up", self.setKey, ["backward", False])
  337. base.accept("q-up", self.setKey, ["rotateLeft", False])
  338. base.accept("e-up", self.setKey, ["rotateRight", False])
  339. base.accept("r-up", self.setKey, ["cameraUp", False])
  340. base.accept("f-up", self.setKey, ["cameraDown", False])
  341. self._mouseEvents = {
  342. "leftJustClicked" : True,
  343. "rightJustClicked" : True
  344. }
  345. self._cursorBackup = [0, 0]
  346. self._cursorPrevPos = [0, 0]
  347. self._currentCameraAngle = [0, 0]
  348. self._cursorBusy = False
  349. self._cameraZoomLevel = 2.0
  350. self._cameraZoomMax = 20
  351. self._cameraZoomMin = 0
  352. self._cameraHorizontalAngle = 0;
  353. self._cameraVerticalAngle = 0;
  354. base.mouseHandler.connect('mouse1', self.setKey, args=["leftMouse", True], priority=10)
  355. base.mouseHandler.connect('mouse1-up', self.setKey, args=["leftMouse", False], priority=10)
  356. base.mouseHandler.connect('mouse3', self.setKey, args=["rightMouse", True], priority=10)
  357. base.mouseHandler.connect('mouse3-up', self.setKey, args=["rightMouse", False], priority=10)
  358. base.mouseHandler.connect('wheel_up', self.mouseWheelUp, priority=10)
  359. base.mouseHandler.connect('wheel_down', self.mouseWheelDown, priority=10)
  360. self._cursorBackup = [0, 0]
  361. self._cursorPrevPos = [0, 0]
  362. self._animationSet = False
  363. self._cameraZoomLevel = 2.0
  364. self._cameraZoomMax = 20
  365. self._cameraZoomMin = 0
  366. self._cameraHorizontalAngle = 0;
  367. self._cameraVerticalAngle = 0;
  368. self.setup()
  369. self._inputLocker = InputLocker()
  370. self._inputChanged = False
  371. self._orientationChanged = False
  372. # Screen filter
  373. filters = CommonFilters(base.win, base.cam)
  374. filters.setBloom()
  375. # Task
  376. taskMgr.add(self.update, 'userInteract')
  377. @property
  378. def cursorBusy(self): return self._cursorBusy
  379. def rotate(self, omega): # override
  380. self._orientationChanged = True
  381. PlayerProto.rotate(self, omega)
  382. def rotateLeft(self, dt): # override
  383. self._orientationChanged = True
  384. return PlayerProto.rotateLeft(self, dt)
  385. def rotateRight(self, dt): # override
  386. self._orientationChanged = True
  387. return PlayerProto.rotateRight(self, dt)
  388. def mouseWheelUp(self):
  389. if (self.camFloater.getY()+0.3) < -1.0:
  390. self.camFloater.setY(self.camFloater.getY()+0.3)
  391. return True
  392. return False
  393. def mouseWheelDown(self):
  394. if (self.camFloater.getY()+-0.3) > -15:
  395. self.camFloater.setY(self.camFloater.getY()-0.3)
  396. return True
  397. return False
  398. def setKey(self, key, value):# override
  399. self._inputChanged = True
  400. self.keyMap[key] = value
  401. def moveCameraVertical(self, amount):
  402. newZ = self.camFloater.getZ(self.characterNP) + amount
  403. if newZ < 15 and newZ > -15: # Max zoomout
  404. self.camFloater.setZ(self.camFloater, amount)
  405. def processInput(self, dt):
  406. omega = 0.0
  407. mouseForward = False
  408. camSen = 220
  409. charSen = 32
  410. if self.keyMap["leftMouse"] or self.keyMap["rightMouse"]:
  411. if self.keyMap["leftMouse"] and self.keyMap["rightMouse"]:
  412. mouseForward = True
  413. if self.keyMap["rightMouse"]:
  414. if self._mouseEvents["rightJustClicked"]:
  415. self._mouseEvents["rightJustClicked"] = False
  416. if not self._cursorBackup[0]:
  417. self._cursorBusy = True
  418. self.showCursor(False);
  419. self.backupCursorPosition();
  420. self.centerCursor();
  421. else:
  422. # Move camera
  423. mw = base.mouseWatcherNode
  424. xDiff = mw.getMouseX()
  425. yDiff = mw.getMouseY()
  426. #camY = self.camFloater.getY() + -(yDiff * 300) * dt
  427. self.moveCameraVertical(-(yDiff * camSen) * dt)
  428. # Rotate characterNP
  429. omega = -xDiff * charSen
  430. #omega = Decimal(-xDiff * charSen).quantize(Decimal('.0001'), rounding=ROUND_DOWN)
  431. self.rotate(omega)
  432. messenger.send('playerRotateEvent', [omega])
  433. self.centerCursor();
  434. elif self.keyMap["leftMouse"]:
  435. if self._mouseEvents["leftJustClicked"]:
  436. self._mouseEvents["leftJustClicked"] = False
  437. if not self._cursorBackup[0]:
  438. self._cursorBusy = True
  439. self.showCursor(False);
  440. self.backupCursorPosition();
  441. self.centerCursor();
  442. else:
  443. mw = base.mouseWatcherNode
  444. xDiff = mw.getMouseX() * 560
  445. yDiff = mw.getMouseY() * 300
  446. self.moveCameraVertical(-yDiff * dt)
  447. self.floater.setH(self.floater, -xDiff * dt)
  448. self.centerCursor();
  449. elif self._cursorBackup[0]:
  450. self._mouseEvents["leftJustClicked"] = True
  451. self._mouseEvents["rightJustClicked"] = True
  452. self.restoreCursorPosition();
  453. self._cursorBusy = False
  454. self.showCursor();
  455. mouseForward = False
  456. # Restore camera behind character if moving and not leftmouse
  457. if self.keyMap['forward'] and not self.keyMap["leftMouse"]:
  458. if self.floater.getH() > 0.4:
  459. self.floater.setH(self.floater, -0.45)
  460. elif self.floater.getH() < -0.4:
  461. self.floater.setH(self.floater, 0.45)
  462. moveVec = Vec3()
  463. if self.keyMap['forward'] or mouseForward:
  464. self.forward(dt, moveVec)
  465. elif self.keyMap['backward']:
  466. self.backward(dt, moveVec)
  467. if self.keyMap['shuffleLeft']:
  468. self.shuffleLeft(dt, moveVec)
  469. elif self.keyMap['shuffleRight']:
  470. self.shuffleRight(dt, moveVec)
  471. if self.keyMap['rotateLeft']:
  472. messenger.send('playerRotateEvent', [self.rotateLeft(dt)])
  473. elif self.keyMap['rotateRight']:
  474. messenger.send('playerRotateEvent', [self.rotateRight(dt)])
  475. if self._orientationChanged:
  476. self._orientationChanged = False
  477. # Send for mini-map
  478. messenger.send('playerOrientationChanged', [self])
  479. if self.keyMap["jump"]: self.doJump()
  480. # Move
  481. self.setPos(moveVec)
  482. self.updatePreviousPos()
  483. if self.isMoving:
  484. messenger.send('playerPositionUpdateEvent', [self._previousCharacterPos]) # self._previousCharacterPos is the current pos, updatePreviousPos set it.
  485. if self.keyMap['cameraUp']:
  486. self.moveCameraVertical(0.2)
  487. elif self.keyMap['cameraDown']:
  488. self.moveCameraVertical(-0.2)
  489. if not self._animationSet and self.isMoving:
  490. if self.keyMap["walk"]:
  491. self.actorNP.loop("walk")
  492. else:
  493. self.actorNP.loop("run")
  494. self._animationSet = True
  495. elif self._animationSet and not self.isMoving:
  496. self.actorNP.stop()
  497. self.actorNP.loop("idle")
  498. self._animationSet = False
  499. base.camera.lookAt(self.floater)
  500. def destroy(self):
  501. taskMgr.remove('userInteract')
  502. PlayerProto.destroy(self)
  503. self.actorNP.cleanup()
  504. self.actorNP.removeNode()
  505. self.floater.removeNode()
  506. self.camFloater.removeNode()
  507. self.characterNameNP.removeNode()
  508. self.miniMap.destroy()
  509. self.miniMap = None
  510. def setup(self):
  511. # Create character
  512. PlayerProto.setup(self)
  513. # Character model
  514. self.actorNP = Actor(
  515. os.path.join(AssetsPath.players, self.character.file)
  516. )
  517. #self.actorNP = Actor(
  518. # "assets/characters/{0}".format(self.character.model.file),
  519. # self.character.model.actions)
  520. self.actorNP.setPlayRate(1.1, 'run')
  521. self.actorNP.reparentTo(self.characterNP)
  522. self.actorNP.setScale(0.3048) # 1ft = 0.3048m
  523. self.actorNP.setH(180)
  524. # Model to collision mesh offset TODO make dynamic
  525. self.actorNP.setPos(0, 0, -0.55)
  526. # Character camera
  527. self.floater = NodePath(PandaNode("floater"))
  528. self.floater.reparentTo(self.characterNP)
  529. self.floater.setZ(0.45) # Set floater height TODO make dynamic
  530. self.floater.setY(1.0)
  531. base.camera.reparentTo(self.floater)
  532. self.camFloater = NodePath(PandaNode("camFloater"))
  533. self.camFloater.setPos(0, -3, 1)
  534. self.camFloater.reparentTo(self.floater)
  535. base.camera.reparentTo(self.camFloater)
  536. # Player name node
  537. # TODO more dynamic height
  538. self.characterName = TextNode('characterName')
  539. self.characterName.setText(self.character.name)
  540. self.characterNameNP = self.floater.attachNewNode(self.characterName)
  541. self.characterNameNP.setScale(0.2)
  542. self.characterNameNP.setPos((0.1, -1, 0.3))
  543. # MiniMap
  544. self.miniMap = MiniMap(self._mapId)
  545. base.camera.lookAt( 0, 0, 0 )
  546. def centerCursor(self):
  547. props = base.win.getProperties();
  548. base.win.movePointer(0, int(props.getXSize() / 2), int(props.getYSize() / 2))
  549. def backupCursorPosition(self):
  550. mw = base.mouseWatcherNode
  551. self._cursorBackup = [mw.getMouseX(), mw.getMouseY()]
  552. def restoreCursorPosition(self):
  553. props = base.win.getProperties()
  554. x = int((props.getXSize() / 2) * (self._cursorBackup[0] + 1 ))
  555. y = int((props.getYSize() / 2) * (-self._cursorBackup[1] + 1 ))
  556. base.win.movePointer(0, x, y)
  557. self._cursorBackup = [0, 0]
  558. def showCursor(self, state=True):
  559. wprops = WindowProperties()
  560. wprops.setCursorHidden(not state)
  561. base.win.requestProperties(wprops)
  562. def update(self, task):
  563. dt = globalClock.getDt()
  564. self.processInput(dt)
  565. return task.cont