Browse Source

samples: various improvements to Roaming Ralph sample:

- add a skybox color (required making boundary around environment transparent)
- use CollisionHandlerPusher and spheres to detect collisions with obstacles
- add ability to walk backwards
- increase minimum distance between follow camera and terrain, to avoid clipping through
- make Ralph run slightly less ridiculously fast

Closes #565

Co-authored-by: rdb <[email protected]>
Mitchell Stokes 6 years ago
parent
commit
017b4b5835
2 changed files with 70 additions and 37 deletions
  1. 70 37
      samples/roaming-ralph/main.py
  2. BIN
      samples/roaming-ralph/models/world.egg.pz

+ 70 - 37
samples/roaming-ralph/main.py

@@ -12,6 +12,7 @@
 from direct.showbase.ShowBase import ShowBase
 from panda3d.core import CollisionTraverser, CollisionNode
 from panda3d.core import CollisionHandlerQueue, CollisionRay
+from panda3d.core import CollisionHandlerPusher, CollisionSphere
 from panda3d.core import Filename, AmbientLight, DirectionalLight
 from panda3d.core import PandaNode, NodePath, Camera, TextNode
 from panda3d.core import CollideMask
@@ -40,12 +41,15 @@ class RoamingRalphDemo(ShowBase):
         # Set up the window, camera, etc.
         ShowBase.__init__(self)
 
-        # Set the background color to black
-        self.win.setClearColor((0, 0, 0, 1))
-
         # This is used to store which keys are currently pressed.
         self.keyMap = {
-            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0}
+            "left": 0,
+            "right": 0,
+            "forward": 0,
+            "backward": 0,
+            "cam-left": 0,
+            "cam-right": 0,
+        }
 
         # Post the instructions
         self.title = addTitle(
@@ -54,8 +58,9 @@ class RoamingRalphDemo(ShowBase):
         self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left")
         self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right")
         self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward")
-        self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left")
-        self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right")
+        self.inst5 = addInstructions(0.30, "[Down Arrow]: Walk Ralph Backward")
+        self.inst6 = addInstructions(0.36, "[A]: Rotate Camera Left")
+        self.inst7 = addInstructions(0.42, "[S]: Rotate Camera Right")
 
         # Set up the environment
         #
@@ -72,6 +77,9 @@ class RoamingRalphDemo(ShowBase):
         self.environ = loader.loadModel("models/world")
         self.environ.reparentTo(render)
 
+        # We do not have a skybox, so we will just use a sky blue background color
+        self.setBackgroundColor(0.53, 0.80, 0.92, 1)
+
         # Create the main character, Ralph
 
         ralphStartPos = self.environ.find("**/start_point").getPos()
@@ -80,7 +88,7 @@ class RoamingRalphDemo(ShowBase):
                             "walk": "models/ralph-walk"})
         self.ralph.reparentTo(render)
         self.ralph.setScale(.2)
-        self.ralph.setPos(ralphStartPos + (0, 0, 0.5))
+        self.ralph.setPos(ralphStartPos + (0, 0, 1.5))
 
         # Create a floater object, which floats 2 units above ralph.  We
         # use this as a target for the camera to look at.
@@ -95,31 +103,51 @@ class RoamingRalphDemo(ShowBase):
         self.accept("arrow_left", self.setKey, ["left", True])
         self.accept("arrow_right", self.setKey, ["right", True])
         self.accept("arrow_up", self.setKey, ["forward", True])
+        self.accept("arrow_down", self.setKey, ["backward", True])
         self.accept("a", self.setKey, ["cam-left", True])
         self.accept("s", self.setKey, ["cam-right", True])
         self.accept("arrow_left-up", self.setKey, ["left", False])
         self.accept("arrow_right-up", self.setKey, ["right", False])
         self.accept("arrow_up-up", self.setKey, ["forward", False])
+        self.accept("arrow_down-up", self.setKey, ["backward", False])
         self.accept("a-up", self.setKey, ["cam-left", False])
         self.accept("s-up", self.setKey, ["cam-right", False])
 
         taskMgr.add(self.move, "moveTask")
 
-        # Game state variables
-        self.isMoving = False
-
         # Set up the camera
         self.disableMouse()
         self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)
 
+        self.cTrav = CollisionTraverser()
+
+        # Use a CollisionHandlerPusher to handle collisions between Ralph and
+        # the environment. Ralph is added as a "from" object which will be
+        # "pushed" out of the environment if he walks into obstacles.
+        #
+        # Ralph is composed of two spheres, one around the torso and one
+        # around the head.  They are slightly oversized since we want Ralph to
+        # keep some distance from obstacles.
+        self.ralphCol = CollisionNode('ralph')
+        self.ralphCol.addSolid(CollisionSphere(center=(0, 0, 2), radius=1.5))
+        self.ralphCol.addSolid(CollisionSphere(center=(0, -0.25, 4), radius=1.5))
+        self.ralphCol.setFromCollideMask(CollideMask.bit(0))
+        self.ralphCol.setIntoCollideMask(CollideMask.allOff())
+        self.ralphColNp = self.ralph.attachNewNode(self.ralphCol)
+        self.ralphPusher = CollisionHandlerPusher()
+        self.ralphPusher.horizontal = True
+
+        # Note that we need to add ralph both to the pusher and to the
+        # traverser; the pusher needs to know which node to push back when a
+        # collision occurs!
+        self.ralphPusher.addCollider(self.ralphColNp, self.ralph)
+        self.cTrav.addCollider(self.ralphColNp, self.ralphPusher)
+
         # We will detect the height of the terrain by creating a collision
         # ray and casting it downward toward the terrain.  One ray will
         # start above ralph's head, and the other will start above the camera.
         # A ray may hit the terrain, or it may hit a rock or a tree.  If it
-        # hits the terrain, we can detect the height.  If it hits anything
-        # else, we rule that the move is illegal.
-        self.cTrav = CollisionTraverser()
-
+        # hits the terrain, we can detect the height.
         self.ralphGroundRay = CollisionRay()
         self.ralphGroundRay.setOrigin(0, 0, 9)
         self.ralphGroundRay.setDirection(0, 0, -1)
@@ -143,7 +171,7 @@ class RoamingRalphDemo(ShowBase):
         self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)
 
         # Uncomment this line to see the collision rays
-        #self.ralphGroundColNp.show()
+        #self.ralphColNp.show()
         #self.camGroundColNp.show()
 
         # Uncomment this line to show a visual representation of the
@@ -181,11 +209,6 @@ class RoamingRalphDemo(ShowBase):
         if self.keyMap["cam-right"]:
             self.camera.setX(self.camera, +20 * dt)
 
-        # save ralph's initial position so that we can restore it,
-        # in case he falls off the map or runs into something.
-
-        startpos = self.ralph.getPos()
-
         # If a move-key is pressed, move ralph in the specified direction.
 
         if self.keyMap["left"]:
@@ -193,17 +216,28 @@ class RoamingRalphDemo(ShowBase):
         if self.keyMap["right"]:
             self.ralph.setH(self.ralph.getH() - 300 * dt)
         if self.keyMap["forward"]:
-            self.ralph.setY(self.ralph, -25 * dt)
+            self.ralph.setY(self.ralph, -20 * dt)
+        if self.keyMap["backward"]:
+            self.ralph.setY(self.ralph, +10 * dt)
 
         # If ralph is moving, loop the run animation.
         # If he is standing still, stop the animation.
+        currentAnim = self.ralph.getCurrentAnim()
 
-        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"]:
-            if self.isMoving is False:
+        if self.keyMap["forward"]:
+            if currentAnim != "run":
                 self.ralph.loop("run")
-                self.isMoving = True
+        elif self.keyMap["backward"]:
+            # Play the walk animation backwards.
+            if currentAnim != "walk":
+                self.ralph.loop("walk")
+            self.ralph.setPlayRate(-1.0, "walk")
+        elif self.keyMap["left"] or self.keyMap["right"]:
+            if currentAnim != "walk":
+                self.ralph.loop("walk")
+            self.ralph.setPlayRate(1.0, "walk")
         else:
-            if self.isMoving:
+            if currentAnim is not None:
                 self.ralph.stop()
                 self.ralph.pose("walk", 5)
                 self.isMoving = False
@@ -228,25 +262,24 @@ class RoamingRalphDemo(ShowBase):
         #self.cTrav.traverse(render)
 
         # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
-        # update his Z. If it hit anything else, or didn't hit anything, put
-        # him back where he was last frame.
+        # update his Z
 
-        entries = list(self.ralphGroundHandler.getEntries())
+        entries = list(self.ralphGroundHandler.entries)
         entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
 
-        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
-            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
-        else:
-            self.ralph.setPos(startpos)
+        for entry in entries:
+            if entry.getIntoNode().getName() == "terrain":
+                self.ralph.setZ(entry.getSurfacePoint(render).getZ())
 
-        # Keep the camera at one foot above the terrain,
-        # or two feet above ralph, whichever is greater.
+        # Keep the camera at one unit above the terrain,
+        # or two units above ralph, whichever is greater.
 
-        entries = list(self.camGroundHandler.getEntries())
+        entries = list(self.camGroundHandler.entries)
         entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
 
-        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
-            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
+        for entry in entries:
+            if entry.getIntoNode().getName() == "terrain":
+                self.camera.setZ(entry.getSurfacePoint(render).getZ() + 1.5)
         if self.camera.getZ() < self.ralph.getZ() + 2.0:
             self.camera.setZ(self.ralph.getZ() + 2.0)
 

BIN
samples/roaming-ralph/models/world.egg.pz