;
;   ;--------------------------------------------------------------------------;
;   ;   Step 10                                                                ;
;   ;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;
;
;,,,,
    ;   Limiting the screen to the size of the background.
    ;   All you need to do is alter the visual/screen positions.
    ;   The world coordinates stay the same.
    ;   Only the things that you see will be different.
    ;
    ;   So it's basically as the program from step 8.
    ;   Only new things are when reaching an edge
    ;    of the background.
    ;   What needs to be done is:
    ;
    ;       1) Altering the background position *on screen*
    ;       2) Altering the player position *on screen*
;----
;
;,,,,
    ;   First, we need to check when an edge is reached.
    ;
    ;       B-------------------------------+··bpY····-
    ;       |                               |         ^
    ;       |   S---=---=---=---+···········|··-      |
    ;       |   |               |           |  ^      |
    ;       |   (               )           |  |      | bsY
    ;       |   |               |           |  |      |
    ;       |   (               )           |  | ssY  |
    ;       |   |               |           |  |      v
    ;       +---(- - - - - - - -)-----------+··|······-
    ;       ·   |               |              v
    ;       ·   +---=---=---=---+··············-
    ;       ·
    ;       bpX
    ;
    ;           Legend
    ;               (bpX,bpY)   Back_Pos
    ;               (bsX,bsY)   Back_Size
    ;               (ssX,ssY)   Screen_Size
    ;
    ;   You see that the lower edge of the background has been crossed.
    ;   What we want is this:
    ;
    ;       B---S---=---=---=---+-----------+
    ;       |   |               |           |
    ;       |   |               |           |
    ;       |   |               |           |
    ;       |   |               |           |
    ;       |   |               |           |
    ;       |   |               |           |
    ;       |   |               |           |
    ;       +---+---=---=---=---+-----------+
    ;
    ;   So how do we do this?
    ;   Below I've marked two vertical positions.
    ;   Background limit bL and Screen limit sL.
    ;
    ;       (bpX,bpY)
    ;          \
    ;           B-------------------------------+·········-
    ;           |                               |         ^
    ;           |   S---=---=---=---+···········|··-      |
    ;           |   |               |           |  ^      |
    ;           |   (               )           |  |      | bsY
    ;           |   |               |           |  |      |
    ;           |   (               )           |  | ssY  |
    ;           |   |               |           |  |      v
    ;           +---(- - - - - - - -)-----------+··|······-··bL
    ;               |               |              v
    ;               +---=---=---=---+··············-··sL
    ;
    ;   You can see that bL has a lower value than sL.
    ;   So we need to set bL to sL if bL is lower than sL.
    ;
    ;   Okay let's zoom in on these vertical points.
    ;
    ;   The orientation is our screen, where (0,0) is exactly
    ;    in the upperleft corner (on the 'S' in the picture).
    ;
    ;   This means that sL is the screen height.
    ;
    ;   Furthermore, zooming in on point bL..
    ;
    ;               -----------------+···-···········-··· bpY
    ;                                |   | bpY       ^
    ;            -------+············|···-······ 0   |
    ;                   |            |               |
    ;                   | background |               | bsY
    ;                   |            |               |
    ;           screen  |            |               |
    ;                   |            |               v
    ;                   |------------+···············-··· bL
    ;                   |
    ;        -----------+
    ;
    ;   In the picture above you can see that..
    ;
    ;       bL = bpY + bsY
    ;
    ;   So, in english, in bL is lower than sL, set bL to sL.
    ;
    ;       if bL < sL then bL = sL
    ;
    ;   Let's fill in what we know..
    ;
    ;       sL = Screen_SizeY
    ;       bL = Back_PosY + Back_SizeY
    ;
    ;       if Back_PosY + Back_SizeY < Screen_SizeY then
    ;           Back_PosY + Back_SizeY = Screen_SizeY
    ;
    ;   The assignment is not yet correct, though.
    ;   So let's flip Back_SizeY to the other side,
    ;    since we want to change the background position, not the size.
    ;
    ;           Back_PosY = Screen_SizeY - Back_SizeY
    ;
    ;   Ofcourse, the same goes for the horizontal right edge.
    ;
    ;   Let's continue with the upperleft corner,
    ;    being the upper and left edge of the background.
    ;
    ;           S---=---=---=---+··············-···· 0
    ;           |               |              | bpY
    ;       B---(- - - - - - - -)-----------+··-···· bpY
    ;       |   |               |           |
    ;       |   (               )           |
    ;       |   |               |           |
    ;       |   (               )           |
    ;       |   |               |           |
    ;       |   +---=---=---=---+           |
    ;       |                               |
    ;       +-------------------------------+
    ;
    ;   You can see that bpY should not (visually) go below 0.
    ;   So bpY should be set to 0 when its value its value is above 0.
    ;   Remember, Y+ still means *down* on today's computer system.
    ;
    ;   Still in english, if the value of bpY is higher than 0, set bpY to 0.
    ;
    ;       if bpY > 0 then bpY = 0
    ;
    ;   Okay, what is bpY?
    ;
    ;       bpY = Back_PosY
    ;
    ;   Fill it in.
    ;
    ;       if Back_PosY > 0 then Back_PosY = 0
    ;
    ;   And again the same goes for the horizontal dimension.
;----
;
;,,,,
    ;   Next, the player needs adjustment when nearing
    ;    the edge of the background.
    ;
    ;   E.g. before it always stayed in the middle of the screen.
    ;   We want it to actually move away from the middle of the screen instead.
    ;
    ;   You can do a lot of fancy stuff to pull this off.
    ;   However, you could also use the background position we just calculated
    ;    to find where to draw the player on screen.
    ;
    ;   Remember the view point formula from step 9?
    ;
    ;       Player_ScreenPos = Screen_Mid - View_WorldPos
    ;
    ;   We used the middle of the screen as orientation.
    ;   And an added (or subtracted) offset of the view point.
    ;
    ;   This is the basics for what we're gonna do next.
    ;
    ;   Take the following situation for example:
    ;
    ;           S---=---=---=---+
    ;           |               |
    ;       B---(- - - - - - - -)-----------+
    ;       |   |               |           |
    ;       |   (       P       )           |
    ;       |   |               |           |
    ;       |   (               )           |
    ;       |   |               |           |
    ;       |   +---=---=---=---+           |
    ;       |                               |
    ;       +-------------------------------+
    ;
    ;   We can already apply the background position adjustment.
    ;   But what we want is that the player keeps
    ;    its relative position at this point.
    ;
    ;       B---S---=---=---=---+-----------+
    ;       |o o|· · · · · · · ·|o o o o o o|
    ;       b-o-(-·-·-·-P-·-·-·-)-o-o-o-o-o-+
    ;       |o o|· · · · · · · ·|o o o o o o|
    ;       | o ( · · · p · · · ) o o o o o |
    ;       |o o|· · · · · · · ·|o o o o o o|
    ;       | o ( · · · · · · · ) o o o o o |
    ;       |o o|· · · · · · · ·|o o o o o o|
    ;       +---+---=---=---=---+-----------+
    ;       |                               |
    ;       +- - - - - - - - - - - - - - - -+
    ;
    ;           Legend
    ;               b       Background pos before adjustment
    ;               B       Background pos after adjustment
    ;               p       Player pos before adjustment
    ;               P       Player pos after adjustment
    ;               S       Screen pos (0,0)
    ;
    ;   You can quickly see that the change from b to B
    ;    is exactly the same as the change from p to P!
    ;
    ;   So we have to know the distance between b and B.
    ;   Even though we do not directly know what b is,
    ;    because we changed it to become B.
    ;
    ;   Look at following equation:
    ;
    ;       Computer = Board + Processor + Memory + Drive
    ;
    ;   Now we add something:
    ;
    ;       Computer = Computer + Power
    ;
    ;   A neat trick we can do is we can remove all components
    ;    from the computer and find our power supply back.
    ;
    ;       FindPower = Computer - ( Board + Processor + Memory + Drive )
    ;
    ;   FindPower would now equal Power.
    ;   The same technique we're gonna use to find 'b'.
    ;
    ;   Only difference (gah!) is that we're using
    ;    the alleged orientation point again.
    ;
    ;   We can calculate the background screen position using:
    ;
    ;       Back_ScreenPos = Back_WorldPos - Player_WorldPos + Screen_Mid
    ;
    ;   Now check in which range this value will be..
    ;
    ;       ( 0 ) to ( Screen_Size - Back_Size )
    ;
    ;   Screen size minus background size?
    ;
    ;           -··B-------------------------------+··-
    ;       bpY |  |                               |  ^
    ;           -··|···S---=---=---=---+··-        |  |
    ;              |   |               |  ^        |  |
    ;              |   (               )  |        |  | bsY
    ;              |   |               |  |        |  |
    ;              |   (       P       )  | ssY    |  |
    ;              |   |               |  |        |  v
    ;              +---(- - - - - - - -)--|--------+··-
    ;                  |               |  v
    ;                  +---=---=---=---+··-
    ;
    ;   So it's *never* outside this range.
    ;
    ;   That's why we can strip the entire original contents:
    ;
    ;      n = Back_ScreenPos - ( Back_WorldPos - Player_WorldPos + Screen_Mid )
    ;
    ;   Now, you *know* this will always be *zero*
    ;    when it is not influenced by something else.
    ;
    ;   Suppose we let the player move up.
    ;
    ;           S---=---=---=---+
    ;           |               |
    ;       B---(- - - - - - - -)-----------+
    ;       |   |               |           |
    ;       |   (       P       )           |
    ;       |   |               |           |
    ;       |   (               )           |
    ;       |   |               |           |
    ;       |   +---=---=---=---+           |
    ;       |                               |
    ;       +-------------------------------+
    ;
    ;   And we apply our background adjustment,
    ;    e.g. let loose our four IF hounds err statements..
    ;   So the vertical position would be set to: 0.
    ;
    ;        ^  S---=---=---=---+··· 0    ^
    ;        |  |               |         |
    ;       B---(- - - - - - - -)-----------+
    ;       |   |               |           |
    ;       |   (       P       )           |
    ;       |   |               |           |
    ;       |   (               )           |
    ;       |   |               |           |
    ;       |   +---=---=---=---+           |
    ;       |                               |
    ;       +-------------------------------+
    ;
    ;   Now let's fill in the vertical values in the formula:
    ;
    ;      n = Back_ScreenPos - ( Back_WorldPos - Player_WorldPos + Screen_Mid )
    ;
    ;       Back_ScreenPos  = 0 (capped)
    ;       Back_WorldPos   = 0 (constant)
    ;       Player_WorldPos = Screen_Size * 1/4 (or something like that)
    ;       Screen_Mid      = Screen_Size * 1/2 (constant)
    ;
    ;   Let's solve it.
    ;
    ;       n = 0 - ( 0 - Screen_Size * 1/4 + Screen_Size * 1/2 )
    ;       n = 0 - ( Screen_Size * 1/2 - Screen_Size * 1/4 )
    ;       n = Screen_Size * 1/4 - Screen_Size * 1/2
    ;       n = Screen_Size * 1/4 - Screen_Size * 2/4
    ;       n = -Screen_Size * 1/4
    ;
    ;   So our player is (vertically) placed a quarter outside of the screen.
    ;   What happened?
    ;
    ;   Well, we used orientation (0,0).
    ;   So just add half the screen and it'll be centered on screen again.
    ;
    ;       n = Back_ScreenPos
    ;            - ( Back_WorldPos - Player_WorldPos + Screen_Mid )
    ;            + Screen_Mid
    ;
    ;   Yes, that can be simplied, as follows;
    ;
    ;       n = 0
    ;           - ( Back_WorldPos + -Player_WorldPos + Screen_Mid )
    ;           + Back_ScreenPos + Screen_Mid
    ;
    ;       n = 0
    ;           - Back_WorldPos + Player_WorldPos - ScreenMid
    ;           + Back_ScreenPos + Screen_Mid
    ;
    ;       n = Back_ScreenPos - Back_WorldPos + Player_WorldPos
    ;           - Screen_Mid + Screen_Mid
    ;
    ;       n = Back_ScreenPos - Back_WorldPos + Player_WorldPos
    ;
    ;   The point is that when you know algebra well,
    ;    it feels like your brain does this almost automatically.
    ;
    ;   Anyway, our final equation is:
    ;
    ;       Player_ScreenPos = Back_ScreenPos - Back_WorldPos + Player_WorldPos
    ;
    ;   Which can be used continuously, after applying the background fix.
;----

    ;   -- Sizes --

    Screen_SizeX = GraphicsWidth ()
    Screen_SizeY = GraphicsHeight ()
    Screen_MidX = Screen_SizeX / 2
    Screen_MidY = Screen_SizeY / 2

    ;   Make background double size of screen to demonstrate the effect better.

    Back_SizeX = Screen_SizeX * 2
    Back_SizeY = Screen_SizeY * 2

    Player_SizeX = 20
    Player_SizeY = 20

    ;   -- Positions --

    Back_WorldPosX = 0
    Back_WorldPosY = 0

    Player_WorldPosX = 0
    Player_WorldPosY = 0

    ;   Put player in middle of background.

    Player_WorldPosX = Back_SizeX / 2
    Player_WorldPosY = Back_SizeY / 2

    ;   -- Loop --

    SetBuffer BackBuffer ()
    Repeat

        ;   -- Input --

        ;   Arrow keys control player world position.

        If KeyDown ( 200 ) Then Player_WorldPosY = Player_WorldPosY - 3
        If KeyDown ( 208 ) Then Player_WorldPosY = Player_WorldPosY + 3
        If KeyDown ( 203 ) Then Player_WorldPosX = Player_WorldPosX - 3
        If KeyDown ( 205 ) Then Player_WorldPosX = Player_WorldPosX + 3

        ;   -- Logic --

        ;   Background screen position calculation (2 lines).

        Back_ScreenPosX = Back_WorldPosX - Player_WorldPosX + Screen_MidX
        Back_ScreenPosY = Back_WorldPosY - Player_WorldPosY + Screen_MidY

        ;   Background screen position fix (4 lines).

        If Back_ScreenPosX > 0 Then Back_ScreenPosX = 0
        If Back_ScreenPosY > 0 Then Back_ScreenPosY = 0

        ;   If you can recall from the beginning;
        ;
        ;       if Back_PosY + Back_SizeY < Screen_SizeY then
        ;           Back_PosY = Screen_SizeY - Back_SizeY
        ;
        ;   Note that the notation below does exactly the same thing :)

        If Back_ScreenPosX <= -Back_SizeX + Screen_SizeX
            Back_ScreenPosX = -Back_SizeX + Screen_SizeX
        End If
        If Back_ScreenPosY <= -Back_SizeY + Screen_SizeY
            Back_ScreenPosY = -Back_SizeY + Screen_SizeY
        End If

        ;   Magical player screen position calculation (2 lines).

        Player_ScreenPosX = Back_ScreenPosX - Back_WorldPosX + Player_WorldPosX
        Player_ScreenPosY = Back_ScreenPosY - Back_WorldPosY + Player_WorldPosY

        ;   -- Render --

        Rect Back_ScreenPosX , Back_ScreenPosY , Back_SizeX , Back_SizeY , False
        Rect Player_ScreenPosX,Player_ScreenPosY,Player_SizeX,Player_SizeY,False
        Flip
        Cls

    Until KeyHit ( 1 )
    End

;,,,,
    ;   Now, when running the program, it may be a little disorienting.
    ;   This is because you have to travel quite some time
    ;    before you reach the end of the background.
    ;
    ;   And please, tell me if something - *anything* - was unclear ;)
    ;   The address is TheChance (TheChange@yahoo.com).
    ;   Constructive spam can be useful too :P
;----