This is a one-player Tic-Tac-Toe game using the mouse.
Code: (Select All)
'I've wanted to make this game for decades and finally am able to!
'This game was made on August 14, 2019 by SierraKen.
'This is Freeware.
'Jan. 28, 2021 update: Choose at random who goes first.
'Jan. 29, 2021 update: Random colored grid, better looking X's, faster welcome screen, centered welcome screen better, made the ability to click to play a new game and another game,
'and added text colors.
'Jan. 30, 2021 update: Added background blue shades. Also added a score in the Title Bar. Turned the game into 3D - Thanks to B+ for the idea!
Dim a(10), b(10)
_Limit 60
_Title "Tic-Tac-Toe by SierraKen"
Screen _NewImage(600, 480, 32)
Cls
Print: Print: Print
Locate 10, 34: Print "-"
Locate 10, 40: Print "-"
For tic = 1 To 10
Locate tic, 30: Print "TIC"
_Delay .1
Locate tic, 30: Print " "
Next tic
Locate 10, 30: Print "TIC"
For tac = 20 To 10 Step -1
Locate tac, 36: Print "TAC"
_Delay .1
Locate tac, 36: Print " "
Next tac
Locate 10, 36: Print "TAC"
For toe = 1 To 10
Locate toe, 42: Print "TOE"
_Delay .1
Locate toe, 42: Print " "
Next toe
Locate 10, 42: Print "TOE"
computer = 0
you = 0
Print: Print: Print
Print " By SierraKen"
Print: Print: Print
Print " Play against the computer in this classic game of Tic-Tac-Toe."
Print " Whoever gets 3 in a row wins."
Print
Print " Choose a sqace by using your mouse."
Print " Computer chooses who goes first."
Color _RGB32(255, 255, 255), _ClearColor
_PrintString (220, 430), "Click Here To Start"
Color _RGB32(255, 255, 255), _RGB32(0, 0, 0)
Do
_Limit 60
mouseWheel = 0
Do While _MouseInput
mouseX = _MouseX
mouseY = _MouseY
mouseLeftButton = _MouseButton(1)
mouseRightButton = _MouseButton(2)
mouseMiddleButton = _MouseButton(3)
mouseWheel = mouseWheel + _MouseWheel
Loop
ag$ = InKey$
If ag$ = Chr$(27) Then End
If ag$ = " " Then Cls: GoTo start:
If mouseLeftButton = -1 And mouseX > 220 And mouseX < 370 And mouseY > 430 And mouseY < 446 Then Cls: GoTo start:
Loop
start:
ag$ = ""
t = 0
turn = 0
comp = 0
For cc = 0 To 480
cl = cl + .5
Line (0, cc)-(640, cc), _RGB32(0, 0, cl)
Next cc
cl = 0
Randomize Timer
c1 = Int(Rnd * 155) + 100
c2 = Int(Rnd * 155) + 100
c3 = Int(Rnd * 155) + 100
GoSub grid:
whosfirst:
Randomize Timer
first = Int(Rnd * 2) + 1
If first = 1 Then GoTo computerchoice:
Go:
_Limit 60
a$ = InKey$
If a$ = Chr$(27) Then End
mouseWheel = 0
Do While _MouseInput
mouseX = _MouseX
mouseY = _MouseY
mouseLeftButton = _MouseButton(1)
mouseRightButton = _MouseButton(2)
mouseMiddleButton = _MouseButton(3)
mouseWheel = mouseWheel + _MouseWheel
Loop
If mouseLeftButton = -1 Then
If mouseX > 88 And mouseX < 218 And mouseY > 93 And mouseY < 182 And b(1) = 0 And a(1) = 0 And t = 0 Then GoSub space1:
If mouseX > 241 And mouseX < 357 And mouseY > 93 And mouseY < 182 And b(2) = 0 And a(2) = 0 And t = 0 Then GoSub space2:
If mouseX > 381 And mouseX < 509 And mouseY > 93 And mouseY < 182 And b(3) = 0 And a(3) = 0 And t = 0 Then GoSub space3:
If mouseX > 88 And mouseX < 218 And mouseY > 205 And mouseY < 302 And b(4) = 0 And a(4) = 0 And t = 0 Then GoSub space4:
If mouseX > 241 And mouseX < 357 And mouseY > 205 And mouseY < 302 And b(5) = 0 And a(5) = 0 And t = 0 Then GoSub space5:
If mouseX > 381 And mouseX < 509 And mouseY > 205 And mouseY < 302 And b(6) = 0 And a(6) = 0 And t = 0 Then GoSub space6:
If mouseX > 88 And mouseX < 218 And mouseY > 326 And mouseY < 410 And b(7) = 0 And a(7) = 0 And t = 0 Then GoSub space7:
If mouseX > 241 And mouseX < 357 And mouseY > 326 And mouseY < 410 And b(8) = 0 And a(8) = 0 And t = 0 Then GoSub space8:
If mouseX > 381 And mouseX < 509 And mouseY > 326 And mouseY < 410 And b(9) = 0 And a(9) = 0 And t = 0 Then GoSub space9:
End If
If mouseLeftButton = -1 And ending = 1 Then GoTo start:
If mouseRightButton = -1 And ending = 1 Then End
If t = 1 Then GoSub computer:
GoTo Go:
checkwin:
'Check to see if you won.
If a(1) = 1 And a(2) = 1 And a(3) = 1 Then GoTo won:
If a(4) = 1 And a(5) = 1 And a(6) = 1 Then GoTo won:
If a(7) = 1 And a(8) = 1 And a(9) = 1 Then GoTo won
If a(1) = 1 And a(4) = 1 And a(7) = 1 Then GoTo won:
If a(2) = 1 And a(5) = 1 And a(8) = 1 Then GoTo won:
If a(3) = 1 And a(6) = 1 And a(9) = 1 Then GoTo won:
If a(1) = 1 And a(5) = 1 And a(9) = 1 Then GoTo won:
If a(3) = 1 And a(5) = 1 And a(7) = 1 Then GoTo won:
turn = turn + 1
Sound 100, .25
If turn = 9 Then GoTo catsgame:
GoTo Go:
won:
For snd = 300 To 900 Step 50
Sound snd, .5
Next snd
For tt = 1 To 9
a(tt) = 0
b(tt) = 0
Next tt
you = you + 1
you$ = Str$(you)
computer$ = Str$(computer)
_Title "You: " + you$ + " Computer: " + comp$
t = 0
Color _RGB32(255, 0, 0), _ClearColor
Locate 2, 32: Print "Y O U W I N ! !"
Color _RGB32(255, 255, 255), _RGB32(0, 0, 0)
GoTo playagain:
computer:
'Check to win.
'Last space gone.
If b(1) = 1 And b(2) = 1 And a(3) = 0 And b(3) = 0 Then GoTo compspace3:
If b(4) = 1 And b(5) = 1 And a(6) = 0 And b(6) = 0 Then GoTo compspace6:
If b(7) = 1 And b(8) = 1 And a(9) = 0 And b(9) = 0 Then GoTo compspace9:
If b(1) = 1 And b(4) = 1 And a(7) = 0 And b(7) = 0 Then GoTo compspace7:
If b(2) = 1 And b(5) = 1 And a(8) = 0 And b(8) = 0 Then GoTo compspace8:
If b(3) = 1 And b(6) = 1 And a(9) = 0 And b(9) = 0 Then GoTo compspace9:
If b(1) = 1 And b(5) = 1 And a(9) = 0 And b(9) = 0 Then GoTo compspace9:
If b(3) = 1 And b(5) = 1 And a(7) = 0 And b(7) = 0 Then GoTo compspace7:
'First space gone.
If b(2) = 1 And b(3) = 1 And a(1) = 0 And b(1) = 0 Then GoTo compspace1:
If b(5) = 1 And b(6) = 1 And a(4) = 0 And b(4) = 0 Then GoTo compspace4:
If b(8) = 1 And b(9) = 1 And a(7) = 0 And b(7) = 0 Then GoTo compspace7:
If b(4) = 1 And b(7) = 1 And a(1) = 0 And b(1) = 0 Then GoTo compspace1:
If b(5) = 1 And b(8) = 1 And a(2) = 0 And b(2) = 0 Then GoTo compspace2:
If b(6) = 1 And b(9) = 1 And a(3) = 0 And b(3) = 0 Then GoTo compspace3:
If b(5) = 1 And b(9) = 1 And a(1) = 0 And b(1) = 0 Then GoTo compspace1:
If b(7) = 1 And b(5) = 1 And a(3) = 0 And b(3) = 0 Then GoTo compspace3:
'Middle space gone.
If b(1) = 1 And b(3) = 1 And a(2) = 0 And b(2) = 0 Then GoTo compspace2:
If b(4) = 1 And b(6) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
If b(7) = 1 And b(9) = 1 And a(8) = 0 And b(8) = 0 Then GoTo compspace8:
If b(1) = 1 And b(7) = 1 And a(4) = 0 And b(4) = 0 Then GoTo compspace4:
If b(2) = 1 And b(8) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
If b(3) = 1 And b(9) = 1 And a(6) = 0 And b(6) = 0 Then GoTo compspace6:
If b(1) = 1 And b(9) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
If b(3) = 1 And b(7) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
'Check to block.
'Last space gone.
If a(1) = 1 And a(2) = 1 And a(3) = 0 And b(3) = 0 Then GoTo compspace3:
If a(4) = 1 And a(5) = 1 And a(6) = 0 And b(6) = 0 Then GoTo compspace6:
If a(7) = 1 And a(8) = 1 And a(9) = 0 And b(9) = 0 Then GoTo compspace9:
If a(1) = 1 And a(4) = 1 And a(7) = 0 And b(7) = 0 Then GoTo compspace7:
If a(2) = 1 And a(5) = 1 And a(8) = 0 And b(8) = 0 Then GoTo compspace8:
If a(3) = 1 And a(6) = 1 And a(9) = 0 And b(9) = 0 Then GoTo compspace9:
If a(1) = 1 And a(5) = 1 And a(9) = 0 And b(9) = 0 Then GoTo compspace9:
If a(3) = 1 And a(5) = 1 And a(7) = 0 And b(7) = 0 Then GoTo compspace7:
'First space gone.
If a(2) = 1 And a(3) = 1 And a(1) = 0 And b(1) = 0 Then GoTo compspace1:
If a(5) = 1 And a(6) = 1 And a(4) = 0 And b(4) = 0 Then GoTo compspace4:
If a(8) = 1 And a(9) = 1 And a(7) = 0 And b(7) = 0 Then GoTo compspace7:
If a(4) = 1 And a(7) = 1 And a(1) = 0 And b(1) = 0 Then GoTo compspace1:
If a(5) = 1 And a(8) = 1 And a(2) = 0 And b(2) = 0 Then GoTo compspace2:
If a(6) = 1 And a(9) = 1 And a(3) = 0 And b(3) = 0 Then GoTo compspace3:
If a(5) = 1 And a(9) = 1 And a(1) = 0 And b(1) = 0 Then GoTo compspace1:
If a(7) = 1 And a(5) = 1 And a(3) = 0 And b(3) = 0 Then GoTo compspace3:
'Middle space gone.
If a(1) = 1 And a(3) = 1 And a(2) = 0 And b(2) = 0 Then GoTo compspace2:
If a(4) = 1 And a(6) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
If a(7) = 1 And a(9) = 1 And a(8) = 0 And b(8) = 0 Then GoTo compspace8:
If a(1) = 1 And a(7) = 1 And a(4) = 0 And b(4) = 0 Then GoTo compspace4:
If a(2) = 1 And a(8) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
If a(3) = 1 And a(9) = 1 And a(6) = 0 And b(6) = 0 Then GoTo compspace6:
If a(1) = 1 And a(9) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
If a(3) = 1 And a(7) = 1 And a(5) = 0 And b(5) = 0 Then GoTo compspace5:
'Computer decides a random space.
computerchoice:
Randomize Timer
comp = Int(Rnd * 9) + 1
If b(comp) = 1 Then GoTo computerchoice:
If a(comp) = 1 Then GoTo computerchoice:
If comp = 1 Then GoTo compspace1:
If comp = 2 Then GoTo compspace2:
If comp = 3 Then GoTo compspace3:
If comp = 4 Then GoTo compspace4:
If comp = 5 Then GoTo compspace5:
If comp = 6 Then GoTo compspace6:
If comp = 7 Then GoTo compspace7:
If comp = 8 Then GoTo compspace8:
If comp = 9 Then GoTo compspace9:
'Cat's Game
catsgame:
For snd = 400 To 300 Step -25
Sound snd, .5
Next snd
For tt = 1 To 9
a(tt) = 0
b(tt) = 0
Next tt
t = 0
Color _RGB32(255, 0, 255), _ClearColor
Locate 2, 29: Print "Cat's Game - No Winners"
Color _RGB32(255, 255, 255), _RGB32(0, 0, 0)
GoTo playagain:
'Check to see if the computer won.
check:
If b(1) = 1 And b(2) = 1 And b(3) = 1 Then GoTo compwon:
If b(4) = 1 And b(5) = 1 And b(6) = 1 Then GoTo compwon:
If b(7) = 1 And b(8) = 1 And b(9) = 1 Then GoTo compwon
If b(1) = 1 And b(4) = 1 And b(7) = 1 Then GoTo compwon:
If b(2) = 1 And b(5) = 1 And b(8) = 1 Then GoTo compwon:
If b(3) = 1 And b(6) = 1 And b(9) = 1 Then GoTo compwon:
If b(1) = 1 And b(5) = 1 And b(9) = 1 Then GoTo compwon:
If b(3) = 1 And b(5) = 1 And b(7) = 1 Then GoTo compwon:
turn = turn + 1
If turn = 9 Then GoTo catsgame:
t = 0
GoTo Go:
compwon:
For snd = 900 To 300 Step -50
Sound snd, .5
Next snd
For tt = 1 To 9
a(tt) = 0
b(tt) = 0
Next tt
t = 0
computer = computer + 1
you$ = Str$(you)
comp$ = Str$(computer)
_Title "You: " + you$ + " Computer: " + comp$
Color _RGB32(128, 255, 255), _ClearColor
Locate 2, 33: Print "Computer Wins"
Color _RGB32(255, 255, 255), _RGB32(0, 0, 0)
GoTo playagain:
'This part draws the computer's circle.
compspace1:
t = 0
b(1) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (160 - xx, 140 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoSub grid:
GoTo check:
compspace2:
t = 0
b(2) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (300 - xx, 140 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoSub grid:
GoTo check:
compspace3:
t = 0
b(3) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (440 - xx, 140 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoSub grid:
GoTo check:
compspace4:
t = 0
b(4) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (160 - xx, 260 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoSub grid:
GoTo check:
compspace5:
t = 0
b(5) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (300 - xx, 260 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoSub grid:
GoTo check:
compspace6:
t = 0
b(6) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (440 - xx, 260 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoSub grid:
GoTo check:
compspace7:
t = 0
b(7) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (160 - xx, 375 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoTo check:
compspace8:
t = 0
b(8) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (300 - xx, 375 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoTo check:
compspace9:
t = 0
b(9) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Circle (440 - xx, 375 - xx), 40 - s, _RGB32(255 - (xx * 10), 0, 0)
Next s
Next xx
GoTo check:
'This last part draws your X.
space1:
a(1) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (115 + s - xx, 104 - xx)-(195 + s - xx, 169 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (195 + s - xx, 104 - xx)-(115 + s - xx, 169 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space2:
a(2) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (255 + s - xx, 104 - xx)-(335 + s - xx, 169 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (335 + s - xx, 104 - xx)-(255 + s - xx, 169 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space3:
a(3) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (395 + s - xx, 104 - xx)-(475 + s - xx, 169 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (475 + s - xx, 104 - xx)-(395 + s - xx, 169 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space4:
a(4) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (110 + s - xx, 224 - xx)-(190 + s - xx, 289 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (190 + s - xx, 224 - xx)-(110 + s - xx, 289 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space5:
a(5) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (255 + s - xx, 224 - xx)-(335 + s - xx, 289 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (335 + s - xx, 224 - xx)-(255 + s - xx, 289 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space6:
a(6) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (395 + s - xx, 224 - xx)-(475 + s - xx, 289 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (475 + s - xx, 224 - xx)-(395 + s - xx, 289 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space7:
a(7) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (110 + s - xx, 339 - xx)-(190 + s - xx, 404 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (190 + s - xx, 339 - xx)-(110 + s - xx, 404 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space8:
a(8) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (255 + s - xx, 339 - xx)-(335 + s - xx, 404 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (335 + s - xx, 339 - xx)-(255 + s - xx, 404 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
space9:
a(9) = 1
For xx = .1 To 10 Step .1
For s = .25 To 10 Step .25
Line (395 + s - xx, 339 - xx)-(475 + s - xx, 404 - xx), _RGB32(0, 255 - (xx * 10), 0)
Line (475 + s - xx, 339 - xx)-(395 + s - xx, 404 - xx), _RGB32(0, 255 - (xx * 10), 0)
Next s
Next xx
t = 1
GoTo checkwin:
playagain:
Color _RGB32(255, 0, 0), _ClearColor
_PrintString (220, 55), "Click Here To Play Again"
Color _RGB32(255, 255, 255), _RGB32(0, 0, 0)
Do
_Limit 60
mouseWheel = 0
Do While _MouseInput
mouseX = _MouseX
mouseY = _MouseY
mouseLeftButton = _MouseButton(1)
mouseRightButton = _MouseButton(2)
mouseMiddleButton = _MouseButton(3)
mouseWheel = mouseWheel + _MouseWheel
Loop
ag$ = InKey$
If ag$ = Chr$(27) Then End
If ag$ = " " Then Cls: GoTo start:
If mouseLeftButton = -1 And mouseX > 220 And mouseX < 412 And mouseY > 55 And mouseY < 69 Then Cls: GoTo start:
Loop
grid:
'Draw Grid
'Vertical Lines
For xx = .1 To 15 Step .1
Line (220 - xx, 100 - xx)-(240 - xx, 410 - xx), _RGB32(c1 - (xx * 10), c2 - (xx * 10), c3 - (xx * 10)), BF
Line (360 - xx, 100 - xx)-(380 - xx, 410 - xx), _RGB32(c1 - (xx * 10), c2 - (xx * 10), c3 - (xx * 10)), BF
Next xx
For xx = .1 To 15 Step .1
'Horizontal Lines
Line (90 - xx, 185 - xx)-(510 - xx, 205 - xx), _RGB32(c1 - (xx * 10), c2 - (xx * 10), c3 - (xx * 10)), BF
Line (90 - xx, 305 - xx)-(510 - xx, 325 - xx), _RGB32(c1 - (xx * 10), c2 - (xx * 10), c3 - (xx * 10)), BF
Next xx
Return
_MIDISOUNDBANK is a QB64-PE v3.14.0 feature. However, before we dive straight into it, let's take a look at a bit of history.
What is MIDI?
MIDI (Musical Instrument Digital Interface) is a communication protocol that enables the control and synchronization of electronic musical instruments, software, and other devices. Unlike audio data, MIDI messages are lightweight, making them ideal for real-time performance and control. MIDI was standardized in 1983 by the MIDI Manufacturers Association (MMA), and its continued use today highlights its enduring versatility.
What is a MIDI File?
A MIDI file is a digital file format that stores MIDI data. Unlike audio files, which contain actual sound recordings, a MIDI file contains instructions for generating sound. These instructions include information such as note pitch, duration, velocity, and timing, as well as control changes and other parameters. MIDI files are highly compact because they do not store actual audio, making them ideal for efficient storage and manipulation of musical compositions. MIDI files can be played back by any MIDI-compatible device, which interprets the data and generates the corresponding sounds.
What is a MIDI soundbank?
A MIDI soundbank is a collection of audio samples and settings that a synthesizer uses to generate sounds when playing a MIDI file. It defines how the notes and instructions in the MIDI file will sound, allowing for different instrument tones and qualities.
QB64 and MIDI
The last SDL version of QB64 (v0.954) was the version that had native MIDI playback support. MIDI and several other audio formats were dropped in the OpenGL version of QB64. QB64-PE v3.2.0 reintroduced support for MIDI playback, although it was initially hidden behind $UNSTABLE:MIDI. QB64-PE v3.14.0 moved MIDI playback support out of $UNSTABLE:MIDI and made it a first-class feature. $UNSTABLE:MIDI and $MIDISOUNDFONT were deprecated, and the new _MIDISOUNDBANK statement was added.
_MIDISOUNDBANK Syntax
Code: (Select All)
_MIDISOUNDBANK: fileName$[, capabilities$]
fileName$ is the file name of the soundbank or a buffer containing the soundbank data. capabilities$ (optional) can be two flags if specified.
"memory" - indicating that the fileName$ is a buffer and not a file name and one of the following.
"ad": Global Timbre Library format for Audio Interface Library.
"op2": DMX OPL-2 format.
"opl": Global Timbre Library format for Audio Interface Library.
"sfo": Bernhard Schelling's Ogg compressed Creative SoundFont 2.0 format.
"tmb": Apogee Sound System timbre format.
"wopl": Vitaly Novichkov's OPL3BankEditor format.
Example: Using an embedded soundbank
Code: (Select All)
$EMBED:'./tiny.sf2','mysf2'
_MIDISOUNDBANK _EMBEDDED$("mysf2"), "memory, sf2"
handle = _SNDOPEN("canyon.xmi")
_SNDPLAY handle
QB64-PE MIDI Player Engine
The QB64-PE MIDI player engine heavily borrows from the foobar2000 MIDI Player plugin (https://www.foobar2000.org/components/view/foo_midi). Unlike the foobar2000 plugin, however, the QB64-PE implementation is cross-platform, except for VSTi support (more on this later). The player internally uses various backends to play MIDI files. All backends need a soundbank. However, the Opal+yfmidi backend has a tiny soundbank embedded by default that is used to play MIDI files if no other soundbank is loaded.
Synth
Type
Setup
Difficulty
Platform
Quality
Opal+yfmidi
Frequency modulation
None
Can I play, Daddy?
All
Retro
Primesynth/TinySoundFont
Sample-based
Less
Don't hurt me.
All
Awesome
VSTi
Implementation defined
More
Bring 'em on!
Windows
Hell yeah!
Playing a MIDI file without any soundbank loaded will default the MIDI engine to use the Opal+yfmidi backend and the default embedded soundbank. Note that the FM Synthesis used is similar to that of a real Yamaha OPL3. However, unlike hardware OPL3 that supports only 18 channels, the Opal+yfmidi backend supports 108 (18 x 6) channels. This allows it to produce exceptional quality retro-sounding music. External AD, OPL2, OPL, TMB, and WOPL FM bank formats are also supported by this backend.
Example: Playing a MIDI files using FM synthesis
Code: (Select All)
handle = _SNDOPEN("groove.xmi")
_SNDPLAY handle
The Primesynth/TinySoundFont backends support sample-based synthesis using SoundFonts (SF2). As such, they can reproduce music using real-life instrument sounds at very high quality. The TinySoundFont backend supports compressed SoundFonts like SF3 & SFO. Note that compression is lossy (OGG), and hence some degradation in quality can be perceived. QB64-PE does not contain any SoundFonts, so the user must specify a SoundFont using _MIDISOUNDBANK to use this backend.
Example: Playing a MIDI file using a SoundFont
Code: (Select All)
_MIDISOUNDBANK "4mgmgsmt.sf2"
handle = _SNDOPEN("onestop.mid")
_SNDPLAY handle
The VSTi backend is Windows-only because it uses a VSTi DLL. QB64-PE itself does not include any code from Steinberg Media Technologies. Therefore, it uses a VST Host module to communicate with the VSTi DLL. Yours truly has taken the effort to adapt the foobar2000 MIDI VST Host for QB64-PE, and the same is available at https://github.com/a740g/vsthost. One should compile the project using Visual Studio 2022 to get the vsthost32.exe and vsthost64.exe files. My sole motivation to add VSTi support to QB64-PE was to get MIDI playing using the Yamaha S-YXG50 VSTi found at https://veg.by/en/projects/syxg50/. A VSTi can be specified using _MIDISOUNDBANK. However, QB64-PE expects the VST Host to be in the same directory as the VSTi DLL. Otherwise, the VSTi will not be loaded, and playback will fail.
Example: Playing a MIDI file using a VSTi
Code: (Select All)
$IF WINDOWS THEN
_MIDISOUNDBANK "syxg50.dll" ' load VSTi on Windows
$ELSE
_MIDISOUNDBANK "4mgmgsmt.sf2" ' fallback to a SoundFont on other platforms
$ENDIF
handle = _SNDOPEN("onestop.mid")
_SNDPLAY handle
The example player (MIDIPlayer64) below contains code that shows how to load various soundbanks, use the various backends, and several other features. Feel free to experiment and use the code in your own projects.
Things to try
Play monkey.mid and Wolfenstein 3D*.mid from the midis directory using FM Synthesis.
Play THE_RAIN.mid, ECHOES.mid, striving.mid, and DOOM MIDIs in the midis directory using soundbanks/gzdoom.sf2.
Play COLDWAVE.mid, MHBB.mid, and TK_EATS.mid in the midis directory using soundbanks/wingroove.sf2.
On Windows, play bi2_polkovnik.mid, Cop Out by Sam Sketty YME '96.mid, Fool's World (XG).mid, The Major Seven (XG).mid, and Technocrat XG Sam Cardon.mid using soundbanks/syxg50.dll.
Is it possible that there is a limit on the $EMBED or _EMBEDDED$?
When I have loaded some sounds, I get a repeat of the first or second sound. I can never play them all.
Example below where 5 different MP3 files are read. But the same sounds are played.
Can you test it? I am using the latest version, so the 3.14 of QB-PE.
In the example you choose 5 MP3 files yourself.
Here's a bare-bones shooter game example that I *think* is easy to learn from and to expand on. It's pretty simple. Shoot the balls, don't let any pass you or touch you. Move the piece at the bottom LEFT/RIGHT using the arrow keys, SPACE shoots. ESC quits. If a ball hits you or you let one pass the game is over.
Nothing much of a game, but it was a lazy Saturday and I just wanted to code something. Maybe some can make use of it. It would be easy to expand this little shooter.
'=============
'ballshoot.bas
'=============
'A bare-bones small shooter game that you can expand on.
'Coded by Dav, AUG/2024 for QB64PE v3.13
'Move player using arrow keys - SPACE bar shoots.
'Shoot the balls. Don't let any hit you or pass you by.
'This is a basic shooter game that is easy enough to
'learn from and expand on so you can make your own game,
'I used balls as an enemy because I had a ball SUB handy,
'and it had a colorful effect. I used it for the enemy
'as well has for the shots. I also used an alpha screen
'clearing method using LINE instead of CLS. This gave
'all the moving pieces a neat trailing/fade effect.
'Game is over if a ball hits you our you let one pass.
'There are many ways to exand this into something better.
'If you do make more out of it, please share it also.
Randomize Timer
balls = 6 'number of balls at one time
shots = 6 'number of shots allowed on screen
Dim ballx(1 To balls) 'ball x pos
Dim bally(1 To balls) 'ball y pos
Dim balld(1 To balls) 'ball direction
Dim ballr(1 To balls) 'ball radius
Dim shotx(1 To shots) 'shot x pos
Dim shoty(1 To shots) 'shot y pos
Dim shota(1 To shots) 'flag if shot is active
'set game defaults
score = 0 'score is zero
shotcount = 0 'no active shots
playerx = _Width / 2 'x pos of player
playery = 475 'y pos of player (this stays same)
'generate random ball info
For i = 1 To balls
ballx(i) = Int(Rnd * _Width) + 1 'x pos
bally(i) = Int(Rnd * (_Height / 4)) + 1 'y pos
balld(i) = Int(Rnd * 3) - 1 'moving direction
ballr(i) = 10 + Int(Rnd * 20) 'radius
Next
'=== main game loop ===
Do
'this make the trailing fade effect on screen (cooler than doing CLS)
Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 75), BF
'draw player along bottom of screen
Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(255, Rnd * 125, Rnd * 128), BF
Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(0, 0, Rnd * 255), B
'handle all active shots...
For i = 1 To shotcount
If shota(i) Then
'draw the shot
glowball shotx(i), shoty(i), 3, 255, 0, 0, 255
shoty(i) = shoty(i) - 5 'make shot go up
'if shot goes up off screen...
If shoty(i) < 0 Then shota(i) = 0 'set shot active flag off
End If
Next
'left/right arrows move player
If _KeyDown(19200) Then playerx = playerx - 5 'left arrow, move left
If _KeyDown(19712) Then playerx = playerx + 5 'right arrow, move right
'make sure player doesn't go off screen
If playerx < 0 Then
playerx = 0
ElseIf playerx > (_Width - 1) Then
playerx = (_Width - 1)
End If
'Spacebar fires a shot
If _KeyDown(32) Then
'look for first inactive shot to shoot
For i = 1 To UBound(shota)
'if this one is free, and lastshot time passed...
If shota(i) = 0 And Timer - lastshot > .2 Then
shotx(i) = playerx 'give it our x/y
shoty(i) = playery
shota(i) = 1 'mark it as active
'update shot count
If i > shotcount Then shotcount = i
lastshot = Timer 'mark time of this shot....
'Note: I'm using shot timer to prevent too rapid fire of shots
Exit For
End If
Next
End If
'see if shot hits a ball
For i = 1 To balls
For j = 1 To shotcount
If shota(j) Then
If Abs(ballx(i) - shotx(j)) < ballr(i) And Abs(bally(i) - shoty(j)) < ballr(i) Then
'flash a circle around hit ball
Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 255, 255)
'Line (0, 0)-(_Width, _Height), _RGBA(255, 255, 255, 10), BF
shota(j) = 0 'set shot active flag off
bally(i) = 1 'give ball new y pos (top)
ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
score = score + 1 'update score
End If
End If
Next
Next
'if a ball hits player, end game
For i = 1 To balls
If Abs(ballx(i) - playerx) < ballr(i) And Abs(bally(i) - playery) < ballr(i) Then End
Next
'show score
Locate 1, 1: Print "Score: "; score;
_Display
_Limit 30
Loop Until _KeyDown(27) 'ESC quits
End
Sub glowball (x, y, size, r, g, b, a)
t = Timer
For y2 = y - size To y + size
For x2 = x - size To x + size
If Sqr((x2 - x) ^ 2 + (y2 - y) ^ 2) <= size Then
clr = (size - (Sqr((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)))) / size
noise = Int(Rnd * 50)
r = Sin(6.005 * t) * size - y2 + size + 255 * 2
g = Sin(3.001 * t) * size - x2 + size + 255
b = Sin(2.001 * x2 / size + t + y2 / size) * r + 255
t = t + .00195
PSet (x2, y2), _RGBA(clr * r - noise, clr * g - noise, clr * b - noise, a)
End If
Next
Next
End Sub
This can be used in an unlimited amount of games. It shows a ball (or cannonball) randomly being thrown or hit in a 3D perspective toward the Z axis. There is no Z axis in the code though, it uses a parabola equation I found on ChatGPT and after experimentation I came up with this. I also found the SGN command on ChatGPT that helps with choosing either a positive or negative random number. I used to do it a different way in my games, but had forgotten how I did it, so I found this.
Feel free to use this in any of your games or programs. Would make a cool baseball or golf game I would think.
Left click the mouse to throw each time.
Code: (Select All)
'Ken's Throw The Ball Demonstration
'I got the parabola equation and SGN command for random numbers from ChatGPT and I made the rest.
'Feel free to use this as you wish.
Screen _NewImage(800, 600, 32)
Cls
_Title "Click The Left Mouse Button To Throw"
' Define the coefficients for the parabola y = ax^2 + bx + c
Dim a As Double, b As Double, c As Double
centerX = 400
centerY = 300
c = 0
s = 100
ball = 8
Do
Do
Do While _MouseInput
oldm = m
m = _MouseWheel
If _MouseButton(1) Then
b = Int(Rnd * _Pi) + 6
a = Int(Rnd * 7) - 7
randomx = (Rnd * 10) * Sgn(Rnd - 0.5)
Cls
End If
Loop
Loop Until _MouseButton(1)
If m > oldm Then
a = a + .1
b = b + .1
Cls
oldm = m
End If
If m < oldm Then
a = a - .1
Cls
oldm = m
End If
' Set up a loop to draw the parabola
For x = -20 To 30 + a Step .5
' Calculate y using the parabola equation
y = a * (x / 10) ^ 2 + b * (x / 10) + c
' Convert to screen coordinates
screenX = centerX + x * randomx
screenY = centerY - y * 10
If ball > 1.5 Then ball = ball - .2
' Plot the point
Circle (screenX, screenY), ball, _RGB32(255, 255, 255)
_Delay .05
s = s + .1
Sound s, 1
_Display
Cls
Next x
s = 100
ball = 8
Loop Until InKey$ = Chr$(27)
End
SOUNDBALLS is a sound immersion environmet experiment. Enter a world where balls have their own unique sound. By placing the balls in desired poisitions in the stereo field, and control it's volume, you can create your own special soundscape.
Each ball has a different sound.
Move the balls to place its sound in the environment.
Move ball left to place its sound more left in the stereo field.
Move ball right to place its sound more right in the stereo field.
Move the balls upward in the distance to make it get softer.
Move the balls down closer towards you to make it get louder.
Right click on a ball to turn its sound On/Off.
Ball will glow when it's turn on, doesn't when off.
By default only 1 ball is turned on when program starts.
Press any key to leave the sound ball world.
USE HEADPHONES OR EXTERNAL SPEAKERS FOR BEST RESULTS
I consider this game finished, for the time being. Keyboard controls are optional, it's really a mouse game. (Don't mind the distorted 3D view, it's a long story )
Grts, T&T
[Edit] Click in the text box at the bottom of the menu screen to see how to handle the mouse and the spacebar to play level 1
The operation and logic of the command seem clear.
However, I would like to point out that at least in one case, the execution causes a problem.
Specifically, it concerns my case:
1) With a Windows launcher (there are many free ones), I start the QB64 IDE (I often use DavisIDE because it is more comfortable and less cumbersome);
2) It performs the compilation (the EXE file is produced in the same folder as the BAS files, and that folder also contains the entire series of folders that make up the application);
3) That said, it would seem that the EXE file correctly sees where it is launched from and behaves as it should.
But no! The path detected by _STARTDIR$ is that of the launcher! So, you have to manually open the folder and launch the executable directly from there.
It's not a serious problem... I created a BAT file that executes everything and runs the execution without this annoying setback.
Perhaps - I say perhaps, but I understand that nothing is easy - _STARTDIR$ should read what it needs to read by looking at itself and where it is located.
I often go crazy over this simple sequence of commands:
$EXEICON: 'myicon.ico'
_ICON
_title title$
What happens is:
1) I don't know because, but sometimes it "fixes" itself so that the icon is not myicon.ico (with the corresponding absolute path) but an old icon that - once the instruction had worked - now it carries along as if it has the memory of an elephant. In other words... it ignores myicon.ico and the icon of the EXE file is that old one, which QB64 seems to like so much...
2) At the same time, the icon that appears on the title bar of the window (along with _TITLE) is the correct one.
3) _ICON with or without the file (_ICON 'myico.ico') seems to have no effect.
Question: why does this behavior occur and how can I correct it?