Obstacle creation at runtime [SOLVED]

I try not add too much questions here, I nevertheless spent some days to read docs & threads but did not found out how to resolve my problem:

[color=brown]It consist of adding a model (wall) when clicking somewhere on the terrain.

it’s ok on a simple tree code, but from the mouswalker I didnot succeed to insert it.

Here is the code, the one that is not working is within the minus lines (putwall,near the end )

# Left click on the ground to move.
# Rotate the camera by moving the mouse pointer to the edges of the screen or
# with the left & right arrow keys.
# Zoom the camera with the mouse wheel or the up & down arrow keys.

import direct.directbase.DirectStart # Start Panda.
from pandac.PandaModules import * # Import the Panda Modules.
from direct.showbase.DirectObject import DirectObject # To handle Events.
from direct.task import Task # To use Tasks.
from direct.actor import Actor # To use animated Actors.
from direct.interval.IntervalGlobal import * # To use Intervals.
# We need to import this function for the player's rotation to work properly.
from direct.showbase.PythonUtil import closestDestAngle
from direct.gui.OnscreenText import OnscreenText
from direct.gui.OnscreenImage import OnscreenImage
import sys
from draw import *


class Controls(DirectObject):
    def __init__(self):
        base.disableMouse() # Disable default camera.
        self.loadModels()
        self.setupCollisions()
        self.drawGrid()
        self.putWall()
        
        # Declare variables.
        self.position = None

        self.playerMovement = None
        self.movementSpeed = 6.0 # Controls how long it takes the player to
        # move to the clicked destination.
        self.speed = .10 # Controls the speed of the camera's rotation and zoom.
        # Setup controls
        self.accept("escape", sys.exit)
        self.accept("player-stopped", self.stopWalkAnim)
        self.accept("mouse1", self.moveToPosition)
        self.accept("arrow_left", self.cameraTurn,[-1])
        self.accept("arrow_right", self.cameraTurn,[1])
        self.accept("arrow_up", self.cameraZoom,[-1])
        self.accept("arrow_down", self.cameraZoom,[1])
        self.accept("wheel_up", self.cameraZoom,[-1])
        self.accept("wheel_down", self.cameraZoom,[1])
##        self.accept("g",self.drawGrid)
        
        textObject = OnscreenText(text = 'Du tExte', pos = (-1, 0.7), scale = 0.07)
       
        
        taskMgr.add(self.edgeScreenTracking, "edgeScreenTracking")
        # End __init__

    def drawGrid(self):
     # Create the static elements of the test environment. Use one Draw
            # object for all the static elements.
        d = Draw()

           # Make a 30x30 grid centered at the origin, in Purple.
        d.drawXYGrid(Vec2(-15.5,-15.2), numSquares=30,squareSize=1.03,color=(0.66,0,0.66,1))

      # Draw a grey 100x100x100 cuboid, with the grid we previously drew as the floor of the cuboid.

        d.drawCuboid(Vec3(-5,-5,0), Vec3(5,5,2.5), color=(0.2,0.3,0.9,1))

        node = d.create() # A special GeomNode that draws the shapes.
        np = NodePath(node)
        np.reparentTo(render)
        
  

    def loadModels(self):
        # Load an environment
        self.environ = loader.loadModel("models/terrain2.egg")
        self.environ.reparentTo(render) # Place it in the scene.
        self.environ.setPos(0, 0, 0)
##        texture = loader.loadTexture("models/rock03.jpg")
##        self.environ.setTexture(texture)


        # For the camera to rotate independently of the player a 'player dummy
        # node' and a 'camera dummy node' need to be created. Both dummy nodes
        # are then 'parented' to the 'player dummy node' making them "siblings"
        # under the player dummy node. This means that any transformations
        # performed on the dummy node will be inherited by the player model and
        # the camera. Moving the player dummy node will move both the player
        # model and the camera, but moving or rotating the player model itself
        # won't effect the camera (because the camera isn't directly parented
        # to it).

        # Create the player's dummy node.
        self.player_dummy_node = render.attachNewNode("player_dummy_node")
        # Position the dummy node.
        self.player_dummy_node.setPos(0, 0, 0)
        self.player_dummy_node.setHpr(0, 0, 0)
        # The terrain model was edited by hand to include a start position for
        # the player. Use the Find command to locate it.
        self.playerStart = self.environ.find("**/start_point").getPos()
        # Now load the player model and its animations.
        self.player = Actor.Actor("models/ralph",{"walk":"models/ralph-walk"})
        # Set the player to the start position.
        self.player.setPos(self.playerStart)
        # Attach/parent the player model to the player dummy node.
        self.player.reparentTo(self.player_dummy_node)
        # The player model is too large, so scale it down by 50%.
        self.player.setScale(.5)
 
        # Now create the camera dummy node.
        self.camera_dummy_node = render.attachNewNode("camera_dummy_node")
        # Attach/parent the camera dummy node to the player dummy node.
        self.camera_dummy_node.reparentTo(self.player_dummy_node)
        # Attach/parent the main camera to the camera dummy node.
        camera.reparentTo(self.camera_dummy_node)
        # Position the main camera.
        camera.setPos(0, -35, 18) # X = left & right, Y = zoom, Z = Up & down.
        camera.setHpr(0, -25, 0) # Heading, pitch, roll.
   
        # End loadModels

    # Define a function to setup collision detection. We need two rays, one
    # attached to the camera for mouse picking and one attached to the player
    # for collision with the terrain. The rays must only cause collisions and
    # not collide with each other so their Into bitMasks are set to allOff().
    def setupCollisions(self):
        # The terrain model was edited by hand to include the following tag:
        # <Collide> Plane01 { Polyset keep descend }.
        #Once we have the collision tags in the model, we can get to them using
        # the NodePath's find command.
        self.ground = self.environ.find("**/terrain")
        # Set the model's Into collide mask to bit (0). Now only objects that
        # have their From bitmask also set to (0) can collide with the terrain.
        self.ground.node().setIntoCollideMask(BitMask32.bit(0))
        # Create a CollisionTraverser for the picker ray. CollisionTraversers
        # are what do the job of calculating collisions.
        self.picker = CollisionTraverser()
        # Create a handler for the picker ray
        self.queue = CollisionHandlerQueue()
        # Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        # Attach that node to the camera since the ray will need to be positioned
        # relative to it.
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        # Set the collision node's From collide mask. Now the ray can only cause
        # collisions with objects that have bitMask(0) such as the terrain.
        self.pickerNode.setFromCollideMask(BitMask32.bit(0))
        # Set the collision node's Into collide mask to allOff so that nothing
        # can collide into the ray.
        self.pickerNode.setIntoCollideMask(BitMask32.allOff())
        # Make our ray
        self.pickerRay = CollisionRay()
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        #Register the ray as something that can cause collisions with the traverser
        self.picker.addCollider(self.pickerNP, self.queue)

        # Setup collision stuff to handle the player's collision with the terrain.
        # Make a collision node for the player's ray.
        self.groundCol = CollisionNode('playerRay')
        # Make a collision ray for the player.
        self.groundRay = CollisionRay()
        # Attach the collision node to the player dummy node.
        self.groundColNp = self.player_dummy_node.attachNewNode(self.groundCol)
        # Set the height of the ray (7 units above the player's head)
        self.groundRay.setOrigin(0, 0, 7)
        # Set the rays direction (pointing down on the Z axis)
        self.groundRay.setDirection(0, 0, -1)
        # Add the collision node to the collision ray
        self.groundCol.addSolid(self.groundRay)
        # Set the collision node's From collide mask. Now the ray can collide
        # with objects (like the terrain) that also have bitMask(0).
        self.groundCol.setFromCollideMask(BitMask32.bit(0))
        # Set the collision node's Into collide mask to allOff so that nothing
        # can collide into the ray.
        self.groundCol.setIntoCollideMask(BitMask32.allOff())
        # Make a CollisionTraverser. This will be used in the correctPlayerZ
        # function.
        self.Zcoll = CollisionTraverser()
        # Make a handler for the ground ray. This will be used in the
        # correctPlayerZ function.
        self.ZcollQueue = CollisionHandlerQueue()
        # Register it as something that can cause collisions with the traverser.
        self.Zcoll.addCollider(self.groundColNp, self.ZcollQueue)

        # Uncomment this line to see the collisions
        # self.Zcoll.showCollisions(render)

        # Uncomment this line to see the collision rays
        # self.groundColNp.show()
        # End setupCollisions


    # Define a task to monitor the position of the mouse pointer & rotate
    # the camera when the mouse pointer moves to the edges of the screen.
    def edgeScreenTracking(self,task):
        # Check if the mouse is available
        if not base.mouseWatcherNode.hasMouse():
            return Task.cont
        # Get the relative mouse position, its always between 1 and -1
        mpos = base.mouseWatcherNode.getMouse()
        if mpos.getX() > 0.99:
            self.cameraTurn(1)
        elif mpos.getX() < -0.99:
            self.cameraTurn(-1)
        return Task.cont
        # End edgeScreenTracking

    # Define the CameraTurn function.
    def cameraTurn(self,dir):
        self.camTurn = LerpHprInterval(self.camera_dummy_node, self.speed, Point3(self.camera_dummy_node.getH()-(10*dir), 0, 0))
        self.camTurn.start()
        # End cameraTurn

    # Define the cameraZoom function.
    def cameraZoom(self,dir):
        self.camZoom = LerpPosInterval(camera, self.speed, Point3(camera.getX(), camera.getY()-(2*dir), camera.getZ()+(.8*dir)))
        self.camZoom.start()
        # End cameraZoom

    # Define a function to correct the player's Z axis so that he follows the
    # contours of the ground.
    def correctPlayerZ(self, time):
        startpos = self.player.getPos()
        # Check for collisions
        self.Zcoll.traverse(render)

        #Gestion de la collision : Retir? au profit d'une d?claration d'obstacles
        if self.ZcollQueue.getNumEntries > 0:
         self.ZcollQueue.sortEntries()
         point = self.ZcollQueue.getEntry(0).getSurfacePoint(self.environ)
         self.player.setZ(point.getZ())
        else:
           self.player.setPos(startpos)
        # End correctPlayerZ

    # Define a function to get the position of the mouse click on the terrain.
    def getPosition(self, mousepos):
        self.pickerRay.setFromLens(base.camNode, mousepos.getX(),mousepos.getY())
        # Now check for collisions.
        self.picker.traverse(render)
        if self.queue.getNumEntries() > 0:
            self.queue.sortEntries()
            # This is the clicked position.
            self.position = self.queue.getEntry(0).getSurfacePoint(self.environ)
            # Set its Z axis to remain on the ground.
            self.position.setZ(0)
            return None
        # End getPosition

    def putWall(self):
      #-------------------------------my code 

        self.wall_dummy_node = render.attachNewNode("wall_dummy_node")
        self.wall_dummy_node.setPos(0,0,0)
        
        self.wall = loader.loadModel("models/mur1.egg")
##        self.wall.setPos(1,1,0)
        self.wall.reparentTo(self.wall_dummy_node) # Place it in the scene.
        
       #-------------------------------


    # Define a function to make the player turn towards the clicked position
    # and then move to that position.
    def moveToPosition(self):
        # Get the clicked position.
        self.getPosition(base.mouseWatcherNode.getMouse())
        if self.position==None:
           return
        # Create a dummy node.
        self.npLook = render.attachNewNode("npLook")
        # Calculate its position.
        self.npLook.setPos(self.player.getPos(render))
        # Make it look at the clicked position.
        self.npLook.lookAt(self.position)
        # Prevent overturning or 'wrap-around' by adjusting the player's heading
        # by 360 degrees.
        reducedH = self.player.getH()%360.0
        # Set the player's heading to that value.
        self.player.setH(reducedH)
        # Get the player's new heading.
        currH = self.player.getH()
        # Get the dummy node's heading.
        npH = self.npLook.getH()
        # Ralph was modeled facing backwards so we need to add 180 degrees to
        # stop him walking backwards. If your model is not modeled backwards
        # then delete the + 180.0.
        newH = closestDestAngle(currH, npH + 180.0)
        # Create a turn animation from current heading to the calculated new heading.
        playerTurn = self.player.hprInterval(.2, Point3(newH, 0, 0))
        # Calculate the distance between the start and finish positions.
        # This is then used to calculate the duration it should take to
        # travel to the new coordinates based on self.movementSpeed.
        travelVec = self.position - self.player_dummy_node.getPos()
        distance = travelVec.length()
        # Create an animation to make the player move to the clicked position.
        playerMove = self.player_dummy_node.posInterval((distance / self.movementSpeed), self.position)
        # We create a LerpFunc Interval to correct the Z axis as we go along.
        # So that the player stays on the ground.
        playerPositionZ = LerpFunc(self.correctPlayerZ, duration=(distance / self.movementSpeed))

        # Put the animations into a parallel sequence and set the doneEvent.
        if self.playerMovement:
           self.playerMovement.setDoneEvent("")
        self.playerMovement = Parallel(playerTurn, playerMove, playerPositionZ)
        self.playerMovement.setDoneEvent("player-stopped")
        # Play the walk animation.
        self.player.loop("walk")
        self.playerMovement.start()
        # End moveToPosition

    def stopWalkAnim(self):
        # This is called when the movement animation has finished.
        # We can then stop the walk animation.
        self.player.stop("walk")
        self.player.pose("walk",17)
        self.playerMovement = None
 
c = Controls()

run()

well . i havent tried your code… but you seems to have most of what you need. a function to load the model, and the point you get from the collission. so all that’s left is calling the function, passing the position as argument, and set the model’s position then.

this would look like

if self.queue.getNumEntries() > 0:
            self.queue.sortEntries()
            # This is the clicked position.
            self.position = self.queue.getEntry(0).getSurfacePoint(self.environ)
            self.putWall(self.position)
 

and later on change the putWall function to

def putWall(self,wallPosition):
      #-------------------------------my code
#since you dont really need the dummy node you can just skipp it..
        #self.wall_dummy_node = render.attachNewNode("wall_dummy_node")
       # self.wall_dummy_node.setPos(0,0,0)
       
        self.wall = loader.loadModel("models/mur1.egg")
        self.wall.setPos(wallPosition)
        self.wall.reparentTo(render) # Place it in the scene.
       
       #-------------------------------

you were wright : the models appears now.

Maybe you know why there is a “shifting” between the clicked and the models coordinates : the models does not appear where you click down.

I tried to print out (don’t know how to debug correctly yet) coordinates on the putwall call from within [color=blue]getposition , and inside [color=blue]putwall function : they match.

I’ve also tried Vec3 to change these positions: not helpfull no more.

Danke sehr.

well maybe your modell’s center is offsett. check it in your model-editor if you can. otherwise you would have to do an additional wall.setpos(wall, [your correction value])

you are right again !, I have been searching into the code instead .

You have been very helpfull,

thanks