Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Eureka! I have discovered autonomous inputs!

Author
Message
Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 11th Aug 2013 04:55 Edited at: 6th Nov 2013 19:04
One of the most common needs for interactive programs is to detect discrete inputs; the ability to register individual key/button presses.
Traditional methods require additional variables, for example
, which is messy and effectively doubles the number of variables in your program.

To solve this issue, Silverman and I have developed the concept of autonomous variables, This literally means, "self-governing variables". A variable is said to be autonomous when its own value forms part of its assignment value. A simple example is a binary flip-flop: x=1-x, where x will either equal 1 or 0 depending on the previous state of x; this "memory" property is very useful for managing input.

Silverman's equation, which I've dubbed "silkey": variable = 3&&(variable<<1||trigger)
As a function:


Libervurto's equation: variable = trigger*((variable=0)-abs(variable))
As a function:

(I would recommend using silkey rather than my version, but I post it because it is a different approach which might prove beneficial in some circumstances.)

————————————————————————————————————————————————————————————————


The silkey can be extended to cater for some common tasks.

Chords
We can easily detect multiple simultaneous inputs: input1&&input2&&input3
The result is in silkey format, so we can tell when the chord is pressed, held and released.

Mouse Input
Managing the mouse buttons takes a simple adjustment: s = 63&&(s<<3||t)


Mouse Chords
If you want to use mouse buttons in chords then it's a lot easier to change the format of the mouse button data to "parallel" rather than in "series"; by this I mean we change the format from 'sssttt' to 'ststst'. In this alternative format we can simply bit-shift the data to grab a certain button and it's already in silkey format.


Mode Toggle
Mode toggling can be used for things like drawing lines in a graphics program, when you want the user to be able to click once to set the start point and again to set the end point.
mode = (mode~~(s&&3))=1


Formerly OBese87.
thenerd
15
Years of Service
User Offline
Joined: 9th Mar 2009
Location: Boston, USA
Posted: 11th Aug 2013 05:31
This is great. So much more elegant than having to store multiple variables.

I think it might be worth it to put this code into a function, that way you won't need to copy and paste it everywhere. I just quickly made it into this:



This way, you can use the same code for other events such as mouseclicks without having to modify the line...



It seems cleaner this way.

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 11th Aug 2013 06:35
Yeah, that's a nice way to implement it.
Does it work as if Tap then DoEvent()?

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 11th Aug 2013 06:46 Edited at: 11th Aug 2013 07:20
I found a way to simplify it. OP updated. Added an 'official' function too, nice idea nerd.

thenerd
15
Years of Service
User Offline
Joined: 9th Mar 2009
Location: Boston, USA
Posted: 11th Aug 2013 15:01
Quote: "Does it work as if Tap then DoEvent()?"


No, because as far as I've seen using if <variable> will return TRUE as long as the variable has any value in it that isn't zero. So if Tap is -1 it still returns TRUE. But that's only a minor annoyance, you just have to add = 1.

Quote: "state = keystate(x) * ((state=0) - (state<>0))
OR
state = keystate(x) * ((state=0) - abs(state))"


I'm wondering which of these is faster - does abs make a difference?

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 11th Aug 2013 16:11
I haven't been able to test it. Would be interesting to know which is faster.
abs() gives an absolute value (without sign) so it ensures that the number subtracted is always positive or zero. There is one minor difference when using an input that can have a value greater than one, eg mouseclick(). When the input is held down the value of state = trigger*-state therefore state grows exponentially (towards negative infinity) when the input is held.


The arse-tit formally known as OBese87.
TheComet
16
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 11th Aug 2013 19:38 Edited at: 11th Aug 2013 20:36
You can simplify it even more with bitwise operators. This here is code from my micro controller project, which can handle 8 buttons with just one calculation.

state = PORT_A & ~state

The above detects positive edge inputs (presses). Similarly, you can detect negative edge inputs (releases) with the following modification:

state = ~PORT_A & state

Translating that to DBP code:



[EDIT] cleaned up my post

TheComet

Daniel wright 2311
User Banned
Posted: 11th Aug 2013 20:10
WOW, This is what I always wanted, Thank you

my signature keeps being erased by a mod So this is my new signature.
Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 11th Aug 2013 20:38
@Comet - what is .. ? Never seen that before. Can you explain how this works: state = keystate(x) && (0xFF .. state)


The arse-tit formally known as OBese87.
TheComet
16
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 11th Aug 2013 20:40
There must be an even easier way though. Aren't there any lower level commands or perhaps some Matrix1 commands that allow you to directly access buffered input? That way you don't need to do all of the above stuff, since generally only presses and releases are registered in the input buffer. You'd have the advantage of being able to use them directly and not miss any input from pressing buttons too quickly.

TheComet

thenerd
15
Years of Service
User Offline
Joined: 9th Mar 2009
Location: Boston, USA
Posted: 11th Aug 2013 20:40 Edited at: 11th Aug 2013 20:43
@TheComet: Can you show an example of that working? I can't seem to get it to work.

[EDIT] A buffered input system might be worth some research. I'll look into it.

TheComet
16
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 11th Aug 2013 20:50 Edited at: 11th Aug 2013 20:50
I'm not near a DBP compiler at the moment, but does this do what it's supposed to do?



It's possible I'm mixing up the bitwise NOT operator, and it should be (0x00 .. press_state) instead of (0xFF .. press_state).

TheComet

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 11th Aug 2013 21:17
Can you explain what state = keystate(x) && (0xFF .. state) does?


The arse-tit formally known as OBese87.
thenerd
15
Years of Service
User Offline
Joined: 9th Mar 2009
Location: Boston, USA
Posted: 11th Aug 2013 21:20 Edited at: 11th Aug 2013 21:22
Neither of those work. Running through it...

First time:
press_state = keystate(17) && (0xFF ~~ press_state)
press_state = 1 AND (OxFF XOR press_state)
press_state = 1 AND (255 XOR 0)
press_state = 1 AND (1)
press_state = 1

After the first time:
press_state = keystate(17) && (0xFF ~~ press_state)
press_state = 1 AND (OxFF XOR press_state)
press_state = 1 AND (255 XOR 1)
press_state = 1 AND (0)
press_state = 0

[EDIT] I don't know how I missed this, changed the OR to an XOR. But it still doesn't work.

...In theory it should work but it doesn't seem to. I feel like I'm missing something.

TheComet
16
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 11th Aug 2013 22:51 Edited at: 11th Aug 2013 22:52
I feel like I'm missing something as well.

First of all:

Explanation.

Here are the bitwise operators supported in DBP, just as a reference.


The key idea behind this method is to encode two bits into producing a logical true only once. The two bits we have are one input bit, and an old state, as can be seen in the following snippet.



We have old_state and new_state, so now they have to be combined somehow to produce a true at the moment the key is pressed, which is precisely when new_state=1 and old_state=0. Similarly, we can also produce a true at the moment the key is released, which is precisely when new_state=0 and old_state=1. Both can be achieved with one AND and one NOT.



0xFF .. old_state will invert all bits in old_state
new_state && x will perform a logical AND on each bit of the variable old_state with x.

All I tried to do was compress the latter into one line, as Livervurto cleverly did with his method:



I see the error in my ways now. All that will happen with the compressed version is pressed will begin to toggle when you press the key, and released will do absolutely nothing at all.

TheComet

Chris Tate
DBPro Master
15
Years of Service
User Offline
Joined: 29th Aug 2008
Location: London, England
Posted: 11th Aug 2013 23:04
Ok I am catching up a bit now

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 12th Aug 2013 00:05 Edited at: 12th Aug 2013 01:02
The key to it is that the switch variable has three possible states: idle, active and disabled; I represented these as 0, 1 and -1 respectively.
I feel like there should be a way to simplify (s=0)-(s<>0). The result is either 1 or -1, never 0.

I've rewritten the OP to make it a bit clearer.


The arse-tit formally known as OBese87.
Chris Tate
DBPro Master
15
Years of Service
User Offline
Joined: 29th Aug 2008
Location: London, England
Posted: 12th Aug 2013 01:33
That does not look like it needs to simplified to me, but why not challenge yourself. I was actually struggling to grasp TheComet's idea, but his explanation does help my brain a little bit.

My keystate system is array based because each key can have multiple triggers attached to them along with user defined modifier key checks, but this all seems like a cool idea for future use in other logical algorithms. Reminds me of what I do with vectors, multiplying them by boolean operated results.

Silverman
17
Years of Service
User Offline
Joined: 18th Jan 2007
Location: France
Posted: 12th Aug 2013 14:40 Edited at: 12th Aug 2013 14:51
hi Libervurto,

I posted a similar thing here:
http://forum.thegamecreators.com/?m=forum_view&t=203846&b=1

My code and your uses the same principle. I simplified the equation of my code. Modified version of your code:


Edit : hey, you're Obese87, new nickname henceforth?

DirectX 9.0c (February 2010)/ DBClassic v1.20
TheComet
16
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 12th Aug 2013 19:28 Edited at: 12th Aug 2013 20:08
Quote: "I posted a similar thing here:
http://forum.thegamecreators.com/?m=forum_view&t=203846&b=1"

And I replied to you, yet I have no memory of it!
Maybe my memory was erased when they changed my name.

I think theComet could fix his version by looking at yours. I was trying to get a -1 output because I thought that meant FALSE, but since that isn't the case it might be better to switch to bitwise operations like you have done.

Cheers

Edit:
DBP can bitshift: s = 3&&(s<<1||t)
Interesting how yours stacks the 'state' and 'trigger' beside each other and then cuts off the largest bit:

It's a two-bit FILO* system: on every loop the trigger value from two loops ago gets popped off and a fresh trigger value is added to the other end. Clever!

*First In Last Out

I'm going to play around with this structure and see what else it can do.

Your signature has been erased by a mod - No swears!
Burning Feet Man
16
Years of Service
User Offline
Joined: 4th Jan 2008
Location: Sydney, Australia
Posted: 13th Aug 2013 01:25 Edited at: 13th Aug 2013 01:28
I love the simplicity of autonomous inputs. But every time I've addressed my mouse code over the past couple of years, I always end up with this system, which is far from simple;



The above UDT's tracks everything that the mouse does. My only gripe with this system is some of the naming, can get confusing at times. The easiest way around this problem is to create some #constants for the common calls, such as;

#Constant LMP Mouse(1).Press_1.State
#Constant RMP Mouse(2).Press_1.State

#Constant M_PosX Mouse(0).Cursor.Position_Application.Current.X
#Constant M_PosY Mouse(0).Cursor.Position_Application.Current.Y

This allows me to write;

If LMP
Print "Lolcats"
endif

Maybe it's overkill... What do you guys do? In the beginning, I had no idea for just how much code is behind the humble mouse!

Help build an online DarkBASIC Professional help archive.
DarkBasic Help Wikia
Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 13th Aug 2013 07:57 Edited at: 13th Aug 2013 21:53
@Burning Feet
I'm not sure what all your types are for but it's an interesting problem. I reckon Silverman's approach could be extended to cater for a lot of mouse data. I will have a think about it.



The gluteus-maximus mammary-gland formally known as OBese87.
Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 13th Aug 2013 21:53 Edited at: 14th Aug 2013 05:59
OP has been rewritten.



The gluteus-maximus mammary-gland formally known as OBese87.
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 16th Aug 2013 11:21 Edited at: 16th Aug 2013 11:54
I like the idea of Autonomous Inputs but in this programming context (Windows DX9 Game) I don't see it solving any major problems that I haven't already solved with other methods.

There's also a number of other small issues this thread didn't cover.

I'd like to thank Libervurto since I find this method of condensing everything into one line quite clever. I'd like to thank Comet since the bitwise details are insightful.


Getting started.
Quote: "One of the most common needs for interactive programs is the ability to detect distinct inputs; that is to detect the entire duration of a key/button press as a single event.
Previously this required additional variables, for example"


Using more than one variable isn't all that big of a concern where inputs are involved. Memory and CPU resources vastly out supply the needs here. Your example is a bit crude, but completely valid.


Quote: "You can simplify it even more with bitwise operators. This here is code from my micro controller project, which can handle 8 buttons with just one calculation."

Now if this was at a low hardware level like a micro controller (which I have done and certainly appreciate) then this sort of detail and expended effort would be crucial. While impressive skill is on display here, doing this won't exactly get me any meaningful performance boost in a typical DBP game.



An Example.
I'll provide an alternative method, but I'll also mention some overall organizational structure at the same time. You could squeeze Autonomous inputs into this example, but like I said it's really not too necessary for most purposes.



Now that's a lot more code then just one or two lines but there are some advantages. You can easily change and swap the buttons, especially if you make a menu in your game for remapping the controls. You can add mouse support by mapping mouse buttons as negative numbers. Gamepad and axis' can be supported similarly by adding a "controller mode" variable and using float variables instead of integer for states.

When you do it this way, the entire program can access player input and it's easy to read. The framework and button scheme are consistent across the entire program.


Button States.
The button states are arranged better...

1 and 2 are Pressed and Held so you can do things like

If Button_Jump() > 0 Then ... `If you want action when the button is held.
If Button_Jump() = 1 `If You want just single action press

The Released state is -1 which is more convenient since you can group it better with 0.

If Button_Jump() < 1 `Button is not being pressed or was just released.


Wrapping Up.
I mostly use a Gamepad but I felt most people don't do this and that adding it into the example would just complicate things. I also wanted to give some practical suggestions. If you were really designing a game for other people to use, they will want to remap the controls.

Just to summarize, I feel that while Autonomous Inputs are interesting, but they really don't help in the long run for the type of programming that this is. It's better to design a flexible but efficient system than to try to squeeze logical operators all onto a single line or space.

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 17th Aug 2013 20:17
Quote: "Using more than one variable isn't all that big of a concern where inputs are involved. Memory and CPU resources vastly out supply the needs here. Your example is a bit crude, but completely valid."

I was thinking more from the coder/reader's standpoint, having a single variable makes it easier to write and follow.

Quote: "
The button states are arranged better...
If Button_Jump() > 0 Then ... `If you want action when the button is held.
If Button_Jump() = 1 `If You want just single action press
The Released state is -1 which is more convenient since you can group it better with 0.
If Button_Jump() < 1 `Button is not being pressed or was just released."

You are not thinking in binary:

If Button_Jump() && 1 Then ... `If you want action when the button is held.
If Button_Jump() = 1 `If You want just single action press
If Button_Jump() ~~ 1 `Button is not being pressed or was just released.





The gluteus-maximus mammary-gland formally known as OBese87.
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 18th Aug 2013 11:51
Quote: "I was thinking more from the coder/reader's standpoint, having a single variable makes it easier to write and follow."

This is true from a limited perspective. The virtue of using less lines. What is also true is that condensing too much onto one line creates a rather difficult to read logic. Properly organizing things keeps the code very readable even if more than one variable is used. Using ~~ && || in place of more common operators and sometimes multiple times on the same line can hardly be considered more readable.


Quote: "You are not thinking in binary:"

Quite right. That's because the input is not binary, it has 4 states. I'm also thinking ahead to using analog input for a game pad and using float values. There's no real need to bit shift or combine bits into a single string of bits here for a typical DBP app.


You're not wrong. I just feel that there is a better way to organize things in this particular programming setting. All things considered.

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 18th Aug 2013 22:46 Edited at: 18th Aug 2013 22:48
Quote: "Using ~~ && || in place of more common operators and sometimes multiple times on the same line can hardly be considered more readable."

That's true, but the procedure is totally self-contained, so all the gobbledygook can be thrown into a function and hidden from the reader. In order to use the procedure, the reader only needs to understand its output.

Quote: "That's because the input is not binary, it has 4 states"

Those four states can be expressed in bits, and the code I posted should handle those states the same way as your code:

If Button_Jump() && 1 Then ... `If you want action when the button is held.
If Button_Jump() = 1 `If You want just single action press
If Button_Jump() ~~ 1 `Button is not being pressed or was just released.

Quote: "There's no real need to bit shift or combine bits into a single string for a typical DBP app."

There is no need for it, we have been getting the same functionality for years without using autonomous assignment, but I think it's a convenient solution for most applications.

Quote: "I'm also thinking ahead to using analogue input for a game pad and using float values."

I don't use gamepads, so I can't comment on that.
If my ideas do not suit your project then I would be interested to see what you come up with if you are creating a similar method for your specific needs.



The gluteus-maximus mammary-gland formally known as OBese87.
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 19th Aug 2013 13:31 Edited at: 19th Aug 2013 13:36
Quote: "That's true, but the procedure is totally self-contained, so all the gobbledygook can be thrown into a function and hidden from the reader. In order to use the procedure, the reader only needs to understand its output."

That's something that I can and did appreciate.


Quote: " Those four states can be expressed in bits, and the code I posted should handle those states the same way as your code:"

I understood this when I made my comments. I merely meant the fact that instead of on/off there is also press/release as well. A 2bit system can represent this. It is a deterministic system.


Quote: "There is no need for it, we have been getting the same functionality for years without using autonomous assignment, but I think it's a convenient solution for most applications."

As clever as it is, I don't see it solving any significant problem. A few extra lines, and I've got a system that does the same thing, supports remapping, and scales to accommodate multiple controllers and analog input.
You're not wrong, I just don't see this as being the best general purpose approach.


Quote: "I don't use gamepads, so I can't comment on that.
If my ideas do not suit your project then I would be interested to see what you come up with if you are creating a similar method for your specific needs."

Using analog input is a common feature in PC games. FPS and Racing Sims for example. There's nothing obscure or trivial about what I suggested.


I don't see light weight games like solitaire being typical. They're games in their own right, but there's a difference between those and mainstream modern games like MMO's / FPS / Race Sim / RTS games. My point is if you are going to take the time to make an actual proper game, it's better to make an efficient but flexible control system. Using less lines is great, but that's not the real problem.

The real problem is remapping, supporting multiple devices, analog, force feedback. Gamers have expectations. It's best to approach this issue in a flexible way where you can address these larger hurdles.

You're not wrong.

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 21st Oct 2013 20:10
Could a mod please change the title of this thread to "Using Autonomous Variables to Manage Input"
Thank you


Formerly OBese87.

Login to post a reply

Server time is: 2024-04-26 04:28:15
Your offset time is: 2024-04-26 04:28:15