In the spirit of Terry's Tutorials - GUARDIAN Alien Space Ship Game
#1
When I build a program, I do so by making subs that can often act independently. It's a very easy way to join things together for bigger project. It also makes debugging a whole lot easier.

So I thought, since Terry provides excellent tutorials for newbies to fast track coding, I would join in the spirit of that perspective and put up some little project which shows step-wise development.

Alien Space Ship is an ASCII  -<>- that, for starters, that flies randomly throughout the screen. The code is adaptable to various screen sizes. I'll start with a single ship for now. I'll show how to make a married ship, later.

Stage 1)

Code: (Select All)
DIM SHARED top, bottom, left, right
a = 120: b = 42
WIDTH a, b
_SCREENMOVE 0, 0
top = 3: bottom = _HEIGHT: left = 0: right = _WIDTH
msg$ = "Alien space ship movement demo."
LOCATE 1, (right - left) \ 2 - LEN(msg$) \ 2
PRINT msg$;
LOCATE 1, 2: PRINT STRING$(_WIDTH, "_");

DO
    _LIMIT 30
    alien_move
LOOP

SUB alien_move:
    STATIC a_y, a_x, olda_y, olda_x, alien$, inertia, ran, ran_y, ran_x, oldran, z5
    IF ABS(z5 - TIMER) > .1 THEN ' Time delay.
        y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.
        IF alien$ = "" THEN alien$ = "-<>-"
        IF olda_y <> 0 AND olda_x <> 0 THEN
            LOCATE olda_y, olda_x: PRINT SPACE$(LEN(alien$));
        ELSE
            a_y = (bottom - top) \ 2: a_x = (right - left) \ 2 ' Center sreen.
        END IF

        IF inertia = 0 THEN
            inertia = INT(RND * (bottom - top) / 2) + 1 ' How many moves to go in any one direction.
            ran = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.
            IF ran = oldran THEN LOCATE y_restore, x_restore: EXIT SUB ' Just hover if direction was not changed.
            SELECT CASE ran ' Get changes in column and row coordinates.
                CASE 1: ran_y = -1: ran_x = 0
                CASE 2: ran_y = -1: ran_x = 1
                CASE 3: ran_y = 0: ran_x = 1
                CASE 4: ran_y = 1: ran_x = 1
                CASE 5: ran_y = 1: ran_x = 0
                CASE 6: ran_y = 1: ran_x = -1
                CASE 7: ran_y = 0: ran_x = -1
                CASE 8: ran_y = -1: ran_x = -1
            END SELECT
            oldran = ran ' Remember last direction.
        ELSE
            inertia = inertia - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
        END IF
        a_y = a_y + ran_y: a_x = a_x + ran_x * 2 ' Next move coordinates. I use * 2 for horizontal movement to match the 16x8 pixel height over width factor.
        IF a_y < top OR a_y > bottom OR a_x <= left OR a_x + LEN(alien$) > right THEN
            olda_x = 0: olda_y = 0: inertia = 0: oldran = 0 ' Out of bounds and off the screen.
        ELSE
            LOCATE a_y, a_x: PRINT alien$; ' Move alien ship.
            olda_y = a_y: olda_x = a_x ' Remember these coordinates to erase ship on next loop.
        END IF
        z5 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF
END SUB


The next stage will demonstrate a way to start a ship on the screen from the left or right side, determined by initial right or left direction, at a somewhat random vertical starting point. Hey, if you develop a shooter game, it's not much of a challenge if you know in advance where the enemy vessel will appear.

Pete out.
Reply
#2
Awesome!
Reply
#3
Next we will start the alien ship at a random upper location in either the right or left side of the screen. Right or left is determined by the inital direction, so if the ship is traveling right, it will enter from the left. How about if up or down is the initial direction. Well, we disallowed this as part of an addition to and existing statement that exits the sub if either of those directions get selected.

Code: (Select All)
IF ran = oldran OR olda_y = 0 AND olda_x = 0 AND ran = 1 OR olda_y = 0 AND olda_x = 0 AND ran = 5 THEN

The other code added to achieve the side entry is:

Code: (Select All)
            IF olda_y = 0 AND olda_x = 0 THEN ' New alien space ship enters the screen.
                a_y = (bottom - top) \ 2: a_x = (right - left) \ 2 ' Center sreen.
                a_y = (bottom - top) \ 4 + RND * (bottom - top) \ 4
                IF ran < 5 THEN ' Determine side of entry from initial direction.
                    a_x = left + 1 ' Enter from the left side and go right.
                ELSE
                    a_x = right - LEN(alien$) ' Enter from the right side and go left.
                END IF
            END IF


Stage 2)

Code: (Select All)
DIM SHARED top, bottom, left, right
a = 120: b = 42
WIDTH a, b
_SCREENMOVE 0, 0
top = 3: bottom = _HEIGHT: left = 0: right = _WIDTH
msg$ = "Alien space ship movement demo."
LOCATE 1, (right - left) \ 2 - LEN(msg$) \ 2
PRINT msg$;
LOCATE 1, 2: PRINT STRING$(_WIDTH, "_");

DO
    _LIMIT 30
    alien_move
LOOP

SUB alien_move:
    STATIC a_y, a_x, olda_y, olda_x, alien$, inertia, ran, ran_y, ran_x, oldran, z5
    IF ABS(z5 - TIMER) > .1 THEN ' Time delay.
        y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.
        IF alien$ = "" THEN alien$ = "-<>-"
        IF olda_y <> 0 AND olda_x <> 0 THEN LOCATE olda_y, olda_x: PRINT SPACE$(LEN(alien$));

        IF inertia = 0 THEN
            inertia = INT(RND * (bottom - top) / 2) + 1 ' How many moves to go in any one direction.
            ran = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.

            IF ran = oldran OR olda_y = 0 AND olda_x = 0 AND ran = 1 OR olda_y = 0 AND olda_x = 0 AND ran = 5 THEN
                LOCATE y_restore, x_restore: EXIT SUB ' 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 ran ' Get changes in column and row coordinates.
                CASE 1: ran_y = -1: ran_x = 0 '  Up.
                CASE 2: ran_y = -1: ran_x = 1 '  Up and right.
                CASE 3: ran_y = 0: ran_x = 1 '   Right.
                CASE 4: ran_y = 1: ran_x = 1 '   Down and right.
                CASE 5: ran_y = 1: ran_x = 0 '   Down.
                CASE 6: ran_y = 1: ran_x = -1 '  Down and left.
                CASE 7: ran_y = 0: ran_x = -1 '  Left.
                CASE 8: ran_y = -1: ran_x = -1 ' Up and left.
            END SELECT

            IF olda_y = 0 AND olda_x = 0 THEN ' New alien space ship enters the screen.
                a_y = (bottom - top) \ 2: a_x = (right - left) \ 2 ' Center sreen.
                a_y = (bottom - top) \ 4 + RND * (bottom - top) \ 4
                IF ran < 5 THEN ' Determine side of entry from initial direction.
                    a_x = left + 1 ' Enter from the left side and go right.
                ELSE
                    a_x = right - LEN(alien$) ' Enter from the right side and go left.
                END IF
            END IF
            oldran = ran ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
        ELSE
            inertia = inertia - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
        END IF
        a_y = a_y + ran_y: a_x = a_x + ran_x * 2 ' Next move coordinates. I use * 2 for horizontal movement to match the 16x8 pixel height over width factor.
        IF a_y < top OR a_y > bottom OR a_x <= left OR a_x + LEN(alien$) > right THEN
            olda_x = 0: olda_y = 0: inertia = 0: oldran = 0 ' Out of bounds and off the screen.
        ELSE
            LOCATE a_y, a_x: PRINT alien$; ' Move alien space ship.
            olda_y = a_y: olda_x = a_x ' Remember these coordinates to erase alien space ship on next loop.
        END IF
        z5 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF
END SUB

The next stage will demonstrate how to use arrays to put two or more ships on the screen.

Pete
Reply
#4
Okay, how about we put 5 alien space ships in on the screen? It's actually easier than it sounds. All we need is a iteration counter (I'll use the variable name itr for that) and the variables already in use, all being changed into arrays. So if we had ship we would replace it with ship(itr). The QB64 IDE has a nice CHANGE routine so if you already coded ship in 20 places, the change feature would change it to ship(itr) in all 20 places at once. I did almost all of the edits from my last post to this post using that method.

With all the variables changed to arrays, we simply DIM or value of 5 space ships in the STATIC statement:

Code: (Select All)
    STATIC a_y(5), a_x(5), olda_y(5), olda_x(5), inertia(5), ran(5), ran_y(5), ran_x(5), oldran(5), z5, itr, alien_ship_max

Sorry, but you have to hard code the number. The STATIC statement won't compile with a variable.

Now we need the space ship max variable added: IF alien$ = "" THEN alien$ = "-<>-": alien_ship_max = 5 ' Initiate.

Finally we just wrap what we already have in a DO:LOOP that moves each of the 5 space ships before exiting.

Stage 3)

Code: (Select All)
DIM SHARED top, bottom, left, right
a = 120: b = 42
WIDTH a, b
_SCREENMOVE 0, 0
top = 3: bottom = _HEIGHT: left = 0: right = _WIDTH
msg$ = "Alien space ship movement demo."
LOCATE 1, (right - left) \ 2 - LEN(msg$) \ 2
PRINT msg$;
LOCATE 1, 2: PRINT STRING$(_WIDTH, "_");

DO
    _LIMIT 30
    alien_move
LOOP

SUB alien_move:
    STATIC a_y(5), a_x(5), olda_y(5), olda_x(5), inertia(5), ran(5), ran_y(5), ran_x(5), oldran(5), z5, itr, alien_ship_max
    IF alien$ = "" THEN alien$ = "-<>-": alien_ship_max = 5 ' Initiate.
    IF ABS(z5 - TIMER) > .1 THEN ' Time delay.
        DO
            itr = itr + 1: IF itr > alien_ship_max THEN itr = 1 ' Needed to offset the EXIT DO hover event, which on exit does not affect the itr variable.
            y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.

            IF olda_y(itr) <> 0 AND olda_x(itr) <> 0 THEN LOCATE olda_y(itr), olda_x(itr): PRINT SPACE$(LEN(alien$));

            IF inertia(itr) = 0 THEN
                inertia(itr) = INT(RND * (bottom - top) / 2) + 1 ' How many moves to go in any one direction.
                ran(itr) = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.

                IF ran(itr) = oldran(itr) OR olda_y(itr) = 0 AND olda_x(itr) = 0 AND ran = 1 OR olda_y(itr) = 0 AND olda_x(itr) = 0 AND ran = 5 THEN
                    EXIT DO ' 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 ran(itr) ' Get changes in column and row coordinates.
                    CASE 1: ran_y(itr) = -1: ran_x(itr) = 0 '  Up.
                    CASE 2: ran_y(itr) = -1: ran_x(itr) = 1 '  Up and right.
                    CASE 3: ran_y(itr) = 0: ran_x(itr) = 1 '   Right.
                    CASE 4: ran_y(itr) = 1: ran_x(itr) = 1 '   Down and right.
                    CASE 5: ran_y(itr) = 1: ran_x(itr) = 0 '   Down.
                    CASE 6: ran_y(itr) = 1: ran_x(itr) = -1 '  Down and left.
                    CASE 7: ran_y(itr) = 0: ran_x(itr) = -1 '  Left.
                    CASE 8: ran_y(itr) = -1: ran_x(itr) = -1 ' Up and left.
                END SELECT

                IF olda_y(itr) = 0 AND olda_x(itr) = 0 THEN ' New alien space ship enters the screen.
                    a_y(itr) = (bottom - top) \ 2: a_x(itr) = (right - left) \ 2 ' Center sreen.
                    a_y(itr) = (bottom - top) \ 4 + RND * (bottom - top) \ 4
                    IF ran(itr) < 5 THEN ' Determine side of entry from initial direction.
                        a_x(itr) = left + 1 ' Enter from the left side and go right.
                    ELSE
                        a_x(itr) = right - LEN(alien$) ' Enter from the right side and go left.
                    END IF
                END IF
                oldran(itr) = ran(itr) ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
            ELSE
                inertia(itr) = inertia(itr) - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
            END IF
            a_y(itr) = a_y(itr) + ran_y(itr): a_x(itr) = a_x(itr) + ran_x(itr) * 2 ' Next move coordinates. I use * 2 for horizontal movement to match the 16x8 pixel height over width factor.
            IF a_y(itr) < top OR a_y(itr) > bottom OR a_x(itr) <= left OR a_x(itr) + LEN(alien$) > right THEN
                olda_x(itr) = 0: olda_y(itr) = 0: inertia(itr) = 0: oldran(itr) = 0 ' Out of bounds and off the screen.
            ELSE
                LOCATE a_y(itr), a_x(itr): PRINT alien$; ' Move alien space ship.
                olda_y(itr) = a_y(itr): olda_x(itr) = a_x(itr) ' Remember these coordinates to erase alien space ship on next loop.
            END IF
            IF itr = alien_ship_max THEN itr = 0: EXIT DO
        LOOP
        z5 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF
END SUB

The next adjustment will be a "flow through" modification. Flow through makes it possible to do other things rather than just be stuck in a task loop until the task is finished. This is a very important timing element for gaming.

Pete
Reply
#5
Thumbs Up 
QB64PE is so fast we don't even care about defining anything as integer! The "default SINGLE" type is good enough to declare variables that would hold numbers. Now somebody is going to want to run performance tests to compare variables, integers to floating-point. This is what I've actually learned in this tutorial, but great job with the game building and teaching.
Reply
#6
(10-05-2022, 12:54 AM)mnrvovrfc Wrote: QB64PE is so fast we don't even care about defining anything as integer! The "default SINGLE" type is good enough to declare variables that would hold numbers. Now somebody is going to want to run performance tests to compare variables, integers to floating-point. This is what I've actually learned in this tutorial, but great job with the game building and teaching.

Good ol' QJurassic days. I used DEFINT i to y just to speed things up a bit back then. Nice trick, but not needed in QB64; however, I was going to include variable typing and TYPE variables somewhere in this project. Normally, if I see I'm getting into a lot of code, I switch it all up to TYPE variables. That's especially good practice when passing variables to subs and functions because it can pass several variables as a type rather than a long list of elements in the sub or function call.

Thanks for the comment, and the memories. (Now I sound like Bob Hope, talk about Jurassic.)

Pete
Reply
#7
Okay, so now will demo the "flow through" for the alien space ships by adding yet another timer to the mix, and some keys to press to speed up or slow down the action.

Press or hold the left Ctrl key to speed it up, the right Alt key to slow things down. Press something else like an arrow key to make a tiny sound. Why? Just to show how the player has a lot of input while everything around the screen is moving. That's what I mean by designing a game to have a "flow through" structure.

Stage 4)

Code: (Select All)
DIM SHARED top, bottom, left, right, s_delay
a = 120: b = 42
WIDTH a, b
_SCREENMOVE 0, 0
top = 3: bottom = _HEIGHT: left = 0: right = _WIDTH
msg$ = "Alien space ship movement demo."
LOCATE 1, (right - left) \ 2 - LEN(msg$) \ 2
PRINT msg$;
LOCATE 1, 2: PRINT STRING$(_WIDTH, "_");
s_delay = 100
DO
    _LIMIT 30
    IF _KEYDOWN(100306) THEN IF s_delay - 5 > 0 THEN s_delay = s_delay - 5: LOCATE 1, 2: PRINT "Speed delay ="; s_delay / 100; "    ";
    IF _KEYDOWN(100308) THEN IF s_delay < 500 THEN s_delay = s_delay + 5: LOCATE 1, 2: PRINT "Speed delay ="; s_delay / 100; "    ";
    IF LEN(INKEY$) THEN SOUND 1000, .1
    alien_move
LOOP

SUB alien_move:
    STATIC a_y(5), a_x(5), olda_y(5), olda_x(5), inertia(5), ran(5), ran_y(5), ran_x(5), oldran(5), z5, z6, itr, alien_ship_max
    IF alien$ = "" THEN alien$ = "-<>-": alien_ship_max = 5 ' Initiate.
    IF ABS(z5 - TIMER) > s_delay / 1000 THEN ' Time delay.
        DO
            itr = itr + 1: IF itr > alien_ship_max THEN itr = 1 ' Needed to offset the EXIT DO hover event, which on exit does not affect the itr variable.
            y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.

            IF olda_y(itr) <> 0 AND olda_x(itr) <> 0 THEN LOCATE olda_y(itr), olda_x(itr): PRINT SPACE$(LEN(alien$));

            IF inertia(itr) = 0 THEN
                inertia(itr) = INT(RND * (bottom - top) / 2) + 1 ' How many moves to go in any one direction.
                ran(itr) = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.

                IF ran(itr) = oldran(itr) OR olda_y(itr) = 0 AND olda_x(itr) = 0 AND ran = 1 OR olda_y(itr) = 0 AND olda_x(itr) = 0 AND ran = 5 THEN
                    EXIT DO ' 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 ran(itr) ' Get changes in column and row coordinates.
                    CASE 1: ran_y(itr) = -1: ran_x(itr) = 0 '  Up.
                    CASE 2: ran_y(itr) = -1: ran_x(itr) = 1 '  Up and right.
                    CASE 3: ran_y(itr) = 0: ran_x(itr) = 1 '   Right.
                    CASE 4: ran_y(itr) = 1: ran_x(itr) = 1 '   Down and right.
                    CASE 5: ran_y(itr) = 1: ran_x(itr) = 0 '   Down.
                    CASE 6: ran_y(itr) = 1: ran_x(itr) = -1 '  Down and left.
                    CASE 7: ran_y(itr) = 0: ran_x(itr) = -1 '  Left.
                    CASE 8: ran_y(itr) = -1: ran_x(itr) = -1 ' Up and left.
                END SELECT

                IF olda_y(itr) = 0 AND olda_x(itr) = 0 THEN ' New alien space ship enters the screen.
                    a_y(itr) = (bottom - top) \ 2: a_x(itr) = (right - left) \ 2 ' Center sreen.
                    a_y(itr) = (bottom - top) \ 4 + RND * (bottom - top) \ 4
                    IF ran(itr) < 5 THEN ' Determine side of entry from initial direction.
                        a_x(itr) = left + 1 ' Enter from the left side and go right.
                    ELSE
                        a_x(itr) = right - LEN(alien$) ' Enter from the right side and go left.
                    END IF
                END IF
                oldran(itr) = ran(itr) ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
            ELSE
                inertia(itr) = inertia(itr) - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
            END IF
            a_y(itr) = a_y(itr) + ran_y(itr): a_x(itr) = a_x(itr) + ran_x(itr) * 2 ' Next move coordinates. I use * 2 for horizontal movement to match the 16x8 pixel height over width factor.
            IF a_y(itr) < top OR a_y(itr) > bottom OR a_x(itr) <= left OR a_x(itr) + LEN(alien$) > right THEN
                olda_x(itr) = 0: olda_y(itr) = 0: inertia(itr) = 0: oldran(itr) = 0 ' Out of bounds and off the screen.
            ELSE
                LOCATE a_y(itr), a_x(itr): PRINT alien$; ' Move alien space ship.
                olda_y(itr) = a_y(itr): olda_x(itr) = a_x(itr) ' Remember these coordinates to erase alien space ship on next loop.
            END IF
            IF itr = alien_ship_max THEN itr = 0: EXIT DO
            IF ABS(z6 - TIMER) > s_delay / 2 THEN skipz5 = -1: EXIT DO
        LOOP
        IF skipz5 = 0 THEN z5 = TIMER
        z6 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF
END SUB


Next up, how about we see what happens when those idiot aliens run into each other?

Pete
Reply
#8
To make an explosion with a collision, a simple FOR/NEXT loop is created to check the coordinates of each space ship. If they intersect, the program call the sub "explosion." The explosion sub consists of a particle burst, flashing screen, produced with a palette loop, and thunder sounds, which require downloading and unzipping the attached zip containing the .ogg sound file.

Stage 5)

Code: (Select All)
DIM SHARED top, bottom, left, right, s_delay
a = 120: b = 42
WIDTH a, b
_SCREENMOVE 0, 0
top = 3: bottom = _HEIGHT: left = 0: right = _WIDTH
msg$ = "Alien space ship movement demo."
LOCATE 1, (right - left) \ 2 - LEN(msg$) \ 2
PRINT msg$;
LOCATE 1, 2: PRINT STRING$(_WIDTH, "_");
VIEW PRINT top TO bottom ' Needed to set print error parameters.
s_delay = 100
DO
    _LIMIT 30
    IF _KEYDOWN(100306) THEN IF s_delay - 5 > 0 THEN s_delay = s_delay - 5: LOCATE 1, 2: PRINT "Speed delay ="; s_delay / 100; "    ";
    IF _KEYDOWN(100308) THEN IF s_delay < 500 THEN s_delay = s_delay + 5: LOCATE 1, 2: PRINT "Speed delay ="; s_delay / 100; "    ";
    IF LEN(INKEY$) THEN SOUND 1000, .1
    alien_move
LOOP

offscreen:
IF ERR = 5 THEN er = -1: RESUME NEXT
PRINT "Opps, you have an error"; ERR
END

SUB alien_move:
    STATIC alien$, a_y(5), a_x(5), olda_y(5), olda_x(5), inertia(5), ran(5), ran_y(5), ran_x(5), oldran(5), z5, z6, itr, alien_ship_max
    IF alien$ = "" THEN
        alien$ = "-<>-": alien_ship_max = 5 ' Initiate.
        CALL explosion ' Loads sound files on first call.
    END IF
    IF ABS(z5 - TIMER) > s_delay / 1000 THEN ' Time delay.
        DO
            itr = itr + 1: IF itr > alien_ship_max THEN itr = 1 ' Needed to offset the EXIT DO hover event, which on exit does not affect the itr variable.
            y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.

            IF olda_y(itr) <> 0 AND olda_x(itr) <> 0 THEN LOCATE olda_y(itr), olda_x(itr): PRINT SPACE$(LEN(alien$));

            IF inertia(itr) = 0 THEN
                inertia(itr) = INT(RND * (bottom - top) / 2) + 1 ' How many moves to go in any one direction.
                ran(itr) = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.

                IF ran(itr) = oldran(itr) OR olda_y(itr) = 0 AND olda_x(itr) = 0 AND ran = 1 OR olda_y(itr) = 0 AND olda_x(itr) = 0 AND ran = 5 THEN
                    EXIT DO ' 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 ran(itr) ' Get changes in column and row coordinates.
                    CASE 1: ran_y(itr) = -1: ran_x(itr) = 0 '  Up.
                    CASE 2: ran_y(itr) = -1: ran_x(itr) = 1 '  Up and right.
                    CASE 3: ran_y(itr) = 0: ran_x(itr) = 1 '   Right.
                    CASE 4: ran_y(itr) = 1: ran_x(itr) = 1 '   Down and right.
                    CASE 5: ran_y(itr) = 1: ran_x(itr) = 0 '   Down.
                    CASE 6: ran_y(itr) = 1: ran_x(itr) = -1 '  Down and left.
                    CASE 7: ran_y(itr) = 0: ran_x(itr) = -1 '  Left.
                    CASE 8: ran_y(itr) = -1: ran_x(itr) = -1 ' Up and left.
                END SELECT

                IF olda_y(itr) = 0 AND olda_x(itr) = 0 THEN ' New alien space ship enters the screen.
                    a_y(itr) = (bottom - top) \ 2: a_x(itr) = (right - left) \ 2 ' Center sreen.
                    a_y(itr) = (bottom - top) \ 4 + RND * (bottom - top) \ 4
                    IF ran(itr) < 5 THEN ' Determine side of entry from initial direction.
                        a_x(itr) = left + 1 ' Enter from the left side and go right.
                    ELSE
                        a_x(itr) = right - LEN(alien$) ' Enter from the right side and go left.
                    END IF
                END IF
                oldran(itr) = ran(itr) ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
            ELSE
                inertia(itr) = inertia(itr) - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
            END IF
            a_y(itr) = a_y(itr) + ran_y(itr): a_x(itr) = a_x(itr) + ran_x(itr) * 2 ' Next move coordinates. I use * 2 for horizontal movement to match the 16x8 pixel height over width factor.
            IF a_y(itr) < top OR a_y(itr) > bottom OR a_x(itr) <= left OR a_x(itr) + LEN(alien$) > right THEN
                olda_x(itr) = 0: olda_y(itr) = 0: inertia(itr) = 0: oldran(itr) = 0 ' Out of bounds and off the screen.
            ELSE
                LOCATE a_y(itr), a_x(itr): PRINT alien$; ' Move alien space ship.
                ' Check for collisions.
                FOR i = 1 TO alien_ship_max
                    IF i <> itr AND a_y(i) <> 0 THEN
                        IF a_y(itr) = a_y(i) AND a_x(itr) >= a_x(i) AND a_x(itr) < a_x(i) + LEN(alien$) THEN
                            LOCATE a_y(i), a_x(i): PRINT SPACE$(LEN(alien$));: LOCATE a_y(itr), a_x(itr): PRINT SPACE$(LEN(alien$));
                            CALL explosion
                            a_y(irt) = 0: a_x(i) = 0 ' Remove exploded alien space ships.
                        END IF
                    END IF
                NEXT
                olda_y(itr) = a_y(itr): olda_x(itr) = a_x(itr) ' Remember these coordinates to erase alien space ship on next loop.
            END IF
            IF itr = alien_ship_max THEN itr = 0: EXIT DO
            IF ABS(z6 - TIMER) > s_delay / 2 THEN skipz5 = -1: EXIT DO
        LOOP
        IF skipz5 = 0 THEN z5 = TIMER
        z6 = TIMER
        LOCATE y_restore, x_restore ' Restore entry column and row positions.
    END IF
END SUB

SUB explosion
    STATIC sound_check, soundfile%, t1&, t6&, t7&, t8&
    IF sound_check = 0 THEN
        IF _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") THEN soundfile% = -1
        IF soundfile% THEN
            t1& = _SNDOPEN("Thunder1.ogg", "SYNC")
            t6& = _SNDOPEN("Thunder6.ogg", "SYNC")
            t7& = _SNDOPEN("Thunder7.ogg", "SYNC")
            t8& = _SNDOPEN("Thunder8.ogg", "SYNC")
        END IF
        sound_check = -1
        EXIT SUB
    END IF

    b_y1 = CSRLIN: b_x1 = POS(0)
    h = 0
    ON ERROR GOTO offscreen
    DO
        IF h = 1 THEN burst$ = " " ELSE burst$ = CHR$(249)
        h = h + 1
        GOSUB flash
        FOR i = 1 TO 5
            SELECT CASE i
                CASE 1
                    COLOR 15
                    LOCATE b_y1, b_x1: PRINT burst$;
                    _DELAY .1
                CASE 2
                    IF burst$ = CHR$(249) THEN burst$ = CHR$(250)
                    COLOR 14, 0
                    LOCATE b_y1 - 1, b_x1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1, b_x1 - 1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1, b_x1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1, b_x1 + 1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1 + 1, b_x1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    _DELAY .1
                CASE 3
                    LOCATE b_y1 - 1, b_x1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1 - 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1 + 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1 + 1, b_x1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                CASE 4
                    COLOR 4
                    LOCATE b_y1 - 1, b_x1 - 1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1 - 1, b_x1 + 1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1, b_x1 - 2
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1, b_x1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1, b_x1 + 2
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1 + 1, b_x1 - 1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    LOCATE b_y1 + 1, b_x1 + 1
                    IF er = 0 THEN PRINT burst$; ELSE er = 0
                    _DELAY .3
                CASE 5
                    LOCATE b_y1 - 1, b_x1 - 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1 - 1, b_x1 + 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1 - 2
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1 - 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1 + 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1, b_x1 + 2
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1 + 1, b_x1 - 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
                    LOCATE b_y1 + 1, b_x1 + 1
                    IF er = 0 THEN PRINT " "; ELSE er = 0
            END SELECT
        NEXT
        IF h = 1 THEN h = 0: EXIT DO
    LOOP
    ON ERROR GOTO 0
    COLOR 7
    EXIT SUB

    flash:
    IF eflag THEN
        IF ABS(z7 - TIMER) > .1 THEN
            eflag = 0
            PALETTE 0, 0
            z7 = TIMER
        ELSE
            j = -j * -1
            IF j = 0 THEN
                PALETTE 0, 63
                _DELAY .05
            ELSE
                PALETTE 0, 0
                _DELAY .05
            END IF
        END IF
    END IF
    IF eflag = 0 THEN
        PALETTE 0, 36
        IF soundfile% THEN
            _SNDPLAY t1&
            _DELAY .05
            PALETTE 0, 0
            _SNDPLAY t7&
        ELSE
            _DELAY .075
        END IF
        eflag = -1
        z7 = TIMER
    END IF
    PALETTE 0, 0
    RETURN
END SUB


In the next update the aliens will be given a bit more A.I. to avoid colliding with one another.

Pete


Attached Files
.7z   ASCII Invaders Sound.7z (Size: 1.45 MB / Downloads: 73)
Reply
#9
cool, this is like Steve's style of tutorial where the code is the tutorial and vice versa, but nice try guys
Reply
#10
(10-05-2022, 07:53 PM)vince Wrote: cool, this is like Steve's style of tutorial where the code is the tutorial and vice versa, but nice try guys

It is. In my younger days, I used to code in all caps, no indentation, and no remark statements. Pushing into my 70's, I can't imagine I could understand my projects if I went back to that coding style. So this is a bit overboard in the other direction, but who knows, a decade from now it might be what keeps me coding.

Pete
Reply




Users browsing this thread: 5 Guest(s)