Limiting the terrain that an actor can walk on

In fact, I liked the idea you present so much that I went ahead and made a working example of it.

You can use any 1024x1024 image for the texture, just save it in the same folder with the name “Terrain.png”. Black areas in the image are traversable, white areas are not. Make sure the center of the image is black, since you start in the middle of the image.

Note that in this example I’m using the Z coordinate in place of Y for the camera position because the texture card is vertical, like a billboard, instead of horizontal, like a terrain would be.

main.py:

import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import *


class Game(DirectObject):
  def __init__(self):
    base.disableMouse()
    
    self.card = loader.loadModel("Terrain.egg")
    self.card.reparentTo(render)
    self.card.setY(1000)
    
    self.dude = loader.loadModel("panda.egg")
    self.dude.reparentTo(base.camera)
    self.dude.setColor(1,0,0,1)
    self.dude.setY(100)
    
    self.image = PNMImage()
    self.image.read("Terrain.png")
    
    self.keyMap = {  "w" : False,
            "s" : False,
            "a" : False,
            "d" : False }
    
    self.accept("w", self.setKey, ["w", True])
    self.accept("s", self.setKey, ["s", True])
    self.accept("a", self.setKey, ["a", True])
    self.accept("d", self.setKey, ["d", True])
    
    self.accept("w-up", self.setKey, ["w", False])
    self.accept("s-up", self.setKey, ["s", False])
    self.accept("a-up", self.setKey, ["a", False])
    self.accept("d-up", self.setKey, ["d", False])
    
    taskMgr.add(self.moveTask, "Move Task")
    
  def setKey(self, key, value):
    self.keyMap[key] = value
    
  def moveTask(self, task):
    dt = globalClock.getDt()
    if (dt > .05):
      return task.cont
      
    newCamPos = base.camera.getPos()
      
    if(self.keyMap["w"] == True):
      newCamPos = newCamPos + Point3(0,0, dt * 100)
    elif(self.keyMap["s"] == True):
      newCamPos = newCamPos + Point3(0,0, dt * -100)
      
    if(self.keyMap["a"] == True):
      newCamPos = newCamPos + Point3(dt * -100, 0,0)
    elif(self.keyMap["d"] == True):
      newCamPos = newCamPos + Point3(dt * 100, 0,0)
      
    imageX = int(newCamPos.getX()) + 512
    imageY = 1024 - (int(newCamPos.getZ()) + 512)
    if(0 < imageX and imageX < 1024):
      if(0 < imageY and imageY < 1024):
        bright = self.image.getBright(imageX, imageY)
        if(bright < 0.5):
          base.camera.setPos(newCamPos)
      
    return task.cont
      
g = Game()
run()

Terrain.egg:

<Comment> {
  "egg-texture-cards -g -512,512,-512,512 -p 1024,1024 -o Terrain.egg Terrain.png"
}
<Texture> Terrain {
  Terrain.png
}
<Group> {
  <VertexPool> vpool {
    <Vertex> 0 {
      -512 512 0
      <UV> { 0 1 }
    }
    <Vertex> 1 {
      -512 -512 0
      <UV> { 0 0 }
    }
    <Vertex> 2 {
      512 -512 0
      <UV> { 1 0 }
    }
    <Vertex> 3 {
      512 512 0
      <UV> { 1 1 }
    }
  }
  <Group> Terrain {
    <Polygon> {
      <RGBA> { 1 1 1 1 }
      <TRef> { Terrain }
      <VertexRef> { 0 1 2 3 <Ref> { vpool } }
    }
  }
}