[DEAD] Blender Plugin - BGE Logic nodes - Alpha

Currently V 0.3.0 - Will never be beta.

Download 0.3.0 63kb

+Math Formula node

Old Test Video (Repeater Node)

Overview (with available nodes)

Very early how to for custom nodes

Original post below…
New week, new project. A plugin for blender that adds a “game logic” tree editor.

Old videos










It uses the built in logic brics just to loop the system, the logic elements themselves (conditions, parameters and actions) are written in python. Basically, anything one can write in python for bge can also be a condition, a parameter or an action.
On the usability side it is still a bit rough around the edges (the user must remember to “apply” the result, there’s not button yet to clean up the applied result, incomplete trees or mistakes like typing a vector instead of an integer are not handled in the UI - but the tree will complain a lot when executed), things like that.
I have to expand the available elements and tweak stuff to see how viable it is for a realistic use, like creating stuff that shoots, things that can be clicked.
And I have to clean up the code, right now it’s garbage.

Wow! Looks promising and it’s so impressive! Keep it up! :smiley:

Looks awesome, but I don’t see any reason for you to define “OWNER” in your setup twice:D

It was a purely aesthetic choice: I didn’t like the idea of having this long line from the owner at the left to the actions on the right. It is not a necessity of the system, an element output can be used as input of as many other elements as the user likes.

Looks like you know what your doing really hope you finish this can’t wait. Hopefully i could maybe do some tutorials about it when it comes out :smiley:

This is really impressive! It’s looks like you are heading towards something similar to Unreal blueprints. If you havn’t heard of them, just look for video tutorials for ue4 blueprints.

If you could make it so user can create own functions etc in python that become available to this node editor, then you are bang on the money.

On a very basic level, this is the work flow Unreal encourages.

Programmer programs all the core functionality in C++ (In this case it would be python)
Designer then takes the functionality made available to the nodes and creates functional things in a creative, visual way so they don’t have to worry about programming.

Being a one man army, this work flow still works great.

Keep it going!

cypher, I find the idea of having sets of nodes defined on a per-project basis very interesting, I’ll steer the project in that direction.
I didn’t know about unreal blueprint, I watched a couple of videos and I have mixed feelings, my first impression was “that looks complicate” - which is badly handled complexity - but that’s most likely because I’m completely unfamiliar with the Unreal interface and workflow.

Yeah its a little weird to get your head around at first, but it actually works very well. They’ve got the interface down to a tee. As the C++ programmer, using macros, you have full control as to what is visible and editable to the designer. The editor reads these programmer macros and knows what to give to the designer. Its pretty clever really. A good example of this is player health. When you are writing code for your player, you might put a health variable and then set it to 100. Normally you’ll want the designer to control that variable value though. So you make it available to the editor. Then in the editor, the designer has a nice visual number box where they can enter the players health in a much for visual UI fashion.

For example, you might have something complex that needs to happen on an event. So you would program that in code, but that event response is encapsulated. So the designer, knows he can activate that response by plugging in that node, but he doesn’t need to know how it works. Then the designer can mess around with how to trigger that event.

Thanks to cyper2012, I… cleaned up everything and restarted from scratch. So now we have a logic tree with optionalperprojectimportable nodes. It makes a lot of sense to have such a feature. Very short example.

An extension works by adding, in a predefined directory, relative to the main blender file (an arbitrary decision), a pair of python files. One file contains the tree node and one file contains the corrensponding logic cell. I’ll have to publish the api documentation if this becomes viable.

Now nodes, nodes, nodes, until I have a set of meaningful elements. As a reminder for myself, the todo list currently contains:

KeyReleased, MousePressed, MouseReleased, GetGameObjectProperty, GetGameObjectAttribute, FindScene, FindObject, AddScene,RemoveScene,RemoveObject,RunPythonModule,ConditionOR,LogicalOperations,VectorMath,GetGlobalValue,SetGlobalValue,SetActiveCamera,GetActiveCamera,LoadBlenderFile,UnloadBlenderFile,MousePick,CameraPick,GetMouseValues,StopLogicNet,SwitchLogicNet and a few Time & Ticks related stuff.
And collision elements. And sound. Sound might be tricky (I always had problems with the 3d sound python api of bge)

This is brilliant!

So it looks like the object rotation was a demonstration of creating custom python script, and then using it as a custom node brick?

If that’s the case, that’s exactly bang on! :slight_smile:

I really hope this project builds as much interest as I have in it! :smiley:

Yep, I pretty much stole your entire idea. User A wants/has to play only with nodes, User B supplies the custom elements, User A “imports” and use those nodes as they were pre-packed ones.
Like “hey, I need an Action that makes my object flash rapidly”, B makes the node-cell pack, A adds it with a ui button and bang, ready to use it from the nodes menu.
It incidentally also allows “custom nodes” to be shared among us users, one could build a set of nodes to write save files or to send data through a network, or nodes that apply shader based materials, and share them. Which is by the way entirely possible with the “normal” blender api.
The only limit is the amount of bugs I manage to put in the code (a quite astonishing number, so far)

A small update, so I make you think that I’m releasing something while I’m not (yet). I’ve added and sort of tested the alternative to “states”. You know, those little many buttons… man I hate those buttons.

An object can have multiple logic networks associated (a logic network is the running product of the logic tree), each one is named and a network can start or stop any other network of any other object.

So if in the brick system one can combine a set of logic flows by activating the states, in the tree system you “say” something like "stop the ATTACK network and start the FLEE and the SCREAM ones).

Next is adding the nodes needed to replicate a “mouse look” functionality. I’ll probably add a single Action node for that but I’m interested in finding a way to present 3d math operations in a friendly way and I have to see how big is the hit when doing math operations.

I also have to properly associate trees with objects, probably with some id-list-bpy black magic. After a while experimenting you end up with a ton of trees and cleaning up unneeded stuff still needs to be done by hand. That’s very bad.

This is super interesting I like what you are implementing, the idea is cool where people could post their custom Node.

Let’s just say, esteemed gentlemen, that I am growing a not so faint feeling of dislike for the blender ui api.

Preach, brother.

what about exposing a generated mouse property, and just having a motion relative mode ?

so head rotates relative to body by applying a rotation that is a property you generate with mouselook

(I know that is a mouth full)

the current mouse actuator gets ‘lost’ if turned on and off this is why I use my mouse property generator…

So mouse movement on x axis adds/removes from a property(X) , so X has a range you set and sensitivity (like -1 to 1)

the code in the ‘mouse motion node’
Head rotation.axis = body.rotation.to_euler().axis+X

this way applying zero rotation is as easy as setting X to zero.

I have wrapped the mouse data in a node that provides other nodes some information. This is an example that basically says "when the mouse is moving along the x axis, rotate the object whose name starts with “head” by an a (x,y,z) amount where y and z are zero and X is the translation of the mouse along the x axis multiplied by the value of the global property “Player head rotation speed”.

I have to add nodes to manipulate rotational values, right now you can get orientations but there is no predefined way to operate on them.
Unfortunately I’m stuck with a couple of UI hacks that I need to remove the “manually update the network if you want this thing to work” feature.
I’m almost done with that, then I’ll be back on track.
I’ve added 6 of the 17 nodes I had in mind yesterday, now I have only… 23 more to go. Every time I add a node I start thinking “I, that would also be cool” and bang, three more nodes on the list.

This is awesome. Even more-so if it’s easy to write custom nodes on a per-game basis.

Well, easy is a relative concept but if I can write them then a baboon should also be able to do it.
The concepts are really straightforward: a logic cell is something that has an “evaluate()” method, in that method it sets its status to WAITING or READY. The first means that the cell is waiting for the result of another cell, the second that the cell has finished its computation and has set its values.
This is the cell that checks if the mouse is pressed:

class ConditionMousePressed(ConditionCell):    def __init__(self):
        ConditionCell.__init__(self)
        self.pulse = False
        self.mouse_button_code = None
        self.network = None
    def setup(self, network):
        self.network = network
    def evaluate(self):
        mouse_button = self.get_parameter_value(self.mouse_button_code)
        if mouse_button is LogicNetworkCell.STATUS_WAITING: return
        self._set_ready()
        mstat = self.network.mouse_events[mouse_button]
        if self.pulse:
            self._set_value(mstat == bge.logic.KX_INPUT_JUST_ACTIVATED or mstat == bge.logic.KX_INPUT_ACTIVE)
        else:
            self._set_value(mstat == bge.logic.KX_INPUT_JUST_ACTIVATED)
    pass

The pattern is always the same. get_parameter_value(self.a_field), if the returned value is STATUS_WAITING it means that the value is not available yet and the cell must wait.
When all the requested fields, passed through get_parameter_value, return something other than STATUS_WAITING, the cell can do its computation, set itself to ready and refresh its value with self.set_value(something).
And just to give the entire framework, if a cell spits more than one value, it has to use SubCells to wrap them.

This cell takes a vector and three numbers and produces a vector and three numbers:

class ParameterVector(ParameterCell):
    def __init__(self):
        ParameterCell.__init__(self)
        self.input_vector = None
        self.input_x = None
        self.input_y = None
        self.input_z = None
        self.output_vector = mathutils.Vector()
        self.OUTX = LogicNetworkSubCell(self, self.get_out_x)
        self.OUTY = LogicNetworkSubCell(self, self.get_out_y)
        self.OUTZ = LogicNetworkSubCell(self, self.get_out_z)
        self.OUTV = LogicNetworkSubCell(self, self.get_out_v)


    def get_out_x(self): return self.output_vector.x
    def get_out_y(self): return self.output_vector.y
    def get_out_z(self): return self.output_vector.z
    def get_out_v(self): return self.output_vector


    def evaluate(self):
        x = self.get_parameter_value(self.input_x)
        y = self.get_parameter_value(self.input_y)
        z = self.get_parameter_value(self.input_z)
        v = self.get_parameter_value(self.input_vector)
        if x is LogicNetworkCell.STATUS_WAITING: return
        if y is LogicNetworkCell.STATUS_WAITING: return
        if z is LogicNetworkCell.STATUS_WAITING: return
        if v is LogicNetworkCell.STATUS_WAITING: return
        self._set_ready()
        if v is not None: self.output_vector[:] = v#TODO: zero vector if v is None?
        if x is not None: self.output_vector.x = x
        if y is not None: self.output_vector.y = y
        if z is not None: self.output_vector.z = z
        self._set_value(self.output_vector)

This is as complicate as it gets, on the logic side.
The Nodes are trickier. They have to be what blender wants them to be, to work as nodes in the interface. That requires to know how to write a blender node (this monkey did it, so it’s no big deal).
Then there is the implementation of what the addon needs to transform the node into a cell. That’s not the best thing in the world, I made it up while I was writing it so it doesn’t look much coherent, but it boils down to:

  1. returning the name of a class from an overridden method
  2. returning the name of the fields associated with input and output sockets, if any
  3. returning, in text form, the value of unconnected input sockets, if any
  4. returning the names of the subcells associated to output sockets, if any
  5. returning the names and the values, in text form, of the custom properties, if any

Lots of names, but not much else. The reason for all that name mapping is that the addon simply translates the node into the python code needed to instantiate a cell and set its fields. So if a Node represents a Cell of type X, with three input values and two output values, the addon will write - through the names supplied by the node - something like:

CELL = X()
CELL.name_a = something
CELL.name_b = something
CELL.name_c = something

where “something” is either the name of another cell or a constant expression (1.0, “hello world”, bge.events.LEFTMOUSE, things like that).

I don’t post the code of a Node because I tried like five different ways to make it “easy” before to find the one that I like more and I still have to refactor it in.

I will, of course, publish a small tutorial on how to do all this stuff, IF the addon ever sees the light: everything is going according to the plan (that I never had) but you never know when a showstopper will pop out. The UI really made me mad.

I’ve updated the first post with a footage of a test session. It starts with a usability bug and ends with a UI bug but it also shows the key improvements to the interface and the system, namely auto-update - there’s no more need to press the “generate code” button to refresh the underlying scripts, the user just changes the tree and everything follows as one should expect - and the use of multiple logic trees to represent interactive states - given an object and the name of the logic tree, there are triggers to start or stop the associated logic networks.
I’m happy with the progresses made so far, it looks like it could work. More bug fixing and more nodes before the alpha.