joystick input demo
I know Clive desperately wanted the Speccy to be regarded as a "serious" business computer but as we all know, they were mainly used for games and thus I suspect many people will also be wanting to use NextBuild to write games above other forms of software. This is why I find it very odd that NextBuild somehow doesn't include any examples of how to process joystick input - not that I can see?
I presume its done in the same way as Boriel BASIC? I found this small example but it doesn't work for me under NextBuild. My USB gamepad works fine with CSpect otherwise. See the second post here for Boriel's joystick input example:
https://www.boriel.com/forum/showthread.php?tid=784
The code given for joystick input:
10 LET x=10: LET y=10
20 LET kj=IN 31: REM get the state of joystick
30 PRINT AT y,x;"*"
40 IF (kj>31) OR (kj=0) THEN GO TO 20: END IF: REM ignore spurious inputs
If I build run that code under Nextbuild, it just prints a * character and it the crashes as soon as I touch my gamepad.
It would be great if NextBuild included a demo that shows how to read input from the joystick to move a sprite around the screen. It could just be a modified version of Sources/MiniExamples/mini2.bas that uses a joystick instead of or in addition to the keyboard.
Ideally, this demo would show how the user can control a sprite with the joystick (if present) or the keyboard if Nextbuild supports this and its easy to implement. Otherwise, maybe it would be best to have the user choose the input method when the demo is run? Extra points if it shows how to read all 4 buttons on a Mega Drive controller too, or 6 buttons if that is supported.
Dim X as ubyte forever: X =IN(31) IF X<>0 THEN PRINT X Goto forever
Thanks Leslie! That works fine.
I will see if I can weave this into min2.bas but I suppose we could also include those 5 lines in your previous comment as a bare bones joystick input example.
I've not tried writing any NextBASIC yet so it'd be quicker and better if someone else creates this demo but I should be able to do it without too much trouble, I hope but I've got a busy month ahead of me.
CSpect is printing values for 4 buttons (A,B,C and START I presume) and the 4 directions using my USB pad.
I have modified mini2.bas to add joystick support.
Maybe we could add this to the repo as mini2-joystick.bas or mini-joystick.bas?
I thought I'd share it here first before I create a PR to add it just in case there is some obvious way to improve it I should know about but it works for me.
#include <nextlib.bas>
#include <keys.bas>
paper 7: border 6 : bright 0: ink 0 : cls
dim x as integer
dim y as integer
dim joy as ubyte
NextReg($7,$1)
NextReg($15,%00000001)
ShowLayer2(1)
'We load 1 sprite image from @Sprites, where they are defined.
InitSprites(1,@Sprites)
x=152
y=128
vel=3
do
WaitRetrace(1)
joy =IN(31)
if MultiKeys(KEYQ) or joy=8
y=y-vel
else
if MultiKeys(KEYA) or joy=4
y=y+vel
end if
end if
if MultiKeys(KEYO) or joy=2
x=x-vel
else
if MultiKeys(KEYP) or joy=1
x=x+vel
end if
end if
'The user can move the sprite diagonally with only up, down , left and right keys defined
'but that doesn't also work for joystick input. The ZX Next uses 8 direction joysticks and so you
'have to scan for the diagonal inputs when required.
'Joystick is moved down and right'
if joy=5
x=x+vel
y=y+vel
end if
'Joystick is moved down and left'
if joy=6
x=x-vel
y=y+vel
end if
'Joystick is moved up and right'
if joy=9
x=x+vel
y=y-vel
end if
'Joystick is moved up and left'
if joy=10
x=x-vel
y=y-vel
end if
UpdateSprite(x,y,0,0,0,0)
loop
end
Sprites:
ASM
; lateral
Sprite1:
db $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $E3, $00, $E3, $E3, $E3, $E3, $E3, $E3, $00, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $00, $18, $00, $E3, $E3, $E3, $E3, $00, $E0, $00, $E3, $E3, $E3;
db $E3, $E3, $E3, $E3, $00, $18, $00, $00, $00, $00, $E0, $00, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $00, $18, $18, $18, $18, $E0, $E0, $E0, $E0, $00, $E3, $E3, $E3;
db $E3, $E3, $00, $18, $18, $18, $18, $18, $E0, $E0, $E0, $E0, $E0, $00, $E3, $E3;
db $E3, $00, $18, $18, $18, $FC, $18, $18, $E0, $E0, $FC, $E0, $E0, $E0, $00, $E3;
db $E3, $00, $18, $00, $18, $18, $18, $18, $E0, $E0, $E0, $E0, $00, $E0, $00, $E3;
db $E3, $00, $18, $00, $18, $18, $18, $18, $E0, $E0, $E0, $E0, $00, $E0, $00, $E3;
db $E3, $00, $18, $00, $18, $00, $00, $00, $00, $00, $00, $E0, $00, $E0, $00, $E3;
db $E3, $E3, $00, $E3, $00, $18, $18, $00, $00, $E0, $E0, $00, $E3, $00, $E3, $E3;
db $E3, $E3, $E3, $E3, $E3, $00, $00, $E3, $E3, $00, $00, $E3, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3;
db $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3, $E3;
end asm
I'm pretty happy with this for a basic joystick demo as is but it doesn't demonstrate or test the fire buttons.
Maybe we could extend this to print "Button A pushed", "Button B pushed" or add a few extra sprites to display the status of the fire buttons?
I want to keep it short, simple and easy to read.
I've added more comments to the joystick demo above.
mini2.bas updated
I plan to update this soon to demonstrate pushing the buttons (A,B, C & START) too and using a second joystick by having a second sprite on screen controlled by joystick #2.
What IN() value is used for joystick #2? IN(32)?
My questions about reading joysticks got answered on the ZXN FB group today. I'm making a note of them here:
[Robin Verhagen-Guest]programming keypresses (which is a good idea) aside, nextreg 178 is how you read the extra buttons that don't fit in IN 31/IN 55 directly.
0X82 (178) (R) => Extended MD Pad Buttons
bit 7 = 1 if Right Pad X is pressed
bit 6 = 1 if Right Pad Z is pressed
bit 5 = 1 if Right Pad Y is pressed
bit 4 = 1 if Right Pad MODE is pressed
bit 3 = 1 if Left Pad X is pressed
bit 2 = 1 if Left Pad Z is pressed
bit 1 = 1 if Left Pad Y is pressed
bit 0 = 1 if Left Pad MODE is pressed
Assuming left is already mapped to MD1 and right to MD2 (which they are in NextBASIC by default), you can do this to test:
10 PRINT AT 0,0; IN 31; " "
20 PRINT IN 55; " "
30 PRINT REG 178; " "
40 GO TO 10
[Simon N Goodwin] put e.g. STR$(IN 55,2) to see the bits 🤓
I don't have a copy of the second revision of the ZX Spectrum Next manual, but I do have a pdf of the first edition and the above info is documented, without example BASIC commands, by the ZX Spectrum Next Hardware Ports List in "Chapter 23 - IN, OUT and the Next registers" on p274.
Dim X as ubyte forever: X =IN(31) IF X<>0 THEN PRINT X Goto forever
Hi @ljg701 and @em00k
I want to modify this so that it also shows when the X, Y or Z buttons are pushed so how do we do that?
It seems Boriel and NextBuild don't have a REG keyword, as recommended by Robin for doing this with NextBASIC. Should we use NextReg instead?
hi, you can read register values with GetReg() function.
#include "nextlib.bas"
MainInit()
' Main loop
do
' Wait for raster line 192
WaitRetrace2(192)
UpdateJoystick()
WaitKey()
loop
'----------------------------------------------------------
' Subroutines go here
sub UpdateJoystick()
dim i as ubyte = GetReg($B2)
dim text$ as string
if i band 128 then text$ = "bit 7 = 1 if Right Pad X pressed"
if i band 64 then text$ = "bit 6 = 1 if Right Pad Z pressed"
if i band 32 then text$ = "bit 5 = 1 if Right Pad Y pressed"
if i band 16 then text$ = "bit 4 = 1 if Right Pad MODE pressed"
if i band 8 then text$ = "bit 3 = 1 if Left Pad X pressed"
if i band 4 then text$ = "bit 2 = 1 if Left Pad Z pressed"
if i band 2 then text$ = "bit 1 = 1 if Left Pad Y pressed"
if i band 1 then text$ = "bit 0 = 1 if Left Pad MODE pressed"
print at 2,0; text$
end sub
sub MainInit()
' set border, paper, ink
border 1 : paper 1 : ink 6 : cls
' print text
print "Welcome to InputTest!"
end sub
Thanks David!
Is the above demo in the NextBuild repo now?
No probs - no I haven't added this as I thought you wanted to do it.
Yes I wanted to add another joystick demo of some sort that monitors all the buttons and of either controller, or both.
I think I might just extend @ljg701 's example a little bit so that it prints the button registers and lets you choose which joystick you want to monitor at the start. It's either that or write a full controller tester program but I prefer demo programs to be minimal and easy to read so I think I prefer the first idea.
Just FYI I do have a simple joystick example in the docs for NBS, maybe we can combine?
Input
There are vairous ways to handle input in NextBuild.
Keyboard
Example
#include <keys.bas>
dim i as ubyte
do
' detect keybaord P
if GetKeyScanCode()=KEYP
print ink 7;at 0,0;"p is pressed"
i = 7
end if
if i > 0
i = i - 1
print at 0,0; over 1; ink i;" "
endif
WaitRaster(192)
loop
To detect multiple keys you will use MultiKeys :
do
' detect keybaord P
if MultiKeys(KEYP) & Multikeys(KEYSPACE)
print ink 7;at 0,0;"keys are pressed"
i = 7
end if
if i > 0
i = i - 1
print at 0,0; over 1; ink i;" "
endif
WaitRaster(192)
loop
The codes for each key are defined in the keys.bas file.
KEYA-KEYZ KEY0-KEY9 KEYSPACE KEYENTER KEYSYMBOL KEYCAPS
Joystick
dim j as ubyte
dim i as ubyte
do
' port 31 if kempston 1, 51 kempston 2
j = in 31 ' Kempston 1
' up and down
if j band BIT_UP
print at 0,0; "up"
elseif j band BIT_DOWN
print at 0,0; "down"
endif
' left and right
if j band BIT_LEFT
print at 0,0; "left"
elseif j band BIT_RIGHT
print at 0,0; "right"
endif
' fade the ink
if i > 0
i = i - 1
print at 0,0; over 1; ink i;" "
endif
WaitRaster(192)
loop
The joystick bit is bitmapped as follows :
| Bit | Kempston joystick | MD controller |
|---|---|---|
| 7 | 0 | start button |
| 6 | 0 | A button |
| 5 | Fire 2 | C button |
| 4 | Fire 1 | B button |
| 3 | up | up |
| 2 | down | down |
| 1 | left | left |
| 0 | right | right |
For all bits: 0 = not pressed / 1 = pressed
Links
- keys.bas
hi, you can read register values with GetReg() function.
#include "nextlib.bas" MainInit() ' Main loop do ' Wait for raster line 192 WaitRetrace2(192) UpdateJoystick() WaitKey() loop '---------------------------------------------------------- ' Subroutines go here sub UpdateJoystick() dim i as ubyte = GetReg($B2) dim text$ as string if i band 128 then text$ = "bit 7 = 1 if Right Pad X pressed" if i band 64 then text$ = "bit 6 = 1 if Right Pad Z pressed" if i band 32 then text$ = "bit 5 = 1 if Right Pad Y pressed" if i band 16 then text$ = "bit 4 = 1 if Right Pad MODE pressed" if i band 8 then text$ = "bit 3 = 1 if Left Pad X pressed" if i band 4 then text$ = "bit 2 = 1 if Left Pad Z pressed" if i band 2 then text$ = "bit 1 = 1 if Left Pad Y pressed" if i band 1 then text$ = "bit 0 = 1 if Left Pad MODE pressed" print at 2,0; text$ end sub sub MainInit() ' set border, paper, ink border 1 : paper 1 : ink 6 : cls ' print text print "Welcome to InputTest!" end sub
This builds fine but the program freezes as soon as I push the MODE button, when I run it on my XBerry Pi.
The X, Y and Z buttons all work fine and print the correct message.
I may never actually use the MODE button in any of my games but I'd like to know it can be used if required.
Joystick
dim j as ubyte dim i as ubyte do ' port 31 if kempston 1, 51 kempston 2 j = in 31 ' Kempston 1 ' up and down if j band BIT_UP print at 0,0; "up" elseif j band BIT_DOWN print at 0,0; "down" endif ' left and right if j band BIT_LEFT print at 0,0; "left" elseif j band BIT_RIGHT print at 0,0; "right" endif ' fade the ink if i > 0 i = i - 1 print at 0,0; over 1; ink i;" " endif WaitRaster(192) loopThe joystick bit is bitmapped as follows : Bit Kempston joystick MD controller 7 0 start button 6 0 A button 5 Fire 2 C button 4 Fire 1 B button 3 up up 2 down down 1 left left 0 right right
For all bits: 0 = not pressed / 1 = pressed
Links
* [keys.bas](keys.bas)
I've found few issues with this. First off, it doesn't build because its missing the nextlib.bas include statement and also I had to replace WaitRaster(192) with WaitRetrace2(192) which I'm guessing are mostly equivalent functions? Doing so fixed the build and got it to run at least.
#include "nextlib.bas"
dim j as ubyte
dim i as ubyte
do
' port 31 if kempston 1, 51 kempston 2
j = in 31 ' Kempston 1
' up and down
if j band BIT_UP
print at 0,0; "up"
elseif j band BIT_DOWN
print at 0,0; "down"
endif
' left and right
if j band BIT_LEFT
print at 0,0; "left"
elseif j band BIT_RIGHT
print at 0,0; "right"
endif
' fade the ink
if i > 0
i = i - 1
print at 0,0; over 1; ink i;" "
endif
WaitRetrace2(192)
loop
The other issue with this code is that it only works for left and right but not up and down. I had this issue under both CSpect and when I ran it on my XBerry Pi.
We should extend this joystick example to also demonstrate reading the X, Y and Z buttons, I think. That may rid of the need for the separate GetReg() example? I wouldn't really want to extend this code until I have UP and DOWN working first tho.
hi, you can read register values with GetReg() function.
#include "nextlib.bas" MainInit() ' Main loop do ' Wait for raster line 192 WaitRetrace2(192) UpdateJoystick() WaitKey() loop '---------------------------------------------------------- ' Subroutines go here sub UpdateJoystick() dim i as ubyte = GetReg($B2) dim text$ as string if i band 128 then text$ = "bit 7 = 1 if Right Pad X pressed" if i band 64 then text$ = "bit 6 = 1 if Right Pad Z pressed" if i band 32 then text$ = "bit 5 = 1 if Right Pad Y pressed" if i band 16 then text$ = "bit 4 = 1 if Right Pad MODE pressed" if i band 8 then text$ = "bit 3 = 1 if Left Pad X pressed" if i band 4 then text$ = "bit 2 = 1 if Left Pad Z pressed" if i band 2 then text$ = "bit 1 = 1 if Left Pad Y pressed" if i band 1 then text$ = "bit 0 = 1 if Left Pad MODE pressed" print at 2,0; text$ end sub sub MainInit() ' set border, paper, ink border 1 : paper 1 : ink 6 : cls ' print text print "Welcome to InputTest!" end sub
I updated NextBuild and tried this again and now its not freezing my XBP when I push the MODE button but I've not seen it print "bit 0 = 1 if Left Pad MODE pressed" ever either. X, Y and Z work fine.
I have tried 2 controllers and both did the same thing.
I posted this to the XBerry Pi FB group yesterday but its still awaiting approval.
The MODE button not working could be some hardware quirk of my model XBP?
Today I was chatting with Alan Tilley and I asked him to test if the X, Y and Z buttons work with the XBP joystick splitter. I sent him a test program and we got an unusual result.
Using the NextBuild GetReg test program linked below,, we have found:
XBP 4C = MODE button doesn't respond
XBP 4E = MODE button works
XBP 4G = MODE buttons doesn't respond
Hi @danboid
This seems to work for me, tested with an 8bitDo M30 2.4g - Make sure Joystick is set to MD1/2:
' Project: InputTest
' Generated by NextBuild Project Creator
'!exe=curl -X POST -F "data=@Sources/InputTest/InputTest.nex" http://192.168.4.1/upload
'!org=$8000
#include "nextlib.bas"
dim c as ubyte
MainInit()
' Main loop
do
WaitRetrace2(192)
UpdateJoystick()
' sanity counter
print at 10,0;c;" "
c = c + 1
loop
'----------------------------------------------------------
' Subroutines go here
sub UpdateJoystick()
dim i as ubyte = GetReg($b2)
dim text$ as string
if i band 128 then text$ = "bit 7 = 1 if Right Pad X pressed"
if i band 64 then text$ = "bit 6 = 1 if Right Pad Z pressed"
if i band 32 then text$ = "bit 5 = 1 if Right Pad Y pressed"
if i band 16 then text$ = "bit 4 = 1 if Right Pad MODE pressed"
if i band 8 then text$ = "bit 3 = 1 if Left Pad X pressed"
if i band 4 then text$ = "bit 2 = 1 if Left Pad Z pressed"
if i band 2 then text$ = "bit 1 = 1 if Left Pad Y pressed"
if i band 1 then text$ = "bit 0 = 1 if Left Pad MODE pressed"
if i = 0 then text$ = " "
print at 2,0; text$
end sub
sub MainInit()
' set up layer 2
InitLayer2(MODE256X192)
' set border, paper, ink
Border 1 : paper 2 : ink 6 : cls
' print text
print "Welcome to InputTest!"
end sub
No luck
* Executing task: python3 ./../Scripts/nextbuild.py /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
===============================================================================================
NextBuild v7.3 : David Saphier / em00k - 19-Mar-2021 https://github.com/em00k/NextBuild
ZX Basic Compiler : Jose Rodriguez aka Boriel https://zxbasic.readthedocs.io/
Cspect Emulator : Mike Dailly https://cspect.org
===============================================================================================
Input File : /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
Looking for ORG...
Found ORG : $8000
Working Dir : /home/dan/src/NextBuild/Sources/InputTest
Compiling : /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
ZXbasic ver : 1.17.1
/home/dan/src/NextBuild/Sources/InputTest/InputTest.bas:56: warning: [W100] Using default implicit type 'float' for 'MODE256X192'
/home/dan/src/NextBuild/Sources/InputTest/InputTest.bas:56: error: Undeclared function "InitLayer2"
* The terminal process "/usr/bin/bash '-c', 'python3 ./../Scripts/nextbuild.py /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas'" terminated with exit code: 255.
So I commented out the the line InitLayer2(MODE256X192) and tried building it again...
===============================================================================================
NextBuild v7.3 : David Saphier / em00k - 19-Mar-2021 https://github.com/em00k/NextBuild
ZX Basic Compiler : Jose Rodriguez aka Boriel https://zxbasic.readthedocs.io/
Cspect Emulator : Mike Dailly https://cspect.org
===============================================================================================
Input File : /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
Looking for ORG...
Found ORG : $8000
Working Dir : /home/dan/src/NextBuild/Sources/InputTest
Compiling : /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
ZXbasic ver : 1.17.1
YAY! Compiled OK!
====================================================
Generating Nexcreator Config ...
Traceback (most recent call last):
File "/home/dan/src/NextBuild/Sources/./../Scripts/nextbuild.py", line 509, in <module>
ParseNEXCfg()
File "/home/dan/src/NextBuild/Sources/./../Scripts/nextbuild.py", line 266, in ParseNEXCfg
sp = int(org) -2
^^^^^^^^
ValueError: invalid literal for int() with base 10: '$8000'
* The terminal process "/usr/bin/bash '-c', 'python3 ./../Scripts/nextbuild.py /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas'" terminated with exit code: 1.
Ahh, change the org address from $8000 to 32768 - you are still on the old NextBuild ;)
Am I using the wrong branch or repo? I thought I updated it in the last 2 weeks and the repo I'm looking at (this one) hasn't been updated for a few weeks?
Can I update NextBuild without deleting all of my vscode settings?
I can do that because NextBuild is the only thing I use vscode for but there must be a less destructive way to update NextBuild?
I know how to update the git repo of course but that won't update things like the vscode plugins and CSpect that get installed when you first open the Sources dir under vscode.
You currently have repos called NextBuild (this one), NextBuildStudio and nextbuild-studio. Which one is the official NB Studio repo? Can you not delete the other?
Seeing as the NextBuild update task doesn't work under Linux yet, I did what I've done previously to update NextBuild (quit vscode then delete the ~/.vscode and ~/.config/Code directories) then I re-installed NextBuild as per the instructions in its README but I'm still getting the same errors that I reported before when I try to build the above InputTest code:
===============================================================================================
NextBuild v7.3 : David Saphier / em00k - 19-Mar-2021 https://github.com/em00k/NextBuild
ZX Basic Compiler : Jose Rodriguez aka Boriel https://zxbasic.readthedocs.io/
Cspect Emulator : Mike Dailly https://cspect.org
===============================================================================================
Input File : /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
Looking for ORG...
Found ORG : $8000
Working Dir : /home/dan/src/NextBuild/Sources/InputTest
Compiling : /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas
ZXbasic ver : 1.17.1
/home/dan/src/NextBuild/Sources/InputTest/InputTest.bas:56: warning: [W100] Using default implicit type 'float' for 'MODE256X192'
/home/dan/src/NextBuild/Sources/InputTest/InputTest.bas:56: error: Undeclared function "InitLayer2"
* The terminal process "/usr/bin/bash '-c', 'python3 ./../Scripts/nextbuild.py /home/dan/src/NextBuild/Sources/InputTest/InputTest.bas'" terminated with exit code: 255.
I presume this code only works with NextBuildStudio? Do you want me to be a Linux beta tester?
Are you going to carry on maintaining NextBuild after NextBuildStudio is released?