1
$\begingroup$

Intro

I have a character with a movement system that runs on a python script, and I use the motion actuator's force to create movements. Using my forward key it works fine. The same with my backwards key, leftwards key, and rightwards key.

Problem

However, when I use certain combinations (forward + left, forward + right, backward + left, backward + right), my character has an imbalance of movement speed.

Changes

On first sight I thought all I needed to do was change my script into the following:

import bge
from bge import logic

cont = logic.getCurrentController()
own = cont.owner
scene = bge.logic.getCurrentScene()
keyboard = bge.logic.keyboard
input_just_activated = bge.logic.KX_INPUT_JUST_ACTIVATED
input_active = bge.logic.KX_SENSOR_ACTIVE 

own["movement_allowed"] = True

forward_input_key = "WKEY"
forward_input = keyboard.events[getattr(bge.events, forward_input_key)]
backward_input_key = "SKEY"
backward_input = keyboard.events[getattr(bge.events, backward_input_key)]
leftward_input_key = "AKEY"
leftward_input = keyboard.events[getattr(bge.events, leftward_input_key)]
rightward_input_key = "DKEY"
rightward_input = keyboard.events[getattr(bge.events, rightward_input_key)]

weapon_decider = scene.objects["weapon_decider"]
forward_force = weapon_decider["forward_force"]
backward_force = weapon_decider["backward_force"]
leftward_force = weapon_decider["leftward_force"]
rightward_force = weapon_decider["rightward_force"]

if (
        forward_input == input_active and
        leftward_input != input_active and
        rightward_input != input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([0, forward_force, 0], True)

if (
        backward_input == input_active and
        leftward_input != input_active and
        rightward_input != input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([0, backward_force, 0], True)

if (
        leftward_input == input_active and
        forward_input != input_active and
        backward_input != input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([leftward_force, 0, 0], True)

if (
        rightward_input == input_active and
        forward_input != input_active and
        backward_input != input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([rightward_force, 0, 0], True)

if (
        forward_input == input_active and
        leftward_input == input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([0.5 * leftward_force, 0.5 * forward_force, 0], True)

if (
        forward_input == input_active and
        rightward_input == input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([0.5 * rightward_force, 0.5 * forward_force, 0], True)

if (
        backward_input == input_active and
        leftward_input == input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([0.5 * leftward_force, 0.5 * backward_force, 0], True)

if (
        backward_input == input_active and
        rightward_input == input_active and
        own["movement_allowed"] == True
    ):
    own.applyForce([0.75 * rightward_force, 0.75 * backward_force, 0], True)

Sorry if it's confusing, but the point is, I added more conditionals to basic forward, backward, leftward, and rightward movements so the key itself and not another key that creates the combo is active, not only the key. Moreover, I added the combos separately. Now the movements are still imbalanced as I expected, so I changed the movement values for the special combos so that diagonal movements use the two directional movement values, and each of the two directional movement values is multiplied by 0.5 so it uses 50% of each value. I thought this would work, but there is still an imbalance of speed.

Conclusion

How can I have diagonal movements, using force, not create an imbalance of speed ? (Changing the script by using 50% of the two directional values doesn't work.) I would like the answer to be in python, thanks!

Notes

And for anyone looking for a script to tell the objects speed/looking for my speed script:

import bge
from bge import logic

cont = bge.logic.getCurrentController()
own = cont.owner

point = [0, 0, 0]
vec = own.getVelocity(point)

x_value = vec[0]
y_value = vec[1]
z_value = vec[2]

own["speed"] = abs(x_value) + abs(y_value) + abs(z_value)

Also, for more clarification, my old script was different in the following ways:

  • Only had forward, backward, leftward, and rightward conditionals.
  • There were no other conditionals and added conditions to each condition. For example, I had forward_input == input_active instead of forward_input == input_active and leftward_input != input_active.
$\endgroup$
  • $\begingroup$ speed = object.getLinearVelocity().length $\endgroup$ – Monster Dec 9 '15 at 13:13
1
$\begingroup$

You combine forces in your script. This means you add each force on top of the already applied velocity. Each single force influences the motion. In your case you can (theoretically) have 8 different forces applied at a single logical frame.

As all of your forces include the counter forces too, if you apply all possible forces there will be no motion changes as the combined force is zero.

Your code can apply non-orthogonal forces within one frame (left, diagonal-left + forward), the combined force will be stronger than a single force.

   E    +    NE       =    NEE      | direction
(1,0,0) + (0.5,0.5,0) = (1.5,0.5,0) | force
   1         1.6           2.2      | strength

this all makes no sense.

You work with forces and vectors. I strongly suggest to change your calculation model.

What you can do is:

A) calculate the direction of the force

B) calculate the strength of the force

Direction

There are not that many directions. You already defined 8 (N, NE, E, SE, S, SW, W, NW). You can either single pick one of 8, or combine 2 of 4 options. This is up to you. The result is a vector.

Strength

I assume you want a constant strength. You can explicitly set it at the direction vector.

Result

Is a vector that can be applied as force (or velocity)

Example

import bge
controller = bge.logic.getCurrentController()

from mathutils import Vector

directions = [
 Vector([ 0,  1 ,0]), # N
 Vector([ 1,  0, 0]), # E
 Vector([ 0, -1, 0]), # S
 Vector([-1,  0, 0])  # W
]

sensors = controller.sensors
direction = Vector([0,0,0])
# assuming the sensors are in this order: N, E, S, W
for i in range(len(sensors)):
    if sensors[i].positive:
        direction += directions[i]

force = direction
force.length = 1

print("this is my force", force)

I hope it helps

$\endgroup$

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.