LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Using DATA to improve your program (Debug; Code readability; and more)

Root / Submissions / [.]

Autz64Created:

Introduction

When programming, we want to make things as generic as possible so our tricks and "hacks" can work on any occasion we need them to. That's why we declare bunch of DEFs, bunch of generic variables and constants... All for that specific goal. But what happend if we want to go beyond generic code? When i mean "beyond", i mean adding bunch of predefined pieces of code that allow us to have: Levels (on the most part); Menus... If you think about it, you would say something like: "Well, that can't go wrong". But can't be? Let's take a look. Imagine we have a generic geim that has bunch of levels. When using the classic approach most users use when coding, it would look like this:
LEVEL%=5

WHILE  <Some Condition>
     VSYNC
     IF LEVEL%==1 THEN
     '...
     ENDIF

     IF LEVEL%==2 THEN
     '...
     ENDIF

     IF LEVEL%==3 THEN
     '...
     ENDIF
WEND
Or something like this:
LEVEL%=5

@MNLOOP
     VSYNC
     IF LEVEL%==1 THEN GOTO @LEVEL1
     IF LEVEL%==2 THEN GOTO @LEVEL2
     IF LEVEL%==3 THEN GOTO @LEVEL3
GOTO MNLOOP

@LEVEL1
'...
GOTO @MNLOOP

@LEVEL2
'...
GOTO @MNLOOP

@LEVEL3
'...
GOTO @MNLOOP

These two examples shares a common problem: It destroys code readability and makes it near impossible to debug if you end up adding like 30 segments of predefined code. So, what's the solution for this? The solution is using DATA.

What is DATA

DATA is the most closest thing SB will have to a "list" of arbitrary data. It allows us to encapsulate a set of predefined data together that we can access later, hence the name.
DATA <data 1>, <data 2>...

DATA "This is data",2,3.5,&HFF00FF00,&B0010,#UP

'Note: all the functions, including user functions, won't work on DATA. Since DATA only handles constant expressions

Accessing to the DATA

Accessing to the DATA is handled by READ command. READ gets the data in the order it's executed. If READ is executed for the first time, it will get the first data of a DATA set, if it is executed again, it will return the second data of the DATA set, and so on...
DATA 1,2,3,4,5
READ X
? X
OUTPUT: 1
DATA 1,2,3,4,5
READ X
READ Y
? Y
OUTPUT: 2 So, if you want to access to the 5th element of a DATA set, you need to run READ 4 times before. So, on much cases you will end up using a FOR loop.

Locating the DATA set

You can "define" segments of DATA sets by using labels (@ABC) and the RESTORE command. Since DATA is being read from the very beginning of the source code to the end, RESTORE will define the start line so we can arbitrariely read what we want.
DATA 1
READ X
? X

DATA 2
OUTPUT: 1
RESTORE @B

DATA 1
READ X
? X

@B
DATA 2
OUTPUT: 2 With this now we can start.

1.- Creating a DATA Parser

1.1.- What is a DATA Parser?

This doesn't have an official name, but i call it "DATA Parser" for the way how it works. On summary: a DATA Parser is a generic piece of code that can handle specific kinds of data and perform certain actions based on the data it receives. Pretty much like a DEF with multiple commands, with the exception that we don't need to call it over and over again, just give him the data it needs. The structure of the DATA list will directly influence the way you setup the DATA parser. And the structure of the DATA list depends on what you want to achieve. Here, i'm going to use a very typical example: Showing a message. Let's suppose i want to show a message on screen with the following arguments: - Author - Message - Color of the message - Duration in seconds when using DATA, it should look like this:
DATA "Author","Message",&HFFFFFF,5
' White message with a duration of 5 seconds
Now, we set an "ID" to the DATA segments we are going to use, by using a @Label:
@TEST
DATA "Author","Message",&HFFFFFF,5
With this setup, we can start making the DATA Parser.

1.2.- Setting up the parser

As explained early, DATA parsers are generic code, so we must do a code that can handle most, if not, all the possible parameters we parse to him. For this example, if we combine READ and RESTORE, we will get something like this:
DIM ARG$[5], DELAY%,GC,PREV_MILI%
RESTORE @TEST

WHILE 1
     VSYNC
     GCLS

     'DATA Parser for messages
     IF !DELAY% THEN
          'I read the necessary arguments before showing anything. Yours can vary based on your needs.
          READ ARG$[0]
          READ ARG$[0]
          READ GC
          READ DELAY%
     ELSE
          GPUTCHR 10,120,ARG$[0]
          GCOLOR GC
          GPUTCHR 10,130,ARG$[1]
     ENDIF
     
    'Clock in seconds
     IF PREV_MILI%+1000 < MILLISEC THEN
          DELAY%=DELAY%-1
          PREV_MILI%=MILLISEC
     ENDIF
WEND

@TEST
DATA "Author","Message",&HFFFFFF,5
Aaaaannndddd... Well, that's all, for a very simple reason: When the DATA Parser is ready, most of your editions will go on the DATA statements and not on the core structure. With that you can sepparate the logic from the arguments, and have a more cleaner code that will not only look "good" (every code is a mess, but anyways), but it will save you time when you want to make quick edits to the levels or the stuff you're showing. What if you want to add or erase messages? Just add more DATA like this:
@TEST
DATA "Me","This is a message using DATA statements (DUR: 5 secs)",&HFFFFFFFF,5
DATA "Me","Is amazing because i don't have to touch the core structure to add more and more (DUR: 5 secs)",&HFFFFFFFF,5
DATA "Someone else","Also, this message is plain red (DUR: 5 secs)",&HFFFF0000,5
DATA "Me","And this message last 3 seconds and is blue (DUR: 3 secs)",&HFF0000FF,3

You forgot the @ under: "Or something like this." Correct syntax: GOTO@MNLOOP

Replying to:CyberYoshi64
You forgot the @ under: "Or something like this." Correct syntax: GOTO@MNLOOP
Yeah, but I'm not going to edit it.