Standing, Crouching, and Proning in Pythong

After hours of tedious and infuriating work: I couldn’t conclude this. So I’ve been trying to make a script that alternates the stance of the player, which would consist of: Standing, crouching, and proning. Unfortunately, I’m not well experienced to properly produce such script, as I attempted for hours.

Here’s what I have so far:


from bge import logic, events


scene = logic.getCurrentScene()
cont = logic.getCurrentController()
own = logic.getCurrentController().owner


key_none = logic.KX_INPUT_NONE
key_tap = logic.KX_INPUT_JUST_ACTIVATED
key_active = logic.KX_INPUT_ACTIVE


ZKEY = logic.keyboard.events[events.ZKEY]
XKEY = logic.keyboard.events[events.XKEY]




#Transition Logic
if own["Standing"] == True:
    own["Crouch"] = False
    own["Prone"] = False
    if ZKEY == key_active:
        own["Crouch"] = True


if own["Crouch"] == True:
    own["Standing"] = False
    own["Prone"] = False
    if ZKEY == key_active:
        own["Standing"] = True 


Sorry, it’s a bit unfinished. Well sorry if I have to ask you guys, my bad…

Do you really want to combine all of that different states?

I do not think they are orthogonal to each other. Either the character is standing or it is crouching.

I strongly suggest you use a single state that can have a value that represents the different states.

You can use a property as state:



character["state"] = "standing"


This can be used with and without Python.

or the build in state:



STATE_STANDING = 1
...

character.state = STATE_STANDING

This can be used with and without Python.

Or you encapsulate it in your own python class:



class Standing:
    ...

class Fsm:
   def __init__(self, initialState):
       self.state = initialState

stateMachine = Fsm(Standing())

I actually have scripts that determine the actions of the properties. I have two scripts at the moment, one for crouching, the other for standing. So I’m not having any problems defining the states, I’m just having problems defining the properties.

I attempted to use the method of defining the properties. This example is not actually a script, but it states my intention:


So if "standing" == True:
        then (other properties false)

def standing(data):
     #standing stuff

def ducking(data):
    #ducking stuff


actDict = {'standing':standing, 'ducking':ducking }

def main():
    

    ## strip = [ ['stateString',[dataForState]] ]
    if len(strip)>0:
        string = strip[0][0]
        command = actDict[string]
        data = strip[0][1]
        command(data)
    else:
        proccessInput()

I use something like this for few reasons

  1. you can add as many states as you wish without introducing any more complexity
  2. you can have a list of states that the agents completes
    (walk to mark, dialog, flip switch, cry about sad thing)
  3. you can process movement input inside states
  4. you can have small states that transition between states
    (ie duck then crawl)

I could use definitions, but the problem is: I’m not very familiar with it. I’ve hardly used it.

So which is why I tend to use separate scripts.

so what we have is

def function(data):

data = a list of arguments
(in the case of states the arguments are usually varied)

this way you can call
[‘navigate’,[me,target,navMesh] ]
to drive enemy agents around

[‘punch’,[frame,endframe,strength]]
is how I handle punch

we need to translate input into states right?

this is where you need a serialized input system :smiley:

(so you can write it 1 time for p1, p2, cars etc)

I gather a list of inputs using dictionary



players = {'p1':[ ], 'p2':[ ] }
if inputString in keyDictionary:
   data = keyDictionary[inputString]
   #format is [gameCommand,index,player]
   #based on player we append the data to a list p1, p2 etc
   players[data[2]].append(data)
   #later after we gather input we sort each list by second value  (index)
   #we then copy over only the game command string to a new list
   #only it not on list removing doubles 

for player in players:
     inputData = sorted(players[player], key=lambda tuple: tuple[2])
     inputs=[]
     for press in inputData:
         if press not in inputs:
             inputs.append(press)


this serializes the input and chops off the doubels
(so the inputs are always in the same order)

from here I just use the list directly to call input vs a dictionary

state = moveDict[input]
(if I am not already inside a state)

if I am in a state I do almost the same thing,

the list look like this my serializer spits out

[ ‘Up’, ‘Left’ ]

I tend to do 2 lists per player

Move and Act

Act looks like [ ‘Punch’, ‘Kick’ , ‘Sprint’ ]

in action =

Wow, this does seem impressive. It’s still kind of complicated to learn since it severely varies from the method I use…

So is there a place where I can learn how to use definitions, or that method?

start a new .blend and get the hang of it

if you get errors or stuck go to discord / blender / blender game engine

Alright, I’ll keep that in mind. Thanks for the offer!

Is there another alternative for communication?

there is many more people there than just me*

@wkk redfrost etc.

I would recommend most of the Ba community join

Alright, I might take it into consideration.

use “key_tap”, not “key_active”. active is looking for a held down key, since the computer is so fast, your single click registers a couple of times to the computer. have a “print(“Crouching”)” next to where you assign your state. look in the console and see how many times its actually switch back and forth. tap will look once and not again.


from bge import logic, events


scene = logic.getCurrentScene()
cont = logic.getCurrentController()
own = cont.owner


key_none = logic.KX_INPUT_NONE
key_tap = logic.KX_INPUT_JUST_ACTIVATED
key_active = logic.KX_INPUT_ACTIVE

ZKEY = logic.keyboard.events[events.ZKEY]
XKEY = logic.keyboard.events[events.XKEY]

#Transition Logic
if own["Standing"] == True:
    own["Crouch"] = False
    own["Prone"] = False
    if ZKEY == key_tap:
        print("Crouching...")
        own["Crouch"] = True

elif own["Crouch"] == True:  #else if, means dont run both in one frame
    own["Standing"] = False
    own["Prone"] = False
    if ZKEY == key_tap:
        print("Standing...")
        own["Standing"] = True

the others are correct about managing states better, but in time you will learn this, dont sweat it this early on. once you know python, you will be able to figure out how to make it faster and cleaner.

That is my point. You have to deal with different combination of properties. This is fine when you want to be able to combine them e.g. when running is just a special form of walking. I guess you want either standing or walking rather than both.

when you have a single property, setting the new state will automatically disable the old state without you need to care about. Otherwise i will be really hard to introduce new states.

so rather than:


if own["Standing"]:
    own["Crouch"] = False
    own["Prone"] = False
    if ZKEY == key_active:
        own["Crouch"] = True

you can use


if own["Status"] == "Standing":
    if ZKEY == key_active:
        character["Status"] = "Crouching"

I think it is importing to be careful with naming. I suggest to use the “-ing” form to express the state as this is what the character is currently doing: Standing, Walking, Crouching. This allows to differentiate from operations (requests) that want to change to the according state: Stand, Walk, Crouch

The state graph will be pretty easy to understand:


if isStanding():
    if shouldCrouch()
        crouch()
    if shouldWalkForward():
        walkForward()

elif isWalking():
   ...
elif isCrouching():
   ...

The transition can be encapsulated into the according operation:


def crouch():
      character["Status"] = "Crouching"
    character.play("CharacterLayDownForCrouchingAction")

You do not need to fiddle wit ha lot of different properties. You have a single one.

Be aware there are quite a different ways to implement a state machine (FSM).

Alright, so you’re stating that I should only require one property? That should be defined by the three states? Alright, sounds good. I’ll take it into consideration.

Exactly. This property is the leading one.

So is the “Status” property a string?

When you want to easily read the meaning, yes I suggest a string.

Many systems use integer (0,1,2,3). This includes the build-in state system. This is mainly for efficiency. To be honest at that level the speed difference between a string and an integer do not matter in that context (You are not programming an embedded micro controller that checks the status 100 time each microsecond).

I think the readability is much more important in your situation.

Beside of that it is much easier to notify that a value is a status, and not an amount or an index when you debug your code.

Ah, well thanks. While waiting for a response, I already found a way to determine the status of the player with that string property. It’s basically the three properties: Standing, Crouching, Proning. If either is true, like Standing. Then the string is that property, and the others turn false. It works efficiently…

Thanks once again.

What happens if standing and crouching are both true?

If one is true, then it sets the other false…