Jump to content
IGNORED

Now available IntyBASIC compiler v0.8 ! :)


nanochess

Recommended Posts

A few questions as I've made some more progress...

 

1. I'm still trying to pull off a stationary background tile while scrolling is enabled. Are there any examples in IntyBasic I could look at for this? I have the tiles themselves built and it works, until it gets to the point of the 8-pixel boundary where the tiles shift. Then I'm having a lot of difficulty with erasing the tile, waiting for the shift, then re-drawing the tile in the same place without any sudden flickering showing up on the screen.

 

2. Are there any examples of scrolling in a long series of tiles? There is a scrolling example, but it's just scrolling a single background. There's also a screen example, but it just re-draws parts of the screen at different points. I'm not sure how to combine screen and scroll in a way that smoothly scrolls in new tiles from a long data set that is, say, 200+ tiles wide. Any examples or tips for how to do this?

 

3. Are there any tools to aid in designing long tile sets? It would be awesome to design it using some visual editor that would spit out the data sets I need. Does it support the program Tiled per chance and, if so, how would that support be integrated (I've never used Tiled, I just know it's free and popular and 7800basic supports it).

 

4. Is there any good way to use the color stack while scrolling, or is that essentially impossible? I've experimented with arranging tiles in clever ways to pull off some nice effects thanks to the color stack, but those effects depend on a certain arrangement of tiles. Once some of those tiles scroll off-screen, the background colors get messed up as that careful stack arrangement is broken. Is this just an inevitability with color stack mode, or is there some trick for using color stack with scrolling?

Edited by Cybearg
Link to comment
Share on other sites

Wow! you always have the most complicated questions :)

 

A few questions as I've made some more progress...

 

1. I'm still trying to pull off a stationary background tile while scrolling is enabled. Are there any examples in IntyBasic I could look at for this? I have the tiles themselves built and it works, until it gets to the point of the 8-pixel boundary where the tiles shift. Then I'm having a lot of difficulty with erasing the tile, waiting for the shift, then re-drawing the tile in the same place without any sudden flickering showing up on the screen.

I would suggest code like this:

 

PRINT AT 29," "    ' Erase your tile
SCROLL x,y,d  
WAIT
' ... do screen insertion if needed ...
PRINT AT 29,"X"    ' Restore your tile

2. Are there any examples of scrolling in a long series of tiles? There is a scrolling example, but it's just scrolling a single background. There's also a screen example, but it just re-draws parts of the screen at different points. I'm not sure how to combine screen and scroll in a way that smoothly scrolls in new tiles from a long data set that is, say, 200+ tiles wide. Any examples or tips for how to do this?

Technically it would be the same than sample, except replacing the PRINT statements with SCREEN after the WAIT.

 

Example, for a scroll right to left, after the X coordinate "cycles" around.

 

This copies a column of the "reference" background, you can have multiple backgrounds and puts it in rightmost column, note how it only copies 1 column and 12 lines.

 

SCREEN background_1,displacement,19,1,12

3. Are there any tools to aid in designing long tile sets? It would be awesome to design it using some visual editor that would spit out the data sets I need. Does it support the program Tiled per chance and, if so, how would that support be integrated (I've never used Tiled, I just know it's free and popular and 7800basic supports it).

This triggers a need for IntyColor to keep a consistent GRAM between multiple bitmaps/screens. For now you should build it manually. Let me think about it.

 

4. Is there any good way to use the color stack while scrolling, or is that essentially impossible? I've experimented with arranging tiles in clever ways to pull off some nice effects thanks to the color stack, but those effects depend on a certain arrangement of tiles. Once some of those tiles scroll off-screen, the background colors get messed up as that careful stack arrangement is broken. Is this just an inevitability with color stack mode, or is there some trick for using color stack with scrolling?

I think it's essentially impossible, because displacing the screen would destroy the "advance-color" bit in important tiles.

Link to comment
Share on other sites

Wow! you always have the most complicated questions :)

 

A few questions as I've made some more progress...

 

1. I'm still trying to pull off a stationary background tile while scrolling is enabled. Are there any examples in IntyBasic I could look at for this? I have the tiles themselves built and it works, until it gets to the point of the 8-pixel boundary where the tiles shift. Then I'm having a lot of difficulty with erasing the tile, waiting for the shift, then re-drawing the tile in the same place without any sudden flickering showing up on the screen.

I would suggest code like this:

 

PRINT AT 219," "    ' Erase your tile
SCROLL x,y,d  
WAIT
' ... do screen insertion if needed ...
PRINT AT 219,"X"    ' Restore your tile

2. Are there any examples of scrolling in a long series of tiles? There is a scrolling example, but it's just scrolling a single background. There's also a screen example, but it just re-draws parts of the screen at different points. I'm not sure how to combine screen and scroll in a way that smoothly scrolls in new tiles from a long data set that is, say, 200+ tiles wide. Any examples or tips for how to do this?

Technically it would be the same than sample, except replacing the PRINT statements with SCREEN after the WAIT.

 

Example, for a scroll right to left, after the X coordinate "cycles" around.

 

This copies a column of the "reference" background, you can have multiple backgrounds and puts it in rightmost column, note how it only copies 1 column and 12 lines.

 

SCREEN background_1,displacement,19,1,12

3. Are there any tools to aid in designing long tile sets? It would be awesome to design it using some visual editor that would spit out the data sets I need. Does it support the program Tiled per chance and, if so, how would that support be integrated (I've never used Tiled, I just know it's free and popular and 7800basic supports it).

This triggers a need for IntyColor to keep a consistent GRAM between multiple bitmaps/screens. For now you should build it manually. Let me think about it.

 

4. Is there any good way to use the color stack while scrolling, or is that essentially impossible? I've experimented with arranging tiles in clever ways to pull off some nice effects thanks to the color stack, but those effects depend on a certain arrangement of tiles. Once some of those tiles scroll off-screen, the background colors get messed up as that careful stack arrangement is broken. Is this just an inevitability with color stack mode, or is there some trick for using color stack with scrolling?

I think it's essentially impossible, because displacing the screen would destroy the "advance-color" bit in important tiles.

Link to comment
Share on other sites

Well I have a very simple question/feature request instead:

 

In prologue.asm where it sets the game title and date (114, 'IntyBASIC program', 0), it should be fairly easy to create an IntyBASIC command to set this in the ROM header, no? I assume there's no ability to do this at the moment within the BASIC code...

 

I realize I can change this in the prologue.asm for each program I write, but it'd be kinda cool to spell it out in the main game code. Not that it affects much - it's only really visible in emulators unless for some reason a person wants the stock intro scree - but it's nice to leave a "stamp" in the final assembled ROM. ;) Unless you're wanting to keep a bit of "credit" for IntyBASIC games.

 

My other questions are not something easily answered in a forum post. I'm running into variables changing for no good reason once I cycle through my code a lot (ie: playing a long time), which means I have register or address corruption somewhere. I can replicate it exactly after a lot of experimentation but for the life of me I can't figure out what's going on. I think I'm gonna have to fire up a debugger. Ick. For a while I thought it was GRAM corruption but it's actually just the variables I use to point to the card address. Highly annoying. Now I know why QA/testers get so annoyed with their jobs :D

  • Like 1
Link to comment
Share on other sites

4. Is there any good way to use the color stack while scrolling, or is that essentially impossible? I've experimented with arranging tiles in clever ways to pull off some nice effects thanks to the color stack, but those effects depend on a certain arrangement of tiles. Once some of those tiles scroll off-screen, the background colors get messed up as that careful stack arrangement is broken. Is this just an inevitability with color stack mode, or is there some trick for using color stack with scrolling?

 

I don't understand what is the problem with Color Stack while scrolling. Here's an example of it being implemented to good effect:

 

http://www.carolvsghost.com/docs/vid/test-menu_scroll.mov

 

Are you talking about setting the "advance" bit on contiguous tiles? In those cases, you would have to re-shuffle the "advance" bit on the remaining surrounding tiles whenever you shift an entire column or row.

 

I use that technique, not in scrolling, but when Carol picks up a present that happens to enable the "advance" bit in order to change the background colour.

 

-dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

My other questions are not something easily answered in a forum post. I'm running into variables changing for no good reason once I cycle through my code a lot (ie: playing a long time), which means I have register or address corruption somewhere. I can replicate it exactly after a lot of experimentation but for the life of me I can't figure out what's going on. I think I'm gonna have to fire up a debugger. Ick. For a while I thought it was GRAM corruption but it's actually just the variables I use to point to the card address. Highly annoying. Now I know why QA/testers get so annoyed with their jobs :D

 

I've learned that most of the time, such strange problems are caused by a stack overflow. An easy way to check is to populate the entire stack with a specific value, run your program in the debugger, and break when the problem manifests. Then take a view at the upper regions of the stack and see if the original value you set is still there. If not, it is clear that the stack at least reached its boundary, so it's likely that it also went past it.

 

Another way is to enable "stack trace" in the jzIntv debugger. Break into the debugger at the beginning of your program and enter the command "k" to enable stack trace. Play for a while, preferably until the problem manifests, then break again and enter the "k" command again to stop the trace. The debugger should create a file called "stack.trc" in your working directory.

 

The trace looks something like this:

--- start of log
Deep: 6
 0000 1A83 1A84 1A85 1738 173A
Deep: 12
 0000 1067 1004 1006 1007 1008 100A 100B 100C 1126 1F2F 10AC
Deep: 16
 0000 1067 1004 1006 1007 1008 100A 100B 100C 1126 1F2F 1F5C 1F65 1F66 1F67 02E0
--- end of log

Each entry represents the deepest incursion the stack took at any given time, with the last one being the longest. The numbers are the addresses from which the "PSHR" instruction was executed, so you can clearly trace all the way through your call stack.

 

Note that you want to enable the trace during your program's execution, after the EXEC initialization, or else you'll get similar entries like the above, which include addresses of the EXEC that are inscrutable to you.

 

Another thing to note: Every VBLANK interrupt service request (ISR) incurs a cost of eight slots of the stack. This is handled by the EXEC directly, which saves your program's state as it enters the ISR, and restores it on the way out. I don't know to which extent IntyBASIC lets you manipulate the "interrupt enabled" CPU status flag or how much leeway you have in controlling the ISR, but if the routine happens to overrun and re-enter on the next cycle, that's another eight slots taken from the stack.

 

Of course, deep calling procedures and creation of "scratch" variables in the stack will also exhaust it rather quickly.

 

-dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

 

I've learned that most of the time, such strange problems are caused by a stack overflow.

 

Thank you thank you thank you.

 

It's been more years than I want to admit since I've programmed at this level. And, I've been using IntyBASIC because it's a great way to "cheat" in the sense that you can very quickly make things happen. It's surprisingly powerful, I have to admit. However it does abstract away some things to the point that they're "hidden". As I was waking up prematurely this morning, I started re-thinking how I handle collision detection and sprite movement, and I was working on cycle counting in my head in case I wanted to do some heavy iterative processing to manage this. For whatever reason, my brain started thinking "be careful of stack overflow here" because I may be branching a lot (hence the cycle counting). And then I almost leaped out of bed because I realized that was exactly what was going on. Or at least, given that I haven't looked at a stack in 10 years, it's a possibility. But - how the hell? I'm not doing anything THAT complex in this game, am I?

 

So I read your post. And re-read it. And shuddered at the thought of running stack traces. I won't lie, I'm not exactly paying close attention to the instruction pointer and such. BASIC hides so much from you. However... after enough reading I realized a likely possibility. I use a lot of GOSUBs in my code but I'm always RETURNing and this should clear the stack... hmm...

 

Oh wait, you idiot. Early on in the program you're calling GOSUBs that you never return from, to initialize a "level" of the game. Because you completely re-factored how the program flows quite a while ago and it's just a bunch of GOTOs now. So yeah, with each "level" you're pushing onto the stack and no shit you're overflowing given enough play.

 

Sigh. Rookie mistake. I love it :D

  • Like 1
Link to comment
Share on other sites

No worries. I know that IntyBASIC is very powerful and useful, but there haven't been many games that put it through its paces yet, so there is a chance of bugs still lurking in the shadows.

 

Regarding your initialization calls with no return, this is typical in assembly programs, where you have to "hijack" the EXEC initialization and take over with yours. However, in BASIC programs you should follow a more structured pattern, and avoid calling subroutines from which you never return.

 

If you show some code, I could try to help debug your problem. Feel free to send me a PM if you do not want to release your source publicly.

 

dZ.

Link to comment
Share on other sites

Well I have a very simple question/feature request instead:

 

In prologue.asm where it sets the game title and date (114, 'IntyBASIC program', 0), it should be fairly easy to create an IntyBASIC command to set this in the ROM header, no? I assume there's no ability to do this at the moment within the BASIC code...

 

I realize I can change this in the prologue.asm for each program I write, but it'd be kinda cool to spell it out in the main game code. Not that it affects much - it's only really visible in emulators unless for some reason a person wants the stock intro scree - but it's nice to leave a "stamp" in the final assembled ROM. ;) Unless you're wanting to keep a bit of "credit" for IntyBASIC games.

It stood that way since beginning of IntyBASIC. I'll think about it. :)

Link to comment
Share on other sites

No worries. I know that IntyBASIC is very powerful and useful, but there haven't been many games that put it through its paces yet, so there is a chance of bugs still lurking in the shadows.

 

Regarding your initialization calls with no return, this is typical in assembly programs, where you have to "hijack" the EXEC initialization and take over with yours. However, in BASIC programs you should follow a more structured pattern, and avoid calling subroutines from which you never return.

 

If you show some code, I could try to help debug your problem. Feel free to send me a PM if you do not want to release your source publicly.

 

dZ.

 

I think, if I followed his explanation correctly, the code originally started out as (at a high level):

  • GOSUB INIT_LEVEL
  • GOSUB PLAY_LEVEL

 

and now INIT_LEVEL GOTOs PLAY_LEVEL without a return. Yep, that'll overflow the stack, assuming PLAY_LEVEL GOTOs the main above-game loop.

 

In Space Patrol, I started out with very structured call/return. But I got tight on RAM, ROM and cycles. INIT functions and other functions that got called from exactly one place often got their call/return replaced with branches in both directions, or in case of the core engine code, directly inlined to save precious cycles. (I kept the branch/branch structure for the INIT stuff because I needed to spread code across the 5/6/D/F splits.)

 

A JSR takes 13 cycles (I know the docs say 12, but someone measured it and we determined it was actually 13) and a JR R5 is 7. That makes a call/return a minimum of 20 cycles. if you have to PSHR R5/PULR PC, that adds to the stack footprint and adds another 21 cycles (41 cycles total), and 5 words of ROM. A branch/branch pair only takes 18 cycles and 4 words of ROM. Inlining takes 0 cycles and 0 words. :-)

 

In higher level languages, the compiler can sometimes detect a function that's called from exactly one place and inline automatically. I don't know if IntyBASIC is structured enough to support that kind of optimization, but if it can, that would be interesting.

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

Also, here's a thought as a debugging aid: You should be able to detect stack overflows pretty easily if you know what the boundaries of the stack should be.

 

For a heavy handed check, put a CMPI #MAX_TOS, R6 ; BC @@stack_overflow in the ISR. The ISR is typically the source of most stack overflows, as an interrupt pushes 8 words to the stack all at once. It's not fool proof, of course, as you may still overflow the stack between interrupts.

 

Another option is to put a 'canary' word at the top bound of the stack, and test its value periodically. If the canary word ever changes, you know you've reached that limit. You can also set a 'watch' on it in jzIntv's debugger. That requires spending 1 word of RAM, but it can help.

  • Like 1
Link to comment
Share on other sites

In Space Patrol, I started out with very structured call/return. But I got tight on RAM, ROM and cycles. INIT functions and other functions that got called from exactly one place often got their call/return replaced with branches in both directions, or in case of the core engine code, directly inlined to save precious cycles. (I kept the branch/branch structure for the INIT stuff because I needed to spread code across the 5/6/D/F splits.)

 

A JSR takes 13 cycles (I know the docs say 12, but someone measured it and we determined it was actually 13) and a JR R5 is 7. That makes a call/return a minimum of 20 cycles. if you have to PSHR R5/PULR PC, that adds to the stack footprint and adds another 21 cycles (41 cycles total), and 5 words of ROM. A branch/branch pair only takes 18 cycles and 4 words of ROM. Inlining takes 0 cycles and 0 words. :-)

I learnt that during the Princess Quest development, as you say the CALL/RET sequence is elegant and structured, but it takes too many cycles.

 

So many subroutines ended inlined and unrolled, it doesn't look pretty internally, but it runs fast and that is what player likes :)

 

In higher level languages, the compiler can sometimes detect a function that's called from exactly one place and inline automatically. I don't know if IntyBASIC is structured enough to support that kind of optimization, but if it can, that would be interesting.

IntyBASIC creates expression trees for very optimized output, but I didn't made it so far for statement trees or macro replacement that would be useful for inlining.

 

Also, here's a thought as a debugging aid: You should be able to detect stack overflows pretty easily if you know what the boundaries of the stack should be.

 

For a heavy handed check, put a CMPI #MAX_TOS, R6 ; BC @@stack_overflow in the ISR. The ISR is typically the source of most stack overflows, as an interrupt pushes 8 words to the stack all at once. It's not fool proof, of course, as you may still overflow the stack between interrupts.

 

Another option is to put a 'canary' word at the top bound of the stack, and test its value periodically. If the canary word ever changes, you know you've reached that limit. You can also set a 'watch' on it in jzIntv's debugger. That requires spending 1 word of RAM, but it can help.

That's a pretty good idea. Maybe I could add a stack-overflow check in IntyBASIC to simplify debugging.

  • Like 1
Link to comment
Share on other sites

I learnt that during the Princess Quest development, as you say the CALL/RET sequence is elegant and structured, but it takes too many cycles.

 

So many subroutines ended inlined and unrolled, it doesn't look pretty internally, but it runs fast and that is what player likes :)

 

In Space Patrol, I created a macro called "ICALL" that really was just an INCLUDE statement that dropped the function in right there. The rest of the functions that remained as CALLs later had to be INCLUDEd separately. (I went back and forth over which functions to inline vs. not.) You can see the result in ENGINE2 here: http://spacepatrol.info/src/engine/engine2.asm

 

Basically, it still looks like a CALL, but because it's really an INCLUDE, it's effectively inlined. I broke all the individual functions out to separate source files, and you can see where I commented out the call/return stuff, so I could switch between CALL and ICALL pretty easily if I figured out that a particular function would need to be called from two places, for example. Rest of the engine files here: http://spacepatrol.info/src/engine/

 

You can see what percentage of the engine logic got inlined by what explicit INCLUDEs remained when I was done, and what ones were commented out.

;       INCLUDE "engine/ckbgb.asm"  ; Check bad-guy bullets
;       INCLUDE "engine/ckggb.asm"  ; Check good-guy bullets
;       INCLUDE "engine/ckbrc.asm"  ; Check buggy-rock collision
;       INCLUDE "engine/ckbgp.asm"  ; Check bad-guy position (culling)
;       INCLUDE "engine/upcrd.asm"  ; Update cards
        INCLUDE "engine/upmux.asm"  ; Update MOB muxing
        INCLUDE "engine/upspa.asm"  ; Update sprite allocations
;       INCLUDE "engine/upspp.asm"  ; Update sprite positions
        INCLUDE "engine/upbsp.asm"  ; Update buggy sprite 
;       INCLUDE "engine/upbgp.asm"  ; Update buggy/ground position
;       INCLUDE "engine/uphbp.asm"  ; Update horiz bullet position
;       INCLUDE "engine/upani.asm"  ; Update animation
        INCLUDE "engine/ttlsp.asm"  ; Title sprite updates
        INCLUDE "engine/clrsp.asm"  ; Clear sprites and update
        INCLUDE "engine/twinkle.asm"; Twinkle stars in the sky

That's what, about 2/3rds inlined? :-)

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

In Space Patrol, I created a macro called "ICALL" that really was just an INCLUDE statement that dropped the function in right there. The rest of the functions that remained as CALLs later had to be INCLUDEd separately. (I went back and forth over which functions to inline vs. not.) You can see the result in ENGINE2 here: http://spacepatrol.info/src/engine/engine2.asm

 

Basically, it still looks like a CALL, but because it's really an INCLUDE, it's effectively inlined. I broke all the individual functions out to separate source files, and you can see where I commented out the call/return stuff, so I could switch between CALL and ICALL pretty easily if I figured out that a particular function would need to be called from two places, for example. Rest of the engine files here: http://spacepatrol.info/src/engine/

 

You can see what percentage of the engine logic got inlined by what explicit INCLUDEs remained when I was done, and what ones were commented out.

;       INCLUDE "engine/ckbgb.asm"  ; Check bad-guy bullets
;       INCLUDE "engine/ckggb.asm"  ; Check good-guy bullets
;       INCLUDE "engine/ckbrc.asm"  ; Check buggy-rock collision
;       INCLUDE "engine/ckbgp.asm"  ; Check bad-guy position (culling)
;       INCLUDE "engine/upcrd.asm"  ; Update cards
        INCLUDE "engine/upmux.asm"  ; Update MOB muxing
        INCLUDE "engine/upspa.asm"  ; Update sprite allocations
;       INCLUDE "engine/upspp.asm"  ; Update sprite positions
        INCLUDE "engine/upbsp.asm"  ; Update buggy sprite 
;       INCLUDE "engine/upbgp.asm"  ; Update buggy/ground position
;       INCLUDE "engine/uphbp.asm"  ; Update horiz bullet position
;       INCLUDE "engine/upani.asm"  ; Update animation
        INCLUDE "engine/ttlsp.asm"  ; Title sprite updates
        INCLUDE "engine/clrsp.asm"  ; Clear sprites and update
        INCLUDE "engine/twinkle.asm"; Twinkle stars in the sky
That's what, about 2/3rds inlined? :-)

 

Just plain awesome! :)

Link to comment
Share on other sites

:o :thumbsup:

 

Someday I should publish the Princess Quest source code :)

 

:thumbsup: I vote for that. :-) If you plan to sell physical carts, you could do something like I did w/ SP and only release partial level data in the source code release.

 

 

I also vote for publishing the IntyBASIC compiler source code someday (perhaps once it's passed a certain threshold of awesomeness). ;-) You never know what outside contributions will end up on your doorstep. Several SDK-1600/jzIntv features came from outside, such as macro support, Scale2x/3x/4x support, ports to different machines, etc.

 

I plan to publish the source code for all my games eventually, warts and all, as I have with what I've done to date.

  • Like 1
Link to comment
Share on other sites

:thumbsup: I vote for that. :-) If you plan to sell physical carts, you could do something like I did w/ SP and only release partial level data in the source code release.

 

Good idea.

 

 

I also vote for publishing the IntyBASIC compiler source code someday (perhaps once it's passed a certain threshold of awesomeness). ;-) You never know what outside contributions will end up on your doorstep. Several SDK-1600/jzIntv features came from outside, such as macro support, Scale2x/3x/4x support, ports to different machines, etc.

 

I plan to publish the source code for all my games eventually, warts and all, as I have with what I've done to date.

Yes, someday I'll not have enough time to continue with IntyBASIC development or I'll be satisfied about it.

 

So far I see I'm only missing some extra features to ease programming and the LTO-Flash support and I want to keep the current style of simple but powerful.

 

Once that is ready, it would be great to leave it for other people to maintain it and see how it evolves.

  • Like 1
Link to comment
Share on other sites

I would suggest code like this:

For whatever reason, I just can NOT wrap my head around this.

 

I have four different subroutines that handle the stars in different ways, with varying levels of success. I'll give examples as I go.

 

The main loop is like this:

main_loop:
	GOSUB timer_tick
	IF (flags AND $10) <> 0 THEN GOSUB draw_stars
	GOSUB scroll_screen
	GOSUB update_states
	GOSUB set_player_states
	IF (flags AND 2) <> 0 THEN GOSUB crashing
	GOSUB set_sprites
	
	WAIT
	GOTO main_loop

So keep in mind that that draw_stars is only executed if one of the flag bits are set.

 

Here are the different star subroutines:

clear_stars: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2) = $0933 THEN PRINT AT temp2 COLOR 0, " "
		IF peek($200 + temp2 + 1) = $093B THEN PRINT AT temp2 + 1 COLOR 0, " "
	NEXT temp1
	flags = flags XOR $10
END

draw_stars: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2) = 0 THEN PRINT AT temp2 COLOR 3, "\294"
		IF peek($200 + temp2 + 1) = 0 THEN PRINT AT temp2 + 1 COLOR 3, "\295"
	NEXT temp1
	flags = flags AND $FFEF
END

clear_stars2: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2 - 1) = $0933 THEN PRINT AT temp2 - 1 COLOR 0, " "
		IF peek($200 + temp2) = $093B THEN PRINT AT temp2 COLOR 0, " "
	NEXT temp1
	GOSUB draw_stars2
END

draw_stars2: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2) = $0933 THEN PRINT AT temp2 COLOR 0, " "
		IF peek($200 + temp2 + 1) = $093B OR peek($200 + temp2 + 1) = 0 THEN PRINT AT temp2 + 1 COLOR 3, "\294"
		IF peek($200 + temp2 + 2) = 0 THEN PRINT AT temp2 + 2 COLOR 3, "\295"
	NEXT temp1
END

And here are the tick and scroll_screen subroutines:

timer_tick: PROCEDURE
	counter = counter + 1
END

scroll_screen: PROCEDURE
	IF (counter AND 15) = 0 THEN IF offset_x<=0 THEN offset_d=2:offset_x=7: GOSUB update_back_cards ELSE offset_x=offset_x-1: GOSUB update_back_cards: pres_x = pres_x - 1
	
	SCROLL offset_x,0,offset_d
	IF offset_d = 2 THEN GOSUB draw_stars2
	offset_d = 0
END

Now, whether that final GOSUB call is for clear_stars, draw_stars2, or clear_stars2 makes a huge difference in how the stars display:

 

clear_stars:

clear_stars.bin

draw_stars2:

draw_stars2.bin

clear_stars2:

clear_stars2.bin

clear_stars2 comes the closest to being right, with the stars that are initially on-screen remaining solid regardless of scrolling, but new stars get the annoying flicker effect that the draw_stars2 stars do, and clear_stars just tries to hide the draw_stars flicker effect by making the stars disappear for a frame (a weak solution to the problem).

 

What am I overlooking here, and how can I get the stars to remain in place like those top 3 clear_stars2 stars, but everywhere and regardless of what may scroll over the stars?

 

As a final note, I call "flags = flags XOR $10" after the initial SCREEN statement to draw the stars to begin with.

Edited by Cybearg
Link to comment
Share on other sites

For whatever reason, I just can NOT wrap my head around this.

 

I have four different subroutines that handle the stars in different ways, with varying levels of success. I'll give examples as I go.

 

The main loop is like this:

main_loop:
	GOSUB timer_tick
	IF (flags AND $10) <> 0 THEN GOSUB draw_stars
	GOSUB scroll_screen
	GOSUB update_states
	GOSUB set_player_states
	IF (flags AND 2) <> 0 THEN GOSUB crashing
	GOSUB set_sprites
	
	WAIT
	GOTO main_loop

So keep in mind that that draw_stars is only executed if one of the flag bits are set.

 

Here are the different star subroutines:

clear_stars: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2) = $0933 THEN PRINT AT temp2 COLOR 0, " "
		IF peek($200 + temp2 + 1) = $093B THEN PRINT AT temp2 + 1 COLOR 0, " "
	NEXT temp1
	flags = flags XOR $10
END

draw_stars: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2) = 0 THEN PRINT AT temp2 COLOR 3, "\294"
		IF peek($200 + temp2 + 1) = 0 THEN PRINT AT temp2 + 1 COLOR 3, "\295"
	NEXT temp1
	flags = flags AND $FFEF
END

clear_stars2: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2 - 1) = $0933 THEN PRINT AT temp2 - 1 COLOR 0, " "
		IF peek($200 + temp2) = $093B THEN PRINT AT temp2 COLOR 0, " "
	NEXT temp1
	GOSUB draw_stars2
END

draw_stars2: PROCEDURE
	FOR temp1 = 0 TO 7
		temp2 = star_locations(temp1)
		IF peek($200 + temp2) = $0933 THEN PRINT AT temp2 COLOR 0, " "
		IF peek($200 + temp2 + 1) = $093B OR peek($200 + temp2 + 1) = 0 THEN PRINT AT temp2 + 1 COLOR 3, "\294"
		IF peek($200 + temp2 + 2) = 0 THEN PRINT AT temp2 + 2 COLOR 3, "\295"
	NEXT temp1
END

And here are the tick and scroll_screen subroutines:

timer_tick: PROCEDURE
	counter = counter + 1
END

scroll_screen: PROCEDURE
	IF (counter AND 15) = 0 THEN IF offset_x<=0 THEN offset_d=2:offset_x=7: GOSUB update_back_cards ELSE offset_x=offset_x-1: GOSUB update_back_cards: pres_x = pres_x - 1
	
	SCROLL offset_x,0,offset_d
	IF offset_d = 2 THEN GOSUB draw_stars2
	offset_d = 0
END

Now, whether that final GOSUB call is for clear_stars, draw_stars2, or clear_stars2 makes a huge difference in how the stars display:

 

clear_stars:

attachicon.gifclear_stars.bin

draw_stars2:

attachicon.gifdraw_stars2.bin

clear_stars2:

attachicon.gifclear_stars2.bin

clear_stars2 comes the closest to being right, with the stars that are initially on-screen remaining solid regardless of scrolling, but new stars get the annoying flicker effect that the draw_stars2 stars do, and clear_stars just tries to hide the draw_stars flicker effect by making the stars disappear for a frame (a weak solution to the problem).

 

What am I overlooking here, and how can I get the stars to remain in place like those top 3 clear_stars2 stars, but everywhere and regardless of what may scroll over the stars?

 

As a final note, I call "flags = flags XOR $10" after the initial SCREEN statement to draw the stars to begin with.

I don't have time to look at this in detail now, but I am guessing that in the middle of your draw_stars routine, the hardware reads backtab and generates the display.

So, stars near the top of the screen have been updated, but stars near the bottom of the screen have not been updated...

Link to comment
Share on other sites

Hmmm. IntyBASIC scrollng (nor Intellivision scroling) wasn't designed with this in mind.

 

The values for the SCROLL statement are "saved" for the next interrupt update.

 

Unfortunately there is no way to know when this is going to happen, so your stars erase subroutine gets executed a little before, erasing while the screen is being displayed.

 

The only way to keep your stars fixed (and flicker free isn't guaranteed) is to update stars after WAIT, replacing moved stars to their original locations.

 

Another suggestion to save time is to put a PRINT AT x COLOR x before the FOR, so the COLOR attribute is fixed and this saves some cycles as in the inner loop you can use only PRINT AT X," "

Link to comment
Share on other sites

In Oopsatron, I had rows of the same star character, so I didn't have to update the stars at all,.

I occasionally moved the stars to the right, and I set the rate so that one of these occasions always occured on the same frame that I was moving the entire screen, so I didn't have to counterscroll for that frame,.

 

People complained that there were just too many stars, so I have to do something trickier...

 

 

post-14916-0-41630500-1412337109_thumb.gif

 

 

Catsfolly

 

Link to comment
Share on other sites

 

I think, if I followed his explanation correctly, the code originally started out as (at a high level):

  • GOSUB INIT_LEVEL
  • GOSUB PLAY_LEVEL

 

and now INIT_LEVEL GOTOs PLAY_LEVEL without a return. Yep, that'll overflow the stack, assuming PLAY_LEVEL GOTOs the main above-game loop.

 

Took a bit to re-read that, to realize you're saying exactly what I am. I had left a bunch of GOSUBs in place that I never returned from (just did a GOTO somewhere else, eventually hopping back to the start of the game). That pushes a bunch of addresses onto the stack that never get popped off. It certainly fixed the problems I was having with variable corruption, once I converted them to GOTOs.

 

Appreciate everyone's help and comments. I figured it out as soon as "stack overflow" got into my brain.

 

Also I'm with you on the inlining of code. I'm not there yet - in fact the various GOSUBs I use every frame have helped with subtle speed aspects - but I can see the impact. It's a huge performance hit and I don't see it as a huge code savings. Not when we can use 16K ROMs without batting an eye. Code isn't my problem and I don't know that it ever will be, from a storage perspective - graphics, sound... now those can take up space once you get heavily into them! Code only seems to get crazy when I get stupid with logic and arithmetic, but a simple re-factor eliminates 75% of it much of the time.

 

So, feature request? Could IntyBASIC support what you're essentially doing with the inlined ASM? Allow readability in the .bas file while avoiding using so many precious cycles hopping around the stack?

Edited by freeweed
  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...