Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Spinner Game Demo
#1
UPDATE: I renamed all asset file names to lower case to work with Linux (thanks for the heads-up Dav). I also made a small change to the source code fixing an issue.
UPDATE: The ZIP below contains the new code and renamed asset files.

I took the arcade spinner code I wrote in another post and converted it to a library. Here is a demo program using that spinner code to control a spaceship around a perimeter on the screen.

Use the mouse to spin the ship around and the left mouse button to fire a bullet.

This is just a demo to see how well the spinner code works but is a good start to a game if someone wants to expand upon it. Someone in another thread was discussing a game that utilized enemy ships coming out of a worm hole or time tunnel. This would be a good start. I would continue work on it but I have way too much to work on with the game library currently.

The ZIP file below contains the assets (sound and image), libraries needed, and demo code.

Code: (Select All)
OPTION _EXPLICIT

'Spinner game demo

'Game Library Variable Inclusions

'$INCLUDE:'lib_type_spoint.bi'           TYPE TYPE_SPOINT     SINGLE x,y point pair
'$INCLUDE:'lib_jpad_spinner.bi'          JPAD_Spinner         get degree of spinner
'$INCLUDE:'lib_img_introtate.bi'         IMG_INTRotate()      rotate an image
'$INCLUDE:'lib_math_deg2vec.bi'          MATH_Deg2Vec()       convert degree to vector
'$INCLUDE:'lib_math_distancep2p.bi'      MATH_DistanceP2P()   get distance of point to another point

CONST SWIDTH% = 800 '           width of screen
CONST SHEIGHT% = 600 '          height of screen
CONST MAXBULLETS% = 10 '        maximum number of bullets available

TYPE TYPE_BULLET '              BULLET PROPERTIES
    InUse AS INTEGER '          array index in use
    p AS TYPE_SPOINT '          bullet position
    v AS TYPE_SPOINT '          bullet vector
    Vel AS SINGLE '             bullet velocity
END TYPE

DIM Bullet(MAXBULLETS) AS TYPE_BULLET ' bullet array
DIM Center AS TYPE_SPOINT '     center point
DIM Degree AS INTEGER '         current spinner location
DIM ShipSheet AS LONG '         player ship sprite sheet
DIM Ship(-3 TO 3) AS LONG '     seven player ship images
DIM c AS INTEGER '              generic counter
DIM Bullets AS INTEGER '        total bullets flying on screen
DIM ShipRadius AS INTEGER '     radius of ship outer perimeter
DIM BulletRadius AS INTEGER '   radius of bullet outer perimeter
DIM SNDBullet AS LONG '         bullet sound

ShipSheet = _LOADIMAGE("shipsheet.png", 32) '          load player ship sprite sheet
SNDBullet = _SNDOPEN("bullet.ogg") '                   load bullet sound
Center.x = SWIDTH \ 2 '                                x center of screen
Center.y = SHEIGHT \ 2 '                               y center of screen
ShipRadius = (MATH_SNGMin(SWIDTH, SHEIGHT) - 64) \ 2 ' ship outer perimeter radius
BulletRadius = ShipRadius - 38 '                       bullet outer perimeter radius

' -----------------------------
'| Clip ship images from sheet |
' -----------------------------

FOR c = -3 TO 3 '                                                               cycle through seven images
    Ship(c) = _NEWIMAGE(64, 64, 32) '                                           create ship image canvas
    _PUTIMAGE , ShipSheet, Ship(c), ((c + 3) * 64, 0)-((c + 3) * 64 + 63, 63) ' clip ship image from sprite sheet
NEXT c

' -----------------
'| Begin demo code |
' -----------------

SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32) '                               graphics window
_MOUSEHIDE '                                                          hide the mouse pointer
DO '                                                                  begin spinner game demo loop
    CLS '                                                             clear screen
    _LIMIT 60 '                                                       60 frames per second
    Degree = JPAD_Spinner '                                           get spinner location
    DrawShip Degree '                                                 draw the player ship
    IF _MOUSEBUTTON(1) THEN FireBullet Degree '                       fire a bullet if player presses left mouse button
    IF Bullets THEN UpdateBullets '                                   updates bullets if any flying
    LOCATE 2, 2: PRINT "Use the mouse tospin ship around perimeter" ' print instructions
    LOCATE 3, 2: PRINT "Left mouse button to fire"
    LOCATE 5, 2: PRINT "Press ESC to exit"
    _DISPLAY '                                                        update screen with changes
LOOP UNTIL _KEYDOWN(27) '                                             leave demo when ESC pressed

' ------------------------
'| Asset cleanup and exit |
' ------------------------

FOR c = -1 TO 3 '                                                     cycle through seven images
    _FREEIMAGE Ship(c) '                                              remove ship image from RAM
NEXT c
_SNDCLOSE SNDBullet '                                                 remove bullet sound from RAM
SYSTEM '                                                              return to the operating system

' ---------------
'| End demo code |
' ---------------

'------------------------------------------------------------------------------------------------------------------------------------------
SUB DrawShip (Degree AS INTEGER)

    ' ------------------------------------------------------
    '| Draw ship on screen at given degree around perimeter |
    '|                                                      |
    '| Degree - position on ship perimeter                  |
    ' ------------------------------------------------------

    SHARED Ship() AS LONG '         need access to ship images
    SHARED Center AS TYPE_SPOINT '  need access to center point
    SHARED ShipRadius AS INTEGER '  need access to ship perimeter radius
    STATIC pDegree AS INTEGER '     previous ship degree
    STATIC Tilt AS INTEGER '        ship tilt amount
    STATIC Frame AS INTEGER '       frame counter
    DIM rShip AS LONG '             rotated image of ship
    DIM ShipDir AS SINGLE '         direction of ship travel around perimeter

    ShipDir = SGN(MATH_ShortAngle(Degree, pDegree)) '   get direction of ship (-1 counter-clockwise, 1 clockwise, 0 still)
    IF ShipDir THEN '                                   is ship moving?
        Tilt = Tilt + ShipDir '                         yes, tilt ship in direction of movement
        IF Tilt < -3 THEN '                             keep tilt value between -3 and 3
            Tilt = -3
        ELSEIF Tilt > 3 THEN
            Tilt = 3
        END IF
        Frame = 0 '                                     reset frame counter
    ELSE '                                              no, ship is standing still
        IF Tilt THEN '                                  is ship tilted?
            Frame = Frame + 1 '                         yes, increment frame counter
            IF Frame = 4 THEN '                         have 4 frames gone by?
                Tilt = Tilt - SGN(Tilt) '               yes, tilt ship back toward center
                Frame = 0 '                             reset frame counter
            END IF
        END IF
    END IF
    rShip = _COPYIMAGE(Ship(Tilt)) '                    get ship image
    IMG_INTRotate rShip, MATH_FixDegree(Degree - 180) ' rotate ship image
    _PUTIMAGE (Center.x + MATH_SIN(Degree) * ShipRadius - _WIDTH(rShip) \ 2,_
               Center.y - MATH_COS(Degree) * ShipRadius - _HEIGHT(rShip) \ 2), rShip ' draw ship
    _FREEIMAGE rShip '                                  ship image no longer needed
    pDegree = Degree '                                  remember previous ship degree

END SUB

'------------------------------------------------------------------------------------------------------------------------------------------
SUB FireBullet (Degree AS INTEGER)

    ' -----------------------------------------
    '| Adds a bullet to the bullet array       |
    '|                                         |
    '| Degree - origin degree around perimeter |
    ' -----------------------------------------

    SHARED Bullet() AS TYPE_BULLET ' need access to bullet array
    SHARED Bullets AS INTEGER '      need access to number of bullets flying
    SHARED Center AS TYPE_SPOINT '   need access to center point
    SHARED BulletRadius AS INTEGER ' need access to bullet origin radius
    SHARED SNDBullet AS LONG '       need access to bullet sound
    STATIC ShotTimer AS INTEGER '    time (frames) between bullets
    DIM b AS INTEGER '               bullet counter
    DIM i AS INTEGER '               free array index

    IF Bullets = MAXBULLETS THEN EXIT SUB '                      leave if maximum bullets flying
    IF ShotTimer THEN '                                          ok to fire another bullet?
        ShotTimer = ShotTimer - 1 '                              no, decrement shot timer
        IF ShotTimer THEN EXIT SUB '                             leave if time still left on shot timer
    END IF
    Bullets = Bullets + 1 '                                      increment number of bullets flying
    ShotTimer = 5 '                                              reset shot timer
    _SNDPLAYCOPY SNDBullet '                                     play bullet sound

    ' ----------------------
    '| Get free array index |
    ' ----------------------

    b = 1 '                                                      reset bullet counter
    DO '                                                         begen bullet loop
        IF Bullet(b).InUse = 0 THEN i = b '                      use this array index if not in use
        b = b + 1 '                                              increment bullet counter
    LOOP UNTIL i '                                               leave when free array index found

    ' --------------------------
    '| Set up bullet parameters |
    ' --------------------------

    Bullet(i).InUse = -1 '                                       mark this array index in use
    Bullet(i).p.x = Center.x + MATH_SIN(Degree) * BulletRadius ' x location of bullet
    Bullet(i).p.y = Center.y - MATH_COS(Degree) * BulletRadius ' y location of bullet
    MATH_Deg2Vec MATH_FixDegree(Degree - 180), Bullet(i).v '     vector of bullet

END SUB

'------------------------------------------------------------------------------------------------------------------------------------------
SUB UpdateBullets ()

    ' --------------------------------------
    '| Updates any flying bullets on screen |
    ' --------------------------------------

    SHARED Bullet() AS TYPE_BULLET ' need access to bullet array
    SHARED Bullets AS INTEGER '      need access to number of bullets flying
    SHARED Center AS TYPE_SPOINT '   need access to center point
    SHARED BulletRadius AS INTEGER ' need access to bullet origin radius
    DIM b AS INTEGER '               bullet counter
    DIM d AS SINGLE '                distance of bullet to center point
    DIM c AS INTEGER '               brightness of bullet
    DIM clr AS _UNSIGNED LONG '      color of bullet

    b = 1 '                                                                 reset bullet counter
    DO '                                                                    begin bullet loop
        IF Bullet(b).InUse THEN '                                           is this bullet in use?
            Bullet(b).p.x = Bullet(b).p.x + Bullet(b).v.x * Bullet(b).Vel ' yes, update x coordinate
            Bullet(b).p.y = Bullet(b).p.y + Bullet(b).v.y * Bullet(b).Vel ' update y coordinate
            d = MATH_DistanceP2P(Bullet(b).p, Center) '                     distance of bullet to center
            IF d < 1 THEN '                                                 has bullet reached center?
                Bullet(b).InUse = 0 '                                       yes, bullet no longer flying
                Bullets = Bullets - 1 '                                     decrement total bullets flying
            ELSE '                                                          no, bullet still heading toward center
                Bullet(b).Vel = MATH_Map(d, 0, BulletRadius, 1, 10) '       update velocity of bullet
                c = MATH_Map(d, 0, BulletRadius, 96, 255) '                 brightness level of bullet
                clr = _RGB32(c, c, 0) '                                     color of bullet
                CIRCLE (Bullet(b).p.x, Bullet(b).p.y), Bullet(b).Vel, clr ' draw bullet
                PAINT (Bullet(b).p.x, Bullet(b).p.y), clr, clr '            paint bullet
            END IF
        END IF
        b = b + 1 '                                                         increment bullet counter
    LOOP UNTIL b > MAXBULLETS '                                             leave when all bullets updated

END SUB

'Game Library Subroutine/Function Inclusions

'$INCLUDE:'lib_jpad_spinner.bm'          JPAD_Spinner()       get degree of spinner
'$INCLUDE:'lib_img_introtate.bm'         IMG_INTRotate()      rotate an image
'$INCLUDE:'lib_math_fixdegree.bm'        MATH_FixDegree()     keep degree within 0 to 359.999...
'$INCLUDE:'lib_math_deg2vec.bm'          MATH_Deg2Vec()       convert degree to vector
'$INCLUDE:'lib_math_distancep2p.bm'      MATH_DistanceP2P()   get distance of point to another point
'$INCLUDE:'lib_math_sngmin.bm'           MATH_SNGMin()        get minimum SINGLE value
'$INCLUDE:'lib_math_map.bm'              MATH_Map()           map one number system to another
'$INCLUDE:'lib_math_shortangle.bm'       MATH_ShortAngle()    get shortest angle between two angles


Attached Files Image(s)
   

.zip   SpinnerGameDemo.zip (Size: 55.82 KB / Downloads: 16)
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#2
This is really cool and reminds me very much of a game I played as a kid. I wish I could remember what that game was. It was either in the arcades or on a BBC Microcomputer. Probably the latter...
RokCoder - dabbling in QB64pe for fun
Reply
#3
(10-03-2024, 09:32 PM)RokCoder Wrote: This is really cool and reminds me very much of a game I played as a kid. I wish I could remember what that game was. It was either in the arcades or on a BBC Microcomputer. Probably the latter...
Tempest from the arcades is the one I think about. That's a line vector game though.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#4
This works really good, Terry!  I had to rename all the included files to lowercase under Linux first, but after that it ran fine.  I also remember a game sorta like this from my arcade days.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#5
(10-03-2024, 10:12 PM)Dav Wrote: This works really good, Terry!  I had to rename all the included files to lowercase under Linux first, but after that it ran fine.  I also remember a game sorta like this from my arcade days.

- Dav

Crap, I always forget about letter case when it comes to Linux. Sorry about that.

Also, in the top post I noted a change that should be made.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#6
No problem, I just put all the files into a folder, dropped down to it and did this command: rename 'y/A-Z/a-z/' *

This kind of thing helps me learn linux commands more, so I actually am glad it happened.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#7
(10-03-2024, 10:22 PM)Dav Wrote: No problem, I just put all the files into a folder, dropped down to it and did this command: rename 'y/A-Z/a-z/' *

This kind of thing helps me learn linux commands more, so I actually am glad it happened.

- Dav
I just renamed all the files to lower case for any other Linux user. Hey, I wonder if a command like that exists in Windows? I just went through all the files on the command line and renamed them all by hand, LOL.

The ZIP file and code in the original post has been updated. Thanks again for the Linux heads-up. I need to remember those things.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#8
What's a "tospin ship?" 

You need to spend less time around the wife and more time at the space bars.

Pete Big Grin

- Coding's a breeze. Typing's a bitch.
Shoot first and shoot people who ask questions, later.
Reply
#9
(10-04-2024, 12:52 AM)Pete Wrote: What's a "tospin ship?" 

You need to spend less time around the wife and more time at the space bars.

Pete Big Grin

- Coding's a breeze. Typing's a bitch.
oops Big Grin
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#10
Gyruss!

An old coin-op game that has a similar looking ship moving in the same way.  That "where have I played this before?" feeling bugged me.  As a proud old arcade regular, I had to figure it out.

I knew it began with a G!


Quote:I just renamed all the files to lower case for any other Linux user. Hey, I wonder if a command like that exists in Windows?
Not such a simple way, unless Win11 added features to RENAME.  There are many free bulk file renaming utilities, and many file managers such as Free Commander can do bulk renaming with case changes.


Here is a way to change uppercase to lowercase (but not lower-to-upper) from the Windows command line, without additional tools:
Code: (Select All)
for /f "Tokens=*" %f in ('dir /l/b/a-d') do (rename "%f" "%f")
if typed directly into the command prompt, or
Code: (Select All)
for /f "Tokens=*" %%f in ('dir /l/b/a-d') do (rename "%%f" "%%f")
if used in a batch script.


It can also be done in PowersHell: 
Code: (Select All)
dir MYDIR -r | % { if ($_.Name -cne $_.Name.ToLower()) { ren $_.FullName $_.Name.ToLower() } }
(replace MYDIR with the name of the directory that contains the offending files, or leave it out to operate on the current directory.  This method will recurse into subdirectories as well.)


Cool ship you've got there, Terry!
Reply




Users browsing this thread: 6 Guest(s)