Help getting a character to face and move in 8 directions. (with or without Python)

Is there any way to make a character instantaneously face one of eight (8) directions and then move forward in that direction with only a single button press? For example, if I pressed left the character would face left and continue walking left until I released the button.

My approach was to use Python to have an empty that would copy the location with an offset that changes depending on the button(s) pressed. I am new at Python, however, and can’t seem to make a function that will do that.

If my question is hard to understand, basically all I need is to know how to copy location, rotation, and scale with an offset in the game engine (preferably with Python). Any help would be appreciated.

Such things are usually simple combination of different tasks:

A) turning
B) moving

let the object turn into the direction you want (e.g. play an action or activate a motion actuator or activate a trackTo actuator)
and at the same time
let it move forward (e.g. play an action or activate a motion actuator)

The way I do it withought python is eather make 8 empties around a base cube. Then add another cube parented to the first cube whitch when u press wasd etc it looks at the empty to get in position.
Or insted of empties you can animate that cube turning 45 degrese every 2 frames and key it 2 times so u have a couple frames to play the animation.

To imporve upon this i also use a mouse look python script whitch u dont realy have to touch to get to work.
you can add rotations to the first cube to make it turn and stuff and use vertex parinting to make the cube stay in the same direction while u rotate around it .

Heres a blend of how i do it
http://www.pasteall.org/blend/18994

Note this blend file as made in 2.49b and the camera script dosent work in 2.6, but the 8 directonal movment dose.

Hope this helped

This is way to do it in python with minimal coding. Make sure it’s run on module mode.


from bge import logic
from mathutils import *

def main(cont):
    own = logic.getCurrentController().owner

    forward_back_vector = Vector((0,1,0))
    side_to_side_vector = Vector((1,0,0))

    #Keyboard controls using senors but you can just as easily use python keyboard handlers
    forwardkey =  cont.sensors['FORWARD']
    backwardkey = cont.sensors['BACKWARD']
    rightkey = cont.sensors['RIGHT']
    leftkey = cont.sensors['LEFT']


    y_aligning_vector = forward_back_vector*(forwardkey.positive -backwardkey.positive)
    #Options: If forward key is pressed, vector = (0,1,0), if backward key is pressed, vector = (0,-1,0), anything else, vector = (0,0,0)
    
    x_aligning_vector = side_to_side_vector*(rightkey.positive-leftkey.positive)
    #Same with this.
    
    direction_vector = x_aligning_vector+y_aligning_vector
    #Adding the vectors together (for 8 direction movement)
    
    own.alignAxisToVect(direction_vector,1,0.7)#Aligning the y axis to the direction vector instantly
    
    
    #Entire code for movement.
    speed = [0,0,0]
    if direction_vector.magnitude:
         speed = [0,5,0]
    own.setLinearVelocity(speed,1) #Moving the object on the local y if there's a magnitude on the direction vector.
    
    #If you really wanted to you could also do this to move the entire movement of the object
    #own.setLinearVelocity([0,1,0]*direction_vector.normalized().magnitude,1)

This code will do the trick for world rotation, to get local rotation you need to vertex parent an object to your main object, and mutltiply the direction vector by the vertex parented object’s orientation. In other words,
you switch this line:


direction_vector = x_aligning_vector+y_aligning_vector

with a line like this:


direction_vector = vertex_parented_object.worldOrientation*(x_aligning_vector+y_aligning_vector)

So when you rotate a camera, you actually rotate the parented empty, and not the main object.

Here’s a .blend I made in 5 minutes, it even uses local movement (just put your camera controls on the empty)
Use WASD to move.
test.blend (431 KB)

Thanks for all the help! I finally got it to work with python. Here’s the code if anyone is interested:

import bge
controller = bge.logic.getCurrentController()
owntwo = controller.owner
guy = bge.logic.getCurrentScene().objects[“P1_Location”]
pressup1 = controller.sensors[“up1”]
pressright1 = controller.sensors[“right1”]
pressdown1 = controller.sensors[“down1”]
pressleft1 = controller.sensors[“left1”]
pressupright1 = controller.sensors[“upright1”]
pressdownright1 = controller.sensors[“downright1”]
pressdownleft1 = controller.sensors[“downleft1”]
pressupleft1 = controller.sensors[“upleft1”]

if pressup1.positive:
owntwo.worldPosition.x = guy.worldPosition.x
owntwo.worldPosition.y = guy.worldPosition.y + 2
owntwo.worldPosition.z = guy.worldPosition.z

elif pressright1.positive:
owntwo.worldPosition.x = guy.worldPosition.x + 2
owntwo.worldPosition.y = guy.worldPosition.y
owntwo.worldPosition.z = guy.worldPosition.z

elif pressdown1.positive:
owntwo.worldPosition.x = guy.worldPosition.x
owntwo.worldPosition.y = guy.worldPosition.y - 2
owntwo.worldPosition.z = guy.worldPosition.z

elif pressleft1.positive:
owntwo.worldPosition.x = guy.worldPosition.x - 2
owntwo.worldPosition.y = guy.worldPosition.y
owntwo.worldPosition.z = guy.worldPosition.z

elif pressupright1.positive:
owntwo.worldPosition.x = guy.worldPosition.x + 2
owntwo.worldPosition.y = guy.worldPosition.y + 2
owntwo.worldPosition.z = guy.worldPosition.z

elif pressdownright1.positive:
owntwo.worldPosition.x = guy.worldPosition.x + 2
owntwo.worldPosition.y = guy.worldPosition.y - 2
owntwo.worldPosition.z = guy.worldPosition.z

elif pressdownleft1.positive:
owntwo.worldPosition.x = guy.worldPosition.x - 2
owntwo.worldPosition.y = guy.worldPosition.y - 2
owntwo.worldPosition.z = guy.worldPosition.z

elif pressupleft1.positive:
owntwo.worldPosition.x = guy.worldPosition.x - 2
owntwo.worldPosition.y = guy.worldPosition.y + 2
owntwo.worldPosition.z = guy.worldPosition.z

Ah. It kind of hurts me to see code like that.
I’m still not super advanced at coding but I can still help you a bit. :slight_smile:
This code does the same thing but it’s cleaner and you don’t need any if statements.

Read all the notes.


import bge
controller = bge.logic.getCurrentController()
owntwo = controller.owner
guy = bge.logic.getCurrentScene().objects["P1_Location"]

<b>#You only really need 4 sensors.</b>
pressup1 = controller.sensors["up1"]
pressright1 = controller.sensors["right1"]
pressdown1 = controller.sensors["down1"]
pressleft1 = controller.sensors["left1"]


<b># Every statement returns 1 or 0. For example:
# If I make a variable called x that has a value of 10, if I print, x == 10, python will return 1.
# Same thing with sensor.positive. If the sensor is positive, it returns 1, if not 0.</b>

<b># So:
</b>
up_down = pressup1.positive - pressdown1.positive
<b># If you think about it...
# If I'm pressing the up arrow, <i>up_down</i> = 1 because (1-0)
# If I'm pressing the down arrow, <i>up_down</i> = -1 because (0-1).
# If I'm pressing none of them, <i>up_down</i> = 0 (0-0)
# And if I'm pressing both, <i>up_down</i> = 0 (1-1)</b>

<b># Do the same thing with left and right</b>
right_left = pressright1.positive - pressleft1.positive


speed = 2
owntwo.worldPosition.y = guy.worldPosition.y + speed*up_down
<b># So you're either adding 2 (up arrow pressed), -2 (down arrow pressed) or 0 (both up and down or none) </b>
owntwo.worldPosition.x = guy.worldPosition.x + speed*right_left
owntwo.worldPosition.z = guy.worldPosition.z

<b># These 3 lines basically cuts down all your if statements</b>


Your code went from 30 - 40+ lines down to just below 15 lines.

Ah, thanks! I’m new to Python so I don’t know all of it’s “shortcuts” if you will.