SideScroll Movementscript - Questions and Answers

EDIT
I am currently developing a Sidescroll Script for my Game Orbito. At the moment the whole Movement is solved via logic bricks. This is something I want to change. I am making good progress! I want to make this script very generic and customizable. I think when it is once finished I will publish it as an template!

Here are some little points I am going to implement.

-usual left/right movement (speed and acceleration can be set via propertys)
-jump and doublejump (can be enabled and disabled via a property)
-walljump

Other things may follow.

EDIT

Hey there…
I have a question concerning intializing variables. How can I create variables that do not get overwritten each tic the script is executed?

For example I have a rotation value of my character with a default setting of rot = 90
And I have a function that changes this value to rot = 180. But when the script is executed again it gets set to rot = 90 again.

It sure is possible but I do not know how. In unity 3d you have an Update()… So everything that is not in it will only be executed once.

Thanks in advance!
Andreas

another quick question! How do I get the rotation angle of a specific axis? I know that I can rotate an object via obj.dRot = [0,0,1]
But lets say I want to rotate this object as long as the z rotation < 90
How do I get the actual angle of my rotation?

You can assign your variables to a global variable in a dedicated script that runs only once. To obtain that the initialization script runs only at start up, it should be triggered by an always sensor with both “level triggering” buttons off (unpressed).
For example:


# Initialization script <b>pseudocode</b> (to be run only at start up)
import GameLogic as GL
GL.var1 = value1
GL.var2 = value2
...

Then you can retrieve your variables in the main program, as in:


# Main script <b>pseudocode</b>:
import GameLogic as GL
print(GL.var1, GL.var2) # print to command window
GL.var1 = GL.var1 + 1.
GL.var2 = GL.var2/2.
...

mb

or you can use object variables.

For example, you can get the owner object of the current controller, then check if a property exists, else assign it.

import bge
cont = bge.logic.getCurrenntController()
own = cont.owner

if not "property" in own:
     own["property"] = 0

#that code checks if the variable in the object exists, otherwise creates it. Once it has been created, it remains on the object.


#then to get the property:
prop = own["property"]

#or set:
own["property"] = 5

Then, if you want the current angle:

First import relevant modules


from mathutils import*
from math import*

Then get the orientation matrix you want, in this example the one of the current object


import bge
cont = bge.logic.getCurrentController()
orientation = cont.owner.worldOrientation


Use the below function to convert orientation matrix to degrees
returns list of X,Y,Z


def get_angle(ori):
    new = ori.to_euler()
    x = degrees(new.x)
    y = degrees(new.y)
    z = degrees(new.z)
    return(x,y,z)

To use the code:


x,y,z = get_angle(orientation)

Done!

All the code in one block:


import bge
from mathutils import*
from math import*
cont = bge.logic.getCurrentController()
orientation = cont.owner.worldOrientation
def get_angle(ori):
    new = ori.to_euler()
    x = degrees(new.x)
    y = degrees(new.y)
    z = degrees(new.z)
    return(x,y,z)
x,y,z = get_angle(orientation)

mb10 has valid code, it simply returns the eulers.
You can use the math module to convert euler to angles, with math.degrees(euler)

This function returns the euler angles of a game object in radians:

# function definition:
def eulAngs(gameObj,local):
    if local==1:
        Mat=gameObj.localOrientation
    else:
        Mat=gameObj.worldOrientation
    eulVec=Mat.to_euler()    # (in radians!!!)
    return eulVec

To retrieve local rotations angles (obj is a formerly defined game object):


...
psi=eulAngs(obj,1)[2]  # z-axis
tet=eulAngs(obj,1)[1] #  y-axis
fi=eulAngs(obj,1)[0]  # x-axis
...

hey thank you so much for your quick response!!!
Without the community I would be totally stuck!!! I think this is a huge problem for newcomers!!! There isn’t any good reference with simple examples for the bge 2.5
These days I have started with unity!! I have to say this is like day and night compared to the bge! The documantation for unity is awesome! Lots of simple examples. That is what a newcomer needs!! I hope there will be some good literature for the bge in the near future!

Once again! Thank you! I will try your examples!

Works everything sofar!!

But now I am stuck again ^^
What if I want it the other way? I have a rotation value… lets say 180°. And This Angle I want to get applied to my object.

This is what I found out. I need to Convert the angle into euler Value via

rot = math.radians(180)

So how do I convert this into a matrix and apply it to my Orientation?

I’ve tried something like this:

rot = math.radians(180)
matrix = rot.to_Matrix()

obj.localOrientation = (0,0,matrix)

You can either use (angles in radians):

# for <b>incremental</b> rotations:
obj.applyRotation([DeltaX, DeltaY, DeltaZ], 1) # with respect to local reference
obj.applyRotation([DeltaX, DeltaY, DeltaZ], 0)# with respect to global reference

# for <b>absolute</b> rotations:
obj.localOrientation = [NewX, NewY, NewZ] # with respect to local reference
obj.worldOrientation  = [NewX, NewY, NewZ] # with respect to global reference

mb

ok… I get it xD

rot = math.radians(180)
obj.worldOrientation= [0,0,rot]

Thank you mb10!!!
Slowly I am getting used to it :smiley:

Hey there… I am trying to create a Ray and check if it hits the floor. Somehow I don’t get it to work properly! Am I doing something wrong? I just want to create a Ray that has its origin at the players position and it is send downwards. therefore i create those to variables ray_from and ray_to. Maybe there is the error?
Strangely it is always printing the “hit”

    
ray_from = obj.position
ray_to = obj.position + mathutils.Vector([0,0,-1])
    
def checkGround():
    ## This function checks if the player hits the ground
    if (obj.rayCast(ray_to, ray_from, 2.0,'plattform', 1, 1) != None):
        print("hit")
    else:
        print("no hit")
        
checkGround()

change the ray_to to

ray_to = obj.position+obj.orientation[2]
ray_to.magnitude = 2

check the API. Look for what the function returns (hint: it never returns None).

It might be better to use a raySensor, as you cast the array all the time.

@agoose77
doesn’t seem to work either

@Monster
I have seen this in a tutorial of solarlune. He has used None too. Would it be better to use True or False?

I have attached a simple file. Maybe someone can help me get this working…

pythontest.blend (390 KB)

It returns always a list. It will never be None.

what you can do is:


hitObject, hitPosition, hitNormal = rayCast...
...
if hitObject is not None:
  ...

That is what the ray sensor already provides ;).

ah… Thanks alot Monster! I got it!!! The good thing about the rayCast to the raySensor is that I can better set its origin from where I send it. Isnt’t it?

Maybe I should rename this Thread to something like more appropriate :smiley:

This would help the users who get the same problems :slight_smile:

I suggest to use the ray sensor if the ray is cast from the object’s origin. The good thing of the sensor is that the controller does not need to run when the ray does not hit. This allows some good performance improvements.
The bad thing is that the ray sensor is running all the time and you would need to change the state to disable it.

On the other hand the rayCast is good:

  • when casting a ray from any other position
  • when casting the ray to any other position (not known before, or not along an local axis)
  • the ray is not always needed
  • more than one ray is required

The ray sensor and the rayCast are both performance eaters. Usem only when really needed.

Monster

I think that you’re almost correct - here’s the change:

    
ray_from = obj.position
ray_to = obj.position + mathutils.Vector([0,0,-1])
    
def checkGround():
    ## This function checks if the player hits the ground
    if (obj.rayCast(ray_to, ray_from, 2.0,'plattform', 1, 1)[0] != None):
        print("hit")
    else:
        print("no hit")
        
checkGround()

I added a [0] to the raycast check. If you print out what the raycast function returns, it will be this if it doesn’t find something:

[None, None, None…]

As Monster said, you can’t just check to see if obj.rayCast(…) == None, because it’s never None - it’s always an array, which possibly has None in it. So, by checking if any value is None, you can see if the function succeeded.

Monster is correct in saying that the Ray sensor is more efficient, but like he said, there are trade-offs.

ok… thanks solarlune! Now I fully understand why my version didn’t work!

Actually I am making good progress!! I am developing a Sidescroll Movement Script for my Game Orbito(Signature)! I will make it very customizable and publish it afterwards as an template! Just as a little thank you for all your help! :smiley:

Here are some little points I am going to implement.

-usual left/right movement (speed and acceleration can be set via propertys)
-jump and doublejump (can be enabled and disabled via a property)
-walljump

Other things may follow.

Ok… I am trying to get used to animation handling via python.

What is the best way to creat actions in the bge?

I know that I at least need to have one action actuator. This I can configure via python. But what if I want to use multiple actions that also blend. Is it recommended to use for each action a new actuator?

I’ve tried to only use one action actuator and configure it via small functions! But this way I do not have smooth transitions between the actions.

Here is the Code. And another question. What is blendTime exactly for? I don’t get it.

def animation():
########## import actuators ##########
c = logic.getCurrentController()
obj = c.owner
obj2 = logic.getCurrentScene().objects[“Cube”]

animation = c.actuators["animation"] 
c.activate(animation)

def aniIdle():
    animation.action = "Orbito_Idle"
    animation.frameStart = 1
    animation.frameEnd = 181
    animation.blendIn = 5
    animation.mode = 3
    animation.useContinue = False
        
def aniRun():
    animation.action = "Orbito_Runfast"
    animation.frameStart = 1
    animation.frameEnd = 15
    animation.blendIn = 5
    animation.mode = 4
    animation.useContinue = False


if round(obj2.localLinearVelocity[1],2) &lt; 0 and obj2["ground"] == True:
    aniRun()
elif round(obj2.localLinearVelocity[1],2) == 0 and obj2["ground"] == True:
    aniIdle()
    #aniRun()
    
print (obj2.localLinearVelocity[1])

I think you should have separate animation actuators so that you can call different animations at the same time. The blendin variable is used to specify how many frames it takes to blend into that animation.