Need help using the gamepad stick with a bullet vehicle

I am trying to create a quick and dirty driving game for my 5 yr old son (while learning to be a better Panda3D programmer). Anyway, I have a bullet vehicle that moves fine with the keyboard. I am trying to add gamepad control. I used debug print statements to verify that I can receive input from the gamepad. The buttons work fine because they are the same as a keyboard keystroke. But the toggle stick logic is not working in my code. No error msg. Just does not respond.

# Chassis
shape = BulletBoxShape(Vec3(0.6, 1.4, 0.5))
ts = TransformState.makePos(Point3(0, 0, 0.5))

np = self.worldNP.attachNewNode(BulletRigidBodyNode('Vehicle'))
np.node().addShape(shape, ts)
np.setPos(80, 50, 1)
np.node().setMass(800.0)
np.node().setDeactivationEnabled(False)

self.world.attachRigidBody(np.node())

# Vehicle
self.vehicle = BulletVehicle(self.world, np.node())
self.vehicle.setCoordinateSystem(ZUp)
self.world.attachVehicle(self.vehicle)

self.yugoNP = loader.loadModel('models/yugo/yugo.egg')
self.yugoNP.reparentTo(np)

inputState.watchWithModifiers('forward', 'w')
inputState.watchWithModifiers('left', 'a')
inputState.watchWithModifiers('reverse', 's')
inputState.watchWithModifiers('right', 'd')
inputState.watchWithModifiers('turnLeft', 'q')
inputState.watchWithModifiers('turnRight', 'e')
inputState.watchWithModifiers('brakes', 'x')
inputState.watchWithModifiers('brakes', 'gamepad-rshoulder')
inputState.watchWithModifiers('brakes', 'gamepad-lshoulder')

#Accept button events of the first connected gamepad
self.accept("gamepad-back", self.doExit)
self.accept("gamepad-start", self.doReset)

def processInput(self, dt):
engineForce = 0.0
brakeForce = 0.0

if inputState.isSet('forward'):
  engineForce = 1000.0
  brakeForce = 0.0

if inputState.isSet('reverse'):
  engineForce = -500.0
  brakeForce = 0.0

if inputState.isSet('brakes'):
  engineForce = 0.0
  brakeForce = 100.0

if inputState.isSet('turnLeft'):
  self.steering += dt * self.steeringIncrement
  self.steering = min(self.steering, self.steeringClamp)

if inputState.isSet('turnRight'):
  self.steering -= dt * self.steeringIncrement
  self.steering = max(self.steering, -self.steeringClamp)

# Apply steering to front wheels
self.vehicle.setSteeringValue(self.steering, 0);
self.vehicle.setSteeringValue(self.steering, 1);

# Apply engine and brake to rear wheels
self.vehicle.applyEngineForce(engineForce, 2);
self.vehicle.applyEngineForce(engineForce, 3);
self.vehicle.setBrake(brakeForce, 2);
self.vehicle.setBrake(brakeForce, 3);

This is only snippets of relevent code and words fine as is.
The following was my attempt to drive the car. DOES NOT WORK.
The print statement does work.

left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

#print(left_x.value, left_y.value, right_x.value, right_y.value)
engineForce = 0.0
if left_y.value > 0.0:
  print("Left Toggle Forward")
  engineForce = left_y.value * 1200

brakeForce = 0.0
self.vehicle.applyEngineForce(engineForce, 2);
self.vehicle.applyEngineForce(engineForce, 3);
self.vehicle.setBrake(brakeForce, 2);
self.vehicle.setBrake(brakeForce, 3);

Hmm… I have four questions:

  1. Where is that last snippet of code–the one that calls “findAxis”–located? Is it in a task, or a constructor, or some other place…?

  2. You say that the print-statement works–I take it that you’re referring to the commented-out print-statement that prints out the values of “left_x.value”, etc. If so, what sort of values does it print out?

  3. Does the printing of “Left Toggle Forward” work?

  4. If either of the above-mentioned print-statements do work, how many times do they print?

  1. findAxis is in a task. Because that is how the sample code did it.
  2. left_x.value is between -1 and 1.
  3. Yes
  4. The text in the IF statement prints five times. The commented out print is continuous.

My thinking is I need to move the this logic to the Class init section with the other code. Using the trigger button for brakes work fine. I just don’t know where to begin to apply numeric value instead of key pressed. I realize there is probably more than one way to make this work.

That’s a little odd–I would expect it to keep printing as long as the relevant axis is held in the positive direction.

If I’m not much mistaken, that should result in the code being run only once, and thus not working, I’m afraid.

“Key pressed”? I don’t see that in your code…

Are you calling “applyEngineForce” in a method that’s called when a keyboard-key is pressed? If so, then that might well be your problem.

In that case, I might suggest simply including a call to “applyEngineForce” with the gamepad code that you already have.

That said, I’m not particularly familiar with the Bullet vehicle, so I don’t know quite how it’s meant to be used. The above is my guess based on what I do know, including what you’ve presented.

I found the missing statement. Need doPhysics after the applyEngineForce.

dt = globalClock.getDt()

self.processInput(dt)
self.world.doPhysics(dt, 10, 0.008)

The processInput routine is for the keyboard input control. I need to write a second routine for the gamepad control. I was trying to lump all of it together. Definitely messy and unprofessional.

I will post my new vehicle gamepad routine after I get it working.

1 Like

As promised: a working gamepad task routine. Trying to change the distance interfered with the tracking function. It was easier to decide I don’t need it. Let me know if anyone has suggestions.

Gamepad control for the vehicle

def GamePadInput(self, dt):
## Respond to gamepad #############
if not self.gamepad:
return 0

engineForce = 0.0
brakeForce = 0.0

## Listen to Gamepad Input
gpstart = self.gamepad.findButton("start")
gpback = self.gamepad.findButton("back")
lshoulder = self.gamepad.findButton("lshoulder")
rshoulder = self.gamepad.findButton("rshoulder")
left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

#Accept button events of the first connected gamepad
if gpback.pressed:
  self.doExit()
if gpstart.pressed:
  self.doReset()

##### Camera Follow Player Controls ###############
camvec = self.yugoNP.getPos(render) - self.camera.getPos()
camvec.setZ(0)
camdist = camvec.length()
camvec.normalize()
if camdist > self.camY: # + 0.2:
  self.camera.setPos(self.camera.getPos() + camvec * (camdist - self.camY))

# Rotate camera around the car in a arc
if right_x.value > 0.02:  # move cam right
  self.camera.setX(self.camera, +20 * dt)
if right_x.value < -0.02:   # move cam left
  self.camera.setX(self.camera, -20 * dt)
if right_y.value > 0.02:  # move cam up
  self.camera.setZ(self.camera, +20 * dt)
if right_y.value < -0.02:   # move cam down
  self.camera.setZ(self.camera, -20 * dt)

### Vehicle Control #####
if left_y.value > 0.01:  # go forward
  engineForce = left_y.value * 1600
  brakeForce = 0.0
if left_y.value < -0.01:   # go backwards
  engineForce = left_y.value * 400
  brakeForce = 0.0

if rshoulder.pressed:   # slow down
  engineForce = 0.0
  brakeForce = 40
if lshoulder.pressed:   # apply brakes
  engineForce = 0.0
  brakeForce = 100

if left_x.value < -0.01:   # turn left
  self.steering = left_x.value * -5
  self.steering = min(self.steering, self.steeringClamp)
if left_x.value > 0.01:   # turn right
  self.steering = left_x.value * -5
  self.steering = max(self.steering, -self.steeringClamp)

### Calibrate Drifting Toggles #######
if left_x.value < 0.01 and left_x.value > -0.01:  # straight ahead
  self.steering = 0.0
if left_y.value < 0.01 and left_y.value > -0.01:  # sit still
  self.engineForce = 0.0

# Apply steering to front wheels
self.vehicle.setSteeringValue(self.steering, 0);
self.vehicle.setSteeringValue(self.steering, 1);

# Apply force to back wheels
self.vehicle.applyEngineForce(engineForce, 2);
self.vehicle.applyEngineForce(engineForce, 3);
self.vehicle.setBrake(brakeForce, 2);
self.vehicle.setBrake(brakeForce, 3);
1 Like