0
\$\begingroup\$

I am making a racing game inside of Blender Game Engine. You can see the latest video here to get the impression of what type of game it is: https://www.youtube.com/watch?v=0i3m-xXtnhc

What I want to do is to replace current constant engine setup which has a constant Nm value(I guess that applyEngineForce() takes torque as input, but I am sure it uses Nm as unit) whith a new setup that calculates RPM, use RPM/torque curves(I've made 2 arrays for them already), aswell as use gearbox with multiple gear ratios(a custom number). This game is planned to be pretty realistic, but at the same time I must make sure that it is not too expensive(although CPU stuff is not the problem for me usually, it is more GPU and graphics).

So any type of help will be appreciated, thank you!:)

So what I have:

I have steering already. I have inputs for brakes, gas, shifting gears, e-brake and reverse.

What I need:

I need to use the inputs correctly to make engine act naturally. I need to have a gear and RPM dependent torque output as final result aswell as RPM to show in the HUDs. Finally I will put the torque into applyEngineForce() and if I am right, than the final value at 1st gear ratio should be around 3500 - 6000 Nm, but it is the case if applyEngineForce() uses torque.

I couldn't find more information about Blender Game Engine vehicle wrapper!:(

P.S. BGE uses python as it's built-in programing language so I use python for this.

My script at current state which needs improvements:

import bge
from bge import logic
import PhysicsConstraints
from gamesystem import gaudges

### Define ###
scene = logic.getCurrentScene()
car = scene.objects["Car"]
keyboard = logic.keyboard
JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
ACTIVE = bge.logic.KX_INPUT_ACTIVE

#keyboard keys
gas = keyboard.events[bge.events.WKEY]
left = keyboard.events[bge.events.AKEY]
reverse = keyboard.events[bge.events.SKEY]
right = keyboard.events[bge.events.DKEY]
ebrake = keyboard.events[bge.events.SPACEKEY]

#stats
gasPower = car["gasPower"] * 10
brakePower = car["brakePower"]
ebrakePower = car["ebrakePower"]
reversePower = car["gasPower"] / 3 * 20
maxSteer = car["maxSteer"]
steerSpeed = car["steerSpeed"]
maxSpeed = car["maxSpeed"]

# Define tire objects
tireFL = scene.objects["TireFL"]
tireFR = scene.objects["TireFR"]
tireRL = scene.objects["TireRL"]
tireRR = scene.objects["TireRR"]

### Initialise ###

if not "ini" in car:
    pid = car.getPhysicsId()
    suspension = PhysicsConstraints.createConstraint(pid, 0, 11)
    cid = suspension.getConstraintId()
    suspension = PhysicsConstraints.getVehicleConstraint(cid)

    wheelRadius = 0.345
    suspensionRestLength = 0.5
    hasSteering = 1

    ### Tweakables ###
    damping = car["damping"]
    stiffness = car["stiffness"]
    compression = car["compression"]
    roll = car["roll"]
    grip = car["grip"]
    drift = car["drift"]

    ### Actions ###

    # Generate tires
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [-0.745, 1.27, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    suspension.addWheel(tireFL, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [0.745, 1.27, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    suspension.addWheel(tireFR, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [-0.75, -1.18, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    hasSteering = 0
    suspension.addWheel(tireRL, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [0.75, -1.18, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    suspension.addWheel(tireRR, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)

    # Update suspension
    for tire in range(4):
        suspension.setSuspensionDamping(damping, tire)

        suspension.setSuspensionStiffness(stiffness, tire)

        suspension.setSuspensionCompression(compression, tire)

        suspension.setRollInfluence(roll, tire)

    suspension.setTyreFriction(grip, 0)
    suspension.setTyreFriction(grip, 1)
    suspension.setTyreFriction(grip / (drift * ((maxSpeed - gaudges.speed) / maxSpeed)), 2)
    suspension.setTyreFriction(grip / (drift * ((maxSpeed - gaudges.speed) / maxSpeed)), 3)

    car["ini"] = True
    car["CID"] = cid

### Car in action ###

suspension = PhysicsConstraints.getVehicleConstraint(car["CID"])

# Drift
suspension.setTyreFriction(car["grip"] / (car["drift"] * ((maxSpeed - gaudges.speed) / maxSpeed)), 2)
suspension.setTyreFriction(car["grip"] / (car["drift"] * ((maxSpeed - gaudges.speed) / maxSpeed)), 3)

# Gas
if gas == ACTIVE:
    car["gas"] = gasPower
else:
    car["gas"] = 0

# Emergency brake
if ebrake == ACTIVE:
    car["ebrake"] = ebrakePower
else:
    car["ebrake"] = 0

# Reverse
if reverse == ACTIVE:
    if car["speed"] > 0:
        car["brake"] = brakePower
        car["gas"] = -reversePower
    else:
        car["brake"] = 0
        car["gas"] = -reversePower
else:
    car["brake"] = 0

# Steering
if right == ACTIVE:
    if car["steer"] > -maxSteer:
        car["steer"] -= steerSpeed
elif left == ACTIVE:
    if car["steer"] < maxSteer:
        car["steer"] += steerSpeed
else:
    car["steer"] = 0.0

drive = car["drive"]
## drives
    # 1: rear
    # 2: front
    # 3: full
frontDrive = 0
rearDrive = 0

if drive == 1 or drive == 3:
    rearDrive = 1
else:
    rearDrive = 0.5

if drive == 2 or drive == 3:
    frontDrive = 1
else:
    frontDrive = 0.5

for tire in range(4):
    # Front tires
    if tire < 2:
        suspension.applyEngineForce(-car["gas"] * frontDrive, tire)
        suspension.applyBraking(car["brake"], tire)
    # Rear tires
    else:
        suspension.applyEngineForce(-car["gas"] * rearDrive, tire)
        suspension.applyBraking(car["ebrake"], tire)

suspension.setSteeringValue(car["steer"], 0)
suspension.setSteeringValue(car["steer"], 1)

gaudges.speed = car.getLinearVelocity(1).y * 3.6
car["speed"] = int(gaudges.speed)

if car["speed"] > maxSpeed:
    car.localLinearVelocity.y = maxSpeed / 3.6

if car["speed"] < -(maxSpeed / 2):
    car.localLinearVelocity.y = -((maxSpeed / 2) / 3.6)

To make sure that you see my knowledge level, here is what I know already aswell as what I need:

http://blenderartists.org/forum/showthread.php?381056-Need-to-find-resources-of-equations-in-engine-RPM-part

\$\endgroup\$
  • 1
    \$\begingroup\$ You're getting yourself in a hell of a ride :) To have it as realistic as it could get, I would suggest you model all of the parts of the drive-train, and find the specifications of a real car (which include engine output and speed for each gear). Use a state machine for the proper behaviour of each gear. Calculating everything as close to reality as possible will allow you to tweak and tune more easily. \$\endgroup\$ – Vaillancourt Sep 8 '15 at 17:06
  • \$\begingroup\$ I mean using approximations as I won't have any existing cars in game. \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 17:20
  • \$\begingroup\$ Gear system: I have a curve for the car and I have to scale it somehow through each gears(1st gear have very high torque and small RPM line), I can do it easily by using each gear ratio value(an array). That way I have 3 lists: RPM list and torque list for curve(RPM is x axis and torque is y axis) and I use numpy.interp() to get the torque based on the RPM. \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 17:23
  • \$\begingroup\$ For the gears I can make a gear ratio array containing something like this: [3.3, 2.7, 2.2, 1.75, 0.9] and use it for car. what I need to find out, though, is how to correctly apply the RPM(based on brake/gas/e-brake/reverse inputs) so that it acts correctly and makes it feel right. Also - each gear has speed limit and I don't know if it is done automaticly in script and if it isn't, than I need also something for natural feeling of this. \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 17:25
  • \$\begingroup\$ For switching gears I can use a timer property during which car has a little of brakes applied so that it feels like it is shifting for real. \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 17:26
3
\$\begingroup\$

First, you'll need to make a model of your engine. It should be a simple function that would resemble the green line.

Torque and RPM relation graph

Quick and dirty inquiry at wolfram alpha gives this estimation:

def max_engine_torque_at_rpm(rpm):
    return -0.0000138889 * rpm ** 2 + 0.0799786 * rpm - 28.2671

Now this is incredibly trivial and not representative at all of what you really want. You should, at least, implement linear interpolation of some dataset, either of a real engine or a made up one.

Then, calculate how fast your wheels are spinning. This will depend on how realistic you want to get. As a most trivial example, just divide movement speed by 2 pi.

Then, divide the wheel's RPM by the current gear's ratio and the result will basically be the engine's RPM (unless you do some damage modeling at the transmission part). Plug that into the function defined earlier, and you get maximum torque from the engine. Scale that by current throttle input.

When you have the torque currently produced by the engine, multiply it by current gear ratio. The result is what should be outputted towards the wheels.

Again, all of this is very simplified. You can add simulation of friction, inertia, damage, and any other influences to any step of this algorithm.

\$\endgroup\$
  • \$\begingroup\$ Sounds like close to my target, but I am not the one who knows what exactly words like throttle etc. mean. I also don't get some of the parts. I may give oyu the file later and maybe you can tell me of the part responsible for wheel RPM is actually possible in default Blender vehicle wrapper? However, it is late for me now already... \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 20:08
  • \$\begingroup\$ @AdriansNetlis throttle is gas pedal \$\endgroup\$ – transistor09 Sep 8 '15 at 20:29
  • \$\begingroup\$ OK! Thanks! This already looks very useful. But could you, please, e-mail me so that I can easily ask you whenever I get lost with this so that I don't have to comment here whole the time? adris3ddev@gmail.com Thank you very much!:) \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 20:34
  • \$\begingroup\$ @AdriansNetlis if your comments are within the scope of this question just add them here, there is no limit. If you have any other questions, add them separately. \$\endgroup\$ – transistor09 Sep 8 '15 at 20:40
  • \$\begingroup\$ ef max_engine_torque_at_rpm(rpm): return -0.0000138889 * rpm ** 2 + 0.0799786 * rpm - 28.2671 What does each of theese numbers, eg -0.0000138889 or 28.2671 stand for? \$\endgroup\$ – Adrians Netlis Sep 8 '15 at 21:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.