Jump to content
IGNORED

Efficient control handling with Intybasic


Vincehood

Recommended Posts

Hello,

I have been looking in other threads and in the SDK examples (like the controller one) and I am still not fully sure about the best way to handle keypad buttons.

I am trying to achieve the following:

1) the MOB moves based on disc direction

2) something happens when a key (1 to 9) on keypad is pressed (both when direction / no direction is pressed on disc)

 

For 1), I am using CONT1.UP, CONT1.DOWN testing and it is working fine.

For 2) I am using the result of the cont command which I compare to KEYPAD_1, KEYPAD_2, ...

 

I realized recently that the values KEYPAD_1 to KEYPAD_9 are the values returned when no direction is pressed on disc.This means my code was not testing the situation where the both a key and the disc are pressed.

 

As an example, the following values are returned by cont when key 5 is pressed: 66 (disc not pressed, defined as KEYPAD_5 in constants.bas), 74 (E), 64 (W), 70 (N), 67 (S), NW (94)...

I noticed also that CONT1.KEY remains constantly equal to 12.

 

So what is the best way to handle that?

- Should I persist in using cont and handle the different key values I have observed in my tests like this:

keypad=cont

IF keypad=KEYPAD_5 or keypad=74 or keypad=64 or keypad=70 or keypad=67 or keypad=94 ... THEN

END IF

 

IF keypad=KEYPAD_1 or keypad=xx or keypad=xx or keypad=xx or keypad=xx or keypad=xx ... THEN

END IF

....

 

- is there any good reason for using both CONT1.x and cont? should I handle the MOV move with cont instead (assuming I need to use it anyway for the keys)

- I am also wondering what is the default control mapping of the SDK to a computer keyboard? Are both controller 1 & 2 mapped? Is it documented somewhere?

 

Thanks for your help

/Vincent

 

 

 

Link to comment
Share on other sites

Unfortunately, there is no way to accurately detect keypad and disc at the same time.

 

The Intellivision hand-controller was designed with two use-cases in mind: either "keyboard entry" (keypad only), or "run and shoot" (disc and action buttons).

 

If you think about it, the controller hardware interface provides only 8-bits of data, yet there are 32 different states (12 keys, 3 buttons, 16 disc directions, and idle). This was accomplished through a clever application of grey codes to accurately tell each input apart from the others. Consequently, most control input signals overlap across input types, meaning that disc input may look exactly like keypad input, but with an extra bit.

 

The accuracy problem is exacerbated by the flaky and noisy analog signal and cheap plastic buttons.

 

Clever use of heuristics and a state machine can help to condition the signal for better accuracy, but they still won't solve the issue of keypad signals overlapping disc signals.

 

In my opinion, game mechanics are more accurate and pleasant to use when programmers embrace this design intent of the Intellivision hand-controller: use keypad for key input and use disc and action buttons for movement and actions; and keep the two separated.

 

In my own P-Machinery framework, I use a state machine with simple heuristics to treat the input as either "keypad" or "disc+action" modes, and ignore invalid signals within the context of the active mode. The mode switches when a valid signal is received following a full and sustained release of the hand-controller input. Note that this is separate from "debouncing" and signal conditioning.

 

dZ.

Link to comment
Share on other sites

Thanks DZ-Jay for the great explanation.

I definitely want to embrace the design intent of the Intellivision controllers.

I might have been mistaken by wrong memories of the Tron Deadly Dics game. I thought you could throw the disc while running (controller disc pressed) and pressing the keytab.

I can no longer verify that myself on real hardware but a quick look at the few Youtube videos around confirms clearly what you say above.

So I am just fine with that!

Thanks

Link to comment
Share on other sites

Hello again,

 

I am just wondering about the last part of my question:

" what is the default control mapping of the SDK to a computer keyboard? Are both controller 1 & 2 mapped? Is it documented somewhere?"

Since I am currently only testing on a PC, I need to make sure that what I observe is correct.

Is the Inty Basic SDK relying on some defaults jzintv emulator settings? Which ones?

Thanks

/Vincent

Link to comment
Share on other sites

I kind of found the answer myself in the jzintv documentation (see further down).

However I am still a bit puzzled.

 

What if I want to differentiate controller 1 keypad and controller 2 keypad in IntyBasic? Aren't the KEYPAD_x constants differentiating them then?

Also I do not have a numeric keypad on my laptop. Does it means I need to reconfigure jzintv if I should test both controller keypads?

Thanks

/V

 

Numeric Keypad, maps 0 and 1
1-9 Left controller 1 - 9
0 Left controller Clear
. Left controller 0
Enter Left controller Enter

Main Keyboard, map 0. (Map 1 just moves right controller mappings to left.)
0-9 Right controller 0 - 9
- Right controller Clear
= Right controller Enter
Left Shift Right controller top action buttons
Left Alt Right controller lower left action button
Left Control Right controller lower right action button

Right Shift Left controller top action buttons
Right Alt Left controller lower left action button
Right Control Left controller lower right action button

Up Arrow Left controller disc up
Down Arrow Left controller disc down
Left Arrow Left controller disc left
Right Arrow Left controller disc right

Link to comment
Share on other sites

Just to clarify your understanding, the constants KEYPAD_X represent the value of the controller signal for each input. That is, when the key "1" is pressed on the keypad, the variable CONT will contain the value represented by the constant "KEYPAD_1". This is why, like GroovyBee said, the constant applies for either controller.

 

Also like GroovyBee said, IntyBASIC provides access to both hand-controllers individually via the variables CONT1 (controller 1, or left) and CONT2 (controller 2, or right). CONT (with no number) is an amalgamation of both controller input signals, allowing a player to choose which controller they wish to use. This is very useful for single-player games where a single controller is employed, but the game remains indifferent to which one the player uses.

 

dZ.

Link to comment
Share on other sites

OK thanks to you three.

 

Here is what I observe with my keyboard:

- cont captures key strokes corresponding to KEYPAD_XXX on number 0 to 9 (I was expecting this)

- cont1 does not capture key strokes corresponding to KEYPAD_XXX on number 0 to 9 (I was not expecting this)

- cont2 captures key strokes corresponding to KEYPAD_XXX

- key strokes on number 0 to 9 are influencing the values of CONT2.x (I was not expecting this)

 

As a result, in the code I am writing, when I press the keys 0-9, it impacts two different sprites which is not what I want (I don't want player 2 to move when player 1 is performing an action with the keypad!).

This makes me wondering:

- do I need to change the keymap in jzintv? I need one suitable for a 2 player game (see keymap list further down). Is the default one the right one then?

- do I need to change something in my keyboard configuration (like enabling a keypad as suggested by carlsson and once I have figure how!)

 

/Vincent

Edited by Vincehood
Link to comment
Share on other sites

As far as I know, the default keymap in jzIntv is fine for 2 players. Controller 1 is mapped to the left side of the Keyboard (ASDF, etc. and the number row on top), and Controller 2 is mapped to the left side of the keyboard (JKL;, etc. and the numerical keypad).

 

You can obviously change this yourself. For more information on how to remap the controllers, see the jzIntv documentation included with the SDK.

 

As for having having individual control over each hand-controller, then avoid CONT completely and only use CONT1 and CONT2.

 

dZ.

Link to comment
Share on other sites

By the way, in case it was not clear from my comment above, the reason you shouldn't use CONT for your purposes is that,

CONT = CONT1 XOR CONT2

 

It actually means: "merge both hand-controller signals so that we treat the input of either one as a single controller." Obviously, this only works if the player uses one or the other. If he tries to press the keypad of both controllers simultaneously, the value of CONT is not reliable.

 

As I said before, CONT is only useful for single-player games where the program doesn't care which controller the player is using, as long as he picks only one of them. This is a very common use case, and in fact the way that a lot of old games worked.

 

dZ.

  • Like 1
Link to comment
Share on other sites

Hello,

yes I do not use CONT any longer.

 

My laptop is an old Clevo M767TU with a Swedish keyboard (see layout in attached picture)

Fn + NumLK activates some keypad support:

M:0

J:1

K:2

L:3

U:4

I:5

O:6

7:7

8:8

9:9

 

I enabled the keypad but it does not seem to help much :( The regular numbers are still influencing both CONT1.XXX and cont2 evaluation.

/Vincent

post-50379-0-22011800-1485271156_thumb.jpg

Link to comment
Share on other sites

OK,

things look better now that I have connected an external USB keyboard with a numeric keypad.

The numeric keypad is mapped on cont1 and the arrows on CONT1.xxxxx

 

I still observe however that the main keyboard 0-9 keys are mapped onto CONT2.xxxx. Isn't it strange?

In other words, a sprite (which is associated to CONT2 values) is moving when pressing 0-9 on the main keyboard which is not according to the jzintv documentation. E, D,S and X keys are also working for movement but this according to the jzintv doc.

 

/V

Edited by Vincehood
Link to comment
Share on other sites

I guess it is actually the reverse of what I said: controller 1 (left) is mapped to the right side of the keyboard, while controller 2 (right) is mapped to the left side.

 

This would make sense since the most common control surfaces are the numerical keypad and the arrow keys, so they are mapped by default to controller 1.

 

Sorry for the confusion.

Link to comment
Share on other sites

If you don't want your player to move while pressing keypad, you should add this code in your IntyBASIC programs.

 

x = CONT AND $E0

IF (x=$80)+(x=$40)+(x=$20) THEN

' Ignore as this is a keypad pressing.

ELSE

' Continue processing disc and side buttons.

END IF

 

Also if you use CONT.KEY, CONT1.KEY or CONT2.KEY you should follow the IntyBASIC manual, these return the current number pressed (0-9), 10 and 11 for special keys and 12 for not pressed.

 

The constants included in constants.bas are for decoding by yourself the keypad.

Link to comment
Share on other sites

Hello

 

OK, I am now using only CONT1.KEY and CONT2.KEY and compare the results with values 0-12.

It works fine for the sprite controlled with CONT1.KEY but I have still have the same issue reported earlier.

I have not yet integrated your code above.

Do you mean that this code would avoid that pressing the left keypad affects the right controller?

/Vincent

Link to comment
Share on other sites

Hello,

I think it is best that I share my code so you can have a look if you wish to. I would really appreciate expert advices.

This is an attempt for a 2 players Tron alike game with discs bouncing on walls.

Given the problems I experienced, I duplicated some procedure per player but it did not make any difference (the code was shorter initially).

The issues I experience are the following ones:

1) for player 1, pressing numeric keypad triggers both move and throwing disc* (it should only trigger the latter)

2) for player 2. pressing numbers on main keyboard triggers both move and throwing disc* (it should only trigger the latter)

3) player 2 keypad based control for throwing disc is not working at all and I am not sure if I miss something obvious or if I did something really wrong for handling controls in a 2 player game

 

Thanks

 

 

Tron3.bas

Link to comment
Share on other sites

Hello

 

OK, I am now using only CONT1.KEY and CONT2.KEY and compare the results with values 0-12.

It works fine for the sprite controlled with CONT1.KEY but I have still have the same issue reported earlier.

I have not yet integrated your code above.

Do you mean that this code would avoid that pressing the left keypad affects the right controller?

/Vincent

 

I think I have added some confusion here because I wasn't very familiar with the way IntyBASIC handles the controllers. I apologize for this.

 

The CONT1 and CONT2 variables return the raw hand-controller input signal. These are a series of bits that must be decoded in order to know which actual signal was returned. As nanochess said, the constants in "Constant.bas" are intended to represent the raw codes for each individual input. If you plan on using these variables and constants, then your program will have to do the decoding itself. This means knowing not only testing for the input you want, but making sure it does not overlap another signal. This is the example that nanochess provided.

 

The same applies to the CONT variable, since it is just "CONT1 AND CONT2" to merge both signals.

 

IntyBASIC provides some facilities to decode the hand-controller signal for you, but this requires additional CPU processing. This is not a big deal, since it is presumably work that your program would have to do anyway. In order to take advantage of this, you can use the following variables:

  ' Both controllers merged
  CONT.UP           Non-zero if any controller pointing up
  CONT.DOWN         Non-zero if any controller pointing down
  CONT.LEFT         Non-zero if any controller pointing left
  CONT.RIGHT        Non-zero if any controller pointing right
  CONT.BUTTON       Non-zero if any controller button pressed.
  CONT.B0           Non-zero if any controller top buttons pressed (left/right)
  CONT.B1           Non-zero if any controller bottom left button pressed.
  CONT.B2           Non-zero if any controller bottom right button pressed.
  CONT.KEY          Current pressed key (0-9 for numbers, 10-Clear, 11-Enter, 12-Not pressed)

  ' Controller 1 (left)
  CONT1.UP          Non-zero if controller pointing up
  CONT1.DOWN        Non-zero if controller pointing down
  CONT1.LEFT        Non-zero if controller pointing left
  CONT1.RIGHT       Non-zero if controller pointing right
  CONT1.BUTTON      Non-zero if controller button pressed.
  CONT1.B0          Non-zero if any of top controller buttons pressed (left/right)
  CONT1.B1          Non-zero if bottom left button pressed
  CONT1.B2          Non-zero if bottom right button pressed
  CONT1.KEY         Current pressed key (0-9 for numbers, 10-Clear, 11-Enter, 12-Not pressed)

  ' Controller 2 (right)
  CONT2.UP          Non-zero if controller pointing up
  CONT2.DOWN        Non-zero if controller pointing down
  CONT2.LEFT        Non-zero if controller pointing left
  CONT2.RIGHT       Non-zero if controller pointing right
  CONT2.BUTTON      Non-zero if controller button pressed.
  CONT2.B0          Non-zero if any of top controller buttons pressed (left/right)
  CONT2.B1          Non-zero if bottom left button pressed
  CONT2.B2          Non-zero if bottom right button pressed
  CONT2.KEY         Current pressed key (0-9 for numbers, 10-Clear, 11-Enter, 12-Not pressed)

Does this make sense?

 

-dZ.

Link to comment
Share on other sites

First I made a solution using the bit patterns as described in constants.bas and by DZ-Jay below. Then I reread Nanochess' post and realized he had a better solution, so I changed my code to what he suggested. It means the following changes:

 

* In CheckControllers, I store the value of CONT1 AND $E0 into a temporary variable and in case that is zero, it means the disc is pressed.

 

* In DisplayDiscs, you simply had a typo which referenced Dy(0) instead of Dy(Disc).

 

Tron3.bas

Edited by carlsson
  • Like 1
Link to comment
Share on other sites

Here's the low-down on the hand-controller signals:

KeyPad:
------- ------- --------
Input   Code    Signal
------- ------- --------
1       0x81    10000001
2       0x41    01000001
3       0x21    00100001
4       0x82    10000010
5       0x42    01000010
6       0x22    00100010
7       0x84    10000100
8       0x44    01000100
9       0x24    00100100
Clear   0x88    10001000
0       0x48    01001000
Enter   0x28    00101000
------- ------- --------

Action:
------- ------- --------
Input   Code    Signal
------- ------- --------
0       0xA0    10100000
1       0x60    01100000
2       0xC0    11000000
------- ------- --------

Disc:
------- ------- --------
Input   Code    Signal
------- ------- --------
0       0x04    00000100
1       0x14    00010100
2       0x16    00010110
3       0x06    00000110
4       0x02    00000010
5       0x12    00010010
6       0x13    00010011
7       0x03    00000011
8       0x01    00000001
9       0x11    00010001
10      0x19    00011001
11      0x09    00001001
12      0x08    00001000
13      0x18    00011000
14      0x1C    00011100
15      0x0C    00001100
------- ------- --------


; SORTED BIT PATTERN
00000001    DISC-8      0x01
00000010    DISC-4      0x02
00000011    DISC-7      0x03
00000100    DISC-0      0x04
00000110    DISC-3      0x06
00001000    DISC-12     0x08
00001001    DISC-11     0x09
00001100    DISC-15     0x0C
00010001    DISC-9      0x11
00010010    DISC-5      0x12
00010011    DISC-6      0x13
00010100    DISC-1      0x14
00010110    DISC-2      0x16
00011000    DISC-13     0x18
00011001    DISC-10     0x19
00011100    DISC-14     0x1C

00100001    KEY-3       0x21
00100010    KEY-6       0x22
00100100    KEY-9       0x24
00101000    KEY-Enter   0x28
01000001    KEY-2       0x41
01000010    KEY-5       0x42
01000100    KEY-8       0x44
01001000    KEY-0       0x48
10000001    KEY-1       0x81
10000010    KEY-4       0x82
10000100    KEY-7       0x84
10001000    KEY-Clear   0x88

01100000    BTN-1       0x60
10100000    BTN-0       0xA0
11000000    BTN-2       0xC0

And here is a diagram showing the disc bits matrix:

post-27318-0-18201300-1485299224_thumb.png

 

The core heuristics I use to decode are:

  • If it matches exactly one of the keypad entries, it's a keypad key. Done.
  • If it doesn't match a keypad entry exactly:
    • Test the low-order 5 bits to see if we have a valid disc entry.
    • Test the high-order 3 bits to see if we have an action button entry.
    • If we have a valid disc entry, test bit 4 to see if we have a disc perfect diagonal.
  • If no match found, it's glitchy noise, ignore.

 

By the way, that's only when I want to use the entire hand-controller. If I only want to read the disc, I look for exact matches of the first 5 bits against the disc codes, and ignore the rest.

Link to comment
Share on other sites

Hello again,

another question on the same theme.

 

I am trying to change my code so keys 1-9 (except 5) can be used for 2 purposes: throwing the disc and getting back the disc.

I have however noticed that a single key press seems to be interpreted as several ones by the code which results in unwanted behavior.

What would the best practice to avoid this issue?

 

Thanks

/Vincent

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...