As I'm getting deeper and deeper into my PICO code, I am finding a few things, and perhaps suggesting some additionally.
Allow FUNCTIONS to be below main code. Many programming languages do not care where you write your functions. It's convenient for me to have them beneath my main code which is the opposite of what PICO requires currently.
Are parentheses really necessary for commands that will always start as the first code ?
PRINT
CLS
I understand it takes two "=" for a comparison. I can think of several programming languages that do not do this. You might keep it as deprecated code, but also allow "=" in a comparison. Quite simply, there should be no need to set a value while making a direct comparison, so "=" could be done this way.
Are parentheses really necessary for other commands ? GFA and BlitzMAX, ONLY used parentheses for functions that return a value or if you wanted to change the order of the operands in a mathematical calculation or a logical comparison. Incidentally, () would never be used except to describe the parameters of a function that does not return a value.
A=ADDUP(16)
CHECKADD A
A=(B+C)*D
CLS clears the whole screen yet ignores CLIP().
A command CLSCOLOR() would be nice to set the CLS color so when it is called, instead of always BLACK, you could have a different color.
Option for LOAD and SAVE state when playing a game from SPLORE. Then you could leave one game, play another. Then go back to the other game at the same position you left it. This would not be cheating as once you SAVE state, you exit that game back to SPLORE.
Only when you load the game again in SPLORE do you have an option to LOAD state and set for the ability to SAVE STATE again. During the game you CANNOT use LOAD state, it is only to recover your position optionally when playing a game.
Instead of an error message stating what line # it occurred on, show an error dialog, perhaps go directly to the editor on the line and column where the error took place along with a dialog box.
Ability to FOLD functions. That is, if you are on the first line of a FUNCTION, you can press F10 or some other select key and it will fold up - not showing the contents and only the name and arguments for it.
FUNCTION ADDUP(N)
RETURN N+1
END
FUNCTION CHECKIT(N)
IF N==0 THEN RETURN -1
END
(2 folded functions)
FUNCTION ADDUP(N)
FUNCTION CHECKIT(N)
Ability to have split edit. That is, you can have one frame above which is at a particular line # in your code and an edit frame below that which can be at an entirely different line #. Useful for debugging complex functions and their calls to main code.
Force readable coding. That is, do not permit this or any other way to convolute coding:
IF (A==5) B=3
Instead it could be:
IF A=5 THEN
B=3
ENDIF
Allow ENDIF as a possible command. END can also be used as a deprecated command, but ENDIF only with an IF statement.
Same with FOR, have a NEXT. Variable name not needed for NEXT, however, unless operating in STRICT mode. (That is something else).
Add a new command, DBUG:
With it, it will choose the top-right-hand corner of the screen and show the variable name + value, updated every time screen is updated:
DBUG A,B,C
A=1
B=A+2
C=10
Display in top-right-hand corner of the screen right-justify flushed during runtime shows:
A=1
B=3
C=10
It could also update every time you call FLIP()
Either that or create a new small panel to the right of the enlarged 128x128 screen and with legible Truetype font and text so it does not interfere at all with the game display.
Use NODBUG to remove a viewed variable during runtime. Exiting a program removes all DBUG variables. Your code MUST have DBUG in order to view them again.
When using UP ARROW for command history when in FILER mode, you could skip over repeated entries. I.E: here is the history
PRINT A,CLS, RUN, CLS, RUN, CLS
Pressing UP will reveal CLS, RUN, but if it is CLS again seeing a repeated pattern, then it will just skip to PRINT A. In fact, there is no reason to save copies of the same command set in history if it is already listed at least once there.
Naturally a repeated command will prompt it to appear at the bottom of history so it is recalled first as it was the last item entered.
NONE of the keys from the keyboard currently work in the PICO editor from NUM-LOCK: HOME, UP, PGUP, LEFT, RIGHT, END, DOWN, PGDN, DEL. I use these all the time in other programming lanuages.
The INSERT KEY is not being used at all. You could use it like SPACEBAR to move typed commands to the right, but instead of the cursor moving additionally, it would stay in the same position, so in effect it just PUSHES what is typed to the right by one-character.
Thus, where the uppercase letter represents the position of the cursor to start, and _ represents the same position of the cursor after pressing INSERT.
ripeApple
ripe_apple
Some commands that I believe would be useful that are not included with PICO:
CHR$(), ASC(), VAL(), STEP, SUBROUTINE, ENDSUB, ENDFUNCTION, PRINT USING,
MKL and CVL to convert 4-bytes to and from a single variable value
PEEKWORD, PEEKLONG, POKEWORD, POKELONG. There may be others.
FILL(X,Y,PaintColor,EdgeColor)
If Paintcolor is not chosen, it uses default color. If Edgecolor is not chosen, it uses any color that is not PaintColor.
add options to CIRCFILL and RECTFILL thus:
CIRCFILL X,Y,Radius(,FillColor,OutlineColor,ThicknessOfOutline)
RECTFILL H,V,X,Y(,FillColor,OutlineColor,Rotation,ThicknessOfOutline)
XRECT H,V,X,Y(,FillColor,OutlineColor,Rotation,ThicknessOfOutline)
(where X & Y are not ending coordinates but pixels across and down)
Same with LINE.
LINE H,V,X,Y(,C,Rotation,Thickness)
XLINE H,V,X,Y(,C,Rotation,Thickness) (where X & Y are pixels across and down, negative for left and up)
LINETO X,Y(,c,Rotation,Thickness) (where the line is drawn directly from the last line drawn and X & Y in this case are not coordinates but pixels adjusted from the last plotted position.
So if you draw a line FROM 50,25 to 100,75 and then used LINETO 0,-10 , the last line drawn will be a vertical one 10 pixels above 75 giving you vertical coordinate 65.
Also add:
OVAL and OVALFILL:
OVAL X,Y,RadiusX,RadiusY,OutlineColor,Rotation,ThicknessOfOutline
OVALFILL X,Y,RadiusX,RadiusY,FillColor,OutlineColor,Rotation,ThicknessOfOutline
Might have ROUND and ROUNDFILL as well, to create Macintosh-style rounded frames.
CurveStep is # of pixels to draw a curve. Zero is none (same as RECT), 1 is 1-pixel, etc. 3 would yield a nice Macintosh style curve.
-- -- -- -- -- -- -- -- ## ## -- -- ## -- -- -- ## -- -- -- -- ## -- -- -- |
ROUND H,V,X,Y,CurveStep,OutlineColor,Rotation,ThicknessOfOutline
ROUNDFILL H,V,X,Y,CurveStep,FillColor,OutlineColor,Rotation,ThicknessOfOutline
If you don't want to have the ROTATION argument for all of the drawing commands, you could make a new command called ROT, SETROT, or SETROTATION.
Naturally it will be up to the programmer to SETROTATION back to 0 for normal default direction.
Since you have POKE(0x5f2d,1) to activate the mouse, you could add another POKE to activate the keyboard, and add three new commands. INPUT, WAITKEY, and INKEY
WAITKEY and INKEY will also retrieve arrow and game keystrokes. If a game keystroke uses a standard digit or letter of the keyboard, it will NOT return as a game keystroke but as a normal keystroke.
You can, however, use WAITKEY and INKEY to read a true joystick entry. (move direction or button A, or B).
"1UP" "1LF" "1RT" "2DN" "1A" "2B" where with a string of more than one character, it is unique and the first character represents which player #. Additional special keystrokes could be retrieved.
"TA" "BS" "CR" in addition to the normal "A" "B" "C" "1" "2" "3" "!" "*" "}" etc.
INPUT like normal basic requires you to press ENTER to record its result. Before you do so, you can make corrections to your input via the BACKSPACE KEY if so desired. And the text you type appears on the screen as you type it - just as a normal INPUT line would.
A=""
POKE(0X5F2DE,1) --ACTIVATE KEYBOARD
PRINT "WHAT IS YOUR NAME?"
REPEAT
INPUT A
PRINT"HELLO "+A+". WHO IS THAT NEXT TO YOU ?"
UNTIL FOREVER
For the FILE MENU, you could add NEW which also clears the screen in addition to all code, images, audio, and maps. It's really not needed when you are loading one .P8 to another, but it gives you peace of mind, a bit like the OFF button on a solar-powered calculator. :)
Could also add typing in SYSTEM or GOODBYE and you do not have to press ALT-F4 to exit.
This is all that comes to mind for now.
If you use _update(), _update60(), and _draw() for your main code, your functions can come after them with no problem. To expand ever so slightly - everything in lua is a table. Trying to call a function before it's defined is like using a variable before you've set it equal to anything.
From the lua manual on calling functions: "a special case to this rule: If the function has one single argument and this argument is either a literal string or a table constructor, then the parentheses are optional"
I hesitate to mention: in full-blown lua, it's possible to modify the global metatable to call a function without paren. (remember when I said everything is a table? visit www.lua.org/pil/13.html and blow your mind)
it seems that you REALLY want to make Lua into BASIC instead of just learning and adapting to Lua style programming.
CLS() does infact reset clip, use rectfill() and cursor() instead
CLS also already takes a color parameter, so CLSCOLOR is not needed
Loading a saving a state is not really possible in standard Lua and needs a patch like eris for that to work
Regarding the if shorthand syntax, why would Zep remove a feature that he himself added
The if (expression) expression is not standard Lua and specific to pico-8
If you want to debug variables, then just add some print calls to the end of your _draw function
Subroutines can be emulated using goto statements or better, normal functions
You can type SHUTDOWN instead of hitting ALT-F4 to exit
Also REPEAT (blah) UNTIL FOREVER isn't some special lua syntax, it just waits until a variable called FOREVER becomes non nil/false, generally if you want an infinite loop you tend to do WHILE TRUE DO (blah) END
Programming languages that don't use ==? Well, C, C++, Lua, Java, Javascript (ish), python, perl (ish), ruby (ish), php (ish) all have that double equals is Comparison (some have that double equals is weakly-equals while triple equals is strongly-equals, hence ish)
CIRCFILL AND RECTFILL also already allow you to specify the fill color, no need to do
COLOR(#) RECTFILL(X1, Y1, X2, Y2) |
Just do
RECTFILL(X1, Y1, X2, Y2, #) |
Hi Tyroney:
- You are referring to object-oriented code. Something I'm not very good at. Here is the current clypse:
repeat color(0) rectfill(0,0,128,128) for j=1,12*(b+1) do spr(0,fnr(128),fnr(128)) end flip() n+=1 if t>0 then t-=1 end if n==125 or n==225 or n==525 then f=5 end if f>0 then color(7) rectfill(0,0,128,128) flip() f-=1 end if n==250 then sfx(0) end if n==550 then sfx(1) end if (btn(4)==true and t==0) or n==400 then b+=1 if b==1 then sfx(3) end t=10 end until forever |
I know I'm supposed to be using _update() and _draw(), but I just can't wrap around that type of coding in my head. I have to have everything running at once, separated by FLIP(), or as it was with GFA, PEEKEVENT(), or earlier than that like back on the APPLE, a FOR/NEXT loop of suitable time so you could see the graphics without flicker.
Fortunately PICO allows for this type of coding - if they didn't, like MONKEY-X doesn't, I would be sorely disappointed.
As it is, I can, so I can definitely write a nice program for others - which is what I'm working on now.
As for reading from your link ... Mind blown, but not in a positive way. I'm not understanding at all what is being said there.
What is it Dr. McCoy says in Star Trek TOS ? "I'm just an old country doctor." :)
dw817, your life would be much easier if you tried to learn the style of code that the PICO8 encourages, rather than fighting against it and making yourself unhappy.
All the _update and _draw functions help to do is separate your code into three stages.
1) get input (this is done implicitly, you just read the state using BTN)
2) update the game (this is the _update function)
3) draw the screen (this is the _draw function, followed by FLIP)
Because it calls each of those every frame, you can abandon the REPEAT UNTIL FOREVER idea.
Behind the scenes, the code basically looks like:
_init() REPEAT _update() _draw() UNTIL FOREVER |
Outside of that, you can maintain your game data, including where game entities should be and scores and other stuff. You can see plenty of examples of that in all the fanzines.
Yep, RectFill has option for color, Gamax92. I mentioned that, but there is also XRectFill, Rotation, OutlineColor, and OutlineThickness which is not currently available.
I'm glad my suggestions were especially helpful for everyone. It will certainly encourage me to add more later. :)
I'm intrigued though. In where of my suggestions above does it mention a different style of programming at all ?
I suggested:
- Function folding
- CHR$(), ASC(), VAL(), STEP, SUBROUTINE, ENDSUB, ENDFUNCTION, PRINT USING,
- Smarter up-key history
- Additional arguments for existing drawing commands
- New drawing commands XLine, LineTo, XRect, XCirc, Oval, Round, SetRotation.
- Allow for true keyboard input
Now in these suggestions if any were made to somehow force you to not program in object-oriented code, I do apologize.
And here's what's really interesting. NONE of my suggestions above would affect anyone's coding or method of coding as they are using today in current PICO. Even if all my suggestions were enacted, everyone's code and source would run just as effectively as they do today - so by all means attack it.
I will learn object-oriented in my own time and - again - my suggestions above do not in any way propose against object-oriented programming, and I'm really curious to know why my ideas are attacked at this level.
btw - if I wanted to put everything in one place and manually flip(), I'd toss all my code into _update() (no need for a loop - it's called every frame) and then go
function _draw() flip() end |
Also try not to interpret people as hostile. Really a lot of "feature requests" are things that can be added manually with a handfull of lines of code. Some people have re-written base functions like rectfill and gotten performance equal to or even better. To point out that having something "built-in" is really only marginally useful.
I'll be happy to chime in that pico-8 has basically no string support, and that's kind of sad. But at the same time, it's created as a console - if you really want a keyboard added, the way to do it is with gpio pins plugged into a keyboard and some custom code. (just like a console would do)
(props to felice and ultrabright both on speedy re-written circlefill() and other info on speed and string support.)
Hi Tyroney:
- The problem I'm seeing is - well, it's like a Solar Powered Calculator.
Beautiful piece of work, but the first ones that came out didn't have a POWER switch.
Silly I know, right ? But that bugged me. And apparently it bugged enough people so - sure enough, you see an OFF button on solar-powered calculators today.
This is very much along the same lines that I don't like code to run unless I programmed it to do so.
I know object-oriented coding is where you can 'fire and forget' functions, but my brain doesn't work that way - and I don't think it ever will.
Curiously in my massive projects, I have seen the need for what I call a NANO function. To me at first it meant very small but continuous.
Today, Nano is usually a huge routine, handling all kinds of nice output, input, and messaging artefacts.
Function nano() Local i,j,vv$,zx#=zoom#,zy#=zoom#,cx,cy,w$,id$,typ,h,v,x,y,r,g,b,t$ shiftkey=Sgn(KeyDown(160)+KeyDown(161)) ctrlkey=Sgn(KeyDown(162)+KeyDown(163)) If shiftkey=0 Then didnoshiftkey=1 arrowkey=0 numkey=0 k$="" If MouseDown(1) sparkadd MouseX()+Rand(-10,10),MouseY()+Rand(-10,10) EndIf If shiftkey Then k$="#" If ctrlkey Then k$="^" wht If apage>7 SetScale 1,1 DrawImage scrn[apage],0,0 Else If zoom#=1 zx#=1 zy#=1 EndIf SetScale zx#,zy# DrawImage scrn[apage],-camx*zx#,-camy*zx# EndIf |
It is your _draw() function essentially with the exception I must call it.
When I do, it is usually for three important things:
(1) Update the screen
(2) Retrieve input
(3) Handle important messages to inform of errors or adjustments
So riddled throughout my code you will see tight loops that call Nano(), but here's the difference.
I get to choose when and where NANO is called. With _draw() and _update(), they are done according to timing of your code and timing of the screen.
I can't see myself writing code that would work this way. There are many times where I do not call NANO as much and more work is intensified for usage in calculations, data moving, and the like.
The only time I saw the keyboard work in PICO, that is where you could use the QWERTY keyboard and retrieve true strings was by using a Javascript plugin.
To my knowledge you still cannot INPUT, INKEY, or WAITKEY to retrieve a true keyboard keystroke.
From your link, Felice & Ultrabright, it is nice to see some requests for similar commands I think would also be helpful.
In any case, I wrote my own CHR routine for the main code I am working on. I just hate to rewrite stuff wherever I go.
' >> RETURN COMMA DELIMITED TEXT FROM A$ Function yank$(a$ Var) Local b=myinstr(a$+",",",")+1,c$=Left$(a$,b-1) a$=Mid$(a$,b+1) ' also remove it from input string Return c$ EndFunction ' >> RETURN VALUE FROM COMMA DELIMITED TEXT OF A$ Function yankno(a$ Var) Return val(yank(a$)) EndFunction |
And as FELICE said, I am not for the removal of ANY code or commands, why can't we just have both ? :)
I'm not entirely sure you know what you're up against here. The IF (THEN) ELSE shorthand is essential for saving tokens - the space restrictions on P8 are really tight... and as a result, so are most projects. This is also where the Splore save/restore thing becomes a fault - the engine is made for simple one-shot arcadey games. That's not to say you couldn't do something along the lines of a JRPG with it - but you'd still have to get to the point and do so kind of quickly; no 3 hours to dawdle like in NES/SNES-era ones.
But even the allowance of suspended gameplay sessions opens up the can of worms that is "save scumming." Nothing is preventing a player from leaving PICO-8 running in windowed mode, copying that savedata to a backup file (or editing it on the fly via Notepad), and restoring it a bajillion times. About all that's really meant to be stored in PICO-8's data is stuff like High Scores; which can be written to the cartridge itself as an updating array/table. (And maybe reset with some kind of function.)
Going from object-oriented to LUA/PICO is quite a leap and it does require some rethinking of projects to work.
Plus, I think the reason CLS() has the parenthesis is because it's really CLS(color) - and it just defaults to 0/black if left blank.
If tokens are tight, the ability to not require parentheses for commands and functions that return no values would help.
I see what you are saying about the SAVE STATE, Tony ... Hmm ... I guess it could be saved directly, internally, and encrypted into the CART itself.
I could build an encryptor that would stop most people, and I have in the past. Even with the source it would be a nightmare to decipher:
' start with index ' shortcut so we can multiply without getting zero ' First we XOR the key characters themselves ' then the key totals ' Tricky ! Last XOR by the last saved encrypted character added ! ' Today's flavor is strawberry ' loop until code pattern is one we haven't added yet ' when so, add it ' loop until all 64-characters are complete and we have a complete cipher |
So - no single external file would be saved. It could either be saved in a single massive encrypted data file for all carts that includes the dates when the player last ran the game - or this data could be saved internal to the .P8 cart itself.
I didn't know CLS has arguments. That would require parentheses. Nonetheless, if a function in PICO is called that has no arguments then the parentheses requirement, once again, should not needed.
Blitz does this, for instance.
Print IncInt() 'prints 1 Print IncInt( 1 ) 'Prints 2 Print IncInt( 1,3 ) 'Prints 4 showast 'prints *** Function showast() Print"***" EndFunction Function IncInt(n=0,p=1) Return n+p End Function |
Pico8 uses the Lua language (with a couple modifications) which means that it currently allows functions to be called without parentheses only if it is being given a single argument which is a string or a table.
I don't think removing parentheses in other circumstances would work well because Lua is a "functional" language, so Functions are considered first-class types, in the same way as String, Number, Table.
Imagine for example that you have:
function getRandomNumber() return 4 end local a = getRandomNumber |
In this circumstance, a would be assigned the function 'getRandomNumber'. This is one of Lua's more powerful features. In the scheme you propose, this would not be possible, as getRandomNumber would be executed immediately and return 4, assigning that to a.
I'm not understanding Springogeek, when you say, a is assigned the function GetRandomNumber. Does this mean when I call on the variable A later, it will always run the function GetRandomNumber before retrieving a value ?
If you ran the above code like this:
print(a()) |
...then the function named getRandomNumber would be executed, so you would see '4' printed out.
As a more useful example, imagine your game had two screens, a game screen and a title screen.
Obviously, these screens behave differently, so each would have their own update and draw functions.
because PICO-8 automatically runs _update and _draw, we could control the screen being drawn like this:
function updateTitle() # do some calculations, or not end function drawTitle() # draw the title screen here end function updateGame() # update the game and respond to input end function drawGame() # draw the game here end function setState(state) if state == 'title' then _update = updateTitle _draw = drawTitle else _update = updateGame _draw = drawGame end end |
If functions were executed even without parenthesis, this very useful style of code would not work.
Neat example, springo. I knew you could "alias" functions that way, but never thought of a use for it. Lua continually surprises.
Ka-Phew ! That's too complex for me, Springo. I'll just make sure everything has a parenthesis then.
I was also asking about the CSTORE command - hoping someone could post a full example program, a simple one, to demonstrate its use and how it could retain the data with a 2nd program even if you change versions of your main program.
Lua has some interesting features.
For example, when you create a function, you assign it a name.
Function _update() #stuff End |
What lua actually treats it as is:
_update = function () #stuff End |
You see, functions are treated the same way numbers and strings are. They are just values to be assigned, or passed around.
Not too complicated if you think about it, just unexpected :)
I'm almost understanding this ... no really. :)
Let me ask. When you assign a variable a VALUE, is that a type of very small function ?
alpha=25 |
function alpha() return(25) end |
When lua hits a token, (the name of something in the code) it looks in the global table to see what it finds. If there's a match, it returns the contents, whatever it may be. So in a sense it's looked up the same way, but a variable just has some data that gets returned and a function has more to it.
You might enjoy Programming in Lua. (don't worry, the meta-tables aren't discussed until chapter 13)
That last sentence can have two meanings.
-
You might enjoy Programming In Lua. (instead of PICO)
A. No, I'm here for PICO. - You might enjoy programming in Lua. (to learn how to code better in PICO since it uses the same notation).
A. Research into LUA likely would not hurt in this respect. Thanks !
It's like the classic misinterpreted sentence.
"Sally saw a lion eating ice cream." (with his paws ?)
"Sally saw a lion, eating ice cream." (while)
In any case, I understand. I'll bookmark it and once I finish writing this chapter (of a book I'm working on. Then I'll sit down and give it a good reading. :)
Just wanted to say thanks, Tyroney. This is indeed good reading and is answering a LOT of questions I have about LUA and (hopefully) PICO.
For those of you new to PICO as well, I HIGHLY recommend you read the website he listed above. For one thing it shows how code can be written in the best possible way, and the vital and important difference between zero and NIL - and that has gotta be useful information for serious coders.
[Please log in to post a comment]