Klicka på Arkiv> Nytt projekt och ange vilket namn i applikationsnamnet och vilket domännamn du vill ha. Hit nästa två gånger. Välj sedan Lägg till inget aktivitetsalternativ och tryck på finish .

Under res> drawables klistra in cirkeln och korsa från resursfiler (se här).

Klistra in ic_launcher- filer till respektive filer (fil under hdpi- katalogen under res> drawable-hdpi och så vidare).

Under källa> ditt paket, hitta och välj MainActivity och tryck på shift + F6 för att byta namn på / refactor det, jag kommer att namnge det GameActivity . Radera de två sista metoderna i den som ska fungera för menyn och vi behöver inte dem i den här appen. Det kommer att se ut som:

 public class GameActivity utökar ActionBarActivity { 
 @Åsidosätta 
 skyddat tomrum onCreate (Bundle sparadInstanceState) { 
 super.onCreate (savedInstanceState); 
 setContentView (R.layout.activity_main); 
 } // vi har här några fler metoder här, som vi inte behöver 
 // Ta bara bort dem. 
 } 

Skapa layout för spelet

Vi använder FrameLayout eftersom det gör att vi kan placera en komponent ovanför den andra (vilket krävs för att skissa rader när spelet är klar. Detta kommer att bli tydligare senare.)

I xml-filen under resurser (det vill säga res> layout> din_layout.xml- fil),

sätta följande:

 xmlns: verktyg = "http://schemas.android.com/tools" 
 android: bakgrund = "@ färg / app_background" 
 android: layout_width = "match_parent" 
 android: layout_height = "match_parent" 
 android: paddingLeft = "@ dimen / activity_horizontal_margin" 
 android: paddingRight = "@ dimen / activity_horizontal_margin" 
 android: paddingTop = "@ dimen / activity_vertical_margin" 
 android: paddingBottom = "@ dimen / activity_vertical_margin" 
 Verktyg: context = "np.com.nabinkhadka.tictactoe.MainActivity"> 

Skapa en färg med namnet app_background under värden> colors.xml. Om du inte har colors.xml under res> värden> xml, högerklicka på värden och välj ny> vales resursfil och ange colors.xml som dess namn.

Lägg till följande tre komponenter i FrameLayout

 android: id = "@ + id / exit" 
 android: layout_gravity = "slut" 
 android: src = "@ android: dragbar / ic_input_delete" 
 android: layout_width = "35dp" 
 android: layout_height = "35dp" /> 
 android: id = "@ + id / replay" 
 android: layout_gravity = "start" 
 android: src = "@ android: dragbar / ic_menu_rotate" 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" /> 
 android: id = "@ + id / display_board" 
 android: text = "CROSS's tur" 
 android: textcolor = "@ färg / display_color" 
 android: textsize = "@ dimen / display_font_size" 
 android: layout_gravity = "top | center" 
 android: layout_marginTop = "80dp" 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" /> 

Den första bilden är att visa exit-alternativet i appen. layout_gravity-attributet är inställt på slut, så att det går till slutet av skärmen (längst till höger).

Den andra bilden är att visa omstart-spelalternativet. startvärde för layout_gravity ställer det till vänster (start) på skärmen.

Då krävs en etikett för att visa status för spelet (som att visa spelarens tur, vinnare, match draw meddelande). Låter ha olika färger för att text ska visas i den. Lägg till följande i filen colors.xml under resurskoden

 #dddddd 

Gå till res> värden> dimension.xml- fil och lägg till följande. Detta kommer att definiera teckenstorleken för texten i statusvisningen.

 18sp 

Eftersom vi vill att 9 block ska fylla antingen kors eller cirkel för spelet, kommer vi att göra detta genom att placera 9 ImageViews i GridView av 3X3- dimensionen.

Låter ge en färg till GridView så att den skiljer sig från bakgrunden. Gå vidare och lägg till en annan färg inuti kleuren.xml .

 #dddddd 
 android: layout_gravity = "center" 
 android: column = "3" 
 android: rowCount = "3" 
 android: bakgrund = "@ färg / grid_color" 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content"> 

Vi har gjort detta GridLayout 3X3 med attribut kolumnenCount och rowCount .

Raderna uppnås genom att separera ImageViews från varandra. När ImageViews skjuts långt från varandra ser vi bakgrunden till GridView som fungerar som linjer för spelet. För detta gör vi marginaler till dessa ImageViews.

Första ImageView som är block 1 erhålls enligt följande:

 android: id = "@ + id / block_1" 
 android: layout_marginBottom = "4DP" 
 android: bakgrund = "@ färg / app_background" 
 android: layout_width = "70dp" 
 android: layout_height = "70dp" /> 

Här drar marginalen mot botten linjen under den. Vi namnger det block_1 .

För nästa ImageView,

 android: id = "@ + id / block_2" 
 android: layout_marginBottom = "4DP" 
 android: layout_marginLeft = "4DP" 
 android: layout_marginStart = "4DP" 
 android: layout_marginRight = "4DP" 
 android: layout_marginEnd = "4DP" 
 android: bakgrund = "@ färg / app_background" 
 android: layout_width = "70dp" 
 android: layout_height = "70dp" /> 

Här drar marginalen mot botten linjen under den, vänster & börjar till vänster för att separera den från block 1, och höger & slut för att skilja den från block 3. Vi namnger det block_2 .

På samma sätt gör vi för de kommande sju ImageViews . Dessa tillsammans med ovanstående två placeras i GridLayout .

Nu har vi slutat göra brädet att spela spel. Men vi måste fortfarande göra pinnar / linje som kommer att visas när spelet är klar. De är antingen horisontella, vertikala eller diagonala. Totalt kan det finnas högst 8 sådana linjer i 3X3 tictactoe.

8 Möjliga uppsättningar

Klicka på miniatyrbild för att se full storlek

Den första raden visas när block 1, block 2 och block 3 har alla samma val (det vill säga antingen kors eller cirkel). Så vi kallar block 1, 2, 3 som set 1.

Alla möjliga uppsättningar:

  •  1, 2, 3 --------> set 1 
  •  4, 5, 6 --------> set 2 
  •  7, 8, 9 --------> set 3 
  •  1, 4, 7 --------> set 4 
  •  2, 5, 8 --------> set 5 
  •  3, 6, 9 --------> set 6 
  •  1, 5, 9 --------> set 7 
  •  3, 5, 7 --------> uppsättning 8 

Eftersom dessa rader inte visas i början av spelet (visas först efter att spelet är klart), kommer vi att dölja dessa med hjälp av synlighet attribut för View .

Låt oss göra en färg för linjen genom att lägga till följande under filen color.xml .

 #aaaaaa 

Lägg till följande vy under FrameLayout strax efter att GridLayout är klar.

 android: id = "@ + id / center_vertical" 
 android: bakgrund = "@ färg / stick_color" 
 android: layout_width = "5dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_height = "250dp" /> 

Här har synlighet = synlig gjort det osynligt för layouten. layout_gravity attribut spelar nyckelroll här som gör det till centrum. Höjden och bredden på vyn är så justerade att den ser vertikal ut.

På liknande sätt kan vi lägga till andra sju vyer.

 android: id = "@ + id / left_vertical" 
 android: bakgrund = "@ färg / stick_color" 
 android: layout_width = "5dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_marginRight = "70dp" 
 android: layout_marginEnd = "70dp" 
 android: layout_height = "250dp" /> 
 android: id = "@ + id / right_vertical" 
 android: bakgrund = "@ färg / stick_color" 
 android: layout_width = "5dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_marginLeft = "70dp" 
 android: layout_marginStart = "70dp" 
 android: layout_height = "250dp" /> 
 android: id = "@ + id / center_horizontal" 
 android: bakgrund = "@ färg / stick_color" 
 android: layout_width = "250dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_height = "5dp" /> 
 android: id = "@ + id / bottom_horizontal" 
 android: bakgrund = "@ färg / stick_color" 
 android: layout_width = "250dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_marginTop = "70dp" 
 android: layout_height = "5dp" /> 
 android: id = "@ + id / top_horizontal" 
 android: bakgrund = "@ färg / stick_color" 
 android: layout_width = "250dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_marginBottom = "70dp" 
 android: layout_height = "5dp" /> 
 android: id = "@ + id / right_left_diagonal" 
 android: bakgrund = "@ färg / stick_color" 
 android: vridning = "45" 
 android: layout_width = "5dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_height = "350dp" /> 
 android: id = "@ + id / left_right_diagonal" 
 android: bakgrund = "@ färg / stick_color" 
 android: vridning = "135" 
 android: layout_width = "5dp" 
 android: synlighet = "osynliga" 
 android: layout_gravity = "center" 
 android: layout_height = "350dp" /> 

För att uppnå diagonala linjer är rotationsattributet inställt på 45 och (90 + 45 =) 135.

Skriva spellogiken

Vi måste ta reda på de fall under vilka spelet inte har slutförts. Vi kommer att definiera olika speltillstånd under en java-klass och ta reda på vilken involverad vinnare och blockuppsättning.

Gå till ditt paketnamn och högerklicka på det. Välj sedan ny> java- klass. Med Android Studio kan du ange ditt klassnamn, som vi namnger GameLogic och tryck på OK.

Skapa en matris med ImageView för att lagra block som måste vara fält för den här klassen.

 privata statiska ImageView [] sBlocks; 

Skapa ett strängfält för att lagra vinnaren och ett heltalsfält för att spåra vilken uppsättning som är nöjd för att spelet ska slutas.

 offentligt statisk sträng sWinner; 
 statisk statisk intSet; 

Skapa två heltalsfält enligt följande:

 offentlig statisk slutlig CIRCLE = 0; 
 offentliga statiska slutliga CROSS = 1; 

Det slutliga nyckelordet speglar här att dessa variabler inte kan ha några andra värden än detta. Från och med nu representerar CIRCLE 0 och CROSS representerar 1.

Vi vill kontrollera om alla tre block i vissa uppsättningar har samma typ av val vid en viss punkt. För detta måste vi göra en metod som tar position för dessa block (första blockets position, andra blockets position och tredje blockets position) och även blocket som ställts in som sista parameter. Huvudsyftet med denna metod är att återvända sann när matchning hittas, annars kommer den att returnera falskt

 privata statiska booleska areSameInSet (int first, int second, int tredje, int set) { 
 booleskt värde = sBlocks [first - 1] .getId () == sBlocks [second - 1] .getId () && sBlocks [second - 1] .getId () == sBlocks [tredje - 1] .getId (); 
 if (värde) { 
 if (sBlocks [first - 1] .getId () == CIRCLE) 
 sWinner = "CIRCLE"; 
 annan 
 sWinner = "CROSS"; 
 sSet = set; 
 } 
 returvärde; 
 } 

Eftersom vi är statiska behöver vi inte en instans / objekt av den här klassen för att överskrida denna metod. Denna metod behöver inte heller kallas utanför klassen och därmed förklaras privat . Ett lokalt booleskt variabelt värde får sant om tre block har samma id (id = 1 för kors, id = 0 för cirkel), annars falskt.

Om värdet är sant (vilket betyder att spelet har vunnits av antingen kors eller cirkel), får vi id och hittar vinnaren.

Följande rad i denna metod behövs för att ta reda på vilken blockuppsättning som har varit involverad för att detta spel ska avslutas.

sSet = set;

Därefter skapar vi den viktigaste metoden för denna klass. Denna metod kommer åtkomst av en annan klass direkt, så den måste vara offentlig och statisk eftersom vi inte vill skapa en instans / objekt.

Denna metod kallas när vi trycker på ett av blocket under spelet och därmed tar position av blocket tappat tillsammans med alla dessa block som array.

 public static boolean isComplete (int position, ImageView [] block) { 
 GameLogic.sBlocks = block; 
 boolean isComplete = falsk; 
 switch (position) { 
 fall 1: 
 isComplete = areSameInSet (1, 2, 3, 1) || 
 areSameInSet (1, 4, 7, 4) || 
 areSameInSet (1, 5, 9, 7); 
 ha sönder; 
 fall 2: 
 isComplete = areSameInSet (1, 2, 3, 1) || 
 areSameInSet (2, 5, 8, 5); 
 ha sönder; 
 fall 3: 
 isComplete = areSameInSet (1, 2, 3, 1) || 
 areSameInSet (3, 6, 9, 6) || 
 areSameInSet (3, 5, 7, 8); 
 ha sönder; 
 fall 4: 
 isComplete = areSameInSet (4, 5, 6, 2) || 
 areSameInSet (1, 4, 7, 4); 
 ha sönder; 
 fall 5: 
 isComplete = areSameInSet (4, 5, 6, 2) || 
 areSameInSet (2, 5, 8, 5) || 
 areSameInSet (1, 5, 9, 7) || 
 areSameInSet (3, 5, 7, 8); 
 ha sönder; 
 fall 6: 
 isComplete = areSameInSet (4, 5, 6, 2) || 
 areSameInSet (3, 6, 9, 6); 
 ha sönder; 
 fall 7: 
 isComplete = areSameInSet (7, 8, 9, 3) || 
 areSameInSet (1, 4, 7, 4) || 
 areSameInSet (3, 5, 7, 8); 
 ha sönder; 
 fall 8: 
 isComplete = areSameInSet (7, 8, 9, 3) || 
 areSameInSet (2, 5, 8, 5); 
 ha sönder; 
 fall 9: 
 isComplete = areSameInSet (7, 8, 9, 3) || 
 areSameInSet (3, 6, 9, 6) || 
 areSameInSet (1, 5, 9, 7); 
 ha sönder; 
 } 
 return isComplete; 
 } 

Vi måste kontrollera om det finns möjliga uppsättningar för varje position. Till exempel för position 1 har vi 1, 4 och 7 som giltig uppsättning (se bilden nedan för att förstå tydligare).

 Set 1 betyder att det har 1, 2 och 3 som giltiga block. 
 Set 4 betyder att det har 1, 4 och 7 som giltiga block. 
 Set 7 betyder att det har 1, 5 och 9 som giltiga block. 

(Se tabellen ovan)

För att göra detta, tar vi hjälp av switch statement och ställer in en lokal variabel isComplete till true om minst en av dem är giltig. Detta görs med hjälp av logisk OR- operatör ( || ).

Arbetar med Main Java Class of Android (GameActivity)

För att göra appen på full skärm låter vi skapa en funktion enligt följande:

 private void makeScreen () { 
 Visa dekorView = getWindow (). GetDecorView (); 
 int uiOptions = Visa.SYSTEM_UI_FLAG_FULLSCREEN; 
 decorView.setSystemUiVisibility (uiOptions); 
 getSupportActionBar () dölja ().; 
 } 

Vi behöver följande:

  • Nio ImageViews som representerar block för spelet

  • Avsluta ImageView för att stänga appen (när du trycker på två gånger)

  • Visa TextView för att visa status för spelet

  • Spela upp ImageView för att starta om / spela om spelet från början

 Så skapar du följande fält, 
 privat ImageView [] mBlocks = ny ImageView [9]; 
 privat TextView mDisplay; 
 privat ImageView mExit, mReplay; 

Skapa följande fält som definierar spelets tillstånd.

 privat enum TURN {CIRCLE, CROSS} 
 privat TURN mTurn; 

Vi behöver ytterligare två fält enligt nedan:

 privat int mExitCounter = 0; 
 privat int mStatusCounter = 0; 

Den första kommer att spåra om man trycker på utgångsknappen två gånger (och därför måste vi stänga appen) medan den andra spårar antalet använda block (och därmed förklarar vi att spelet dras om dess värde når 9. Som 9 betyder att alla block används men ingen är vinnaren)

Vi måste initiera fält och ställa in actionlyssnare / händelse lyssnare på dem. Så vi skapar en annan metod som nedan:

 privat tomrum initialisera () { 
 } 

Inuti det initialiserar vi mExit ImageView och ställer in händelse listene r som avslutar appen på tappade två gånger.

 mExit = (ImageView) findViewById (R.id.exit); 
 mExit.setOnClickListener (ny View.OnClickListener () { 
 @Åsidosätta 
 public void onClick (Visa v) { 
 if (mExitCounter == 1) { 
 Avsluta(); 
 System.exit (0); 
 } annat { 
 mExitCounter ++; 
 Toast.makeText (getApplicationContext (), "Tryck igen för att avsluta", Toast.LENGTH_SHORT) .show (); 
 } 
 } 
 }); 

Efter det initialiserar vi mDisplay och mReplay ImageView. Vi kommer att komma ihåg denna spelaktivitet när mReplay trycks.

 mDisplay = (TextView) findViewById (R.id.display_board); 
 mReplay = (ImageView) findViewById (R.id.replay); 
 mReplay.setOnClickListener (ny View.OnClickListener () { 
 @Åsidosätta 
 public void onClick (Visa v) { 
 Avsiktstarter = getIntent (); 
 Avsluta(); 
 starter.setFlags (Intent.FLAG_ACTIVITY_NO_ANIMATION); 
 startActivity (starter); 
 } 
 }); 

Omedelbart efter det initialiserar vi blocket ImageViews .

 för (int position = 0; position <9; position ++) { 
 int resId = getResources (). getIdentifier ("block_" + (position + 1), "id", getPackageName ()); 
 mBlocks [position] = (ImageView) findViewById (resId); 
 final int finalPosition = position; 
 mBlocks [position] .setOnClickListener (new View.OnClickListener () { 
 @Åsidosätta 
 public void onClick (Visa v) { 
 switchTurn (finalPosition); 
 } 
 }); 
 } 

Vi har definierat namn som block_1, block_2, block_3 och så vidare till ImageViews. Så för att göra detta dynamiskt kan vi använda metoden getResources (). GetIdentifier () som visas ovan. När du klickar på dessa ImageViews måste vi visa CROSS eller CIRCLE och ändra spelarens tur. Detta görs med hjälp av en metod switchTurn () som tar positionen till vilken klick / kran gjordes. Vi kommer att göra denna metod nästa.

Så vi kallar dessa två metoder inifrån onCreate-metoden eftersom onCreate-metoden körs när applikationen körs. Således ska metoden onCreate se ut

 @Åsidosätta 
 skyddat tomrum onCreate (Bundle sparadInstanceState) { 
 super.onCreate (savedInstanceState); 
 setContentView (R.layout.activity_main); 
 makeScreen (); 
 initialisera (); 
 } 

Inuti metoden switchTurn () kontrollerar vi om vridning och ställer in displayen, motsvarande ImageViews bild och ID för den (CIRCLE har 0 som id whild CROSS har 1) Vi inaktiverar också ImageView från att vidare trycka på. Det viktigaste som görs här är att använda GameLogic-klassen för att kontrollera om spelet har slutförts. Om det har det kommer vi att inaktivera alla ImageViews och visa relevant linje / stick över block. Samtidigt tänker vi också på visningsstatusen.

 privat void switchTurn (int position) { 
 if (mTurn == TURN.CIRCLE) { 
 mBlocks [läge] .setImageResource (R.drawable.circle); 
 mBlocks [läge] .setId (GameLogic.CIRCLE); 
 mTurn = TURN.CROSS; 
 mDisplay.setText ("CROSS's tur"); 
 } annat { 
 mBlocks [läge] .setImageResource (R.drawable.cross); 
 mBlocks [läge] .setId (GameLogic.CROSS); 
 mTurn = TURN.CIRCLE; 
 mDisplay.setText ("CIRCLE's tur"); 
 } 
 mBlocks [läge] .setEnabled (false); 
 mStatusCounter ++; 
 if (GameLogic.isFyllt (position + 1, mBlocks)) { 
 mDisplay.setText (GameLogic.sWinner + "vann"); 
 displayStick (GameLogic.sSet); 
 inaktivera alla(); 
 } annat om (mStatusCounter == 9) { 
 mDisplay.setText ("DRAW. Försök igen"); 
 } 
 } 

displayStick () -metod som tar numret som parameter för att representera vilken pinne som ska visas. Följaktligen visas pinnen / vyn.

 privat ogiltig displayStick (int stick) { 
 Visa vy; 
 växla (stick) { 
 fall 1: 
 view = findViewById (R.id.top_horizontal); 
 ha sönder; 
 fall 2: 
 view = findViewById (R.id.center_horizontal); 
 ha sönder; 
 fall 3: 
 view = findViewById (R.id.bottom_horizontal); 
 ha sönder; 
 fall 4: 
 view = findViewById (R.id.left_vertical); 
 ha sönder; 
 fall 5: 
 view = findViewById (R.id.center_vertical); 
 ha sönder; 
 fall 6: 
 view = findViewById (R.id.right_vertical); 
 ha sönder; 
 fall 7: 
 view = findViewById (R.id.left_right_diagonal); 
 ha sönder; 
 fall 8: 
 view = findViewById (R.id.right_left_diagonal); 
 ha sönder; 
 standard: // vilket aldrig kommer att hända 
 view = findViewById (R.id.top_horizontal); 
 } 
 view.setVisibility (View.VISIBLE); 
 } 

Lägg till följande metod för att inaktivera alla ImageViews

 private void disableAll () { 
 för (int i = 0; i <9; i ++) 
 mBlocks [i] .setEnabled (false); 
 } 

Överstyr metoden onBackPressed () och gör den tom. Detta kommer att inaktivera enhetens tillbaka-knapp.

 @Åsidosätta 
 public void onBackPression () { 
 } 

Kör projektet

Gå nu och kör ditt projekt. Du kan se att appen är klar nu.

Video

Återkoppling

Jag svarar mer än gärna på dina frågor relaterade till den här artikeln. Lämna bara en kommentar så svarar jag er inom en dag.

© 2015 Nabin Khadka