What algorithm can solve the radian for left and right movement of a moveable object in 360 degrees?

Hello everyone, I am trying to figure out what algorithm can work when moving left or right when I have a moveable object that can move in 360 degrees in any directions, even turning. My code is influenced by azizalbastaki’s code:

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from panda3d.core import Vec3
import math

class Game(ShowBase):
    def __init__(self):
        super().__init__()

        base.disableMouse()

        self.heading = 0

        environment = loader.loadModel("models/environment")
        environment.reparentTo(render)

        self.object = loader.loadModel("models/box")
        self.object.setScale(10, 10, 10)
        self.object.setPos(30, -160, 1)
        self.object.reparentTo(render)

        self.camera.setPos(35, -250, 50)
        self.camera.setHpr(0, -20, 0)

        self.playerKeyControl = {
            "up" : False,
            "down" : False,
            "left" : False,
            "right" : False,
            "left-turn" : False,
            "right-turn" : False}

        taskMgr.add(self.CheckControl, "CheckControl")
        taskMgr.add(self.Update, 'Update')

    def CheckControl(self, task):
        base.accept('w', self.UpdateControl, ["up", True])
        base.accept('w-up', self.UpdateControl, ["up", False])
        base.accept('s', self.UpdateControl, ["down", True])
        base.accept('s-up', self.UpdateControl, ["down", False])
        base.accept('a', self.UpdateControl, ["left", True])
        base.accept('a-up', self.UpdateControl, ["left", False])
        base.accept('d', self.UpdateControl, ["right", True])
        base.accept('d-up', self.UpdateControl, ["right", False])
        base.accept('q', self.UpdateControl, ["left-turn", True])
        base.accept('q-up', self.UpdateControl, ["left-turn", False])
        base.accept('e', self.UpdateControl, ["right-turn", True])
        base.accept('e-up', self.UpdateControl, ["right-turn", False])

        return Task.cont

    def UpdateControl(self, controlName, controlState):
        self.playerKeyControl[controlName] = controlState

    def Update(self, task):
        dt = globalClock.getDt()

        if self.playerKeyControl["up"]:
            self.object.setPos(self.object.getPos() + Vec3(30 * dt *
                                         (-math.sin(math.radians(self.heading))),
                                         30 * dt * (math.cos(math.radians(self.heading))), 0))
        if self.playerKeyControl["down"]:
            self.object.setPos(self.object.getPos() + Vec3(30 * dt *
                                         (math.sin(math.radians(self.heading))),
                                         -30 * dt * (math.cos(math.radians(self.heading))), 0))
        if self.playerKeyControl["left"]:
            self.object.setPos(30 * dt , 0, 0) # <--- What algorithm for left?
        if self.playerKeyControl["right"]:
            self.object.setPos(-30 * dt, 0, 0) # <--- What algorithm for right?
        if self.playerKeyControl["left-turn"]:
            self.heading += 1
            self.object.setH(self.heading)
        if self.playerKeyControl["right-turn"]:
            self.heading -= 1
            self.object.setH(self.heading)

        if self.heading > 360:
            self.heading -= 360
        elif self.heading < 0:
            self.heading += 360

        return Task.cont

game = Game()
game.run()

Everything is easier :slightly_smiling_face:

    def Update(self, task):
        dt = globalClock.getDt()

        if self.playerKeyControl["up"]:
            self.object.setY(self.object, 0.5 * dt)
        if self.playerKeyControl["down"]:
            self.object.setY(self.object, -0.5 * dt)
        if self.playerKeyControl["right"]:
            self.object.setX(self.object, 0.5 * dt)
        if self.playerKeyControl["left"]:
            self.object.setX(self.object, -0.5 * dt)
        if self.playerKeyControl["right-turn"]:
            self.object.setH(self.object, -20 * dt)
        return Task.cont
1 Like

Or alternatively:

 def Update(self, task):
        dt = globalClock.getDt()

        # Get a quaternion that represents the object's orientation
        quat = self.object.getQuat()

        # From that quaternion, get the object's "forward" and
        # "right" vectors.
        forward = quat.getForward()
        right = quat.getRight()

        newPos = self.object.getPos()

        if self.playerKeyControl["up"]:
            newPos += forward * 0.5 * dt
        if self.playerKeyControl["down"]:
            newPos -= forward * 0.5 * dt
        if self.playerKeyControl["right"]:
            newPos += right * 0.5 * dt
        if self.playerKeyControl["left"]:
            newPos -= right * 0.5 * dt

        self.object.setPos(newPos)

        # Handle turning here as you already are

        return Task.cont

Either this approach or serega’s, above, should work. :slight_smile:

As to caveats, either of these approaches will be affected by any transformations of the ancestor-nodes (i.e. parent-node, its parent-node, etc.) of the object in question. In the version that I’ve given, this can be prevented by getting the quat, getting the position, and placing the object all relative to some higher node, such as “render”.

[edited a bit for correctness, simplicity, and neatness.]

My goodness, this took me months to figure out how to set these type of rotations. Now, I needed only to modify one of the objects method called setH. Seriosuly, I almost thought that Panda3D requires me to write sophisticated codes to do this. Thank you so much!

Thanks for providing an alternative solution. It seems that Panda3D allows different ways to approach a situation.

Actually, yours and serega-kkz’s code confirms that my character movement with the mouse that controls the player’s rotation with the billboard effect, and applying any movement, messes up the 360 degree movements. I’ll relook into this.

Edit: while I was reformating my code, I noticed that self.object actually rotates on a edge, instead of the object’s center:
edgeSpin

I am assuming that it requires a specific algorithm in setH method of self.object to have it rotate its center. Any clues?

Is the model one of your own? If so, then I’d guess that it’s simply that your object’s origin–the point that is at (0, 0, 0) relative to your object–isn’t at the centre of the object.

Specifically, it looks like you have the origin at one of the bottom corners.

And it’s around the origin that objects are generally rotated. (And from the origin that they’re generally scaled, or positioned.)

To explain, let me use a 2D example. In the diagrams below, at each corner are the coordinates of that corner relative to the object itself. In each, the centre of the rectangle is marked with an “x”.

Your object is analogous to this rectangle:

(0, 1)           (1, 1)
   o---------------o
   |               |
   |               |
   |       x       |
   |   (0.5, 0.5)  |
   |               |
   o---------------o
(0, 0)           (1, 0)

Note that the origin–the point (0, 0)–corresponds to one of the corners.

To have the object naturally rotate around its centre, a square like this would work better:

(-0.5, 0.5)       (0.5, 0.5)
   o---------------o
   |               |
   |               |
   |       x       |
   |    (0, 0)     |
   |               |
   o---------------o
(-0.5, -0.5)      (0.5, -0.5)

Note that here, the origin–the point around which it will rotate–is in the centre of the object, not at one of its corners.

You just need to set up the nodes correctly or opt out of the compass effect. You essentially have to control the node on which the node will rotate freely. Instead of controlling a rotating node.

In modeling, there is a concept of the center of an object, which is called pivot. Obviously, the center was changed in the 3d editor.

1 Like