|
Forum Index : Microcontroller and PC projects : Sprite interrupt
| Author | Message | ||||
| yock1960 Senior Member Joined: 18/08/2020 Location: United StatesPosts: 167 |
As per usual, I'm probably doing something unexpected/wrong and I'm really not quite sure where I'm running into trouble or even if it's sprite interrupt's fault! I'm trying to create a Qbert clone. This is something I've never remotely attempted...in fact I've never used sprites. After a month of programming, I have a 'kind of working' WIP, but now that I've added my 3rd 'character' (red ball, Qbert being 1 and Coily 2), I'm experiencing problems with 'sprite internal error', when hiding or showing sprites. I've been seeing these for a while, but just came up with the idea that perhaps it has something to do with what happens when the program returns from the interrupt and the fact that the 'interrupted' routine, was called by another interrupt. I've been adding 'on error skip's pretty liberally...which is treating a symptom...and I think I'm suffering from 'rebound'! I originally started adding the on error skips for 'not showing' errors, which may have just been bad/sloppy coding. The problem seems random. Sometimes I can play for a while...several rounds, but eventually, it strikes, sometimes sooner, sometimes later. I will say that it seems to have gotten worse after a rewrite, necessitated by only having 64 sprite/blit buffers, which after I progressed to a certain point, I realized I did not have the luxury of having a buffer for each character/direction/position and needed to redefine them on the fly. Maybe if I knew what conditions generate an 'internal error'? Steve |
||||
| Nelno Regular Member Joined: 22/01/2021 Location: United StatesPosts: 59 |
It looks like SHOW, HIDE, SWAP and CLOSE all have the potential to generate the "sprite internal error" error. From what I can tell just glancing at the MMBASIC code (I am a total noob at this code and have only spent maybe 30 minutes looking at it): It looks like the code tracks sprites in what it calls a LIFO (Last In First Out) buffer. This sounds a bit like a stack, but it looks like it might be a sorted list of sprite numbers. The code tracks the number of sprites in use in a separate integer variable. The error you're seeing can be generated if: - the number of sprites in use doesn't match the number of sprites in the LIFO buffer OR - the number of sprites in use doesn't match the total number of sprites in use across all layers (which I think is derived by going through each layer and counting the sprites in use, just for this test). I suspect none of that is a great deal of help. I don't think your error would be caused specifically by ON ERROR SKIP, but it is possible you're hiding some issue that's allowing the sprite system to get in a bad state. Your idea of it being related to the interrupt holds some merit. One thing you could try to do is not do any other sprite work inside of the interrupt itself, but instead set a flag or keep a list of work you should do in your frame loop based on the interrupt. This could get you around any issue that might be caused by some sort of nested interrupt scenario. OR... set up a global variable in your sprite interrupt handler to catch when there's a nested interrupt (i.e. increment a variable when entering the interrupt handler, decrement it on exit, call ERROR or somehow log if you see that counter > 1 (put something on the screen you can see) to see if it's related to the internal error event. Edited 2021-02-14 17:03 by Nelno |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10590 |
The SPRITE INTERNAL ERROR was included precisely to find any problems that could cause the sprite data structures to get out of line. Up to now no-one had managed to trigger it. yock1960 is doing something that the firmware isn't handling properly, but to solve it I need a simple example program that can reliably trigger the problem otherwise I'm searching for a needle in a haystack Edited 2021-02-14 18:48 by matherp |
||||
| yock1960 Senior Member Joined: 18/08/2020 Location: United StatesPosts: 167 |
Here you go Peter. This program is using on the fly sprite definition...well, it would if the program got that far, but it fails on the 1st collision. I have moved away from on the fly sprite re-definition, since I discovered that sprite mirroring works fine...some other error when I tried it apparently...and now the internal error happens less frequently, but still happens, especially when I have tried to add a duplicate, but independent sprite....same sprite definitions, different sprite numbers (not a copy) and using array variables for tracking location/status. I'm still on 5.07.00b9. Steve sprite_test.zip |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10590 |
Need the png file - thanks |
||||
| yock1960 Senior Member Joined: 18/08/2020 Location: United StatesPosts: 167 |
DOH! qbert_creatures.zip |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10590 |
I'm getting immediately on running Error in line 330: Buffer not in use Two things though - NEVER EVER EVER use PAUSE in an interrupt routine. You don't need to disable and re-enable interrupts in the interrupt routine Edited 2021-02-15 05:50 by matherp |
||||
| yock1960 Senior Member Joined: 18/08/2020 Location: United StatesPosts: 167 |
Yes, I put that in there for the demo, disabling or not disabling and removing the pause makes no difference to the internal error. I think I put the disable/enable in after I started seeing the problem. Not sure why you're getting the buffer not in use error....obviously, I don't. Steve |
||||
| yock1960 Senior Member Joined: 18/08/2020 Location: United StatesPosts: 167 |
So, with setting the sprite interrupt up before any sprites are shown and the sprite nointerrupt statement commented out, no buffer error is seen, but if you then comment out the 'sprite interrupt collision' statement inside the collision sub, the buffer not in use error occurs. It looks like setting up the sprite interrupt routine calls it....seems like it shouldn't be called until there is a collision. Edited 2021-02-15 06:09 by yock1960 |
||||
| yock1960 Senior Member Joined: 18/08/2020 Location: United StatesPosts: 167 |
I fibbed. I did have the pause in the regular program sprite interrupt routine. I had to think a bit, but am now in the process of re-doing this to get rid of it. It impacts the immediacy of the collision result....at least the way I'm doing it, but in the end, it doesn't really affect game play. Perhaps this will eliminate the internal errors that I still was sometimes seeing. Steve |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10590 |
Found the problem You are trying to "hide safe" a sprite that is already hidden and the firmware isn't giving an error. Try b16 and you should get the error "Not Showing" then it is up to you to fix your code General point: you don't have to use the sprite interrupt have a look at the brownian motion demo on the welcome tape. If you do use the interrupt my recommendation is that is is used to deal with the cause of the interrupt in its entirety. Have a look at the attached. Option explicit Option default none option y_axis up Option console serial Const stepdef=4 Dim integer i, x=1, y=160, stepsize=stepdef, last_one_gone, update Dim float current_angle=90 Dim integer showing(64) Mode 2,16,0,frameint Pause 3000 Page write 1 CLS Box 401,1,18,48,2,RGB(green),RGB(Magenta) Box 421,1,18,48,2,RGB(red),RGB(cyan) Box 441,1,18,48,2,RGB(yellow),RGB(blue) Box 461,1,18,48,2,RGB(white),RGB(red) Box 481,1,18,48,2,RGB(Magenta),RGB(GREEN) Play modfile "cartoon" 'for i=0 to 7 SPRITE read 10+i,401,1,18,48 SPRITE read 18+i,421,1,18,48 SPRITE read 26+i,441,1,18,48 SPRITE read 34+i,461,1,18,48 SPRITE read 42+i,481,1,18,48 SPRITE copy 10,11,7 SPRITE copy 18,19,7 SPRITE copy 26,27,7 SPRITE copy 34,35,7 SPRITE copy 42,43,7 Load bmp "court" 'CLS For i=0 To 7 SPRITE show 10+i,401,i*50,1 showing(10+i)=1 SPRITE show 18+i,421,i*50,1 showing(18+i)=1 SPRITE show 26+i,441,i*50,1 showing(26+i)=1 SPRITE show 34+i,461,i*50,1 showing(34+i)=1 SPRITE show 42+i,481,i*50,1 showing(42+i)=1 Next i SPRITE loadpng 1,"ball" vector 0,current_angle,0,x,y SPRITE show 1,x,y,1 update=1 page copy 1 to 0 Do Loop Until update=0 SPRITE INTERRUPT collision Do vector 0,current_angle,stepsize,x,y SPRITE show 1,x,y,1 update=1 Do Loop Until update=0 Loop Until last_one_gone Pause 2000 Play stop SPRITE close all Mode 2,8 'disable the interrupt' Option console both End Sub frameint If update Then Page copy 1 To 0 update =0 End Sub Sub vector(obj As integer, angle As float, distance As float, x_new As integer, y_new As integer) Static float y_move(9), x_move(9) Static float x_last(9), y_last(9) Static float last_angle(9) If distance=0 Then x_last(obj)=x_new y_last(obj)=y_new EndIf If angle<>last_angle(obj) Then y_move(obj)=-Cos(Rad(angle)) x_move(obj)=Sin(Rad(angle)) last_angle(obj)=angle EndIf x_last(obj) = x_last(obj) + distance * x_move(obj) y_last(obj) = y_last(obj) + distance * y_move(obj) x_new=Cint(x_last(obj)) y_new=Cint(y_last(obj)) Return Sub collision Local integer i ' First use the SPRITE(S) function to see what caused the interrupt If sprite(S) <> 0 Then 'collision of specific individual sprite 'sprite(S) returns the sprite that moved to cause the collision 'print "Collision on sprite ",sprite(S) process_collision(sprite(S)) ' print "" ' Else '0 means collision of one or more sprites caused by background move ' SPRITE(C, 0) will tell us how many sprites had a collision ' print "Scroll caused a total of ",sprite(C,0)," sprites to have collisions" For i=1 To sprite(C,0) ' SPRITE(C, 0, i) will tell us the sprite number of the Ith sprite ' print "Sprite ",sprite(C,0,i) process_collision(sprite(C,0,i)) Next i ' print "" EndIf End Sub ' get details of the specific collisions for a given sprite Sub process_collision(S As integer) Local integer i ,j, k, m 'sprite(C, #n) returns the number of current collisions for sprite n 'print "Total of ",sprite(C,S)," collisions" 'print SPRITE(C, S, 1)' will tell us the sprite number of the Ith sprite For i=1 To sprite(C,S) If k Then Exit For j=sprite(C,S,i) If j=&HF1 Then 'collision with left of screen current_angle=360-current_angle+(Rnd-0.5)*20 Do While (current_angle>=180 And current_angle<=359) Or current_angle=0 current_angle=current_angle+(Rnd-0.5)*20 Loop Else If j=&HF2 Then 'collision with top of screen current_angle=((540-current_angle) Mod 360) +(Rnd-0.5)*20 Do While current_angle<=90 Or current_angle>=270 current_angle=current_angle+(Rnd-0.5)*20 Loop Else If j=&HF4 Then 'collision with right of screen current_angle=360-current_angle+(Rnd-0.5)*20 Do While current_angle>=0 And current_angle<=180 current_angle=current_angle+(Rnd-0.5)*20 Loop Else If j=&HF8 Then 'collision with bottom of screen current_angle=((540-current_angle) Mod 360) +(Rnd-0.5)*20 Do While current_angle>=90 And current_angle<=270 current_angle=current_angle+(Rnd-0.5)*20 Loop Else If j=&HF3 Or j= &Hf6 Or j=&Hf9 Or j=&HfC Then current_angle = current_angle+180 Else current_angle=360-current_angle+(Rnd-0.5)*20 If s=1 Then vector 0,current_angle,stepsize,x,y ' SPRITE hide 1 SPRITE hide safe j:showing(j)=0 ' SPRITE show 1,x,y,1 Play effect "gunshot" m=0 For k=10 To 49 If showing(k) Then m=m+1 Next k If m=0 Then last_one_gone=1 EndIf Page copy 1 To 0 EndIf EndIf Next i End Sub Edited 2021-02-15 20:37 by matherp |
||||
| The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |