You'd think this would be faster, but NO!!!!!! [Resolved]
#11
(10-14-2022, 05:22 AM)Pete Wrote: Hi Matt,

I've already modified the code to the SELECT CASE snippet I posted, which solved the slow down the h = SCREEN() created. I do have a backup copy of the one with the speed killing situation. No, $CHECKING:OFF does nothing to offset the decreased speed issue in the backup copy with the speed reduction problem.

h, btw is an integer, defined by a DEFINT H-K at the top of the program.

Pete

Thanks for trying Smile I'll have to give it some more thinking. Unfortunately on my machine just putting that logic into a loop (with some dummy types to make it compile) comes out with it running slightly faster if you store the value in
h
rather than use
SCREEN()
three times (as you originally assumed would be the case).

I'm not sure this is what you're doing, but I would note that the usage of
h
gets more expensive if it's in a
SUB
or
FUNCTION
and you're constantly calling it - there's some allocation overhead that goes on for
h
every time you enter the
SUB
or
FUNCTION
it is declared in. This is also a notable difference from
SELECT CASE
, as the internal variable that stores the value you're selecting on (to do the comparisons with each
CASE
) does not get allocated the same way and thus does not have that overhead. None of my testing on this can get close to a 5x slowdown though  Undecided
Reply
#12
(10-14-2022, 05:50 AM)Pete Wrote: Steve must have missed my second post.

Pete

I did, but it's amazing how similar we're thinking -- except, of course, you're once again thinking WRONG.  Tongue

Code: (Select All)
FOR i = 0 TO LEN(a.ship) - 1
    SELECT CASE SCREEN(j, k + i)
        CASE ASC(g.flagship)
            ii = 1
            EXIT FOR
        CASE g.m_asc
            ii = 2
    END SELECT
NEXT


I'd simplify this with one out of loop step, and then I wouldn't forget my EXIT and bug my code like you are:

Code: (Select All)
A = ASC(g.flagship) 'we do nothing to change the value of g.flagship in the loop.  Why do we need to calculate this value over and over repeatedly?
FOR i = k TO k + LEN(a.ship) - 1
    SELECT CASE SCREEN(j, i) 'no need to have a math operation here with each pass.  Do the math once in the FOR statement and be done with it.
        CASE A 'unchanging value of ASC(g.flagship) -- again, no need for multiple unchanging function calls to get this value.
            ii = 1
            EXIT FOR
        CASE g.m_asc
            ii = 2
            EXIT FOR 'Whoops!  Pete forgot the EXIT which the original had here.  
    END SELECT
NEXT


So now maybe Pete can see why I only ever read about half his posts and code -- at best, they're only about half as good as a Steve(tm) Post!  Big Grin
Reply
#13
Typing out a small loop with all the lines does run faster than a loop, yeah. I saw this demonstrated by 8 Bit Guy on YouTube. He showed how the old BASIC programs often had small loops just written all the way out.
Ask me about Windows API and maybe some Linux stuff
Reply
#14
Steve is pretty good with graphics, but his text ability is pretty half-ASCII. Big Grin

Hey guys, banter aside, just don't miss the point of why I made this post in the first place, to call attention to a peculiar slow-down event, caused by assigning a variable to SCREEN(). Look at it this way, if assigning a variable to avoid repeated asc() checking should speed things up, assigning a variable to SCREEN() should also speed things up; ah, but it didn't. It markedly slowed the animation down. Steve's other suggestion of creating and assigning a new variable to ASC() is correct, but is imperceptible in regard to speed, the difference in speed change by assigning a variable to SCREEN(), in my routine, again, is markedly noteable.

BTW - The CASE 2 part is simply unfinished. I was in the process of adding another condition when this occurred, that's why it is empty with no EXIT FOR, so ignore it, it's not the problem, anyway.

@DSman195276

If it helps, I stripped 70% of the code out to make it easier.

Code example 1 demos the speed as it should be.

Code example 2 demos assigning h to SCREEN(), which slows it down 5x.

To find the code in question, search: Check area through width of ship

Code Example #1
Code: (Select All)
DEFINT H-K
$RESIZE:ON
_RESIZE OFF
RANDOMIZE TIMER
' Note: timer is not adjusted for stroke of midnight event, so don't stay up late playing this.
REM Main
f1 = 22 ' Sets font size to 22 and calculates the max screen height and width for your desktop.
h = (_DESKTOPHEIGHT - 60) \ f1
w = _DESKTOPWIDTH \ (f1 / 1.66)
WIDTH w, h
_SCREENMOVE 0, 0
fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, f1, "monospace")
_FONT font&
_DELAY .25
_RESIZE ON , _SMOOTH ' Allows resizing. Note: this is for slight adjustments. As of this version there is no compensitory function to change the font size during screen size changes.
TYPE gen_var
    intro AS INTEGER ' Runs a protion of the alien subroutine as part of the intro.
    nol AS INTEGER ' Number of game levels.
    level AS INTEGER ' Current game level.
    level_up AS INTEGER ' Routes code to next game level.
    top AS INTEGER ' Top boundary. (Changeable).
    bottom AS INTEGER ' Bottom boundary. (Changeable).
    left AS INTEGER ' Left boundary. (Changeable).
    right AS INTEGER ' Right boundary. (Changeable).
    kb_access AS INTEGER ' Routes code to either Guardian/Alien or general keyboard routine. -1 Guardian/Alien, 0 keyboard.
    mouse_or_key_move AS INTEGER
    play AS INTEGER
    snd1 AS LONG ' Explosion sound effect.
    snd2 AS LONG ' Explosion sound effect.
END TYPE

DIM SHARED v AS gen_var

TYPE guardian
    num AS INTEGER ' Number of Guardians aka lives.
    diry AS INTEGER ' Guardian row move. +1, 0, -1.
    dirx AS INTEGER ' Guardian column move. +2, 0, -2. Equals vertical pixel movement. 16x8.
    y AS INTEGER ' Guardian coordinates row.
    x AS INTEGER ' Guardian coordinates column.
    thrusters AS INTEGER ' Guardian speed. (User Determined).
    m_max AS INTEGER ' Restricts # of missiles fired in one direction.
    m_status AS INTEGER ' Missile status. -1 when fired, 1 while moving.
    m_fired AS INTEGER ' The number of missile deployed and still active.
    m_n AS INTEGER ' FOR/NEXT counter variable shared by other routines to index through the number of missiles fired in a specific direction.
    m_d AS INTEGER ' Missile direction. (1-8).
    m_y AS INTEGER ' Missile row advancement increment: +1, 0, -1 Note: Missile row and column coordinates are defined in arrays.
    m_x AS INTEGER ' Missile column advancement increment: +2, 0, -2. Equals vertical pixel movement. 16x8.
    m_asc AS INTEGER ' ASCII charater representing a fired missile.
    m_launcher AS STRING
    icon AS STRING ' Gardian comm icon. For this edition, it is the same as the flagship: "*"
    flagship AS STRING ' Guardian ascii character.
END TYPE

DIM SHARED g AS guardian

TYPE alien
    max AS INTEGER ' Maximum # of alien ships on screen.
    count AS INTEGER ' Number of alien ships. (Counter).
    itr AS INTEGER ' Iteration array number to cycle through the active alien ships. (Counter).
    cycle_delay AS SINGLE ' Timer cycle controls how fast alien ships move.
    ship AS STRING ' Alien ship ASCII design.
END TYPE

DIM SHARED a AS alien

DO
    GOSUB set_arrays

    SELECT CASE v.play
        CASE 1
            CALL set_up
            CALL comm
            v.level = -1: CALL game_level: v.level_up = 0
        CASE 0
            CALL set_up
            CALL comm
            CALL intro
            v.intro = 0: a.max = 0
            GOSUB set_arrays
            v.level = -1: CALL game_level: v.level_up = 0 ' This variable is canceled here so game will play instead of go another level up.
    END SELECT

    g.y = (v.bottom - v.top) \ 2 + v.top: g.x = (v.right - v.left + 1) \ 2 + v.left ' Set initial column and row for Guardian craft.

    CALL game

    GOSUB zero_variables
LOOP

set_arrays:
ii = 15 ' Default max setting for number of alien ships used here to intially dim arrays.
g.m_max = 8 ' * missiles max per direction.
REDIM SHARED a_y(ii), a_x(ii), a_mask_y(ii), a_mask_x(ii), a_inertia(ii) ' Alien movement.
REDIM SHARED a_ran(ii), a_olda_ran(ii), a_y_loc(ii), a_x_loc(ii) ' Alien motvement.
REDIM SHARED m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8) ' Guardian missiles.

' Array descriptions and actions.
' a_y() , a_x() Alien ship postions rows and columns.
' a_mask_y(), a_mask_x() Alien ship last position. Masked on next move.
' a_inertia(ii) Number of moves in one direction selected by random for an alien ship.
' a_ran(ii), a_olda_ran(ii) Determines the direction in which the inertia will travel and the prior direction is kept to disallow the same direction twice.
' a_y_loc(ii), a_x_loc(ii) The row and column cordinates of the aliens ships.
' m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8)  Missile number and Missile index 1 to g.m_max for position. 8 is the fixed number of 8 different directions.
RETURN

zero_variables:
' Zero variables.
g.diry = 0: g.dirx = 0: g.m_status = 0: g.m_fired = 0: g.m_d = 0: g.m_y = 0: g.m_x = 0
a.count = 0: a.itr = 0: a.cycle_delay = 0: v.level_up = 0: v.mouse_or_key_move = 0: g.m_launcher = ""
RETURN

skipintro:
RETURN

' Error handler.
offscreen: ' Prevents error if blast particles row and column are off-screen. Effect is a partial blast on side of screen.
IF ERR = 5 THEN er = -1: RESUME NEXT
PRINT "Opps, unexpected error"; ERR
END

SUB intro
    j = (v.bottom - v.top) \ 2 + v.top
    k = (v.right - v.left) \ 2 + v.left
    v.intro = -1: a.max = 10
    FOR i = 1 TO 90
        SOUND 900, .05
        CALL alien_move
        LOCATE j, k: COLOR 15: PRINT g.flagship;: COLOR 7
        _DELAY .07
    NEXT
END SUB

SUB set_up
    v.top = 3: v.bottom = _HEIGHT: v.left = 1: v.right = _WIDTH
    g.flagship = CHR$(15)
    a.ship = "-<>-"
    g.num = 3 ' 3 Guardian (lives) to start.
    g.thrusters = 10 ' Shows 1/2 thrust at start up on comm.
    g.icon = g.flagship
    g.m_asc = 250: g.diry = -1: ' Initiate missile ASCII character. g.diry = -1 initiates fire upwards if unmoved.
    IF _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") THEN ' Sound effects provided by TheBOB, Bob Seguin, from The QBasic Forum.
        v.snd1 = _SNDOPEN("Thunder1.ogg", "SYNC")
        v.snd2 = _SNDOPEN("Thunder7.ogg", "SYNC")
    END IF
    v.play = -1 ' Skip into on replay.
    LOCATE 2, 1: PRINT STRING$(_WIDTH, CHR$(196));
    _KEYCLEAR ' Clear any previous key presses in buffer.
END SUB

SUB game
END SUB

SUB comm
END SUB

SUB Guardian_missiles
END SUB

SUB missile_check (k)
END SUB

SUB alien_move
    STATIC z5
    y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.
    IF ABS(z5 - TIMER) > a.cycle_delay OR v.intro THEN ' z5 is a time delay for alien space ship maneuvers. It can be altered in the "game" subroutine.
        IF v.intro = 0 THEN hh = INT(RND * a.max) + 1 ELSE hh = 15
        FOR h = 1 TO hh
            a.itr = a.itr + 1: IF a.itr > a.max THEN a.itr = 1 ' Needed to offset the EXIT DO hover event, which on exit does not affect the a.itr variable.
            IF a_ran(a.itr) <> -1 THEN ' This is how a destroyed ship is bypassed. -1 is a destroyed alien ship. Code moves to end of DO:LOOP.
                IF a_inertia(a.itr) = 0 THEN ' Determine how many moves in one direction.
                    a_inertia(a.itr) = INT(RND * (v.bottom - v.top) / 2) + 1 ' How many moves to go in any one direction.
                    a_ran(a.itr) = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.

                    IF a_ran(a.itr) = a_olda_ran(a.itr) OR a_mask_y(a.itr) = 0 AND a_mask_x(a.itr) = 0 AND ran = 1 OR a_mask_y(a.itr) = 0 AND a_mask_x(a.itr) = 0 AND ran = 5 THEN
                        EXIT FOR ' Just hover if direction was not changed on existing alien space ship or if a new alien space ship is entering from the sides and up or down was generated.
                    END IF

                    SELECT CASE a_ran(a.itr) ' Get changes in column and row coordinates.
                        CASE 1: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = 0 '  Up.
                        CASE 2: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = 2 '  Up and right.
                        CASE 3: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 2 '   Right.
                        CASE 4: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = 2 '   Down and right.
                        CASE 5: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = 0 '   Down.
                        CASE 6: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = -2 '  Down and left.
                        CASE 7: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = -2 '  Left.
                        CASE 8: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = -2 ' Up and left.
                    END SELECT

                    IF a_y(a.itr) = 0 AND a_x(a.itr) = 0 AND a_ran(a.itr) <> -1 THEN ' New alien space ship enters the screen.
                        i = RND * (v.bottom - v.top) \ 4
                        a_y(a.itr) = (v.bottom - v.top) \ 4 + i + v.top
                        IF a_ran(a.itr) < 5 THEN ' Determine side of entry from initial direction.
                            IF SCREEN(a_y(a.itr), v.left + LEN(a.ship)) = 32 THEN
                                a_x(a.itr) = v.left + 1 ' Enter from the left side and go right.
                            ELSE
                                CALL a_erase
                                EXIT FOR
                            END IF
                        ELSE
                            IF SCREEN(a_y(a.itr), v.right - LEN(a.ship) + 1) = 32 THEN
                                a_x(a.itr) = v.right - LEN(a.ship) ' Enter from the right side and go left.
                            ELSE
                                CALL a_erase
                                EXIT FOR
                            END IF
                        END IF
                    END IF
                    a_olda_ran(a.itr) = a_ran(a.itr) ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
                ELSE
                    a_inertia(a.itr) = a_inertia(a.itr) - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
                END IF

                FOR i = 1 TO a.max
                    IF i <> a.itr AND a_y(i) <> 0 THEN
                        IF a_y(a.itr) + a_y_loc(a.itr) = a_y(i) THEN
                            IF a_x(a.itr) + a_x_loc(a.itr) + LEN(a.ship) > a_x(i) AND a_x(a.itr) + a_x_loc(a.itr) < a_x(i) + LEN(a.ship) THEN
                                collide = 1
                                EXIT FOR
                            END IF
                        END IF
                    END IF
                NEXT
                IF collide = 1 THEN
                    j = a_y(a.itr): k = a_x(a.itr)
                    a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 0: a_inertia(a.itr) = 0
                    collide = 0 ' Collision detection off. Collision was detected and avoided.
                ELSE
                    j = a_y(a.itr) + a_y_loc(a.itr): k = a_x(a.itr) + a_x_loc(a.itr)
                END IF

                IF j <= v.top OR k <= v.left OR k + LEN(a.ship) > v.right THEN ' Alien ship out of range off screen.
                    a_inertia(a.itr) = 0 ' These two lines keep the out of range ship(s) reasonably nearby.
                    IF j > v.top - 4 AND k < v.right + 3 AND k > v.left - 4 THEN a_y(a.itr) = j: a_x(a.itr) = k
                    IF a_mask_y(a.itr) <> 0 AND a_mask_x(a.itr) <> 0 THEN
                        LOCATE a_mask_y(a.itr), a_mask_x(a.itr)
                        PRINT SPACE$(LEN(a.ship)); ' Mask old position here because the show part of the mask and show routine cannot be used when out of range.
                    END IF
                    a_mask_y(a.itr) = 0: a_mask_x(a.itr) = 0
                ELSE
                    ' Check for v.bottom collision and reverse course if detected.
                    COLOR a.itr
                    IF j >= v.bottom THEN
                        a_y_loc(a.itr) = -a_y_loc(a.itr): a_x_loc(a.itr) = -a_x_loc(a.itr)
                    ELSE
                        a_y(a.itr) = j: a_x(a.itr) = k ' Next move coordinates.
                        ii = 0
                        FOR i = 0 TO LEN(a.ship) - 1 ' Check area through width of ship. Remember all or parts of ship are still present on screen.
                            IF SCREEN(j, k + i) = ASC(g.flagship) OR SCREEN(j, k + i) = g.m_asc THEN ' Check for contact (collision) with Guardian or missile.
                                IF SCREEN(j, k + i) = ASC(g.flagship) THEN
                                    ii = 1 ' Indicates contact with flagship and evokes call abduction routine a few lines down.
                                    EXIT FOR
                                ELSE
                                    ii = 2 ' Indicates ship into missile collision.
                                    EXIT FOR
                                END IF
                            END IF
                        NEXT
                        IF ii <> 2 THEN
                            '--------------------------------------------Move alien ship-------------------------------------------------
                            IF a_mask_y(a.itr) <> 0 AND a_mask_x(a.itr) <> 0 THEN LOCATE a_mask_y(a.itr), a_mask_x(a.itr): PRINT SPACE$(LEN(a.ship));
                            LOCATE j, k: PRINT a.ship;
                            a_mask_y(a.itr) = j: a_mask_x(a.itr) = k ' Remember these coordinates to erase alien space ship on next loop.
                            '------------------------------------------------------------------------------------------------------------
                        END IF
                        SELECT CASE ii
                            CASE 1
                                CALL guardian_abduction: EXIT FOR ' Exit loop.
                            CASE 2
                                '''BEEP: BEEP: BEEP: DO: _LIMIT 10: LOOP UNTIL INKEY$ = CHR$(13)
                        END SELECT
                    END IF
                    COLOR 7
                END IF
            END IF ' a_ran(a.itr) > -1 exit point.
            IF a.itr = a.max THEN a.itr = 0: EXIT FOR ' Finished loop. Keep this outside the IF/THEN statement.
        NEXT h
        z5 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF ' End time event.
END SUB

SUB explosion
END SUB

SUB remove_missile
END SUB

SUB mask_missiles
END SUB

SUB a_erase
    a_y(a.itr) = 0: a_x(a.itr) = 0: a_mask_y(a.itr) = 0: a_mask_x(a.itr) = 0: a_inertia(a.itr) = 0: a_ran(a.itr) = 0: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 0: a_olda_ran(a.itr) = 0
END SUB

SUB remove_ship
END SUB

SUB guardian_abduction
END SUB

SUB game_level ' Evaluates both alien defeated on a level and Guardian abduction.
END SUB

SUB mouse (mouse_event1, mouse_event2)
END SUB

Code Example #2, the slow-down problem.
Code: (Select All)
DEFINT H-K
$RESIZE:ON
_RESIZE OFF
RANDOMIZE TIMER
' Note: timer is not adjusted for stroke of midnight event, so don't stay up late playing this.
REM Main
f1 = 22 ' Sets font size to 22 and calculates the max screen height and width for your desktop.
h = (_DESKTOPHEIGHT - 60) \ f1
w = _DESKTOPWIDTH \ (f1 / 1.66)
WIDTH w, h
_SCREENMOVE 0, 0
fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, f1, "monospace")
_FONT font&
_DELAY .25
_RESIZE ON , _SMOOTH ' Allows resizing. Note: this is for slight adjustments. As of this version there is no compensitory function to change the font size during screen size changes.
TYPE gen_var
    intro AS INTEGER ' Runs a protion of the alien subroutine as part of the intro.
    nol AS INTEGER ' Number of game levels.
    level AS INTEGER ' Current game level.
    level_up AS INTEGER ' Routes code to next game level.
    top AS INTEGER ' Top boundary. (Changeable).
    bottom AS INTEGER ' Bottom boundary. (Changeable).
    left AS INTEGER ' Left boundary. (Changeable).
    right AS INTEGER ' Right boundary. (Changeable).
    kb_access AS INTEGER ' Routes code to either Guardian/Alien or general keyboard routine. -1 Guardian/Alien, 0 keyboard.
    mouse_or_key_move AS INTEGER
    play AS INTEGER
    snd1 AS LONG ' Explosion sound effect.
    snd2 AS LONG ' Explosion sound effect.
END TYPE

DIM SHARED v AS gen_var

TYPE guardian
    num AS INTEGER ' Number of Guardians aka lives.
    diry AS INTEGER ' Guardian row move. +1, 0, -1.
    dirx AS INTEGER ' Guardian column move. +2, 0, -2. Equals vertical pixel movement. 16x8.
    y AS INTEGER ' Guardian coordinates row.
    x AS INTEGER ' Guardian coordinates column.
    thrusters AS INTEGER ' Guardian speed. (User Determined).
    m_max AS INTEGER ' Restricts # of missiles fired in one direction.
    m_status AS INTEGER ' Missile status. -1 when fired, 1 while moving.
    m_fired AS INTEGER ' The number of missile deployed and still active.
    m_n AS INTEGER ' FOR/NEXT counter variable shared by other routines to index through the number of missiles fired in a specific direction.
    m_d AS INTEGER ' Missile direction. (1-8).
    m_y AS INTEGER ' Missile row advancement increment: +1, 0, -1 Note: Missile row and column coordinates are defined in arrays.
    m_x AS INTEGER ' Missile column advancement increment: +2, 0, -2. Equals vertical pixel movement. 16x8.
    m_asc AS INTEGER ' ASCII charater representing a fired missile.
    m_launcher AS STRING
    icon AS STRING ' Gardian comm icon. For this edition, it is the same as the flagship: "*"
    flagship AS STRING ' Guardian ascii character.
END TYPE

DIM SHARED g AS guardian

TYPE alien
    max AS INTEGER ' Maximum # of alien ships on screen.
    count AS INTEGER ' Number of alien ships. (Counter).
    itr AS INTEGER ' Iteration array number to cycle through the active alien ships. (Counter).
    cycle_delay AS SINGLE ' Timer cycle controls how fast alien ships move.
    ship AS STRING ' Alien ship ASCII design.
END TYPE

DIM SHARED a AS alien

DO
    GOSUB set_arrays

    SELECT CASE v.play
        CASE 1
            CALL set_up
            CALL comm
            v.level = -1: CALL game_level: v.level_up = 0
        CASE 0
            CALL set_up
            CALL comm
            CALL intro
            v.intro = 0: a.max = 0
            GOSUB set_arrays
            v.level = -1: CALL game_level: v.level_up = 0 ' This variable is canceled here so game will play instead of go another level up.
    END SELECT

    g.y = (v.bottom - v.top) \ 2 + v.top: g.x = (v.right - v.left + 1) \ 2 + v.left ' Set initial column and row for Guardian craft.

    CALL game

    GOSUB zero_variables
LOOP

set_arrays:
ii = 15 ' Default max setting for number of alien ships used here to intially dim arrays.
g.m_max = 8 ' * missiles max per direction.
REDIM SHARED a_y(ii), a_x(ii), a_mask_y(ii), a_mask_x(ii), a_inertia(ii) ' Alien movement.
REDIM SHARED a_ran(ii), a_olda_ran(ii), a_y_loc(ii), a_x_loc(ii) ' Alien motvement.
REDIM SHARED m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8) ' Guardian missiles.

' Array descriptions and actions.
' a_y() , a_x() Alien ship postions rows and columns.
' a_mask_y(), a_mask_x() Alien ship last position. Masked on next move.
' a_inertia(ii) Number of moves in one direction selected by random for an alien ship.
' a_ran(ii), a_olda_ran(ii) Determines the direction in which the inertia will travel and the prior direction is kept to disallow the same direction twice.
' a_y_loc(ii), a_x_loc(ii) The row and column cordinates of the aliens ships.
' m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8)  Missile number and Missile index 1 to g.m_max for position. 8 is the fixed number of 8 different directions.
RETURN

zero_variables:
' Zero variables.
g.diry = 0: g.dirx = 0: g.m_status = 0: g.m_fired = 0: g.m_d = 0: g.m_y = 0: g.m_x = 0
a.count = 0: a.itr = 0: a.cycle_delay = 0: v.level_up = 0: v.mouse_or_key_move = 0: g.m_launcher = ""
RETURN

skipintro:
RETURN

' Error handler.
offscreen: ' Prevents error if blast particles row and column are off-screen. Effect is a partial blast on side of screen.
IF ERR = 5 THEN er = -1: RESUME NEXT
PRINT "Opps, unexpected error"; ERR
END

SUB intro
    j = (v.bottom - v.top) \ 2 + v.top
    k = (v.right - v.left) \ 2 + v.left
    v.intro = -1: a.max = 10
    FOR i = 1 TO 90
        SOUND 900, .05
        CALL alien_move
        LOCATE j, k: COLOR 15: PRINT g.flagship;: COLOR 7
        _DELAY .07
    NEXT
END SUB

SUB set_up
    v.top = 3: v.bottom = _HEIGHT: v.left = 1: v.right = _WIDTH
    g.flagship = CHR$(15)
    a.ship = "-<>-"
    g.num = 3 ' 3 Guardian (lives) to start.
    g.thrusters = 10 ' Shows 1/2 thrust at start up on comm.
    g.icon = g.flagship
    g.m_asc = 250: g.diry = -1: ' Initiate missile ASCII character. g.diry = -1 initiates fire upwards if unmoved.
    IF _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") THEN ' Sound effects provided by TheBOB, Bob Seguin, from The QBasic Forum.
        v.snd1 = _SNDOPEN("Thunder1.ogg", "SYNC")
        v.snd2 = _SNDOPEN("Thunder7.ogg", "SYNC")
    END IF
    v.play = -1 ' Skip into on replay.
    LOCATE 2, 1: PRINT STRING$(_WIDTH, CHR$(196));
    _KEYCLEAR ' Clear any previous key presses in buffer.
END SUB

SUB game
END SUB

SUB comm
END SUB

SUB Guardian_missiles
END SUB

SUB missile_check (k)
END SUB

SUB alien_move
    STATIC z5
    y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.
    IF ABS(z5 - TIMER) > a.cycle_delay OR v.intro THEN ' z5 is a time delay for alien space ship maneuvers. It can be altered in the "game" subroutine.
        IF v.intro = 0 THEN hh = INT(RND * a.max) + 1 ELSE hh = 15
        FOR h = 1 TO hh
            a.itr = a.itr + 1: IF a.itr > a.max THEN a.itr = 1 ' Needed to offset the EXIT DO hover event, which on exit does not affect the a.itr variable.
            IF a_ran(a.itr) <> -1 THEN ' This is how a destroyed ship is bypassed. -1 is a destroyed alien ship. Code moves to end of DO:LOOP.
                IF a_inertia(a.itr) = 0 THEN ' Determine how many moves in one direction.
                    a_inertia(a.itr) = INT(RND * (v.bottom - v.top) / 2) + 1 ' How many moves to go in any one direction.
                    a_ran(a.itr) = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.

                    IF a_ran(a.itr) = a_olda_ran(a.itr) OR a_mask_y(a.itr) = 0 AND a_mask_x(a.itr) = 0 AND ran = 1 OR a_mask_y(a.itr) = 0 AND a_mask_x(a.itr) = 0 AND ran = 5 THEN
                        EXIT FOR ' Just hover if direction was not changed on existing alien space ship or if a new alien space ship is entering from the sides and up or down was generated.
                    END IF

                    SELECT CASE a_ran(a.itr) ' Get changes in column and row coordinates.
                        CASE 1: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = 0 '  Up.
                        CASE 2: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = 2 '  Up and right.
                        CASE 3: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 2 '   Right.
                        CASE 4: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = 2 '   Down and right.
                        CASE 5: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = 0 '   Down.
                        CASE 6: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = -2 '  Down and left.
                        CASE 7: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = -2 '  Left.
                        CASE 8: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = -2 ' Up and left.
                    END SELECT

                    IF a_y(a.itr) = 0 AND a_x(a.itr) = 0 AND a_ran(a.itr) <> -1 THEN ' New alien space ship enters the screen.
                        i = RND * (v.bottom - v.top) \ 4
                        a_y(a.itr) = (v.bottom - v.top) \ 4 + i + v.top
                        IF a_ran(a.itr) < 5 THEN ' Determine side of entry from initial direction.
                            IF SCREEN(a_y(a.itr), v.left + LEN(a.ship)) = 32 THEN
                                a_x(a.itr) = v.left + 1 ' Enter from the left side and go right.
                            ELSE
                                CALL a_erase
                                EXIT FOR
                            END IF
                        ELSE
                            IF SCREEN(a_y(a.itr), v.right - LEN(a.ship) + 1) = 32 THEN
                                a_x(a.itr) = v.right - LEN(a.ship) ' Enter from the right side and go left.
                            ELSE
                                CALL a_erase
                                EXIT FOR
                            END IF
                        END IF
                    END IF
                    a_olda_ran(a.itr) = a_ran(a.itr) ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
                ELSE
                    a_inertia(a.itr) = a_inertia(a.itr) - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
                END IF

                FOR i = 1 TO a.max
                    IF i <> a.itr AND a_y(i) <> 0 THEN
                        IF a_y(a.itr) + a_y_loc(a.itr) = a_y(i) THEN
                            IF a_x(a.itr) + a_x_loc(a.itr) + LEN(a.ship) > a_x(i) AND a_x(a.itr) + a_x_loc(a.itr) < a_x(i) + LEN(a.ship) THEN
                                collide = 1
                                EXIT FOR
                            END IF
                        END IF
                    END IF
                NEXT
                IF collide = 1 THEN
                    j = a_y(a.itr): k = a_x(a.itr)
                    a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 0: a_inertia(a.itr) = 0
                    collide = 0 ' Collision detection off. Collision was detected and avoided.
                ELSE
                    j = a_y(a.itr) + a_y_loc(a.itr): k = a_x(a.itr) + a_x_loc(a.itr)
                END IF

                IF j <= v.top OR k <= v.left OR k + LEN(a.ship) > v.right THEN ' Alien ship out of range off screen.
                    a_inertia(a.itr) = 0 ' These two lines keep the out of range ship(s) reasonably nearby.
                    IF j > v.top - 4 AND k < v.right + 3 AND k > v.left - 4 THEN a_y(a.itr) = j: a_x(a.itr) = k
                    IF a_mask_y(a.itr) <> 0 AND a_mask_x(a.itr) <> 0 THEN
                        LOCATE a_mask_y(a.itr), a_mask_x(a.itr)
                        PRINT SPACE$(LEN(a.ship)); ' Mask old position here because the show part of the mask and show routine cannot be used when out of range.
                    END IF
                    a_mask_y(a.itr) = 0: a_mask_x(a.itr) = 0
                ELSE
                    ' Check for v.bottom collision and reverse course if detected.
                    COLOR a.itr
                    IF j >= v.bottom THEN
                        a_y_loc(a.itr) = -a_y_loc(a.itr): a_x_loc(a.itr) = -a_x_loc(a.itr)
                    ELSE
                        a_y(a.itr) = j: a_x(a.itr) = k ' Next move coordinates.
                        ii = 0
                        FOR i = 0 TO LEN(a.ship) - 1 ' Check area through width of ship. Remember all or parts of ship are still present on screen.
                            h = SCREEN(j, k + i)
                            IF h = ASC(g.flagship) OR h = g.m_asc THEN ' Check for contact (collision) with Guardian or missile.
                                IF h = ASC(g.flagship) THEN
                                    ii = 1 ' Indicates contact with flagship and evokes call abduction routine a few lines down.
                                    EXIT FOR
                                ELSE
                                    ii = 2 ' Indicates ship into missile collision.
                                    EXIT FOR
                                END IF
                            END IF
                        NEXT
                        IF ii <> 2 THEN
                            '--------------------------------------------Move alien ship-------------------------------------------------
                            IF a_mask_y(a.itr) <> 0 AND a_mask_x(a.itr) <> 0 THEN LOCATE a_mask_y(a.itr), a_mask_x(a.itr): PRINT SPACE$(LEN(a.ship));
                            LOCATE j, k: PRINT a.ship;
                            a_mask_y(a.itr) = j: a_mask_x(a.itr) = k ' Remember these coordinates to erase alien space ship on next loop.
                            '------------------------------------------------------------------------------------------------------------
                        END IF
                        SELECT CASE ii
                            CASE 1
                                CALL guardian_abduction: EXIT FOR ' Exit loop.
                            CASE 2
                                '''BEEP: BEEP: BEEP: DO: _LIMIT 10: LOOP UNTIL INKEY$ = CHR$(13)
                        END SELECT
                    END IF
                    COLOR 7
                END IF
            END IF ' a_ran(a.itr) > -1 exit point.
            IF a.itr = a.max THEN a.itr = 0: EXIT FOR ' Finished loop. Keep this outside the IF/THEN statement.
        NEXT h
        z5 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF ' End time event.
END SUB

SUB explosion
END SUB

SUB remove_missile
END SUB

SUB mask_missiles
END SUB

SUB a_erase
    a_y(a.itr) = 0: a_x(a.itr) = 0: a_mask_y(a.itr) = 0: a_mask_x(a.itr) = 0: a_inertia(a.itr) = 0: a_ran(a.itr) = 0: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 0: a_olda_ran(a.itr) = 0
END SUB

SUB remove_ship
END SUB

SUB guardian_abduction
END SUB

SUB game_level ' Evaluates both alien defeated on a level and Guardian abduction.
END SUB

SUB mouse (mouse_event1, mouse_event2)
END SUB

Pete
Reply
#15
(10-14-2022, 05:55 PM)Pete Wrote: Hey guys, banter aside, just don't miss the point of why I made this post in the first place, to call attention to a peculiar slow-down event, caused by assigning a variable to SCREEN(). 

I'm just not seeing that type of behavior.  Something else is causing your slow-down event, but I don't think it's the use of SCREEN being assigned a variable.  See this little timed demo below:

Code: (Select All)
Cls , 4
t# = Timer
For i = 1 To 10000000
    If Screen(1, 1) Then
        If Screen(1, 1) <> Screen(1, 1) Then End
    End If
Next
t1# = Timer
For i = 1 To 10000000
    h = Screen(1, 1)
    If h Then
        If h <> h Then End
    End If
Next
t2# = Timer
Print Using "###.#### seconds with 3 screen"; t1# - t#
Print Using "###.#### seconds with 3 variables"; t2# - t1#


[Image: image.png]

And the screenshot of my results -- ran first without any c-optimizations, and then a second time by clicking the option to enable c-optimations.

First run was 0.2 seconds vs 0.05 seconds.
Second run was 0.17 seconds vs 0.05 seconds.

In both cases, it was noticeably faster to assign the value of SCREEN to a variable, than it was to make 3 distinct calls to that same SCREEN statement.  (OF course, keep in mind that this is also over 10,000,000 iterations, so the overall difference in speed is almost negligible one way or the other.)

There's nothing here, however, that seems to indicate that using SCREEN is faster than using a variable holding the value of SCREEN.  You might be seeing a speed difference in your code, but I don't think it's from what you're attributing it to.
Reply
#16
Did you run my 2 code examples?

That's why I posted the two code examples in post #14, because by those few lines alone, I can't find it either. We need to include the accompanying animation code. With the accompanying code, there is an estimated 5x speed difference in how fast the alien ships move on the intro screen. Since the only difference in the two code snippets is the two ways shown to use SCREEN(), something involving that function sure seems to be the only thing causing the animation slowdown.

Pete
Reply
#17
(10-14-2022, 07:25 PM)Pete Wrote: Did you run my 2 code examples?

That's why I posted the two code examples in post #14, because by those few lines alone, I can't find it either. We need to include the accompanying animation code. With the accompanying code, there is an estimated 5x speed difference in how fast the alien ships move on the intro screen. Since the only difference in the two code snippets is the two ways shown to use SCREEN(), something involving that function sure seems to be the only thing causing the animation slowdown. 

Pete

Code 1 was definitely faster than code 2. I'm always looking for ways to optimize code (do ... loop instead of for ... next for example). It seems counter-intuitive to have functions called over and over again instead of just once to get faster results. Maybe a section in the Wiki on optimization techniques would be beneficial. When better ways are discovered they can be added to the entry.
Reply
#18
@TerryRitchie

I know, right? I think this one still has the devs a bit mystified. I had Steve mesmerized for days the time I pulled a rabbit out of my hat. He said it caught him off guard, because he was so used to me pulling ideas out of my other end. Ah, misdirection, my favorite tool in my SCREEN ZERO magic kit!

Pete
If eggs are brain food, Biden takes his scrambled.
Reply
#19
@Pete check line 168, that's the issue.
h
is already used as a loop variable, so by reusing it for the assignment you're messing with that loop and presumably it ends up running many more times than just 1 to
hh
.
Reply
#20
Eeeeeeeks! It looks like I sent you guys on a snipe hunt this time around. My apologizes for wasting your time.

That's it, double use of a looping variable. I'm usually on the lookout for this kind of error. In the code, there are a lot of uses of the local variables h, i, j, and k. So much so, I had to make some exceptions to avoid the problem, you just found, by going to names like k2 or ii.

Well this puts a platter of eggs on my face, but I'm actually glad it isn't some internal compiler problem. Thanks for figuring it out. The important thing is... you beat Steve!

Pete

Edited thread title to reflect "Resolved."
Reply




Users browsing this thread: 17 Guest(s)