the best option to ease yourself in may be snail's struct library : https://smilebasicsource.com/page?pid=587
How do/can you make objects in SmileBasic?
Root / Programming Questions / [.]
cakecatCreated:
For example, in python, you can say
class Apple: def __init__(self, color, x, y): self.color = color self.x = x self.y = y def beRainbow(self,color): self.color = 'Rainbow' apple1 = Apple('Red',12,23) apple2 = Apple('Green',14,23)And then apple1.color is 'Red', and I can make apple1.color equal 'Rainbow' by doing apple1.beRainbow() Is there some sort of workaround to this? Do you have to use arrays or something? Thank you for any help, I really like being able to make programs on my 3ds, I am just having some difficulty with these concepts.
You can do that be doing something like this:
ACLS RAINBOW=TRUE @MAINLOOP WAIT 10 GCLS IF RAINBOW==FALSE THEB GPUTCHR 0,0,"APPLE",RGB(255,0,0) ELSE GPUTCHR 0,0,"APPLE",RGB(RND(255),RND(255),RND(255) GOTO @MAINLOOPBy setting the rainbow boolean to be false it is going to display the text in red. If there is anything you don't understand feel free to ask I am probaly not avaible for the time being but I will try to answer as soon as possible. Ps. I recomend you to watch petiteprofessor smilebasic tutorials on youtube they are very helpfull to people new to the progamming language.
Okay, so I did some experimenting, and I found a workaround, but it's quite messy I think, hopefully I'll be able to get better at using arrays like this by looking more at the sample programs.
So I wanted 10 apples to fall to the ground, each with their own x and y values, so I was able to do this
SIZE = 10 'Number of apples DIM AX[SIZE], AY[SIZE] 'Arrays for the apple coordsso now that there are variables for each apple. Then I can use a for loop to check them all
FOR I=0 TO SIZE-1 INC AY[I] IF AY[I]<=28 THEN 'If within y limit of screen LOCATE AX[I],AY[I] PRINT("A") ELSE resetApple(I) 'At random time puts apple I back to top at random X position ENDIF NEXTHopefully I'll be able to get a better grip of this kind of organization, it just seems clunky, but it somewhat resembles how EX7ALIEN is able to manage the enemy invaders without using objects.
You can't make real objects in SB; it isn't a language feature. Using arrays to be like "pools" for object data isn't a bad idea. If you're working with sprites, they actually do have their own features that you can apply to be really similar to "objects" but it depends on what exactly you're doing.
The sample programs areโฆ okay. They aren't exactly shining examples of what SB is truly capable of (or even how to write good SB code) since many of them are PTC conversions (and others were slightly botched by localization and updates.)
the best option to ease yourself in may be snail's struct library : https://smilebasicsource.com/page?pid=587This is a decent approach if you absolutely can't live without something like an object, but they aren't "real" and they aren't very efficient, either. I haven't maintained this library in a while.
You can't make real objects in SB; it isn't a language feature. Using arrays to be like "pools" for object data isn't a bad idea. If you're working with sprites, they actually do have their own features that you can apply to be really similar to "objects" but it depends on what exactly you're doing. The sample programs areโฆ okay. They aren't exactly shining examples of what SB is truly capable of (or even how to write good SB code) since many of them are PTC conversions (and others were slightly botched by localization and updates.)I know you can't make real objects, but there has to be a way around that, right? People can still make games and stuff, I just don't get what they are doing to work around this incapability. If you wanted multiple entities in a dungeon crawler, how would you manage every entity's X and Y position and HP for example? In any other language I would use a class, but what is the convention for SB? (Sorry for all the questions x.x)
I know you can't make real objects, but there has to be a way around that, right? People can still make games and stuff, I just don't get what they are doing to work around this incapability. If you wanted multiple entities in a dungeon crawler, how would you manage every entity's X and Y position and HP for example? In any other language I would use a class, but what is the convention for SB? (Sorry for all the questions x.x)An array for entity HPs, an array for entity X positions, and an array for entity Y positions would be the simplest way to do it.
You could do what iโm doing and store it in one string array, and read the data listed above from each string. Much more space efficient.I know you can't make real objects, but there has to be a way around that, right? People can still make games and stuff, I just don't get what they are doing to work around this incapability. If you wanted multiple entities in a dungeon crawler, how would you manage every entity's X and Y position and HP for example? In any other language I would use a class, but what is the convention for SB? (Sorry for all the questions x.x)An array for entity HPs, an array for entity X positions, and an array for entity Y positions would be the simplest way to do it.
But why?You could do what iโm doing and store it in one string array, and read the data listed above from each string. Much more space efficient.I know you can't make real objects, but there has to be a way around that, right? People can still make games and stuff, I just don't get what they are doing to work around this incapability. If you wanted multiple entities in a dungeon crawler, how would you manage every entity's X and Y position and HP for example? In any other language I would use a class, but what is the convention for SB? (Sorry for all the questions x.x)An array for entity HPs, an array for entity X positions, and an array for entity Y positions would be the simplest way to do it.
Okay, thank you!I know you can't make real objects, but there has to be a way around that, right? People can still make games and stuff, I just don't get what they are doing to work around this incapability. If you wanted multiple entities in a dungeon crawler, how would you manage every entity's X and Y position and HP for example? In any other language I would use a class, but what is the convention for SB? (Sorry for all the questions x.x)An array for entity HPs, an array for entity X positions, and an array for entity Y positions would be the simplest way to do it.
If you want a much cleaner way to do it, you could setup your own object-like system like this:
VAR MAX_ENTITIES=100 DIM ENTITIES[4, MAX_ENTITIES] 'Add a new entity DEF NEW_ENTITY(X, Y, HP) 'Search for empty space to store an entity VAR I FOR I=0 TO MAX_ENTITIES-1 IF ENTITIES[0, I]==FALSE THEN BREAK ENDIF NEXT 'If no empty space was found, return -1 IF I==MAX_ENTITIES THEN RETURN -1 ENDIF 'Store the entity and return its address. ENTITIES[0, I]=TRUE ENTITIES[1, I]=X ENTITIES[2, I]=Y ENTITIES[3, I]=HP RETURN I END 'Destroy an entity DEF DESTROY_ENTITY E ENTITIES[0, E]=FALSE END 'Accessors DEF GET_X(E) RETURN ENTITIES[1, E] END DEF GET_Y(E) RETURN ENTITIES[2, E] END DEF GET_HP(E) RETURN ENTITIES[3, E] END 'Mutators DEF SET_X E, X ENTITIES[1, E]=X END DEF SET_Y E, Y ENTITIES[2, E]=Y END DEF SET_HP E, HP ENTITIES[3, E]=HP END 'Main code VAR PLAYER=NEW_ENTITY(25,25,100) PRINT "Player stats..." PRINT " X: " + STR$(GET_X(PLAYER)) PRINT " Y: " + STR$(GET_Y(PLAYER)) PRINT " HP: " + STR$(GET_HP(PLAYER))Here we can create an entity called "PLAYER" with the X and Y values 25, 25, and HP 100. We can get these values with our accessors. Such as "GET_HP(PLAYER)" will return the player's HP, and we can change them with our mutators, such as "SET_Y PLAYER, 5" will change the player's Y value to 5. We can make as many entities as we want up until MAX_ENTITIES. There's a fourth property for each entity here, that is the "alive" property. A created entity has that value initially set to true, and it is always true until the entity is destroyed. When you go to create an entity, it searches for the first slot where a destroyed entity is located by checking their "alive" property, and it stores the entity there. This will be fast enough for most purposes, but if you're dealing with thousands of entities, creating entities this way can be pretty slow. A much quicker way to do it would be to keep a "journal".
VAR MAX_ENTITIES=100 DIM ENTITIES[4, MAX_ENTITIES] VAR ENTITIES_SIZE=0 VAR JOURNAL[.] 'Add a new entity DEF NEW_ENTITY(X, Y, HP) VAR ID IF LEN(JOURNAL)>0 THEN ID=POP(JOURNAL) ELSEIF ENTITIES_SIZE!=MAX_ENTITIES THEN ID=ENTITIES_SIZE INC ENTITIES_SIZE ELSE RETURN -1 ENDIF 'Store the entity and return its address. ENTITIES[0, ID]=TRUE ENTITIES[1, ID]=X ENTITIES[2, ID]=Y ENTITIES[3, ID]=HP RETURN ID END 'Destroy an entity DEF DESTROY_ENTITY E 'Store the entity and return its address. ENTITIES[0, E]=FALSE IF E==ENTITIES_SIZE-1 THEN DEC ENTITIES_SIZE ELSE PUSH JOURNAL, E ENDIF ENDThis journal basically logs every time an entity is destroyed, so when you go to create a new entity, you can immediately know where to put it just by looking at the journal. Creating entities the first way is linear time O(n) since it has to search potentially the entire dimension of the array while keeping a journal makes it constant time O(1) since there is no searching, you can just look at the journal and immediately know where to store the next entity.
It was really easy, i got learn more about strings, and i could hold all the needed data in one array.But why?You could do what iโm doing and store it in one string array, and read the data listed above from each string. Much more space efficient.I know you can't make real objects, but there has to be a way around that, right? People can still make games and stuff, I just don't get what they are doing to work around this incapability. If you wanted multiple entities in a dungeon crawler, how would you manage every entity's X and Y position and HP for example? In any other language I would use a class, but what is the convention for SB? (Sorry for all the questions x.x)An array for entity HPs, an array for entity X positions, and an array for entity Y positions would be the simplest way to do it.
If you want a much cleaner way to do it, you could setup your own object-like system like this:Thank you for the tip! I never thought of doing it like that!VAR MAX_ENTITIES=100 DIM ENTITIES[4, MAX_ENTITIES] 'Add a new entity DEF NEW_ENTITY(X, Y, HP) 'Search for empty space to store an entity VAR I FOR I=0 TO MAX_ENTITIES-1 IF ENTITIES[0, I]==FALSE THEN BREAK ENDIF NEXT 'If no empty space was found, return -1 IF I==MAX_ENTITIES THEN RETURN -1 ENDIF 'Store the entity and return its address. ENTITIES[0, I]=TRUE ENTITIES[1, I]=X ENTITIES[2, I]=Y ENTITIES[3, I]=HP RETURN I END 'Destroy an entity DEF DESTROY_ENTITY E ENTITIES[0, E]=FALSE END 'Accessors DEF GET_X(E) RETURN ENTITIES[1, E] END DEF GET_Y(E) RETURN ENTITIES[2, E] END DEF GET_HP(E) RETURN ENTITIES[3, E] END 'Mutators DEF SET_X E, X ENTITIES[1, E]=X END DEF SET_Y E, Y ENTITIES[2, E]=Y END DEF SET_HP E, HP ENTITIES[3, E]=HP END 'Main code VAR PLAYER=NEW_ENTITY(25,25,100) PRINT "Player stats..." PRINT " X: " + STR$(GET_X(PLAYER)) PRINT " Y: " + STR$(GET_Y(PLAYER)) PRINT " HP: " + STR$(GET_HP(PLAYER))Here we can create an entity called "PLAYER" with the X and Y values 25, 25, and HP 100. We can get these values with our accessors. Such as "GET_HP(PLAYER)" will return the player's HP, and we can change them with our mutators, such as "SET_Y PLAYER, 5" will change the player's Y value to 5. We can make as many entities as we want up until MAX_ENTITIES. There's a fourth property for each entity here, that is the "alive" property. A created entity has that value initially set to true, and it is always true until the entity is destroyed. When you go to create an entity, it searches for the first slot where a destroyed entity is located by checking their "alive" property, and it stores the entity there. This will be fast enough for most purposes, but if you're dealing with thousands of entities, creating entities this way can be pretty slow. A much quicker way to do it would be to keep a "journal".VAR MAX_ENTITIES=100 DIM ENTITIES[4, MAX_ENTITIES] VAR ENTITIES_SIZE=0 VAR JOURNAL[.] 'Add a new entity DEF NEW_ENTITY(X, Y, HP) VAR ID IF LEN(JOURNAL)>0 THEN ID=POP(JOURNAL) ELSEIF ENTITIES_SIZE!=MAX_ENTITIES THEN ID=ENTITIES_SIZE INC ENTITIES_SIZE ELSE RETURN -1 ENDIF 'Store the entity and return its address. ENTITIES[0, ID]=TRUE ENTITIES[1, ID]=X ENTITIES[2, ID]=Y ENTITIES[3, ID]=HP RETURN ID END 'Destroy an entity DEF DESTROY_ENTITY E 'Store the entity and return its address. ENTITIES[0, E]=FALSE IF E==ENTITIES_SIZE-1 THEN DEC ENTITIES_SIZE ELSE PUSH JOURNAL, E ENDIF ENDThis journal basically logs every time an entity is destroyed, so when you go to create a new entity, you can immediately know where to put it just by looking at the journal. Creating entities the first way is linear time O(n) since it has to search potentially the entire dimension of the array while keeping a journal makes it constant time O(1) since there is no searching, you can just look at the journal and immediately know where to store the next entity.
Here's how I've been taught how to make an array...
ACLS DIM ARRAY[X,Y]'X AND Y ARE THE NUMBER OF THINGS YOU WANT IN EACH DIMENSION, SO LETS SAY 4 BY 4 RESTORE @ARRAY FOR I=0 TO X FOR J=0 TO Y READ A' READS THE DATA ARRAY[X,Y]=A NEXT NEXT @ARRAY DATA 1,4,77,0 DATA 1,4,2,8 DATA 3,8,7,99 DATA 1,34,22,555
String Array Storage System (S.A.S.S)
ACLS DIM OBJ$[100] DEF SET_OBJ ID,X,Y OBJ$[ID] = STR$(X) + โ,โ + STR$(Y) END DEF READ_OBJ(TYPE$,ID) DIM C[1] FOR I=0 TO LEN(OBJ$[ID]) IF MID$(OBJ$[ID],I,1) == โ,โ THEN PUSH C,I+1 NEXT IF TYPE$ == โXโ THEN RETURN VAL(MID$(OBJ$[ID],C[0],C[1])) IF TYPE$ == โXโ THEN RETURN VAL(MID$(OBJ$[ID],C[1],LEN(OBJ$[ID]))) END DEF EDIT_OBJ TYPE$,ID,VALUE DIM CC[0] FOR I=0 TO LEN(OBJ$[ID]) IF MID$(OBJ$[ID],I,1) == โ,โ THEN PUSH CC,I+1 NEXT IF TYPE == โXโ THEN OBJ$[ID] = SUBST$(OBJ$[ID],0,LEN(STR$(READ_OBJ(โXโ,ID))),STR$(VALUE)) IF TYPE == โYโ THEN OBJ$[ID] = SUBST$(OBJ$[ID],CC[0],LEN(STR$(READ_OBJ(โYโ,ID))),STR$(VALUE)) ENDFrom here you can create, edit, and read object data from a single string, no hassle required. The only thing though is that any value over 10 digits will make things not what they are, because SmileBasics way of handling things, but those high of values are usually uncommon for objects. Demo code :
SET_OBJ 1,100,10 PRINT READ_OBJ(โXโ,1) EDIT_OBJ โXโ,1,999 PRINT READ_OBJ(โXโ,1)Whatโs cool about this system is that you can easily add more data to each object and use the same array. If you want have 100 objects defined you donโt need 3 100 slotted arrays, youโll only need 1 100 slotted arrays. This is super useful if each object needs lots of data attached to it. EDIT : Amiharts system is better (I worked too hard again, even when there was a simple solution.... time to restructure my object orientated system thing...)
String Array Storage System (S.A.S.S)While this technically works a method like this should only be used for saving/loading data (such as JSON), not manipulating data in real-time in something like a video game. It is pretty slow, and the more complex your object is the slower it will take to parse it.
One other example is this:
DEF Entity() DIM OBJECT[8] OBJECT[0]=0'SP# OBJECT[1]=200'X OBJECT[2]=120'Y OBJECT[3]=0'Z OBJECT[4] = 0'U OBJECT[5] = 0'V OBJECT[6] = 16'W & H OBJECT[7] = 1'SCALING FACTOR RETURN OBJECT END DEF RENDER ENTITY SPSET ENTITY[0],ENTITY[4],ENTITY5],ENTITY[6],ENTITY[6] SPOFS ENTITY[0],ENTITY[1],ENTITY[2],ENTITY[3] SPSCALE ENTITY[0],ENTITY[7],ENTITY[7] END
I got very similar.
but its all very manual. So inside the "class" you have to keep putting the prefix before it... very bloated and tedious.
I used an array for each member of the object and a count, and some have strings to help do field to text translation, think I even used a call to var to lookup fields. But seeing as most classes have the same fields such as count/type/name or whatever... I kept the class prefix in the name so kinda useless to try to generalize the field access, smilebasic likes unique named.I gave most objects their own "out" functions so they could format their own debug outs.
F=VAR(TI_$[I])'where i is the field F[object_index]' such as F[player] or F[T] I use T as "this"I was working with a bunch of fields, like seconds, minutes, hours that were overflowing into each other so I liked to think of things as F and F2 instead of seconds/minutes and it made debug'ing a lot easier.
I=TI_FIELDS-1 F=VAR(TI_$[I]) F2=VAR(TI_$[I-1]) TI_OFLOW T,F,F2 I=TI_FIELDS-2 F=VAR(TI_$[I]) F2=VAR(TI_$[I-1]) TI_OFLOW T,F,F2I know its ugly but it let me manually debug things, had to unroll a for loop etc. Hope it makes sense...or shows how not to do things at the least ;) In hindsight it would of been nice to say .sec .min .hour when writing the time handling, made it easier to read etc. I didn't care to put any object limits in, just push things ontop of their array. do a copy for array to array, if I recall, sb wont' push arrays onto arrays, have to mem copy. which means you have to keep track of where an objects portion of the array begins and ends. Its all indices. an index that is used by functions, generally one index will work with all the members. battling between what you can read and type in before forgetting how to read an objects value. all that goes in a separate slot from my main program.
load "PRG1:LIBRARYNAME1",FALSE USE 1 GOSUB "1:@DEFDT" VAR CUR=NEWTI(2016,9,20,2,0,0):?"CUR=";CUR TI_OUT CUR 'will output the time in the "CUR" objectThe idea is that being in a separate slot it is out of my way and I can use the time fields with a few update calls or setting new time and now I got timers and a sorta minimal calender support. Programming in SB is always a tradeoff of what inputs fast, holds some value to re-reading the code, and what keeps good namespace.. obviously I'd run out of namespace as it quickly turns into abbreviations for object names but ohwell. No inheritance, but objects can have "references" to other objects.. its just an index afterall. If you are dealing with AX and AY array for aliens. sure that works. and it is very easy to input. You got an "object" or "index" you just need to write the functions on what to do with it. so you get the nice function names that are backwards of the dot operator version
Apple1.set_color("red") 'turns into AppleSet_color(Apple1,"red")the goal of object based is to get it so you don't have to type as much, and can forget the nuances of array definition and access... so using the libraries seems the way to go when your objects differ so much from each other that they need their own unique fields that aren't useable by other functions etc.