Programmeren computer spelletjes is misschien wel de meest technisch uitdagende (en mogelijk de best betaalde) baan die een programmeur kunnen hebben. Games op het hoogste niveau vereisen het beste van zowel programmeurs als computers.
Visual Basic 6 is nu grondig omzeild als platform voor het programmeren van games. (Het was er nooit een. Zelfs in de 'goede oude tijd' zouden programmeurs van serieuze games nooit een taal op hoog niveau zoals VB 6 gebruiken, omdat je gewoon niet kon knippen randprestaties die de meeste games vereisen.) Maar het eenvoudige "Tic Tac Toe" -spel is een geweldige introductie tot programmeren die iets geavanceerder is dan "Hallo Wereld!"
Dit is een geweldige introductie tot veel van de fundamentele concepten van programmeren omdat het technieken combineert, waaronder:
- Het gebruik van arrays. De X- en O-markeringen worden in afzonderlijke arrays bewaard en de hele arrays worden tussen functies doorgegeven om de voortgang van het spel bij te houden.
- Grafische afbeeldingen op VB 6-niveau gebruiken: VB 6 biedt geen geweldige grafische mogelijkheden, maar de game is een goede introductie tot wat beschikbaar is. Een groot deel van de rest van deze serie is een verkenning van hoe GDI +, de volgende generatie Microsoft graphics, de VB 6 level graphics vervangt.
- Wiskundige berekeningen gebruiken voor programmabesturing: het programma gebruikt slimme modulo (Mod) en integer divisie berekeningen met behulp van de twee-game marker arrays om te bepalen wanneer een "win" met drie elementen heeft heeft plaatsgevonden.
De klasse van programmeren in dit artikel is misschien net iets voorbij het beginniveau, maar het zou goed moeten zijn voor "gemiddelde" programmeurs. Maar laten we beginnen op een elementair niveau om enkele van de concepten te illustreren en u op weg te helpen met uw Visual Basic game programmeer carrière. Zelfs studenten die geavanceerder zijn, kunnen merken dat het een beetje een uitdaging is om de objecten precies in de juiste vorm te krijgen.
Hoe Tic Tac Toe te spelen
Als je nog nooit hebt gespeeld Boter kaas en eieren, hier zijn de regels. Twee spelers wisselen elkaar af bij het plaatsen van Xs en Os in een 3x3 speelveld.
Voordat het spel begint, moeten beide spelers het eens zijn over wie als eerste zal gaan en wie zijn zetten met welk symbool zal markeren. Na de eerste zet plaatsen de spelers afwisselend hun markeringen in een lege cel. Het doel van het spel is om de eerste speler te zijn met drie markeringen in een horizontale, diagonale of verticale lijn. Als er geen lege cellen zijn en geen van beide spelers een winnende combinatie heeft, is het spel gelijkspel.
Voordat u met daadwerkelijke codering begint, is het altijd een goed idee om de namen van alle componenten die u gebruikt te wijzigen. Zodra je begint coderingwordt de naam automatisch gebruikt door Visual Basic, dus u wilt dat het de juiste naam is. We gebruiken de formuliernaam frmTicTacToe en we veranderen ook het bijschrift in "Over Tic Tac Toe".
Met het formulier vastgesteld, gebruikt u de lijntoolboxcontrole om een raster van 3 x 3 te tekenen. Klik op het lijngereedschap en teken vervolgens een lijn waar u het wilt hebben. Je moet op deze manier vier lijnen maken en hun lengte en positie aanpassen om ze er goed uit te laten zien. Visual Basic heeft ook enkele handige tools in het menu Opmaak die zullen helpen. Dit is een geweldige kans om met hen te oefenen.
Naast het speelraster hebben we enkele objecten nodig voor de X- en O-symbolen die op het raster worden geplaatst. Omdat er negen spaties in het raster zijn, maken we een objectarray met negen spaties, elementen genoemd in Visual Basic.
Er zijn verschillende manieren om zo ongeveer alles in de Visual Basic-ontwikkelomgeving te doen, en het maken van control-arrays is geen uitzondering. Waarschijnlijk is de gemakkelijkste manier om het eerste label te maken (klikken en tekenen net als de lijntool), het een naam te geven, alle attributen in te stellen (zoals Font en ForeColor) en er vervolgens kopieën van te maken. VB 6 zal vragen of je een control array wilt creëren. Gebruik de naam lblPlayGround voor het eerste label.
Om de andere acht elementen van het raster te maken, selecteert u het eerste labelobject, stelt u de eigenschap Index in op nul en drukt u op CTRL + C (kopiëren). Nu kunt u op CTRL + V (plakken) drukken om een ander labelobject te maken. Wanneer u dergelijke objecten kopieert, neemt elke kopie alle eigenschappen over, behalve de Index van de eerste. De index wordt voor elk exemplaar met één verhoogd. Dit is een controlearray omdat ze allemaal dezelfde naam hebben, maar verschillende indexwaarden.
Als u de array op deze manier maakt, worden alle kopieën op elkaar gestapeld in de linkerbovenhoek van het formulier. Sleep elk label naar een van de speelrasterposities. Zorg ervoor dat indexwaarden opeenvolgend zijn in het raster. De logica van het programma hangt ervan af. Het labelobject met indexwaarde 0 moet in de linkerbovenhoek staan en het label rechtsonder moet index 8 hebben. Als de labels het speelraster bedekken, selecteer dan elk label, klik met de rechtermuisknop en selecteer Verzenden naar rug.
Aangezien er acht manieren zijn om het spel te winnen, hebben we acht verschillende lijnen nodig om de winst op het speelveld te tonen. U gebruikt dezelfde techniek om een andere controlearray te maken. Teken eerst de lijn, noem deze linWin en stel de eigenschap Index in op nul. Gebruik vervolgens de kopieer-plaktechniek om nog zeven lijnen te produceren. De volgende afbeelding laat zien hoe u de indexnummers correct instelt.
Naast de label- en lijnobjecten heb je enkele opdrachtknoppen nodig om het spel te spelen en meer labels om de score bij te houden. De stappen om deze te maken zijn hier niet gedetailleerd, maar dit zijn de objecten die u nodig heeft.
Twee knop voorwerpen:
- cmdNewGame
- cmdResetScore
Frame-object fraPlayFirst met twee optieknoppen:
- optXPlayer
- optOPlayer
Frame object fraScoreBoard met zes labels. Alleen lblXScore en lblOScore worden gewijzigd in de programmacode.
- lblX
- lblXScore
- lblO
- lblOScore
- lblMinus
- lblColon
Ten slotte heb je ook het labelobject lblStartMsg nodig om de cmdNewGame-knop te 'maskeren' wanneer er niet op moet worden geklikt. Dit is niet zichtbaar in de onderstaande afbeelding omdat het dezelfde ruimte inneemt in het formulier als de opdrachtknop. Mogelijk moet u de opdrachtknop tijdelijk verplaatsen om dit label op het formulier te tekenen.
Tot nu toe is er geen VB-codering gedaan, maar we zijn er eindelijk klaar voor.
Initialisatie
Nu moet je eindelijk beginnen met het coderen van het programma. Als je dat nog niet hebt gedaan, wil je misschien de broncode downloaden om mee te volgen terwijl de werking van het programma wordt uitgelegd.
Een van de eerste ontwerpbeslissingen die moet worden genomen, is hoe de huidige 'status' van het spel kan worden bijgehouden. Met andere woorden, wat zijn de huidige Xs en Os op het speelrooster en wie er daarna beweegt. Het concept 'staat' is van cruciaal belang bij veel programmeren, en in het bijzonder is het belangrijk bij het programmeren van ASP en ASP.NET voor het web
Dit kan op verschillende manieren, dus het is een cruciale stap in de analyse. Als u dit probleem zelf zou oplossen, wilt u misschien een stroomschema tekenen en verschillende opties met 'kladpapier' uitproberen voordat u begint met coderen.
Onze oplossing maakt gebruik van twee "tweedimensionale arrays" omdat dat helpt bij het bijhouden van de 'status' door simpelweg de array-indexen in programmalussen te wijzigen. De staat van de linkerbovenhoek bevindt zich in het array-element met index (1, 1), de rechterbovenhoek staat in (1, 3), de rechteronderhoek in (3,3), enzovoort. De twee arrays die dit doen, zijn:
iXPos (x, y)
en
iOPos (x, y)
Er zijn veel verschillende manieren waarop dit kan worden gedaan en de laatste VB.NET-oplossing in deze serie laat zien hoe u dit kunt doen met slechts één eendimensionale array.
De programmering om deze arrays te vertalen in beslissingsbeslissingen van spelers en zichtbare weergaven in het formulier staan op de volgende pagina.
Je hebt ook een paar globale variabelen nodig als volgt. Merk op dat deze in de code Algemeen en Verklaringen voor het formulier staan. Dit maakt ze "moduleniveau" variabelen waarnaar overal in de code voor dit formulier kan worden verwezen. Raadpleeg voor meer informatie De reikwijdte van variabelen begrijpen in Visual Basic Help.
Er zijn twee gebieden waar variabelen in ons programma worden geïnitialiseerd. Eerst worden enkele variabelen geïnitialiseerd terwijl het formulier frmTicTacToe wordt geladen.
Private Sub Form_Load ()
Ten tweede worden voor elk nieuw spel alle variabelen die moeten worden gereset naar startwaarden toegewezen in een initialisatiesubroutine.
Sub InitPlayGround ()
Merk op dat de initialisatie van het laden van formulieren ook de initialisatie van de speelplaats aanroept.
Een van de kritische vaardigheden van een programmeur is de mogelijkheid om de foutopsporingsfaciliteiten te gebruiken om te begrijpen wat de code doet. U kunt dit programma gebruiken om te proberen:
- Door de code bladeren met de F8-toets
- Een horloge instellen op belangrijke variabelen, zoals sPlaySign of iMove
Een breekpunt instellen en de waarde van variabelen opvragen. Bijvoorbeeld in de binnenste lus van de initialisatie:
lblPlayGround ((i - 1) * 3 + j - 1) .Caption = ""
Merk op dat dit programma duidelijk laat zien waarom het een goede programmeerpraktijk is om gegevens waar mogelijk in arrays te bewaren. Als u geen arrays in dit programma had, zou u code als volgt moeten schrijven:
Line0.Visible = False
Line1.Visible = False
Line2.Visible = False
Line3.Visible = False
Line4.Visible = False
Line5.Visible = False
Line6.Visible = False
Line7.Visible = False
in plaats van dit:
Voor i = 0 tot 7
linWin (i) .Visible = False
Volgende ik
Een zet doen
Als een deel van het systeem kan worden gezien als 'het hart', is het subroutine lblPlayGround_Click. Deze subroutine wordt aangeroepen telkens wanneer een speler op het speelrooster klikt. (Klikken moeten zich in een van de negen lblPlayGround-elementen bevinden.) Merk op dat deze subroutine een argument heeft: (Index als geheel getal). De meeste andere 'event-subroutines', zoals cmdNewGame_Click () niet. Index geeft aan op welk labelobject is geklikt. Index zou bijvoorbeeld de waarde nul voor de linkerbovenhoek van het raster en de waarde acht voor de rechteronderhoek bevatten.
Nadat een speler op een vierkant in het spelraster heeft geklikt, wordt de opdrachtknop om een ander spel te starten, cmdNewGame, 'ingeschakeld' door het zichtbaar te maken. De status van deze opdrachtknop heeft een dubbele functie, omdat deze later in het programma ook wordt gebruikt als een booleaanse beslissingsvariabele. Het gebruik van een eigenschapswaarde als beslissingsvariabele wordt meestal afgeraden omdat als het ooit nodig wordt om het programma te wijzigen (bijvoorbeeld om de cmdNewGame-opdrachtknop de hele tijd zichtbaar), dan zal het programma onverwachts mislukken omdat je je misschien niet meer herinnert dat het ook als onderdeel van het programma wordt gebruikt logica. Om deze reden is het altijd een goed idee om door programmacode te zoeken en het gebruik van alles wat u verandert te controleren bij het uitvoeren van programmaonderhoud, zelfs eigendomswaarden. Dit programma schendt de regel deels om dit punt te maken en deels omdat dit een relatief eenvoudig stuk code is waar het gemakkelijker is om te zien wat er wordt gedaan en problemen later te voorkomen.
Een spelerselectie van een spelveld wordt verwerkt door de GamePlay-subroutine aan te roepen met Index als argument.
Verwerking verwerken
Eerst controleer je of er op een leeg veld is geklikt.
If lblPlayGround (xo_Move) .Caption = "" Dan
Zodra we zeker weten dat dit een legitieme zet is, wordt de verplaatsingsteller (iMove) verhoogd. De volgende twee regels zijn erg interessant omdat ze de coördinaten vertalen vanuit het eendimensionale Als lblPlayGround componentarray naar tweedimensionale indexen die u in iXPos of iOPos kunt gebruiken. Mod en integer-deling (de 'backslash') zijn wiskundige bewerkingen die u niet elke dag gebruikt, maar hier is een goed voorbeeld dat laat zien hoe ze erg nuttig kunnen zijn.
If lblPlayGround (xo_Move) .Caption = "" Dan
iMove = iMove + 1
x = Int (xo_Move / 3) + 1
y = (xo_Move Mod 3) + 1
De xo_Move-waarde 0 wordt vertaald naar (1, 1), 1 naar (1, 2)... 3 tot (2, 1)... 8 tot (3, 3).
De waarde in sPlaySign, een variabele met modulebereik, houdt bij welke speler de zet heeft gedaan. Zodra de verplaatsingsarrays zijn bijgewerkt, kunnen de labelcomponenten in het speelraster worden bijgewerkt met het juiste teken.
Als sPlaySign = "O" Dan
iOPos (x, y) = 1
iWin = CheckWin (iOPos ())
Anders
iXPos (x, y) = 1
iWin = CheckWin (iXPos ())
Stop als
lblPlayGround (xo_Move) .Caption = sPlaySign
Als de X-speler bijvoorbeeld in de linkerbovenhoek van het raster klikt, hebben variabelen de volgende waarden:
Het gebruikersscherm toont alleen een X in het vak linksboven, terwijl de iXPos een 1 in het vak linksboven en 0 in alle andere. De iOPos heeft 0 in elke doos.
De waarden veranderen wanneer de O-speler op het middelste vierkant van het raster klikt. Nu toont de iOPos een 1 in het middenvak terwijl het gebruikersscherm een X linksboven en een O in het middenvak toont. De iXPos toont alleen de 1 in de linkerbovenhoek, met 0 in alle andere vakjes.
Nu u weet waar een speler heeft geklikt en welke speler heeft geklikt (met de waarde in sPlaySign) hoeft u alleen maar uit te zoeken of iemand een game heeft gewonnen en uit te zoeken hoe u dat kunt laten zien in de Scherm.
Een winnaar vinden
Na elke zet controleert de CheckWin-functie op de winnende combinatie. CheckWin werkt door elke rij, over elke kolom en door elke diagonaal naar beneden toe te tellen. Het kan erg leerzaam zijn om de stappen via CheckWin te volgen met behulp van de debugfunctie van Visual Basic. Het vinden van een overwinning is een kwestie van eerst controleren of er drie 1-en zijn gevonden in elk van de afzonderlijke controles in de variabele iScore, en vervolgens het retourneren van een unieke "handtekening" -waarde in Checkwin die wordt gebruikt als de array-index om de eigenschap Visible van één element in de linWin te wijzigen component array. Als er geen winnaar is, zal CheckWin de waarde -1 bevatten. Als er een winnaar is, wordt de weergave bijgewerkt, wordt het scorebord gewijzigd, wordt een felicitatiebericht weergegeven en wordt het spel opnieuw gestart.
Laten we een van de controles in detail doornemen om te zien hoe het werkt. De andere zijn vergelijkbaar.
'Controleer rijen voor 3
Voor i = 1 tot 3
iScore = 0
CheckWin = CheckWin + 1
Voor j = 1 tot 3
iScore = iScore + iPos (i, j)
Volgende j
Als iScore = 3 Dan
Functie afsluiten
Stop als
Volgende ik
Het eerste dat opvalt, is dat de eerste indexteller i de rijen aftelt, terwijl de tweede j over de kolommen telt. De buitenste lus gaat dan gewoon van de ene rij naar de volgende. De binnenste lus telt de enen in de huidige rij. Als er drie zijn, heb je een winnaar.
Merk op dat u ook het totale aantal geteste vierkanten bijhoudt in de variabele CheckWin, de waarde die wordt teruggegeven wanneer deze functie wordt beëindigd. Elke winnende combinatie krijgt een unieke waarde in CheckWin van 0 tot 7 die wordt gebruikt om een van de elementen in de linWin () -componentenarray te selecteren. Dit maakt ook de volgorde van de code in de functie CheckWin belangrijk! Als je een van de blokken van hebt verplaatst lus code (zoals hierboven), zou de verkeerde lijn op het speelveld worden getrokken wanneer iemand wint. Probeer het en zie!
Afwerkingsdetails
De enige code die nog niet besproken is, is de subroutine voor een nieuw spel en de subroutine die de score zal resetten. De rest van de logica in het systeem maakt het maken ervan vrij eenvoudig. Om een nieuw spel te starten, hoef je alleen de InitPlayGround-subroutine aan te roepen. Voor het gemak van spelers, aangezien de knop midden in een spel kan worden aangeklikt, vraag je om bevestiging voordat je verder gaat. U vraagt ook om bevestiging voordat u het scorebord opnieuw start.