TIC-80 icon indicating copy to clipboard operation
TIC-80 copied to clipboard

Keyboard text line input

Open sssilver opened this issue 3 years ago • 13 comments

I use the TIC-80 fantasy computer to teach my daughter basics of programming, and, given that it is supposed to be a computer, it would be fantastic if we could do something like:

print('What is your name?')
name = input()

It would make teaching basic concepts of programming easier and more natural. Also, computers are supposed to have full keyboards -- not just 6 gamepad buttons!

I understand I can accomplish this by importing third-party functions, however it would be a lot simpler/clearer if the input feature was part of the core API.

sssilver avatar Nov 04 '20 18:11 sssilver

Just so you know, TIC-80 supports a mouse and keyboard as inputs, alongside the four 8-button gamepads.

StinkerB06 avatar Nov 04 '20 19:11 StinkerB06

I kind of agree with @sssilver on this, but I can see how it's a big leap.

If TIC-80 were an Apple ][ or Commodore 64, you would have an immediate/direct mode where the interpreter would process the commands as you enter them. Seems to me that's at odds with the scanline/frame structure of TIC-80's design, not to mention the fact that TIC-80 works with multiple languages.

Not sure what @nesbox wants the system to be, long term, but if it had a BASIC-type mode that would be neat. And such an interface could then be amenable to PRINT and INPUT commands to create very basic text console programs to prototype pieces of a larger program.

SDMelipone avatar Nov 05 '20 01:11 SDMelipone

One user made an example of how to use text input in TIC https://tic80.com/play?cart=449. Looks a bit difficult, maybe we could add an input() API function in the future to simplify it.

nesbox avatar Nov 05 '20 14:11 nesbox

JS code from the cart above:

// title:  Input lib
// author: Tau
// script: js
/* WARNING! This variables
(keys,skeys,inf,counter and output)
are required
*/
const keys = " abcdefghijklmnopqrstuvwxyz0123456789-=()\;'`.,."
const skeys=' abcdefghijklmnopqrstuvwxyz=!"*$%&/() _     ^  ;:'
var inf = "_"//Indicator
var counter=0
var output=""
var mode="type"
function _upinf(){counter++;if(counter==40){counter=0;if(inf=="_"){inf=""}else{inf="_"}}}
function sl(a,b){return output.slice(a,b)}
function getInput(){if(keyp(48)){output=output+" "};if(keyp(51,20,5)){output=sl(0,output.length-1)};if(keyp()){for(var i=1;i<keys.length;i++){if(keyp(i)){if(key(64)){if(output==""){output=skeys[i].toUpperCase();break}else{output=output+skeys[i].toUpperCase()}}else{if(output==""){output=keys[i];break}else{output=output+keys[i]}}}}}return output}
function prompt(msg,finish,infa,x,y){if(!x)x=0;if(!y)y=0;if(!finish||typeof finish!="function")throw "Prompt: Missing finish behaviour";var r="";if(infa){_upinf();r=getInput()+inf}else{r=getInput()};if(keyp(50))finish(r);return print(msg+r,x,y)
}
function TIC()
{
 cls()
	if(mode=="type"){
	prompt("Name: ",function(r){
	mode="show"},1)
	}
	if(mode=="show"){
	print("Hello "+output)
	}
}
/*
Documentation
TIC-80 Input lib (Javascript)
API:
Global variables:
 - output:
	 All the input recieved from keyboard on getInput()
		can be reseted by setting its value to ""
functions:
 - getInput():
		Returns output
	- prompt(message,functionOnFinish,indicator,x,y):
	 variables:
		 - message: Message to show to user
			- functionOnFinish: This function is
			  called when user press "Enter"
			- indicator(Boolean): Show indicator or not
			- x,y: Coordinates to print the message
*/

nesbox avatar Nov 05 '20 14:11 nesbox

Another one example https://github.com/nesbox/TIC-80/wiki/code-examples-and-snippets#text-only-game

nesbox avatar Nov 05 '20 14:11 nesbox

If we could make an input() API function, I would be thrilled and do a screen recording of how my seven year old invokes it and share it with you guys

sssilver avatar Nov 05 '20 20:11 sssilver

If we could make an input() API function

What do you imagine that function would do? It can't freeze the machine... TIC() still needs to run at 60 FPS... so I'm not sure this is even possible to do in a function at all (without global state). Anything like "wait for input and enter" is going to require many, many ticks and the string is going to be built up slowly across many frames... hence the global state... I suppose you could pass it a memory location or something that it could use for it's "buffer" though... like passing a pointer in C. :)

Even then you'd still have to allow for two possible return scenarios:

  • a string
  • an "i'm still getting input" type placeholder

I think some of the examples already show this, but it does get complex.


From example: https://github.com/nesbox/TIC-80/wiki/example-text-only-game

function TIC()
  cls(0)

  print("Hello What's your name?", 4, 8, 11)

  name = input:text()
  if not (name == "") then
    print("Hello " ..name, 4, 24, 11)
  end
-- ...

You see this runs every loop so if the user hasn't hit enter yet input:text() returns an empty string (the signal to keep waiting)... and of course input:text() handles drawing the current state of the input to the screen, etc...

joshgoebel avatar Jan 29 '21 00:01 joshgoebel

Personally I would prefer for it to actually block the machine until Enter is pressed. This would simplify things a lot.

Otherwise, if this is unacceptable (why?), it could take a callback that gets invoked when Enter is pressed.

sssilver avatar Jan 30 '21 03:01 sssilver

I would guess a block is likely incompatible with the design of the entire system. But that's a guess. And yes a callback would certainly be another workable possibility.

For starters there is no way to update the screen if the machine is "frozen" waiting for input. The whole update process depends on the TIC callback.

So I think you're asking tic80 to just be something it's not. Very curious to see what a callback solution might look like in a real small demo.

joshgoebel avatar Jan 31 '21 06:01 joshgoebel

I will say I was learning python about 7-8 months ago, and I'm still learning things like "what is LUA's intended uses and strengths compared to Python?" or any other language really. So admittedly I'm not exactly sure what LUA is all about other than its high "portability" and versatility. And I think it can run on about any piece of hardware that uses C? I'm guessing like doom you can practically run it on an old calculator? (being sarcastic ofc)

In any case, I learned a lot of python things in an interactive shell, and was thinking I would have been tempted to learn LUA from ground zero on TIC-80, just like sssilver describes. In the meantime I'm trying to learn some LUA nuances with Virtual Studio, and learn, like, practical TIC-80 game functions on TIC-80 since I'm learning LUA purely for fun and tryina make some games anyway (for me Python has been more for academic purposes). I must say LUA is already betwizzling me, with its lack of intuitive library importing and its sorta... indiscriminate attitude towards data types like floats and integers. No more x+=1, now x=x+1... just like a lot of basic little things I thought would be obvious but aren't.

Anyway I'm very intrigued by sssilver's idea, it would be awesome if input() was an internal function in TIC-80. What an awesome educational tool TIC-80 would be if it had something like an interactive shell for running a chunk or something! But also I don't understand the fine details, and I get it if LUA just isn't supposed to do that. Either way, wish me luck, and I hope your kid has lots of fun sssilver. Also I look forward to whatever's next for TIC-80 nesbox! All the best 🤙

ManlyPinkPony avatar Jul 11 '22 16:07 ManlyPinkPony

Hi. My comments come with only a couple of hours into the API, but:

+1 to having native text input (ideally with a fallback to keypad-text input like NES did for character names)

I don't think it's a problem if the solution felt ugly (callbacks or other concern): Having a capability is better than not having the capability..

sprive avatar Sep 08 '23 17:09 sprive

nesbox added this to To do in dev version 1.2

Interesting, @nesbox does that mean you intent to tackle this now?

joshgoebel avatar Sep 09 '23 00:09 joshgoebel

I developed an approach using lua co-routines, but that is invisible to your client code, which just looks like imperative console IO: example program() :

https://github.com/nesbox/TIC-80/wiki/Code-examples-and-snippets "Console Program Example"

dcaillia avatar Feb 04 '24 13:02 dcaillia