[Solved] Set State : Copy/Add/Sub/Inv through Python?

Hi all,

  1. Is that possible to do this : Set State : Copy/Add/Sub/Inv without using logic bricks?
    Note : http://www.tutorialsforblender3d.com/GameModule/ClassKX_GameObject.html

gets/sets the sum of the active State Mask groups
I don’t understand much the use of the state variable.
What does “active” means? Copy? Add?

I think that it would be great if we could have an easier control of those states.
Something like :

obj.copy_state(1)
obj.inv_state(5)
obj.add_state(3)

  1. Also, can somebody give explanations for the use of the Inv option of the State Actuator?
    For exemple, if the state actuator is set to ‘Inv’ the first state when activated, does it mean that all the others states will then be activated? How?
    Is “Inv State 1” == “Add State 2 + Add State 3 + Add State 4, 5, 6, etc”?

  2. I would like a clear explanation of the Level and Tap options of the sensors.
    I couldn’t find much documentation (except basic translation).

Working .blend are welcome, if it doesn’t take much time.
That would be helpful, thank you :slight_smile:

  1. I think you can do
MyOb.state = GameLogic.KX_STATE1|GameLogic.KX_STATE2
MyOb.state = MyOtherOb.state
  1. That’s what I thought…

  2. Tap makes the sensor trigger once… I think that if you have it on a keyboard sensor it will only trigger when you press the button and then be negative the logic tic after, even if you hold the button down.

Thank you.

  1. This doesn’t look like a way to set states through Python.
    (I mean, not in the case that I don’t want to copy it from another object)

  2. I hope I can get confirmation about that.

  3. That would be nice if we had working examples for Tap and Level.
    That would help a lot of people. What is Level, I still don’t know.

Can somebody help? :slight_smile:

I couldn’t find ben’s notes on states but there was some way to set multiple states through python, and I think it was | or & or AND to set more at once.

I believe that the state system functions off of a 32 bit bitmask (which you can set with object.setState(bitmask) ). So:


00000000000000000000000000000001

Would be the bitmask’s value if only state 1 were active, and


00000000000000000000000000000010

Would be the bitmask’s value if only state 2 were active… and


 00000000000000000000000000000011
 

Would be the bitmask’s value if both state 1 and state 2 were active.

Typing in a ton of 0’s and 1’s into your script isn’t very helpful though… but you can give the number an integer! However, don’t think of the integer as the actual state you want… remember to convert from decimal to binary!

For example:
1 in decimal is 1 in binary… so setState(1) will correctly set your state to JUST 1.
2 in decimal is 10 in binary… so once again, setState(2) will correctly set your state to JUST 2.
3 in decimal is 11 in binary… so this time, setState(3) will enable both state 1 and state 2.
4 in decimal is 100 in binary… so setState(4) will enable JUST state 3.

You can find more info on how to convert from binary to decimal to binary online… it’s very easy though!

I haven’t tested all of this recently… so anybody who knows better correct me!
edit: Just did some testing… this is indeed how it works.

-Sam

1 Like

Oh… and to questions 2 and 3:

2, is… I think you’re right? Play around with it?

Level was a bit confusing, but here’s what I did to test:

I created a keyboard sensor and connected to a state actuator that switched to state 2.
In state 2, I connected that same keyboard sensor to an end object actuator.
When space was pressed without level enabled, you had to hit space twice to end the object (once to switch states, once to end the object).
When space was pressed with level enabled, once space press was all that you needed.

Note! I did this WITHOUT true fire pulse mode enabled… with it enabled, both level enabled and disabled ended the object with one press.

What I take from this is level will reactivate the sensor through a state transition?

Try the same thing as above but with a delay sensor instead (with Rep NOT enabled).

In terms of “tap”… I believe it causes the sensor to send a false pulse immediately after the initial true pulse, rather than the usual “send a true pulse when the sensor is activated, then send a false pulse when it’s deactivated.” This is really useful with the motion sensor… which doesn’t deactivate until it receives the false pulse.

-Sam

Hi Cray,

---------------------level button (sensor)---------------------------

As far as I know, this only works with the mouse and keyboard. But I could be wrong.

Sensors can belong to more than one State Mask group. When you switch from one State to another, the sensors belonging to the State Mask Group are reset.

If the level button is enabled, the keyboard/mouse status is checked.

Example. W Key moves your hero forward. It belongs to State Mask Group 1 and State Mask Group 2.

Level button not enabled. Switch from State 1 to State 2. W Key will be reset and your hero will stop moving forward. You’ll have to release the key and press it again to make your hero move forward.

Level button enabled, the Key is checked and if it is being pressed, a pulse is sent to the controller and your hero keeps on moving.

-----------------------------Inv button (actuator)-----------------------

This works like a toggle button.

Example: State Mask Group 2 selected
If State Mask Group 2 is active, if will be deactivated.
If State Mask Group 2 is deactivated, it will be activated.

Clark

Sim, TheSambassador, Cthames :Thank you all for your explanations, I appreciate it and I understood all of it.

A last word about states :
I could understand Sambassador’s explanations (I had read about it on cthame’s great site : tutorialsforblender3d.com) but I think that creating


obj.<b>copy_state</b>(1)
obj.<b>inv_state</b>(5)
obj.<b>add_state</b>(3)

would still be very helpful and easier.
What is your opinion about that?

Hi Cray,

First, thanks for the kind words about my site. It’s appreciated.

If I understand what you are saying, you want to use python to trigger/switch an object’s State Mask Groups by ‘remote control’.

Sure. You can do that. It isn’t as simple as your suggested setup but it isn’t hard. 9 or 10 lines of code.

If that’s what you mean, I’ll explain it and post a blend. (And if it isn’t, well I don’t want to waste the time. Feeling lazy today:).)

Clark

You could probably write a function for this (though obviously having it built in would be easier).

Here’s what I would do for a simple function:


def copy_state(obj, state):
    i = 1
    i = i &lt;&lt; (state - 1)
    obj.state = i

Then you could set the object in the script “own” to state 3 by doing


copy_state(own, 3)

However, this only works for setting a single state at once, and won’t allow you to set multiple states to be active at once. That would call for a more complex function… I’ll write one in a bit when I have time.

Edit: actually was quite easy!


def copy_state(obj, states):
    i = 0
    for state in states:    
        k = 1
        k = k &lt;&lt; (state - 1)
        i = i | k
    obj.state = i

Then you can call it with


copy_states(own, [1,3])

Which will set own’s state to 1 and 3. You can put as many states as you want in the list, and they can be in any order.

hi TheSambassador,

There already is a function for setting the State Mask Groups. It’s in Class KX_StateActuator.

mask

gets/sets the State Mask Group.

Type: integer
1 = State Mask group 1 active
2 = State Mask group 2 active
3 = State Mask groups 2 and 1 active
4 = State Mask group 3 active
5 = State Mask groups 3 and 1 active
6 = State Mask groups 3 and 2 active
7 = State Mask groups 3 and 2 and 1 active
8 = State Mask group 4 active
etc
16 = layer 5
etc
32 = layer 6
etc

# get the controller
controller = GameLogic.getCurrentController()

# get the state actuator named act 
act = controller.actuators["act"]  

# make State Mask groups 1 & 2 active
act.mask = 3

Clark

Hey cthames,

In my first post here, I explained that “part” of it (scroll up!). However, cray had asked for actual functions that would correspond to the things that the state actuator does, so that’s what I wrote.

Here is a complete list of them… fun! :


import math
def copy_state(obj, states):
    i = 0
    for state in states:    
        k = 1
        k = k &lt;&lt; (state - 1)
        i = i | k
    obj.state = i

def inv_state(obj, states):
    i = obj.state
    for state in states:    
        k = 1
        k = k &lt;&lt; (state - 1)
        i = i ^ k
    obj.state = i

def add_state(obj, states):
    i = obj.state
    for state in states:    
        k = 1
        k = k &lt;&lt; (state - 1)
        i = i | k
    obj.state = i

def sub_state(obj, states):
    i = obj.state
    for state in states:
        i -= math.pow(2,state-1)
    obj.state = i

All of them take a game object and a list of states as input. If you want to set the bitmask to include states 1, 2, 3, and 4, you can do so with copy_state(own, [1,2,3,4]).

This is a bit easier than converting from binary to decimal when you want specific states active… to enable states 1, 4, and 6 with the normal own.state = bla, you’d have to convert 101001 to decimal and input into that. Here, you can just do copy_state(own, [1,4,6].

Hope that helps!

edit - fixed inv

-Sam

hi TheSambassador,

I must be missing something.

What’s the advantage in writing your own functions and not using the functions already hard coded into the game engine?

The mask function sets/gets an object’s State Mask group. You can set/change one or two or all of the State Mask groups using this function

The operation function gets/sets the ‘operation’: Cpy, Sub, Add, Inv.

Clark

cthames: A few reasons:

  1. You still have to use a state actuator to use the methods you mentioned… when cray was wanting a direct way to set the state in python (without the state brick).
  2. While you can directly set the state using the object.state variable, it requires you to create that bitmask. These functions just simplify that creation process and make it more user friendly.

People are used to working in decimal, not binary, and it confuses people when to enable JUST state 3 you have to use state = 4, while to enable JUST state 2 you use state = 2.

This is the reason you write functions - to simplify things. To me it’s easier to use a function for this…


copy_state(own, [1,5,7])

Than to write out 1010001, convert it to decimal (81), and do


own.state = 81

You could argue that the pow function of the math module is unnecessary… why not just use loops and the basic multiplication function? It’s the same reason… it simplifies things for people.

-Sam

This is great, I had never really understood the bitmask and just used the defined KX_STATE things. This explanation was much better, thanks Sambassador!

hi TheSambassador,

Thanks for taking the time to explain it.

Clark

Hi,

cthames

What’s the advantage in writing your own functions and not using the functions already hard coded into the game engine?
I understand that point of view.
On the other hand, TheSambassador well-explained what I (and some other users maybe) could be looking for : no state brick, and user-friendly.

Some would think that not using the hard coded functions is kind of lazy behavior, but those functions really bring advantages and give access to those functionalities to more blender artists.
I’m not a coder, I would rather spend time working on my characters, artworks and gameplay than playing with binaries :slight_smile:
That’s the same thing I am trying to do with my template : providing a framework to make the creation process more user-friendly.
Both methods can coexist because they are made for different kind of users.
That’s why I asked, please don’t think that I am a lazy beginner :wink:

Edit : I saw your previous message after I posted.

TheSambassador
Thank you again for taking the time and sharing, that’s exactly what I needed :slight_smile:

No problem cray/cthames. Maybe I should post these in the resources section?

I might note that I had an incorrect understanding of the inv function (I thought that it set the state to the inverse of what was set… it just inverts the selected bits). I fixed it above, (what was changed was removing the i = ~i and changed i | k to i ^ k), and I’ll post it again here.


def inv_state(obj, states):
    i = obj.state
    for state in states:    
        k = 1
        k = k &lt;&lt; (state - 1)
        i = i ^ k
    obj.state = i

Cya!

-Sam

hi Cray,

Cray wrote:

please don’t think that I am a lazy beginner
I don’t. A lazy beginner never would have spent all that time developing the third person template :).

I asked because I didn’t understand and I like to understand. I appreciate that TheSambassador was nice enough to explain it.

Clark