I have been toying with a system to control everything from players to cars, To AI,
Object1 Remote = A collection of sensors that generates a list, that is all the sensors that are positive, in a certain order, it also has a property, that is a target object.
Object 2 = To be controlled,
Property in object
Move is changed---------python
When a move is received the python then runs a filter
If Move= [‘Sensor1’,‘Sensor2’]:
(Tab)Do stuff
This way control is separated from animation and locomotion,
So the control object can change targets.
My Question is do you see any design flaws?
Would this make developing games using premade assets much easier?
Drop actor in, set property in controller, and its running?
It works well and looks easy to integrate. If I were to use logic bricks and I had to control more than one one player object I would certainly consider it.
I usually implement the separation of the input from the operation via message. This causes a one frame delay but is very easy.
One or more “UI” objects deal with the devices (keyboard, joystick, mouse). They translate this input to a meaning e.g “move forward” or “move forward” by 0.34.
The operation does not directly rely on the device, but the messages coming from the UI objects.
The implementation for boolean input (key presses) is very simple with logic bricks. You simply replace the keyboard sensors with message sensors.
The implementation of dynamic input (mouse, joystick values) needs a little bit of Python. I usually transfer that data in the message body. So it can be read from there.
The usage is very simple too. Either you have an UI object, or not. You can have any number of UI objects. Each UI object can deal with several devices which unfortunately makes it very complex or it deals with a subset of purposes (e.g. player UI, menu UI, camera UI, debug UI). You can even link UI’s from other .blend files. This way you create them once to be used in all levels.
This system does not deal with switching controls from one object to another (e.g. from player when entering a car) which does not need Python at all. This is explained in How to: enter a vehicle or how to: switch controls and has no relation to the described method.
I send over mouse controls and Keyboard Presses now,
and really the switchable agent target it more for drag and drop, however it also will be handy
for vehicle control etc.
Drop in a Controller cube, Drop in a Actor Type, set the name of the agent in the controller,
Parent a Armature to the agent, add a property in it ‘Armature’, and some type of index of actions.
I want the bge to murder all engines in simplicity to get a simple game running,
drag and drop assets that are well documented are it.
polling1 (big)
if init.positive or reset.positive:
for objects in bge.logic.getCurrentScene().objects: # <- slow
if objects.name == own['target']: # <- slow
own['target']=objects
polling2
for sensor in own['SensList']:
if sensor.positive:
Move+=[sensor.name]
Controller only generates properties when active…
active = pool all sensors , if some is True -> run controller (polling)
Just as a side note, a curiosity, polling is the process of checking values in an execution flow that runs in parallel with the data flow. The parallelism makes polling an active process and that’s the difference between polling and callbacks. If there is not that parallel flow, it’s a callback, which does the same thing but in a passive way. It might look like a poller because the check condition is moved inside the callback, but it is still a callback. No parallel flow, no polling.
I have a very peculiar view or software programming, so I might not be the best person to give advice on the subject. But I will give it anyway
Don’t waist time thinking about polling, callbacks and stuff like that. Write your system as you like it, object oriented languages are powerful enough to let you express your idea of how things should work as you imagined it.
Place your sensor where it makes sense for you to have a thing that you see as a “sensor”. If you’re concerned by performances, don’t be: you cannot measure the performance of a system that doesn’t work (to clarify: you have to first write your system, check that it works, and then you can measure its performances).
I do not like the term “callback”.
I prefer the term “listener” as it expresses it is an object (the mechanics are pretty much the same).
Regardless of the name both refer to an event system see Observer pattern.
A sensor can be both. The sensor performs polling as it runs at each frame. This is no problem as the sensor runs in native code.
The sensor perform complex processing (as the ray sensor). This is real … processor intensive polling.
It can also check the results of a listener towards other components (e.g. on collision -> listener to the physics engine).
While the sensor is polling … your (higher level) logic does not need to do that. It get notified by the sensor = event driven.
Yes and no… the listeners get notified when the observed object decides to notify it’s listeners. Typically this is shortly after getting the results. This can also happen at a later time e.g. collecting all results and notify later vs. notify on each single new result. The active part is the observed object.
When polling the observer is the active object and decides when to check for new results.
thanks for explanation, more or less seem to understand , but what is not clear is if there ever a “clear line” where start one and ends the other… i not see it…
ie: a callback should call a function specific, but supposing it call a function generic… the function generic can do a bunch of checks teoretically… it is yet a callback?
The line is quite definite: you need two control flows to poll. That means two parallel threads or two processes. If not, it’s callback. The condition that leads to the invocation of the function might have been moved to the moon, but it is still a callback. It’s passive, someone else will cause its invocation.
A poller polls, no matter what other parts of the system might decide. They might even not be running at all, but the poller will. That’s what makes it an active way to check things.
Note that if you collect states somewhere in the main loop and later on you call a function that checks those states and to see if some value means “do something”, its still a callback, there is just one control flow, the one driven by the main loop of the engine.