Jump to content
IGNORED

Scanline problem. I'm stuck


Recommended Posts

Ok so I've been fighting the scanlines in my game the last few days but to no avail. I've narrowed it down to it being the AI as its stable when in 2p mode and flickering when in 1p mode. (leftwitch to A) The flicker always seems to happen when playfieldpos = 7 or 8 (It depends on if the frame showing too many scanlines is the one on which its happening or if thats the frame after the overload.) However, turning off the AI at certain playfieldpos does not seem to work. Adding in an additional drawscreen solves the problem, but it also slows down the game beyond the point of it being playable.

 

So I was wondering if anyone has an idea on how to solve this.

  • Is there a way to keep the scrollspeed high while adding a new drawscreen?
  • Is there a way to know were in the script the code is when its overloading? Most sections are not timing critical within 1 frame, so heavy things could be turned off at a certain playfieldpos.
  • Are there any other brilliant solutions that I am missing?

The starting speed in this version is high because the blinking only happens at high speeds. That's ~100 in this build.

 

Any help would be massively appreciated, as the grim alternative is killing the AI.

MonkeyKing_NTSC.bas

score_graphics.asm

playerscores.asm

Link to comment
https://forums.atariage.com/topic/283615-scanline-problem-im-stuck/
Share on other sites

What I did in the past was moved the drawscreen to another location in bank and that solved it. Example was that the collision need to be after the drawscreen to work properly. That may help you until someone else chimes in.

I don't know when I'll have a chance to look at your code, but a couple of thoughts:

 

The latest RevEng build of bB has a change that names the build files with names that will be recognized by the Stella debugger. Using the debugger and being able to see your variable/label names makes troubleshooting this stuff much easier.

 

Lewis has a good point about whether the code is before or after the drawscreen, because playfieldpos is incremented at this point.

 

At any rate, the problem happens when the AI is active, so it may just be a matter of trial and error to figure out where it is encountering problems. Maybe go extreme for the sake of experimentation, and only run the AI when playfieldpos < 5. If that works, move it up to 6 or 7.

 

Since you had issues with the AI being too good, having a couple of frames where it does nothing might cause it to make a few mistakes without being overly obvious.

What I did in the past was moved the drawscreen to another location in bank and that solved it. Example was that the collision need to be after the drawscreen to work properly. That may help you until someone else chimes in.

I tried that and it does need to be above the collisions yes, but other then that it doesn't seem to change much. Also moving the AI section to above or below it doesn't seem to help much. (Apart from the AI getting dumber when it's above :P)

 

I don't know when I'll have a chance to look at your code, but a couple of thoughts:

 

The latest RevEng build of bB has a change that names the build files with names that will be recognized by the Stella debugger. Using the debugger and being able to see your variable/label names makes troubleshooting this stuff much easier.

 

Lewis has a good point about whether the code is before or after the drawscreen, because playfieldpos is incremented at this point.

 

At any rate, the problem happens when the AI is active, so it may just be a matter of trial and error to figure out where it is encountering problems. Maybe go extreme for the sake of experimentation, and only run the AI when playfieldpos < 5. If that works, move it up to 6 or 7.

 

Since you had issues with the AI being too good, having a couple of frames where it does nothing might cause it to make a few mistakes without being overly obvious.

I've tried just running it on certain pfpostions but it doesn't seem to solve the issue. And that surprised me because it still only happens when the pfpos is ~0. But turning it off all together does solve it. So that's strange. Perhaps I'm doing something very dumb, I'll keep looking. But if you manage to find some time that would be great too! I'll also look into the debugger, as I still cant get that to work properly.

Found two problems so far:


   if bally > 200 && !(rand&7) then bally = 0 : _Ch0_Sound = 5 : _Ch0_Duration = 25 : _F0 = 31 : _bleep =0 ;: missile0y = 160 : missile1y = 160


   if _speed > 254 && !_left_right{1} then _left_right{1} = 1 : _speed = 0


According to the chart, NOT cannot be used with < > =. You also have "_bleep =0 ;: missile0y = 160 : missile1y = 160" is that semicolon supposed to be there?

Just glancing at the code below, could that last if-then cause too much time to go by before a drawscreen happens?


__scrolldown

   ; animate sprite 
   _animate = _animate + 1
   if _animate > 5 then _animate = 0


   ; check if a new tree block needs to be made and then see if a branch should be made
   if playfieldpos = 1 then _left_right{0} = 1  : pfpixel 8 0 8 on : pfpixel 24 0 24 on   else _left_right{0} = 0 
   if _left_right{0} && (rand&1) then gosub __branch 


   ; Move magic stones & ball & scroll screen

   missile0y = missile0y + 1
   missile1y = missile1y + 1
   bally = bally + 2
   pfscroll down

__skipscroll

   if _left_right{1} && _left_right{2} then _left_right{2} =0 : goto __scrolldown


I'm not very familiar with bB, but I think replacing this

if _left_right{1} && _left_right{2} then

with

if (_left_right & 6) = 6 then

may be faster.

 

Also I think you could replace

if _left_right{0} && (rand&1) then gosub __branch 

with

if _left_right & rand & 1 then gosub __branch 

Of course you would probably want to verify the cycle counts with stella to confirm which way is faster.

 

*Edit: Fixed syntax for equal comparison

Edited by ZackAttack

Just glancing at the code below, could that last if-then cause too much time to go by before a drawscreen happens?


__scrolldown

   ; animate sprite 
   _animate = _animate + 1
   if _animate > 5 then _animate = 0


   ; check if a new tree block needs to be made and then see if a branch should be made
   if playfieldpos = 1 then _left_right{0} = 1  : pfpixel 8 0 8 on : pfpixel 24 0 24 on   else _left_right{0} = 0 
   if _left_right{0} && (rand&1) then gosub __branch 


   ; Move magic stones & ball & scroll screen

   missile0y = missile0y + 1
   missile1y = missile1y + 1
   bally = bally + 2
   pfscroll down

__skipscroll

   if _left_right{1} && _left_right{2} then _left_right{2} =0 : goto __scrolldown


 

It only happens at high speeds (so when _left_right{1} = 1) so I think that that running that twice + the AI is too much yes. But without it the game moves to slowly so I never really did much with that line. I tried to turn it off on certain PFpositions once but then the tree got very glitchy with holes in it and double branches, etc. The blink also usually happens when a block is made, but not always! So this probably also is a culprit.

if playfieldpos = 1 then _left_right{0} = 1  : pfpixel 8 0 8 on : pfpixel 24 0 24 on   else _left_right{0} = 0 

And this one should stay on PFpos=1 because otherwise the scrolling of the tree is ugly.

 

I'm not very familiar with bB, but I think replacing this

if _left_right{1} && _left_right{2} then

with

if (_left_right & 6) = 6 then

may be faster.

 

Also I think you could replace

if _left_right{0} && (rand&1) then gosub __branch 

with

if _left_right & rand & 1 then gosub __branch 

Of course you would probably want to verify the cycle counts with stella to confirm which way is faster.

 

*Edit: Fixed syntax for equal comparison

 

What does the first one actually do? The (_left_right & 6) ? _left_right{3} is also sometimes used, so you can't just compare it to a value based on the rest being 0. (If thats what it does!) And if it is I might be able to make the rest 0 and move the used bits to other variables.

 

Same question with the other line. What does the single & do? (Not really easy to google for :P). (Don't have my laptop on me now, so can't try it until later this evening.)

 

Thanks for looking everyone!

Edited by Coolcrab

I've looked at this a bit, and I don't think there's a simple "magic bullet" solution - it will take trial and error and rearranging code to see what works. I noticed that it overcycles sometimes when playfieldpos = 1 even without the AI. pfpixel operations are expensive in terms of cycles, so this may be a factor.

 

What may help is using cycles from vblank. If you add a vblank section and move your AI code there, and perhaps your pfpixel operations as well then this may help solve your issue with overcycling.

What does the first one actually do? The (_left_right & 6) ? _left_right{3} is also sometimes used, so you can't just compare it to a value based on the rest being 0. (If thats what it does!) And if it is I might be able to make the rest 0 and move the used bits to other variables.

 

Same question with the other line. What does the single & do? (Not really easy to google for :P). (Don't have my laptop on me now, so can't try it until later this evening.)

 

Thanks for looking everyone!

 

See http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#bitwise_simplified

 

The & is the bitwise AND operator 6 is %00000110 in binary which is the mask you would need for bits 1 and 2. So _left_right & 6 is basically giving you a value that is only dependent on _left_right{1} and _left_right{2}. Then we compare that value with 6 to verify that both bits 1 and 2 are set.

 

In the second case you only car about bit 0 everywhere so it's possible to just bitwise AND them all together and then the result will only be 1 if all 3 values had bit 0 set.

 

I assume both examples will be smaller and faster because they should reduce the amount of compare/branch pairs needed to implement the same logic.

I've looked at this a bit, and I don't think there's a simple "magic bullet" solution - it will take trial and error and rearranging code to see what works. I noticed that it overcycles sometimes when playfieldpos = 1 even without the AI. pfpixel operations are expensive in terms of cycles, so this may be a factor.

 

What may help is using cycles from vblank. If you add a vblank section and move your AI code there, and perhaps your pfpixel operations as well then this may help solve your issue with overcycling.

I tried this plus some rearranging and I think that it worked!!! I'm now trying it out to see if it still glitches, but so far so good. Thanks a million!

 

 

See http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#bitwise_simplified

 

The & is the bitwise AND operator 6 is %00000110 in binary which is the mask you would need for bits 1 and 2. So _left_right & 6 is basically giving you a value that is only dependent on _left_right{1} and _left_right{2}. Then we compare that value with 6 to verify that both bits 1 and 2 are set.

 

In the second case you only car about bit 0 everywhere so it's possible to just bitwise AND them all together and then the result will only be 1 if all 3 values had bit 0 set.

 

I assume both examples will be smaller and faster because they should reduce the amount of compare/branch pairs needed to implement the same logic.

The first one works the 2nd one does something different. (Hardly any branches show up) So I'm guessing that there is some kind of translation error.

I know that bB does not like more than 2 &&'s so maybe it's the same for &'s?

MonkeyKing_NTSC.bas

Edited by Coolcrab
  • Like 1

Here I've meddled with your code some.

 

Aside from thowing in a few goto's in empty goto spots (necessary to even get it to compile) and other minor rearrangements

 

mainly I

 

poked the screen variables directly in some places, clearing the branches in particular

 

moved the new row/branch generation to after the scroll down and added a drawscreen

so that's all you do in the rest of that frame having bumped the playfield up in the scroll routine (which takes time)

 

moved the drawscreen into the sprite_color routine since they go together

 

 

Unfortunately I've added a bug which I haven't figured out yet (you'll probably notice it ;) ) edit: fixed (so you wont notice it :) )

 

I haven't seen it go over on the line count (neither this, or your original code)

 

 

What makes you think bB doesn't like more than two &&'s ?

MonkeyKing_NTSC_2_mod.bas

Edited by bogax
  • Like 2

Here I've meddled with your code some.

 

Aside from thowing in a few goto's in empty goto spots (necessary to even get it to compile) and other minor rearrangements

 

mainly I

 

poked the screen variables directly in some places, clearing the branches in particular

 

moved the new row/branch generation to after the scroll down and added a drawscreen

so that's all you do in the rest of that frame having bumped the playfield up in the scroll routine (which takes time)

 

moved the drawscreen into the sprite_color routine since they go together

 

 

Unfortunately I've added a bug which I haven't figured out yet (you'll probably notice it ;) ) edit: fixed (so you wont notice it :) )

 

I haven't seen it go over on the line count (neither this, or your original code)

 

 

What makes you think bB doesn't like more than two &&'s ?

Wow that's amazing! Could you explain what you did exactly with the branch destruction? You are not using PFpixel but how does this other thing work?

 

Like how does this

 var0 = 15 : var2 = 15 

equal

pfhline 4 0 7 on : pfhline 20 0 23 on

?

Edited by Coolcrab

This applies to the plain vanilla standard kernel, things will be different with some of the kernel options

 

the playfield is 32 pfpixels x 12 pfpixels

each pfpixel is 4 pixels x 8 scanlines

 

the pfpixels are represented in memory by 32 x 12 bits

the pf pixels go row x column starting at the top left

the top left corner is pfpixel 0 0 (x y) the bottom right is 11 31

with 8 bits per byte that's 48 bytes 4 x 12

those are named var0..var47 in bB

 

the bytes are consecutive in memory and every 4 bytes is a playfield row

var0 is pfpixels 0..7 in row 0, var4 is pfpixels 0..7 in row 1 (the second row of pixels)

 

the odd number bytes are reversed

 

we number the the bits in a byte 7 6 5 4 3 2 1 0

 

var0 = %10000000 (128 decimal) will result in pfpixel 0 0 on and pf pixels 1..7 0 off (ie x = 1 to 7 with y = 0)

var1 = %00000011 (3 decimal) will result in pfpixels 8..9 0 on and pfpixels 10..15 0 off

 

the trunk of the player0 tree is at pfpixel 8 0..11

 

so to clear the branches on the right var1 = 1

the second column of 8 pfpixels are reversed so the bits in var1 numbered as 7 6 5 4 3 2 1 0

appear as playfield pixels 8 9 10 11 12 13 14 15 corresponding to var1 bits 0 1 2 3 4 5 6 7

 

to create a player0 tree right branch on row 0,

var1 = %00011111 (31 decimal)

(and it just occured to me that you've got the right side branch creation

under the __left label and I used the value15 so the right side branches are only

3 pfpixels wide in my code)

 

the branch clearing just sets every fourth playfield variable to the correct value

 

and the way bB works it's faster if you put all the assignments on the same line (because they're all the same value)

if you put the assignments on different lines it'd be something like this (in bB)(acc is a processor register, the accumulator)

  acc = 1
 var1 = acc
 acc = 1
 var5 = acc
 acc = 1
 var9 = acc  etc.

since they're all assigning the same value and if they're all consecutively on the same line it's more like this

 acc = 1
 var1 = acc
 var5 = acc
 var9 = acc  etc.

(of course it's in machine code not bB)

 

 

if playfieldpos is 1 when pfscroll down returns

you know pfscroll down just spent a lot of time moving

the playfield otherwise it just increments playfieldpos

 

you could move the playfield in bB it might save you 200+ cycles

but it would take 200 bytes or so

you'd basically do your own version of pfscroll down in bB

Edited by bogax
  • Like 4

I'll probably have to do this on paper to really get it, but I understand the principle. Thanks!

 

Also does this mean that basically you never want to use PFread? Since most of that stuff can be done with bitwise, would that be faster?

 

It freed up a lot of space at any rate. :) I'm now making a hybrid version between yours and mine to make sure I get all the steps.

The draw screen in the loop seems to have trouble though as the glitching score number is back. (Which apparently appears if the code has too many compound gosubs to deal with.)

what do you expect

player0score = $a

to display?

 

if you're shooting for 10 it should be $10

I added 6 extra custom font chars for the powerups. They are in the font under $a - $f

Its those symbols. They come from the minikernel thats on the bottom. (That you turned off)

You can download it in the top post, together with the font.

post-48701-0-89230900-1539066231.png

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...