|
Post by eyfenna on Jul 30, 2019 9:31:26 GMT -6
Heya,
while RCBasic offers a lot of functionality yet I found that for sprite-sheet drawing entire canvases calling drawImage_blit for each part of the canvas to be drawn feels like a hassle. To fill a 800x600 window with a 80x60 picture out of a sprite sheet leads to 100 times entering image slot, the two coordinates of the upper left corner, the two coordinates of the upper left corner of subpicture on the sourceimage, the width and height of subpicrture overall 700 numbers to juggle with. In so far it seems that a bit of restructuring or creating extra functions is worthwhile. To reduce the calls to maybe three numbers, subpicture are stored in a series of arrays that hold the data of from which image slot is drawn, the src-x,src-y,src-w,src-h entries. A function that adds a picture and one function that calls DrawImage_Blit is provided, additional one for changing src-x and src-y required for spritesheets that have "moving" sprites like a figure looking like running.
The number of pictures is 5000 in the below code, more picture space can be created by increasing the size of the arrays.
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000]
sub addPic(picnum, slot, src_x,src_y,src_w, src_h) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 end if end sub
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub
sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
More functions might be added in the future
|
|
|
Post by eyfenna on Jul 31, 2019 12:55:34 GMT -6
As for an example from a simple spritesheet of ground tiles following code
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000] sub addPic(picnum, slot, src_x,src_y,src_w, src_h) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 end if end sub sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
WindowOpen ( 0, "TEST WINDOW", 100, 100, 640, 480, 0 ) CanvasOpen ( 0, 640, 480, 0, 0, 640, 480, 0 ) SetColor( RGB ( 255, 255, 255 ) ) loadImage(0,"ground2.png") addPic(0,0,1,1,15,15) addPic(1,0,1,17,15,15) addPic(2,0,17,1,15,15) addPic(3,0,17,17,15,15) addPic(4,0,1,33,15,15)
while true drawblit(0,0,0) drawblit(1,0,15) drawblit(2,0,30) drawblit(3,0,45) drawblit(4,0,60) Update ( ) wend returns a quick lineup of the five grass tiles:
still it does end up as a lot of code to fill a single window this way, therefore next part is to write a subroutine to fill a lot of space in a easy to write manner.
|
|
|
Post by eyfenna on Aug 1, 2019 10:28:12 GMT -6
This time I introduce a subroutine which uses drawblit(picnum, x,y) and fills an entire window with tiles.
For the example I created a tilesheet with four different 70x70 px tiles which can be viewed here.
The new concept introduced is called field, a single field is 10x10 subpic drawn as a rectangle, therefore it holds 100 subpic numbers plus the topleft edge coordinate of the field as well as a variable that stores if a field exists by either being set to 0 (doesn't exist) or a different number. If the single tile is very small (like 15x15 px in the post before) several fields will be needed to fill a window. For a generous start an amount of 100 fields seem sufficient. Thus two arrays are created:
dim field[100,102] dim fielde[100] As with fields it is possible to fill a canvas larger then the screen which might lead to fields being drawn which are not shown and even when the canvas moves are not going to be shown in a short while leading to wasted draw calls. A counter measure to massive redundant draw calls is called culling in game engines.
I establish a simple method of culling for canvases that move by only drawing what is within the window dimension plus one times the length of a field edge this gives an invisible rectangle around the window. If edges of a field are outside the rectangle then it is not drawn. Starting with a simple sub that takes the fieldnumber to be drawn the windows width and height as well as the offset of the canvas on which is drawn and defining two variables and an array the first check is if a field "exists":
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then 'more is entered here end if end sub The next step is to calculate the endges of the reactangle that the field occupies and do the culling through an if then check:
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = field[fieldnum,0] fieldy = field[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then 'culling check 'if the culling check is passed more happens here ' end if end if end sub
Arriving at the point of drawing the next part of the subroutine is to calculate the position where each subpic will be drawn and call drawblit
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = field[fieldnum,0] fieldy = field[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then for i = 2 to 101 xpos = (i - 2) mod 10 ypos = ((i - 2) / 10 ) mod 10 drawx = fieldx + picsw[field[fieldnum,i]]*xpos drawy = fieldy + picsh[field[fieldnum,i]]*ypos picnum = field[fieldnum,i] drawblit(picnum,drawx,drawy) next end if end if end sub
If anyone wonders about the ypos calculation, (i-2)/10 returns a comma number leading to a "stairs effect" doing a rest division or modulo 10 gives an integer value.
This function inside the sourcecode and after setting one hundret and two members of one field produces the output viewable here.
The whole sourcecode is:
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000]
sub addPic(picnum, slot, src_x,src_y,src_w, src_h) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 end if end sub
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
dim field[100,102] dim fielde[100]
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = fieldsection[fieldnum,0] fieldy = fieldsection[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then for i = 2 to 101 xpos = (i - 2) mod 10 ypos = ((i - 2) / 10 ) mod 10 drawx = fieldx + picsw[field[fieldnum,i]]*xpos drawy = fieldy + picsh[field[fieldnum,i]]*ypos picnum = field[fieldnum,i] drawblit(picnum,drawx,drawy) next end if end if end sub
WindowOpen ( 0, "TEST WINDOW", 100, 100, 640, 480, 0 ) CanvasOpen ( 0, 640, 480, 0, 0, 640, 480, 0 )
loadImage(0,"exampleground.png") addPic(0,0,1,1,70,70) addPic(1,0,1,72,70,70) addPic(2,0,72,1,70,70) addPic(3,0,72,72,70,70)
fielde[0] =1 field[0,0] = 0 : field[0,1] =0 field[0,2] = 0 : field[0,3] = 0 : field[0,4] = 3 : field[0,5] = 1 : field[0,6] = 0 : field[0,7] = 0 : field[0,8] = 0 : field[0,9] = 0 : field[0,10] = 0 : field[0,11] =0 field[0,12] = 0 : field[0,13] = 1 : field[0,14] = 3 : field[0,15] = 0 :field[0,16] = 2 : field[0,17] = 2: field[0,18] = 2: field[0,19] = 2 : field[0,20] = 2 : field[0,21] = 2 field[0,22] = 0 : field[0,23] = 0 : field[0,24] = 3 : field[0,25] = 0 : field[0,26] = 2 : field[0,27] = 1 : field[0,28] = 0 : field[0,29] = 0 : field[0,30] = 0 : field[0,31] = 0 field[0,32] = 1 : field[0,33] = 0 : field[0,34] = 3 : field[0,35] = 0 : field[0,36] = 2 : field[0,37] = 0 : field[0,38] = 0 : field[0,39] = 0 : field[0,40] = 1 : field[0,41] = 0 field[0,42] = 0 : field[0,43] = 0 : field[0,44] = 3 : field[0,45] = 0 : field[0,46] = 2 : field[0,47] = 0 : field[0,48] = 1 : field[0,49] = 0 : field[0,50] = 0 : field[0,51] = 0 field[0,52] = 3 : field[0,53] = 3 : field[0,54] = 3 : field[0,55] = 3 : field[0,56] = 3 : field[0,57] = 3 : field[0,58] = 3 : field[0,59] = 3 : field[0,60] = 3 : field[0,61] = 3 field[0,62] = 0 : field[0,63] = 1 : field[0,64] = 0 : field[0,65] = 1 : field[0,66] = 2 : field[0,67] = 0 : field[0,68] = 0 : field[0,69] = 0 : field[0,70] = 0 : field[0,71] = 0 field[0,72] = 0 : field[0,73] = 0 : field[0,74] = 0 : field[0,75] = 0 : field[0,76] = 2 : field[0,77] = 0 : field[0,78] = 0 : field[0,79] = 1 : field[0,80] = 0 : field[0,81] = 0 field[0,82] = 1 : field[0,83] = 0 : field[0,84] = 1 : field[0,85] = 0 : field[0,86] = 2 : field[0,87] = 2 : field[0,88] = 2 : field[0,89] = 2 : field[0,90] = 2 : field[0,91] = 2 field[0,92] = 0 : field[0,93] = 1 : field[0,94] = 0 : field[0,95] = 0 : field[0,96] = 0 : field[0,97] = 1 : field[0,98] = 0 : field[0,99] = 0 : field[0,100] = 0 : field[0,101] = 0
while true drawField(0,640,480,0,0) Update ( ) wend
Still it is obvious that a lot of datas have to be written in code, which can make it unreadable. An external file which things are read from thus separating data from code seems like a nice idea here.
|
|
|
Post by tbird on Aug 2, 2019 9:13:00 GMT -6
Nicely done on simplifying the process, I personally don't use sprite sheets, but I see the appeal.
|
|
|
Post by johnno56 on Aug 2, 2019 20:27:29 GMT -6
eyfenna, On my machine, I needed to place a 'clearcanvas' just before the 'while loop', because I was getting all kinds of artefacts... Your sprites displayed as they should, but the rest of the screen, was filled with what I would call 'screen garbage'. The clearcanvas did the trick and displayed only your sprites.... So, in a nutshell, you have coded an RC program to slice sprites off a spritesheet.... Cool. This would be handy for those that are not familiar with graphics editor. Nicely done! I am also going to assume that, now one has a method of extracting and storing said sprites, one could use these images to create a "tile-based" game? Cool. Looking forward to your 'next phase'... J
|
|
|
Post by eyfenna on Aug 3, 2019 5:49:45 GMT -6
Okay as I implied in my last post, a field has a lot of entries which can obfusciate the readability of the source code, on the other hand tbird reminded me that I had another basic techique available for spritesheets being animations. Thanks for your nice and motivating posts tbird and jhonno by the way.
This time I will separate code from data. For a quick definition code is that what does things, and data is that with which things are done. The definitions are entirely correct but for this post they are enough correct to be understandable. RCBasic already separates code from data when it comes to images. No one on this forum would think about writing an encoded image of the ufo or car he/she uses in code. Besides png encoding is weird to write with hand.
In RCBasic an image is loaded from a image file and then used. Similar is the reasoning to separate the displaying one or several fields from the place where the dat about the field is stored. I have added an attachment of a complete layout window to this post it will be used later.
For the example later a increased spritesheet based on the one in the second posting is used. As you can measure in a graphic program each tile is 15x15 px large, filling a window required some 20 fields or 2000 datas.
For the start I have to decided in which format I store the data, here I decide to store it in text format and a simple *.txt file. To load a file in RCBasic the built in function is:
FileOpen ( stream, fileName$, mode ) For the subroutine I build I decide to provide the filename in the call, reading a text and use stream one:
fileopen(1,filename,TEXT_INPUT)
and not forgetting to close the file after using it the first and last commands of the subroutine are therefore
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) '...more here later fileclose(1) end sub
While the file is open a loop will run until the end of the file:
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then
'... here the actual loading of data from the file happens
else truth = false end if wend fileclose(1) end sub Now I am at the point that I need to decide how to read in my data, do I highlight it someway so that only specific data is used or that during the reading process that subroutine can decide what data belongs to where. I decide for a field data I highlight it by writing an "F" at the first position.
Second do I write the data one after another or do I put in a delimiter. For the start I decide to put in a delimiter being a ',' now this is nice for writing the file and clearly readable. However in this case I need a function to calculate the delimiter out and think about how to approach each value. Afterall I decide I read from the position of the single data to several characters long and then find a string that is before the first comma:
function findBeforeComma$(substr$) '... the string is evalutated return substr end function this is the first form of the function that takes in a string with comma and returns a string before a comma.
As several commas might be in a string I decide to go through a while loop until no comma is in the string anynore and each iteration of the loop the length of the string is shortened:
function findBeforeComma$(substr$) tv = true while(tv) if InStr(substr,",") <> -1 then 'InStr returns -1 if in "," is not found in substr strl = length(substr) -1 substr = Left$(substr,strl) else tv = false end if wend return substr end function
Now I can return to the first subroutine and work on it some more so far I have:
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then
'... here the actual loading of data from the file happens
else truth = false end if wend fileclose(1) end sub a single field is an array of 102 elements, an additional element in the fielde array and for the highlight purpose a "F" in the beginning. That is 104 entries separated by commas in each line.
The subroutine reads a line checks wether there is a "F" in the beginning of the line and if the line starts with "F" it procedes with reading the number of the field described in the line, then follow the x and y position of a field and last the 100 elements that name the pic which is displayed at a location within the field. If the line starts with something else then "F" the values are discarded.
First the position from reading the fieldnumber is set, then two string variables named fieldpos to make it understandable that the number stored is a position value and fieldval for other values are created:
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then output$ = readline(1) pos = 2 dim fieldpos$ dim fieldval$ if instr(output, "F") <> -1 then '... here the actual loading of data from the file happens end if else truth = false end if wend fileclose(1) end sub Now its time to read in the rest of the line and put it into specific arrays. After reading in a entry in the line as a string through the in built Mid$ function and shortening it with the
findBeforeComma$ function written above the position counter has to be increased by the length of the outcome string +1.
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then output$ = readline(1) pos = 2 dim fieldpos$ dim fieldval$ if instr(output, "F") <> -1 then
'... for the number of the field to set it as visible in the fielde array, the number of the field is stored in the variable SN fieldval = findBeforeComma$(MId$(output,pos,6)) pos = pos + length(fieldval)+1 SN = VAL(fieldval) fielde[SN] = 1
'...the x position of the field fieldpos = findBeforeComma$(Mid$(output,pos,6)) pos = pos + length(fieldpos)+1 field[SN,0] = VAL(fieldpos) -150
'....y position of the field fieldpos = findBeforeComma$(MId$(output,pos,6)) field[SN,1] = VAL(fieldpos)-150 pos = pos + length(fieldpos)+1
'... the 100 entires that tell which subpic or tile is going to be drawn for i = 2 to 101 fieldval = findBeforeComma$(Mid$(output,pos,5)) field[SN,i] = VAL(fieldval) pos = pos + length(fieldval)+1 next end if else truth = false end if wend fileclose(1) end sub
Now we arrived at the point where we can put together the source code with the one from my last positng:
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000]
sub addPic(picnum, slot, src_x,src_y,src_w, src_h) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 end if end sub
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub
sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
dim field[100,102] dim fielde[100]
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = field[fieldnum,0] fieldy = field[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then for i = 2 to 101 xpos = (i - 2) mod 10 ypos = ((i - 2) / 10 ) mod 10 drawx = fieldx + picsw[field[fieldnum,i]]*xpos drawy = fieldy + picsh[field[fieldnum,i]]*ypos picnum = field[fieldnum,i] drawblit(picnum,drawx,drawy) next end if end if end sub
function findBeforeComma$(substr$) tv = true while(tv) if InStr(substr,",") <> -1 then strl = length(substr) -1 substr = Left$(substr,strl) else tv = false end if wend return substr end function
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then output$ = readline(1) pos = 2 dim fieldpos$ dim fieldval$ if instr(output, "F") <> -1 then fieldval = findBeforeComma$(Mid$(output,pos,6)) pos = pos + length(fieldval)+1 SN = VAL(fieldval) fielde[SN] = 1 fieldpos = findBeforeComma$(Mid$(output,pos,6)) pos = pos + length(fieldpos)+1 field[SN,0] = VAL(fieldpos) -150 fieldpos = findBeforeComma$(MId$(output,pos,6)) field[SN,1] = VAL(fieldpos)-150 pos = pos + length(fieldpos)+1 for i = 2 to 101 fieldval = findBeforeComma$(Mid$(output,pos,5)) field[SN,i] = VAL(fieldval) pos = pos + length(fieldval)+1 next end if else truth = false end if wend fileclose(1) end sub
WindowOpen ( 0, "TEST WINDOW", 100, 100, 640, 480, 0 ) CanvasOpen ( 0, 640, 480, 0, 0, 640, 480, 0 ) loadImage(0,"ground2.png") addPic(0,0,1,1,15,15) addPic(1,0,1,17,15,15) addPic(2,0,17,1,15,15) addPic(3,0,17,17,15,15) addPic(4,0,1,33,15,15) addPic(5,0,33,1,15,15) addPic(6,0,33,17,15,15) addPic(7,0,33,33,15,15) addPic(8,0,33,49,15,15) addPic(9,0,33,65,15,15) addPic(10,0,49,1,15,15) addPic(11,0,49,17,15,15) addPic(12,0,49,33,15,15) addPic(13,0,49,49,15,15) addPic(14,0,65,1,15,15) addPic(15,0,65,17,15,15) addPic(16,0,65,33,15,15) addPic(17,0,65,49,15,15) addPic(18,0,81,1,15,15) addPic(19,0,81,17,15,15) addPic(20,0,97,1,15,15) addPic(21,0,97,17,15,15) addPic(22,0,97,33,15,15) addPic(23,0,97,49,15,15)
buildFieldfromFile("level1.txt")
while true clearcanvas
drawField(0,640,480,0,0) drawField(1,640,480,0,0) drawField(2,640,480,0,0) drawField(3,640,480,0,0) drawField(4,640,480,0,0) drawField(5,640,480,0,0) drawField(6,640,480,0,0) drawField(7,640,480,0,0) drawField(8,640,480,0,0) drawField(9,640,480,0,0) drawField(10,640,480,0,0) drawField(11,640,480,0,0) drawField(12,640,480,0,0) drawField(13,640,480,0,0) drawField(14,640,480,0,0) drawField(15,640,480,0,0) drawField(16,640,480,0,0) drawField(17,640,480,0,0) drawField(18,640,480,0,0) drawField(19,640,480,0,0)
Update ( ) wend
If everything is without typos then following window should appear:
current windowAttachments:level1.txt (4.38 KB)
|
|
|
Post by eyfenna on Aug 5, 2019 10:06:19 GMT -6
I corrected some sourcecode typos in the posting before, it should compile now.
Today I introduce Tzir, a peasant of the lush valley of Femru. Tzir is going to assist in introducing animations. The spritsheet of Tzir is in the attachment of the post. An animation with 2d pictures is created by switching between different images in a fixed order.
Spritesheets are handy for this as not the whole image has to be changed instead only the source-x and source-y need to be modified. With drawBlit this means that after displaying the first subpicture, the source coordinate on the spritesheet is changed replacig the first picture and so on, until a last picture is reached and then source coordinate returns to the position of origin eahc picture is one frame of the animation.
The source code already has a function to change the source coordinates of a specific subpicture on a spritesheet:
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub and a spritesheet of Tzir with a fixed distance between each subpicture, so all that is needed now is a counter that after a fixed time interval increases the framnumber to the total ammount of frames - 1 and then resets to frame 0. Now it is possible to do this per hand each time needed.
A better solution is to make a reusable system, first the computer needs to be told that there is a animation related to one of the pictures, and as it is reasonable that many animations are used in a game thus connect this to a specific number. Also the infor ont he maximum frames and the x and y distance between each sprite on the sheet are needed. Additional an animation like for a one time switchable lever might not return to the original picture, this gives us the hull for following subroutine:
sub registerAnimation(number, basepicture, maxframes, reversable, xdistance, ydistance) end sub
for the program 1000 animations seems like a reasonable ammount. The number itself serves as the index of several arrays representing a single animation:
dim anime[1000] dim animp[1000] dim animf[1000] dim animr[1000] dim animx[1000] dim animy[1000] dim animdx[1000] dim animdy[1000]
anime stores if an animation is used, animp the number of the picture, animf the ammount of frames, animr if it is revesable represented through 0 or a number different from 0,
animx the source-x of the basepicture, animy the source-y of the basepicture, animdx and animdy the distance between each frame.
the registerAnimation function writes the required values in the specific array index:
sub registerAnimation(number, basepicture, maxframes, reversable, xdistance, ydistance) anime[number] = 1 animp[number] = basepicture animf[number] = maxframes animr[number] = reversable animx[number] = picsx[animp[number]] animy[number] = picsy[animp[number]] animdx[number] = xdistance animdy[number] = ydistance end sub the second part is a subroutine that plays the animation. The process is following:
each time it is called the animation number and the time at the start of the current loop is handed to this subroutine. Then this time is subtracted form the current time to get a timeinterval. This timeinterval is added to a collected timeimterval. If this collected timeinterval is greater then 1000ms / 16 frames (~ 62ms/frame) the current frame count is increased and the collected timeinterval set to zero. If the current frame count is greater than the maximum frame count the current frame count a check is done if the animation is reversable. If true then the current frame count is reset to zero, else it sticks at the maximum frame number.
The current frame count is multiplied with the distance between each frame and added to the source coordinates of the basepicture.
To achieve this two additional arrays are needed for animations:
dim animt[1000] dim animfc[1000]
The hull of the subroutine for playanimation is pretty simple:
sub playanimation(number, timing)
end sub
as described above the calculation of the time interval and the increasing of the frame after 62 ms
sub playanimation(number, timing) currtime = timer - timing animt[number] = animt[number] + currtime if animt[number] > 62 then animfc[number] = animfc[number] + 1 animt[number] = 0 end if '... end sub
Next step when current framecount is larger then maximum frame count checking if it is reversable - current frame count becomes zero - or not - current frame count stays at maximum value.
sub playanimation(number, timing) currtime = timer - timing animt[number] = animt[number] + currtime if animt[number] > 62 then animfc[number] = animfc[number] + 1 animt[number] = 0 end if if animfc[number] > animf[number] then if animr[number] = 0 then animfc[number] = animf[number] elseif animr[number] = 1 then animfc[number] = 0 end if end if '..... end sub and last calculating the source coordinates of the new frame:
sub playanimation(number, timing) currtime = timer - timing animt[number] = animt[number] + currtime if animt[number] > 62 then animfc[number] = animfc[number] + 1 animt[number] = 0 end if if animfc[number] > animf[number] then if animr[number] = 0 then animfc[number] = animf[number] elseif animr[number] = 1 then animfc[number] = 0 end if end if x = (animfc[number]*animdx[number] + animx[number]) y = (animfc[number]*animdy[number] + animy[number]) modifiySourceXY(animp[number],x ,y) end sub
Last one subroutine is required not only for the resetting the one time switch lever yet also when a character sprite moves for a while and then stops, it might end up on the original frame where the character stands or it might end up on a frame in the middle of walking. As the playanimation function doesn't do this a subroutine which resets the frame to the base picture is needed:
sub resetAnimation(number) modifiySourceXY(animp[number],animx[number], animy[number]) animfc[number] = 0 end sub
simply said it resets the the picture to the source x and y of the basepicture and the current frame count to zero.
Now its time to put the above into the source code:
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000]
sub addPic(picnum, slot, src_x,src_y,src_w, src_h) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 end if end sub
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub
sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
dim field[100,102] dim fielde[100]
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = field[fieldnum,0] fieldy = field[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then for i = 2 to 101 xpos = (i - 2) mod 10 ypos = ((i - 2) / 10 ) mod 10 drawx = fieldx + picsw[field[fieldnum,i]]*xpos drawy = fieldy + picsh[field[fieldnum,i]]*ypos picnum = field[fieldnum,i] drawblit(picnum,drawx,drawy) next end if end if end sub
function findBeforeComma$(substr$) tv = true while(tv) if InStr(substr,",") <> -1 then strl = length(substr) -1 substr = Left$(substr,strl) else tv = false end if wend return substr end function
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then output$ = readline(1) pos = 2 dim fieldpos$ dim fieldval$ if instr(output, "F") <> -1 then fieldval = findBeforeComma$(MId$(output,pos,6)) pos = pos + length(fieldval)+1 SN = VAL(fieldval) fielde[SN] = 1 fieldpos = findBeforeComma$(Mid$(output,pos,6)) pos = pos + length(fieldpos)+1 field[SN,0] = VAL(fieldpos) -150 fieldpos = findBeforeComma$(MId$(output,pos,6)) field[SN,1] = VAL(fieldpos)-150 pos = pos + length(fieldpos)+1 for i = 2 to 101 fieldval = findBeforeComma$(Mid$(output,pos,5)) field[SN,i] = VAL(fieldval) pos = pos + length(fieldval)+1 next end if else truth = false end if wend fileclose(1) end sub
dim anime[1000] dim animp[1000] dim animf[1000] dim animr[1000] dim animt[1000] dim animfc[1000] dim animx[1000] dim animy[1000] dim animdx[1000] dim animdy[1000]
sub registerAnimation(number, basepicture, maxframes, reversable, xdistance, ydistance) anime[number] = 1 animp[number] = basepicture animf[number] = maxframes animr[number] = reversable animx[number] = picsx[animp[number]] animy[number] = picsy[animp[number]] animdx[number] = xdistance animdy[number] = ydistance end sub
sub resetAnimation(number) modifiySourceXY(animp[number],animx[number], animy[number]) animfc[number] = 0 end sub
sub playanimation(number, timing) currtime = timer - timing animt[number] = animt[number] + currtime if animt[number] > 62 then animfc[number] = animfc[number] + 1 animt[number] = 0 end if if animfc[number] > animf[number] then if animr[number] = 0 then animfc[number] = animf[number] elseif animr[number] = 1 then animfc[number] = 0 end if end if x = (animfc[number]*animdx[number] + animx[number]) y = (animfc[number]*animdy[number] + animy[number]) modifiySourceXY(animp[number],x ,y) end sub
WindowOpen ( 0, "TEST WINDOW", 100, 100, 640, 480, 0 ) CanvasOpen ( 0, 640, 480, 0, 0, 640, 480, 0 ) loadImage(0,"ground2.png") addPic(0,0,1,1,15,15) addPic(1,0,1,17,15,15) addPic(2,0,17,1,15,15) addPic(3,0,17,17,15,15) addPic(4,0,1,33,15,15) addPic(5,0,33,1,15,15) addPic(6,0,33,17,15,15) addPic(7,0,33,33,15,15) addPic(8,0,33,49,15,15) addPic(9,0,33,65,15,15) addPic(10,0,49,1,15,15) addPic(11,0,49,17,15,15) addPic(12,0,49,33,15,15) addPic(13,0,49,49,15,15) addPic(14,0,65,1,15,15) addPic(15,0,65,17,15,15) addPic(16,0,65,33,15,15) addPic(17,0,65,49,15,15) addPic(18,0,81,1,15,15) addPic(19,0,81,17,15,15) addPic(20,0,97,1,15,15) addPic(21,0,97,17,15,15) addPic(22,0,97,33,15,15) addPic(23,0,97,49,15,15) buildFieldfromFile("level1.txt") while true clearcanvas drawField(0,640,480,0,0) drawField(1,640,480,0,0) drawField(2,640,480,0,0) drawField(3,640,480,0,0) drawField(4,640,480,0,0) drawField(5,640,480,0,0) drawField(6,640,480,0,0) drawField(7,640,480,0,0) drawField(8,640,480,0,0) drawField(9,640,480,0,0) drawField(10,640,480,0,0) drawField(11,640,480,0,0) drawField(12,640,480,0,0) drawField(13,640,480,0,0) drawField(14,640,480,0,0) drawField(15,640,480,0,0) drawField(16,640,480,0,0) drawField(17,640,480,0,0) drawField(18,640,480,0,0) drawField(19,640,480,0,0) Update ( ) wend And now in comes Tzir, loading the spritesheet and adding the basepictures is simple:
loadImage(1,"tzir.png") addPic(24,1,1,1,30,30) addPic(25,1,1,31,30,30) addPic(26,1,1,62,30,30) addPic(27,1,1,92,30,30)
the next step is to register the animations on each basepicture:
registerAnimation(0,24,5,1,31,0) registerAnimation(1,25,5,1,31,0) registerAnimation(2,26,5,1,31,0) registerAnimation(3,27,5,1,31,0)
As the spritesheet has pictures of Tzir moving in the four cardinal directions and moving over the screen three variables are needed:
fx = 0 fy = 330 direction = 0
now it is possible to show Tzir depending on the direction set:
if direction = 0 then drawblit(24,fx,fy) elseif direction = 2 then drawblit(25,fx,fy) elseif direction = 1 then drawblit(26,fx,fy) elseif direction = 3 then drawblit(27,fx,fy) end if still adding this to the source code will only show a static image, a trigger for the animation is needed and as it is a moving animation this trigger can also change the postion of Tzir on the screen:
if Key(K_D) and fx < 610 then direction = 0 fx = fx +0.5 playanimation(0,timing) elseif Key(K_A) and fx > 0 then direction = 2 fx = fx - 0.5 playanimation(1,timing) elseif Key(K_W) and fy > 0 then direction = 1 fy = fy -0.5 playanimation(2,timing) elseif Key(K_S) and fy < 450 then direction = 3 fy = fy + 0.5 playanimation(3,timing) else resetAnimation(0) resetAnimation(1) resetAnimation(2) resetAnimation(3) end if Putting all together the complete sourcecode is:
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000]
sub addPic(picnum, slot, src_x,src_y,src_w, src_h) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 end if end sub
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub
sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
dim field[100,102] dim fielde[100]
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = field[fieldnum,0] fieldy = field[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then for i = 2 to 101 xpos = (i - 2) mod 10 ypos = ((i - 2) / 10 ) mod 10 drawx = fieldx + picsw[field[fieldnum,i]]*xpos drawy = fieldy + picsh[field[fieldnum,i]]*ypos picnum = field[fieldnum,i] drawblit(picnum,drawx,drawy) next end if end if end sub
function findBeforeComma$(substr$) tv = true while(tv) if InStr(substr,",") <> -1 then strl = length(substr) -1 substr = Left$(substr,strl) else tv = false end if wend return substr end function
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then output$ = readline(1) pos = 2 dim fieldpos$ dim fieldval$ if instr(output, "F") <> -1 then fieldval = findBeforeComma$(MId$(output,pos,6)) pos = pos + length(fieldval)+1 SN = VAL(fieldval) fielde[SN] = 1 fieldpos = findBeforeComma$(Mid$(output,pos,6)) pos = pos + length(fieldpos)+1 field[SN,0] = VAL(fieldpos) -150 fieldpos = findBeforeComma$(MId$(output,pos,6)) field[SN,1] = VAL(fieldpos)-150 pos = pos + length(fieldpos)+1 for i = 2 to 101 fieldval = findBeforeComma$(Mid$(output,pos,5)) field[SN,i] = VAL(fieldval) pos = pos + length(fieldval)+1 next end if else truth = false end if wend fileclose(1) end sub
dim anime[1000] dim animp[1000] dim animf[1000] dim animr[1000] dim animt[1000] dim animfc[1000] dim animx[1000] dim animy[1000] dim animdx[1000] dim animdy[1000]
sub registerAnimation(number, basepicture, maxframes, reversable, xdistance, ydistance) anime[number] = 1 animp[number] = basepicture animf[number] = maxframes animr[number] = reversable animx[number] = picsx[animp[number]] animy[number] = picsy[animp[number]] animdx[number] = xdistance animdy[number] = ydistance end sub
sub resetAnimation(number) modifiySourceXY(animp[number],animx[number], animy[number]) animfc[number] = 0 end sub
sub playanimation(number, timing) currtime = timer - timing animt[number] = animt[number] + currtime if animt[number] > 62 then animfc[number] = animfc[number] + 1 animt[number] = 0 end if if animfc[number] > animf[number] then if animr[number] = 0 then animfc[number] = animf[number] elseif animr[number] = 1 then animfc[number] = 0 end if end if x = (animfc[number]*animdx[number] + animx[number]) y = (animfc[number]*animdy[number] + animy[number]) modifiySourceXY(animp[number],x ,y) end sub
WindowOpen ( 0, "TEST WINDOW", 100, 100, 640, 480, 0 ) CanvasOpen ( 0, 640, 480, 0, 0, 640, 480, 0 ) loadImage(0,"ground2.png") addPic(0,0,1,1,15,15) addPic(1,0,1,17,15,15) addPic(2,0,17,1,15,15) addPic(3,0,17,17,15,15) addPic(4,0,1,33,15,15) addPic(5,0,33,1,15,15) addPic(6,0,33,17,15,15) addPic(7,0,33,33,15,15) addPic(8,0,33,49,15,15) addPic(9,0,33,65,15,15) addPic(10,0,49,1,15,15) addPic(11,0,49,17,15,15) addPic(12,0,49,33,15,15) addPic(13,0,49,49,15,15) addPic(14,0,65,1,15,15) addPic(15,0,65,17,15,15) addPic(16,0,65,33,15,15) addPic(17,0,65,49,15,15) addPic(18,0,81,1,15,15) addPic(19,0,81,17,15,15) addPic(20,0,97,1,15,15) addPic(21,0,97,17,15,15) addPic(22,0,97,33,15,15) addPic(23,0,97,49,15,15)
loadImage(1,"tzir.png") addPic(24,1,1,1,30,30) addPic(25,1,1,31,30,30) addPic(26,1,1,62,30,30) addPic(27,1,1,92,30,30)
registerAnimation(0,24,5,1,31,0) registerAnimation(1,25,5,1,31,0) registerAnimation(2,26,5,1,31,0) registerAnimation(3,27,5,1,31,0)
buildFieldfromFile("level1.txt")
fx = 0 fy = 330 direction = 0 while true clearcanvas timing = timer drawField(0,640,480,0,0) drawField(1,640,480,0,0) drawField(2,640,480,0,0) drawField(3,640,480,0,0) drawField(4,640,480,0,0) drawField(5,640,480,0,0) drawField(6,640,480,0,0) drawField(7,640,480,0,0) drawField(8,640,480,0,0) drawField(9,640,480,0,0) drawField(10,640,480,0,0) drawField(11,640,480,0,0) drawField(12,640,480,0,0) drawField(13,640,480,0,0) drawField(14,640,480,0,0) drawField(15,640,480,0,0) drawField(16,640,480,0,0) drawField(17,640,480,0,0) drawField(18,640,480,0,0) drawField(19,640,480,0,0)
if Key(K_D) and fx < 610 then direction = 0 fx = fx +0.5 playanimation(0,timing) elseif Key(K_A) and fx > 0 then direction = 2 fx = fx - 0.5 playanimation(1,timing) elseif Key(K_W) and fy > 0 then direction = 1 fy = fy -0.5 playanimation(2,timing) elseif Key(K_S) and fy < 450 then direction = 3 fy = fy + 0.5 playanimation(3,timing) else resetAnimation(0) resetAnimation(1) resetAnimation(2) resetAnimation(3) end if
if direction = 0 then drawblit(24,fx,fy) elseif direction = 2 then drawblit(25,fx,fy) elseif direction = 1 then drawblit(26,fx,fy) elseif direction = 3 then drawblit(27,fx,fy) end if Update ( ) wend
Attachments:
|
|
|
Post by eyfenna on Aug 7, 2019 11:25:00 GMT -6
Last tip and trick in this thread: Collision detection.
As you will have noticed when compiling and executig the final source code of the last posting, Tzir does walk around within then window. However if the blue fields are water then Tzir also walks over water and that though cool is not intended. In so far it is time to add a simple collision detection. To do this a new array is itroduced for each tile which holds a block value, later this block value is scanned for at a point on each side of Tzir's sprite and if it has a value that the program interpretates as blocked field then no movement is done by Tzir. So far the plan. On to modify the sourcecode.
The first thing is to add the array to hold the block values for a pic, just below the other subpicture related arrays therefore in line 7 following code is added:
dim picb[5000]
the addPic subroutine also gets an additional line an a additional call value:
sub addPic(picnum, slot, src_x,src_y,src_w, src_h, blockvalue) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 -> picb[picnum] = blockvalue <- new line end if end sub
The other subroutines stay the same as they are, what needs to be done also is to add a blockvalue on each line a picture is added. For the moment 0 means no block and 1 means a block
loadImage(0,"ground2.png") addPic(0,0,1,1,15,15,0) addPic(1,0,1,17,15,15,0) addPic(2,0,17,1,15,15,0) addPic(3,0,17,17,15,15,0) addPic(4,0,1,33,15,15,0) addPic(5,0,33,1,15,15,1) addPic(6,0,33,17,15,15,1) addPic(7,0,33,33,15,15,1) addPic(8,0,33,49,15,15,1) addPic(9,0,33,65,15,15,1) addPic(10,0,49,1,15,15,1) addPic(11,0,49,17,15,15,1) addPic(12,0,49,33,15,15,1) addPic(13,0,49,49,15,15,1) addPic(14,0,65,1,15,15,1) addPic(15,0,65,17,15,15,1) addPic(16,0,65,33,15,15,1) addPic(17,0,65,49,15,15,1) addPic(18,0,81,1,15,15,0) addPic(19,0,81,17,15,15,0) addPic(20,0,97,1,15,15,0) addPic(21,0,97,17,15,15,0) addPic(22,0,97,33,15,15,0) addPic(23,0,97,49,15,15,0)
loadImage(1,"tzir.png") addPic(24,1,1,1,30,30,0) addPic(25,1,1,32,30,30,0) addPic(26,1,1,63,30,30,0) addPic(27,1,1,94,30,30,0)
Now a function is needed which queries the block value of a singel field element on the screen, this depends on Tzir's position and returns the value of block of the specific fieldelement, by quering what number the fieldelement has:
function fieldvalue(px,py) return picb[field[fieldnum,fieldelem]] end function
To achieve this loop through each field and each fieldelement, it is reasonable to not loop through fieldelements which are in a field far away from the point entered into the function. Basically only fieldelements of the field in which the point entered into the function sits are looked at, therefore the coordinates of the field are calculated after checking if it exists:
function fieldvalue(px,py) dim fieldelem dim fieldnum for i = 0 to 99 if fielde[i] <> 0 then fieldx = field[i,0] fieldxs = field[i,0]+150 fieldy = field[i,1] fieldys = field[i,1] + 150 if px > fieldx and px < fieldxs and py > fieldy and py < fieldys then '... more here end if end if next return picb[field[fieldnum,fieldelem]] end function Additional with the position values calculated before looking at field elements and some math a bit of magic can be done requireing no further loop is necessary, as the coodinate given minus the upper left corner of the field provides us with the coordinate inside the fieldelement we want to know about, we need to divide this through the length of a fieldelement. For the tilesheet used above 15 and turn this into an integer value by a modulo 10 division. Then we have to return it to its number in the array that sets a field by inverting the calculation used for the place it is painted on:
dx = px - fieldx dy = py - fieldy xfield = (dx / 15) mod 10 yfield = (dy / 15) mod 10 fieldelem = yfield*10 + xfield +2 Last we need to store the value of the loop over all fields and voila we have the block value:
function fieldvalue(px,py) dim fieldelem dim fieldnum for i = 0 to 99 if fielde[i] <> 0 then fieldx = field[i,0] fieldxs = field[i,0]+150 fieldy = field[i,1] fieldys = field[i,1] + 150 if px > fieldx and px < fieldxs and py > fieldy and py < fieldys then fieldnum = i dx = px - fieldx dy = py - fieldy xfield = (dx / 15) mod 10 yfield = (dy / 15) mod 10 fieldelem = yfield*10 + xfield +2 end if end if next return picb[field[fieldnum,fieldelem]] end function
The next step is to query four points each at one side of Tzir, a block array is introduced for this above the fieldvalue function:
dim block[4]
And above the lines setting the movement done by Tzir they are first cleared to 0 and then filled by calling the function fieldvalue with the positions of the query points being in the middle of a side and 7 away from the border. Tzir's sprite is 30 px on each side therefore the values to be entered into the fieldvalue function are:
for i = 0 to 3 block[i] =0 next block[0] = fieldvalue(fx +37,fy + 15) block[1] = fieldvalue(fx+ 15,fy-7) block[2] = fieldvalue(fx -7,fy + 15) block[3] = fieldvalue(fx +15,fy+37) block[0] sits to the right side of the sprite
block[1] on top of the sprite block[2] to the left side of the sprite block[3] below the sprite.
Finally the conditions for moving are modified:
if Key(K_D) and block[0] <>1 and fx < 610 then direction = 0 fx = fx +0.5 playanimation(0,timing) elseif Key(K_A) and block[2] <> 1and fx > 0 then direction = 2 fx = fx - 0.5 playanimation(1,timing) elseif Key(K_W) and block[1] <> 1and fy > 0 then direction = 1 fy = fy -0.5 playanimation(2,timing) elseif Key(K_S) and block[3] <> 1 and fy < 450 then direction = 3 fy = fy + 0.5 playanimation(3,timing) else resetAnimation(0) resetAnimation(1) resetAnimation(2) resetAnimation(3) end if
Now all is ready to be tested:
Final sourcode of this thread:
dim picslot[5000] dim picsx[5000] dim picsy[5000] dim picsw[5000] dim picsh[5000] dim pice[5000] dim picb[5000]
sub addPic(picnum, slot, src_x,src_y,src_w, src_h, blockvalue) if pice[picnum] <> 0 then fprint("Already a picture at picnum ") print(picnum) else picslot[picnum] = slot picsx[picnum] = src_x picsy[picnum] = src_y picsw[picnum] = src_w picsh[picnum] = src_h pice[picnum] = 1 picb[picnum] = blockvalue end if end sub
sub modifiySourceXY(picnum, src_x, src_y) picsx[picnum] = src_x picsy[picnum] = src_y end sub
sub drawblit(picnum, x,y) if pice[picnum] =0 then fprint("No picture at ") print(picnum) else DrawImage_Blit ( picslot[picnum], x, y, picsx[picnum], picsy[picnum], picsw[picnum], picsh[picnum]) end if end sub
dim field[100,102] dim fielde[100]
sub drawField(fieldnum,windowsw, windowsh, offsetx, offsety) dim fieldx dim fieldy dim fieldedge[4] if fielde[fieldnum] <> 0 then fieldx = field[fieldnum,0] fieldy = field[fieldnum,1] piclength = picsw[field[fieldnum,2]] sidedimension = 10*piclength fieldedge[0] = fieldx fieldedge[1] = fieldx + sidedimension fieldedge[2] = fieldy fieldedge[3] = fieldy + sidedimension if fieldedge[0] > (offsetx - sidedimension) and fieldedge[1] < (windowsw + sidedimension+ offsetx) and fieldedge[2] > (offsety- sidedimension ) and fieldedge[3] < (windowsh + sidedimension + offsety) then for i = 2 to 101 xpos = (i - 2) mod 10 ypos = ((i - 2) / 10 ) mod 10 drawx = fieldx + picsw[field[fieldnum,i]]*xpos drawy = fieldy + picsh[field[fieldnum,i]]*ypos picnum = field[fieldnum,i] drawblit(picnum,drawx,drawy) next end if end if end sub
function findBeforeComma$(substr$) tv = true while(tv) if InStr(substr,",") <> -1 then strl = length(substr) -1 substr = Left$(substr,strl) else tv = false end if wend return substr end function
sub buildFieldfromFile(filename$) fileopen(1,filename,TEXT_INPUT) truth = true while(truth) if not EOF(1) then output$ = readline(1) pos = 2 dim fieldpos$ dim fieldval$ if instr(output, "F") <> -1 then fieldval = findBeforeComma$(MId$(output,pos,6)) pos = pos + length(fieldval)+1 SN = VAL(fieldval) fielde[SN] = 1 fieldpos = findBeforeComma$(Mid$(output,pos,6)) pos = pos + length(fieldpos)+1 field[SN,0] = VAL(fieldpos) -150 fieldpos = findBeforeComma$(MId$(output,pos,6)) field[SN,1] = VAL(fieldpos)-150 pos = pos + length(fieldpos)+1 for i = 2 to 101 fieldval = findBeforeComma$(Mid$(output,pos,5)) field[SN,i] = VAL(fieldval) pos = pos + length(fieldval)+1 next end if else truth = false end if wend fileclose(1) end sub
dim anime[1000] dim animp[1000] dim animf[1000] dim animr[1000] dim animt[1000] dim animfc[1000] dim animx[1000] dim animy[1000] dim animdx[1000] dim animdy[1000]
sub registerAnimation(number, basepicture, maxframes, reversable, xdistance, ydistance) anime[number] = 1 animp[number] = basepicture animf[number] = maxframes animr[number] = reversable animx[number] = picsx[animp[number]] animy[number] = picsy[animp[number]] animdx[number] = xdistance animdy[number] = ydistance end sub
sub resetAnimation(number) modifiySourceXY(animp[number],animx[number], animy[number]) animfc[number] = 0 end sub
sub playanimation(number, timing) currtime = timer - timing animt[number] = animt[number] + currtime if animt[number] > 62 then animfc[number] = animfc[number] + 1 animt[number] = 0 end if if animfc[number] > animf[number] then if animr[number] = 0 then animfc[number] = animf[number] elseif animr[number] = 1 then animfc[number] = 0 end if end if x = (animfc[number]*animdx[number] + animx[number]) y = (animfc[number]*animdy[number] + animy[number]) modifiySourceXY(animp[number],x ,y) end sub
dim block[4]
function fieldvalue(px,py) dim fieldelem dim fieldnum for i = 0 to 99 if fielde[i] <> 0 then fieldx = field[i,0] fieldxs = field[i,0]+150 fieldy = field[i,1] fieldys = field[i,1] + 150 if px > fieldx and px < fieldxs and py > fieldy and py < fieldys then fieldnum = i dx = px - fieldx dy = py - fieldy xfield = (dx / 15) mod 10 yfield = (dy / 15) mod 10 fieldelem = yfield*10 + xfield +2 end if end if next return picb[field[fieldnum,fieldelem]] end function
WindowOpen ( 0, "TEST WINDOW", 100, 100, 640, 480, 0 ) CanvasOpen ( 0, 640, 480, 0, 0, 640, 480, 0 ) loadImage(0,"ground2.png") addPic(0,0,1,1,15,15,0) addPic(1,0,1,17,15,15,0) addPic(2,0,17,1,15,15,0) addPic(3,0,17,17,15,15,0) addPic(4,0,1,33,15,15,0) addPic(5,0,33,1,15,15,1) addPic(6,0,33,17,15,15,1) addPic(7,0,33,33,15,15,1) addPic(8,0,33,49,15,15,1) addPic(9,0,33,65,15,15,1) addPic(10,0,49,1,15,15,1) addPic(11,0,49,17,15,15,1) addPic(12,0,49,33,15,15,1) addPic(13,0,49,49,15,15,1) addPic(14,0,65,1,15,15,1) addPic(15,0,65,17,15,15,1) addPic(16,0,65,33,15,15,1) addPic(17,0,65,49,15,15,1) addPic(18,0,81,1,15,15,0) addPic(19,0,81,17,15,15,0) addPic(20,0,97,1,15,15,0) addPic(21,0,97,17,15,15,0) addPic(22,0,97,33,15,15,0) addPic(23,0,97,49,15,15,0)
loadImage(1,"tzir.png") addPic(24,1,1,1,30,30,0) addPic(25,1,1,32,30,30,0) addPic(26,1,1,63,30,30,0) addPic(27,1,1,94,30,30,0)
registerAnimation(0,24,5,1,31,0) registerAnimation(1,25,5,1,31,0) registerAnimation(2,26,5,1,31,0) registerAnimation(3,27,5,1,31,0)
buildFieldfromFile("level1.txt")
fx = 0 fy = 330 direction = 0 while true clearcanvas timing = timer drawField(0,640,480,0,0) drawField(1,640,480,0,0) drawField(2,640,480,0,0) drawField(3,640,480,0,0) drawField(4,640,480,0,0) drawField(5,640,480,0,0) drawField(6,640,480,0,0) drawField(7,640,480,0,0) drawField(8,640,480,0,0) drawField(9,640,480,0,0) drawField(10,640,480,0,0) drawField(11,640,480,0,0) drawField(12,640,480,0,0) drawField(13,640,480,0,0) drawField(14,640,480,0,0) drawField(15,640,480,0,0) drawField(16,640,480,0,0) drawField(17,640,480,0,0) drawField(18,640,480,0,0) drawField(19,640,480,0,0)
for i = 0 to 3 block[i] =0 next block[0] = fieldvalue(fx +37,fy + 15) block[1] = fieldvalue(fx+ 15,fy-7) block[2] = fieldvalue(fx -7,fy + 15) block[3] = fieldvalue(fx +15,fy+37)
if Key(K_D) and block[0] <>1 and fx < 610 then direction = 0 fx = fx +0.5 playanimation(0,timing) elseif Key(K_A) and block[2] <> 1and fx > 0 then direction = 2 fx = fx - 0.5 playanimation(1,timing) elseif Key(K_W) and block[1] <> 1and fy > 0 then direction = 1 fy = fy -0.5 playanimation(2,timing) elseif Key(K_S) and block[3] <> 1 and fy < 450 then direction = 3 fy = fy + 0.5 playanimation(3,timing) else resetAnimation(0) resetAnimation(1) resetAnimation(2) resetAnimation(3) end if
if direction = 0 then drawblit(24,fx,fy) elseif direction = 2 then drawblit(25,fx,fy) elseif direction = 1 then drawblit(26,fx,fy) elseif direction = 3 then drawblit(27,fx,fy) end if Update ( ) wend
Abbendum:
I hope you enjoyed this thread about using tilesheets in games with RCBasic. If you have suggestions for improvements in my writing style let me know. This was my first coding tutorial.
|
|
|
Post by johnno56 on Aug 7, 2019 16:13:02 GMT -6
Very nicely done indeed...
|
|
|
Post by tbird on Aug 7, 2019 19:44:19 GMT -6
I concur, well written, very well explained. Good job.
|
|
|
Post by eyfenna on Sept 8, 2019 12:03:48 GMT -6
I added a lot of things to the spritsheet engine and am currently working on an level editor. Additional a lot of drawing has happened in the meantime.
For a first look:
|
|
|
Post by tbird on Oct 3, 2019 8:23:21 GMT -6
Oh looks good, can't wait!
|
|
|
Post by n00b on Oct 3, 2019 9:03:18 GMT -6
I really like your pixel art on the tiles. They put my pixel art to shame. I am looking forward to seeing how your editor turns out.
|
|
|
Post by johnno56 on Oct 3, 2019 15:17:48 GMT -6
Looks great! An editor as well? Cool...
|
|
|
Post by eyfenna on Oct 4, 2019 12:14:45 GMT -6
The mapeditor is going through it's thrid iteration currently, I worked in water tiles which change translucency when the weather gets bad. (there are some more things I have on my mind for integration.)
As some eye candy a zelda-som-stylish work in progress Tzir the race of Tzir is called Tengral a upright walking cat race withn long ears like night elves. They have three basic skin colours basalt, alabaster and sand.(Think of panther, lion and snowleopard as real world examples.)
[Man that was a lot of ctrl-zing and cursing until the picture became as it is currently.]
|
|