Array vs. Data Bank
Blitz3D Forums/Blitz3D Beginners Area/Array vs. Data Bank
| ||
Hello Everybody, I've only had Blitz3D and Plus for about 6 weeks, but as my first learning experiment, I wrote a simple 2D copy of the "Snake (Race)" game. Anyway, it runs great on my 1200 Mhz/128 Mb RAM system, but it's so slow you can't play it on my friend's 400 Mhz/64 Mb RAM system. I've narrowed the problem down to my snake drawing/shrinking/growing algorithm. I keep the coordinates for each "block" of the snakes body in a two dimensional array which gets copied and updated every loop of the game. I'm wondering if I'd be better off switching all the array data to a data bank. Krylar's book says, " . . . they [data banks] tend to be quick." Does this mean quicker than arrays? Significantly quicker? I've just been struggling to figure out what could be slowing it down, so I was hoping someone could let me know if this is even going down the right path or if arrays and data banks are really about as fast as each other and it's just my algorithm that needs re-working. Thanks in advance for any suggestions or ideas anyone can offer! -Dave |
| ||
what I did when I made snake on my TI 89, was have the direction of the head set into a map array, and move the eraser (which is at the tail) each loop, to the direction stored in that map position when the head was there, so the eraser will act as the tail and erase the snake. that has to be the fastest way, because it runs fast on my TI 89 calculator, made in the interpreted basic. |
| ||
Most likely, your program in general is inefficient. I own a PIII-450 and it can play well beyond a simple 'snake' game. I know because I've written many variations through the years and my original (and successful) attempts were on an ADAM computer system 20 years ago which probably only ran at about 8 MHz. |
| ||
Bank access is (or was - I see there are B3D updates available) slower than simple variables/arrays. However they are much more flexible. As WolRon stated it is very likely an inefficiency that is causing the slowdown. Why not post the suspect code for inspection? I've seen some truly impressive optimisations on these forums. |
| ||
Thanks for all the comments everybody. Since I first posted, I tried two new variations: data banks, which seemed to be a little slower, and a comma-delimited string in which I parsed every loop (in place of the array) and that was WAY too slow. The basic layout of what I'm doing is this: 1. Create a 2 dimensional array at the start of the level where array$(1,1) through array$(1,8) hold x coords and array$(2,1) through array$(2,8) hold y coords for the snake's body. 2. Each loop, I determine the direction the snake is heading (n,s,e,w), and then I add +1 body block to array$(1,1) while removing the values at array$(1,8) and array$(2,8). (In other words, I push a new value to the first index of the array and pop the last value off.) 3. I do a For loop on the array and draw a rectangle at every x,y coord in the array. Ex. For i% = 1 To 8 x% = array$(1,i%) y% = array$(2,i%) Rect x%,y%,8,8,1 Next When the game starts the snake's body is 8 "blocks." This works fine and is fast. But, as the snake eats food, it grows, and when the snake grows to 60+ "blocks" the whole thing starts to slow down to an unplayable crawl on the less powerful machine. I wish I had a way to test if this is a problem with the algorithm or BlitzPlus. None of the demo games that come with BlitzPlus are playable on this machine either, but they are on my faster one. For example, the "Insectoids" game that came with BlitzPlus runs close to one frame/second on this machine. That doesn't seem right even on a PII 400Mhz with 64Mb of RAM, does it? I like B3D a lot, but I was hoping to be able to let people without 3D video cards play this. Thanks again for all the comments so far, and I'd love to hear any other thoughts or suggestions. -Dave |
| ||
you have way more than enough speed in blitz on that computer to do it. the easiest way is to use a type and its fast, every loop create a New position Insert it Before First position Delete Last position and draw with a For Each loop. |
| ||
Dave, Blitz can do hundreds of sprites almost instantly, so it is probably a problem with your implementation. If you post a copy of your source here, or send me a copy of your source, I/we should be able to sort it out for you. Question - why did you use a string array? That might be the problem, or part of it anyway. |
| ||
I can't see anything in your general method which suggests a problem. It's probably a little glitchy bug that you're missing. There are a thousand and one possibilities so it's difficult to guess without seeing the code. |
| ||
Also, the drivers for the 'slow' machine may be inadequit. Try your code on a third 'slow' machine and see what the results are. |
| ||
Or your game may be running at thousands of FPS on your better computer but only hundreds of FPS on the slower one. |
| ||
Hi Again Everybody, Well, thank you all very much for all the suggestions so far. Unfortunately, I haven't been able to solve the problem yet. The string array I used in the example code was just a mistake. The actual code uses an integer array. I would like to try the code on a third 'slow' machine, but I don't have another one to try it on. But, like I mentioned, one of the things that makes me suspicious of this machine as a whole is that it can't run any of the demo games that came with Blitz Plus. But if it is some hardware issue, is that something I need to be concerned about when trying to distribute Blitz Plus games to the general public? I thought Blitz Plus was supposed to run on all Win95+ systems? Anyway, I've narrowed the problem down to something that happens in one of the following functions. I apologize for posting so much code, and if there's a more appropriate way to post code to this site, please just let me know. Although I said the game involved a "snake" that was just for simplicity. It's exactly like the "snake" game, except that mine uses Dachshunds. Below you'll find the type declaration for the dogs, the initial array I use for the starting body coordinates and the three functions that move, update and draw the dog. The rest of the game involves drawing a perimiter and maze of walls to go through, a computer opponent dog, and bowls and bones for eating. I've even tried taking away all the walls and opponent dog, but I get the same problem, when the dog eats about 10 bowls, he grows to an array of 58 blocks and he just slows down way too much to play. I think the probem may be in the "update_hund()" function below, but maybe my whole approach is flawed. Again, thanks for any help or suggestions. -Dave ----------------------------------------------------------- Code ----------------------------------------------------------- Type Hunden Field head% ; anim image index Field head_x% ; X value of head image Field head_y% ; Y value of head image Field tail% ; anim image index Field tail_x% ; X value of tail image Field tail_y% ; Y value of tail image Field red% ; red value of the dog Field blue% ; blue value of the dog Field green% ; green value of the dog Field heading$ ; v|h which way's the dog heading Field x_incr% ; how many x increments to go each move Field y_incr% ; how many y increments to go each move Field id% ; ID of dog : Black = 0, Brown = 8, ; Red = 16, Tan = 24 Field owner$ ; (h|c) human or computer Field grow% ; how many blocks to let the dog grow by ; from eating food Field shrink% ; how many blocks to let the dog shrink by ; from eating a bone End Type ; Beginning body block locations for this dog Dim my_coords%(2,8) my_coords%(1,1) = 645 my_coords%(2,1) = 196 my_coords%(1,2) = 650 my_coords%(2,2) = 196 my_coords%(1,3) = 655 my_coords%(2,3) = 196 my_coords%(1,4) = 660 my_coords%(2,4) = 196 my_coords%(1,5) = 665 my_coords%(2,5) = 196 my_coords%(1,6) = 670 my_coords%(2,6) = 196 my_coords%(1,7) = 675 my_coords%(2,7) = 196 my_coords%(1,8) = 680 my_coords%(2,8) = 196 LAST_INDEX% = 8 ; This is called when the user presses one of the arrow ; keys. Function move_my_hund(hund.Hunden,direction$) ; Get beginning and ending body array values before we ; update so we can compare and turn the the tail the right ; direction. old_first_x% = my_coords%(1,1) old_first_y% = my_coords%(2,1) last_x% = my_coords%(1,LAST_INDEX%) last_y% = my_coords%(2,LAST_INDEX%) ; Move the direction that was passed to this function Select direction$ Case "up" hund\y_incr% = Abs(hund\y_incr%) * -1 next_x% = last_x% ; Check top perimiter If last_y% < 12 lose_life() Else ; No problem, go up one next_y% = last_y% + hund\y_incr% hund\heading$ = "v" EndIf ; Animation If hund\head% = 2 + hund\id% hund\head% = 3 + hund\id% Else hund\head% = 2 + hund\id% EndIf Case "down" hund\y_incr% = Abs(hund\y_incr%) next_x% = last_x% ; Check bottom perimiter If last_y% > 397 lose_life() Else ; No problem, go down one next_y% = last_y% + hund\y_incr% hund\heading$ = "v" EndIf ; Animation If hund\head% = hund\id% hund\head% = 1 + hund\id% Else hund\head% = hund\id% EndIf Case "left" next_y% = last_y% ; Check left perimiter If last_x% < 11 And gate_state$ = "closed" lose_life() Else ; No problem, go right one hund\x_incr% = Abs(hund\x_incr%) * -1 next_x% = last_x% + hund\x_incr% hund\heading$ = "h" EndIf ; Animation If hund\head% = 6 + hund\id% hund\head% = 7 + hund\id% Else hund\head% = 6 + hund\id% EndIf Case "right" next_y% = last_y% ; Check right perimiter If last_x% > 621 And gate_state$ = "closed" lose_life() Else ; No problem, go right one hund\x_incr% = Abs(hund\x_incr%) next_x% = last_x% + hund\x_incr% hund\heading$ = "h" EndIf ; Animation If hund\head% = 4 + hund\id% hund\head% = 5 + hund\id% Else hund\head% = 4 + hund\id% EndIf End Select ; Update the dog's body coords update_hund(hund.Hunden, next_x%,next_y%) ; Compare new first x,y to old first x,y and see what way ; the last block moved and display the ; appropriate dog butt. new_first_x% = my_coords%(1,1) new_first_y% = my_coords%(2,1) If new_first_y% < old_first_y% ; UP hund\tail_x% = my_coords%(1,1) - 5 hund\tail_y% = my_coords%(2,1) + 8 ; Animation If hund\tail% = 4 + (hund\id% * 2) hund\tail% = 5 + (hund\id% * 2) ElseIf hund\tail% = 5 + (hund\id% * 2) hund\tail% = 6 + (hund\id% * 2) ElseIf hund\tail% = 6 + (hund\id% * 2) hund\tail% = 4 + (hund\id% * 2) Else hund\tail% = 4 + (hund\id% * 2) EndIf ElseIf new_first_y% > old_first_y% ; DOWN hund\tail_x% = my_coords%(1,1) - 5 hund\tail_y% = my_coords%(2,1) - 16 ; Animation If hund\tail% = hund\id% * 2 hund\tail% = 1 + (hund\id% * 2) ElseIf hund\tail% = 1 + (hund\id% * 2) hund\tail% = 2 + (hund\id% * 2) ElseIf hund\tail% = 2 + (hund\id% * 2) hund\tail% = 3 + (hund\id% * 2) Else hund\tail% = hund\id% * 2 EndIf ElseIf new_first_x% < old_first_x% ; LEFT hund\tail_x% = my_coords%(1,1) + 5 hund\tail_y% = my_coords%(2,1) - 5 ; Animation If hund\tail% = 12 + (hund\id% * 2) hund\tail% = 13 + (hund\id% * 2) ElseIf hund\tail% = 13 + (hund\id% * 2) hund\tail% = 14 + (hund\id% * 2) ElseIf hund\tail% = 14 + (hund\id% * 2) hund\tail% = 15 + (hund\id% * 2) Else hund\tail% = 12 + (hund\id% * 2) EndIf ElseIf new_first_x% > old_first_x% ; RIGHT hund\tail_x% = my_coords%(1,1) - 17 hund\tail_y% = my_coords%(2,1) - 5 ; Animation If hund\tail% = 8 + (hund\id% * 2) hund\tail% = 9 + (hund\id% * 2) ElseIf hund\tail% = 9 + (hund\id% * 2) hund\tail% = 10 + (hund\id% * 2) ElseIf hund\tail% = 10 + (hund\id% * 2) hund\tail% = 11 + (hund\id% * 2) Else hund\tail% = 8 + (hund\id% * 2) EndIf EndIf End Function ; Updates the body coordinates of the requested dog Function update_hund(hund.Hunden, next_x%,next_y%) ; First figure out if we're growing, shrinking or neither If hund\grow% > 0 ; Growing start% = 1 end_point% = LAST_INDEX% + 1 hund\grow% = hund\grow% - 1 ; This is so that when we return to normal, we don't have a ; LAST_INDEX% 1 too high If hund\grow% > 1 new_last_index% = LAST_INDEX% + 1 Else new_last_index% = LAST_INDEX% EndIf ElseIf hund\shrink% > 0 ; Shrinking start% = 3 end_point% = LAST_INDEX% + 1 hund\shrink% = hund\shrink% - 1 new_last_index% = LAST_INDEX% - 1 If start% > end_point% start% = end_point% - 1 new_last_index% = LAST_INDEX% EndIf Else ; Not shrinking or growing start% = 2 end_point% = LAST_INDEX% new_last_index% = LAST_INDEX% EndIf ; Now, if we're growing or shrinking copy current ; my_coords%() to loc_coords%() If hund\grow% > 0 Or hund\shrink% > 0 Dim loc_coords%(2,end_point%) For i% = 1 To LAST_INDEX% loc_coords%(1,i%) = my_coords%(1,i%) loc_coords%(2,i%) = my_coords%(2,i%) Next ; Re-dimension my_coords and re-populate Dim my_coords%(2,end_point%) For i% = 1 To LAST_INDEX% my_coords%(1,i%) = loc_coords%(1,i%) my_coords%(2,i%) = loc_coords%(2,i%) Next EndIf ; Cut out or add to the appropriate places for the new body For i% = start% To LAST_INDEX% n% = i% - 1 my_coords%(1,n%) = my_coords%(1,i%) my_coords%(2,n%) = my_coords%(2,i%) Next ; Add the new next x,y my_coords%(1,end_point%) = next_x% my_coords%(2,end_point%) = next_y% ; Update LAST_INDEX% for new DIM LAST_INDEX% = new_last_index% End Function ; Draw a dog Function draw_hund(hund.Hunden) ; Whose dog (and coords) is this? If hund\owner$ = "h" ; Human's ; Prepare loc_coords%() for human data and load Dim loc_coords%(2,LAST_INDEX%) For i% = 1 To LAST_INDEX% loc_coords%(1,i%) = my_coords%(1,i%) loc_coords%(2,i%) = my_coords%(2,i%) Next Else ; Computer's ; Prepare loc_coords%() for computer data and load Dim loc_coords%(2,LAST_INDEXC%) For i% = 1 To LAST_INDEXC% loc_coords%(1,i%) = your_coords%(1,i%) loc_coords%(2,i%) = your_coords%(2,i%) Next EndIf ; Set drawing color to dog color and draw body Color hund\red%, hund\green%, hund\blue% If hund\owner$ = "h" end_body% = LAST_INDEX% Else end_body% = LAST_INDEXC% EndIf For i% = 1 To end_body% x% = loc_coords%(1,i%) y% = loc_coords%(2,i%) Rect(x%, y%, 8, 8, 1) Next ; Draw head in right location If hund\heading$ = "h" If hund\x_incr% > 0 ; Moving horizontally right hund\head_x% = loc_coords%(1,end_body%) + 8 hund\head_y% = loc_coords%(2,end_body%) - 6 ElseIf hund\x_incr% < 0 ; Moving horizontally left hund\head_x% = loc_coords%(1,end_body%) - 16 hund\head_y% = loc_coords%(2,end_body%) - 6 EndIf EndIf If hund\heading$ = "v" If hund\y_incr% < 0 ; Moving vertically up hund\head_x% = loc_coords%(1,end_body%) - 5 hund\head_y% = loc_coords%(2,end_body%) - 16 ElseIf hund\y_incr% > 0 ; Moving vertically down hund\head_x% = loc_coords%(1,end_body%) - 5 hund\head_y% = loc_coords%(2,end_body%) + 8 EndIf EndIf ; Draw head and tail for this dog at the right locations DrawImage heads, hund\head_x%, hund\head_y%, hund\head% DrawImage tails, hund\tail_x%, hund\tail_y%, hund\tail% End Function |
| ||
Dave, I must admit that I have difficulty reading so much code, especially if it is written by someone else than me! Besides, all that % is distracting - unlike other Basics that I've used, Blitz uses integer variables by default and doesn't need the % symbol. The code can't be run too, so that makes it even more difficult for someone else to debug for you. Can you maybe post a (minimal) source code that can be run and yet contain the problem to be solved? Or maybe try starting off with a predefined 58-block snake without all the rest of the code (to make it grow in length), and see whether that is a problem? |
| ||
Yeah, I had a feeling it was probably too long to be much good. It's gonna be tough to get it much smaller I think without potentially cutting out the problem. I did try starting off with a predefined 58-block snake, and the problem still existed. But, as I was reviewing everything just now to see if I couldn't find a shorter sample to post, I came across something unexpected that leads me to believe I just don't get arrays in Blitz . . . which is probably causing my problem. I thought that when you Dim an array, whatever you Dim it at is the highest index in the array that Blitz is storing. For example, if you say: Dim array%(2) Then array%(3) should say something like "out of bounds." But, this isn't the case. I wrote a little test: Graphics 640,480 Dim array%(1) array%(1) = 1 array%(2) = 2 array%(3) = 3 array%(4) = 4 next_y = 0 For i = 1 To 10 Text 0,next_y%, i + ": " + array%(i%) next_y = next_y + 15 Next WaitKey() End On my computers, this repeatedly prints out the same thing: 1: 1 2: 2 3: 3 4: 4 5: 524544 6: 24495808 7: 11286568 8: 11333336 9: 0 10: 197152 First off, what are all these values at index 5 and above? I even tried going up to index 100 and it just kept spitting back numbers. Is it affecting memory usage if Blitz is storing all these values that I didn't even define? Secondly, if I can just add values at indeces higher than the Dim, then what's the point in ever saying anything other than Dim array%(1) and then just letting Blitz dynamically resize as I add more values? I guess I just really don't get arrays in Blitz. I've read the chapter about them in Krylar's book, but I guess I need more info. Can anyone explain this or point somewhere that I can read more about them? Sorry to keep posting questions, but I really do appreciate everyone's help! -Dave |
| ||
Delete all the '%' from your code, then try it again. As robleong has stated, they are completely useless, because they indicates an integer declaration, which is the default. So when you declare Global abc% is exactly the same of Global abc Only, abc is more readable than abc%. Try. One more thing. I think, if I recall well, than if you declare an array with: Dim arr(0) then you can later re-dim the array like dim arr(5) But I'm not 100% sure. Argh ! I've typed a '%'.. ! ;) |
| ||
Thanks for the '%' suggestion. I took them all out, but I get the same results. Dim'ing and then re-Dim'ing an array makes sense to me, but I still don't get why after only one Dim, there are all kinds of values being stored above the original Dim declaration. Thanks again! -Dave |
| ||
Drankin, As to your question about arrays, actually, I get an "Array index out of bounds" error when I run your code, but I'm using Blitz3D. So, not sure whether you're using Blitz+; if that's the case, some error-checking code might be missing in Blitz+... As to why you're getting all those weird values, I think it's simply interpreting any value that's left in memory (and not cleared), offset by so many bytes as pointed to by your array value (which it shouldn't!). |
| ||
Oh, and Drankin, can you just recreate and post an executable/'runnable' source code with just the 58-block predefined snake (maybe just going automatically around a square area) and we can try to see why there's a problem even with this? |
| ||
Well, like I've been saying all along, I really do appreciate all the help. But, I do have to admit that I figured something out when I was trying to give you what you asked for (a runnable 58 block snake with just the necessary code). There was a problem with my implementation. The slow down didn't start at 58 blocks, it started at 580 blocks. Technically, it's when there are about 600 sprites being updated per frame. Also, I've been using Blitz Plus for this, but this afternoon, I made a Blitz 3D copy and ran it on another machine that was also only 400Mhz/64Mb RAM and the B3D copy ran fine--even with 600 sprites/fame. I guess I figured at least in terms of speed, Blitz Plus and B3D would be the same. I would just use B3D, but it seems kind of silly to me that I'd make a 2D game that would require a 3D video card. Anyway, I corrected the implementation in the Blitz Plus version and now in its corrected state it only ever gets to about 70 sprites per frame and it runs just fine like that. I still don't know why I'm able to do that array stuff I mentioned two posts ago in Blitz Plus, but I guess I won't worry about it for now. Well, thank you again everyone for all your help, and thank you robleong for all the suggestions and asking me to do the thing that led to me finding my error. I'm really very happy that I decided to get into Blitz. So far I love it, and the Blitz community has been great. -Dave |