Створення мережевої гри в "хрестики-нулики" на платформі Android

  1. Мережеві розраховані на багато користувачів "хрестики-нулики"
  2. Створення серверної частини
  3. Лістинг 1. db.sql
  4. Лістинг 2. start.php
  5. Лістинг 3. games.php
  6. Лістинг 4. show_moves.php
  7. Лістинг 5. moves.php
  8. Лістинг 6. move.php
  9. Створення Android-інтерфейсу
  10. Малюнок 1. Створення Android-додатки в Eclipse
  11. Малюнок 2. Файли проекту TicTacToe
  12. Лістинг 7. AndroidManifest.xml
  13. Лістинг 8. layout.xml
  14. Лістинг 9. TicTacToeActivity.java
  15. Лістинг 10. GameService.java
  16. Лістінг 11. BoardView.java
  17. Лістинг 12. UpdateTimer.java
  18. Малюнок 3. Запуск Android-емулятора
  19. Малюнок 4. Емулятор запущений і готовий до роботи
  20. Малюнок 5. Гра до виконання першого ходу
  21. Малюнок 6. Природно, хід хрестиком робиться в центральний квадрат
  22. Малюнок 7. Нулик в кутовому квадраті
  23. Висновок
  24. Ресурси для скачування

Створюємо мережеву багато користувачів гру в "хрестики-нулики", використовуючи технології PHP, XML і комплект інструментальних засобів для розробки додатків на платформі Android

Мережеві розраховані на багато користувачів "хрестики-нулики"

Часто використовувані скорочення
  • API: Application Programming Interface (прикладний інтерфейс програмування)
  • HTTP: Hypertext Transfer Protocol (протокол передачі гіпертексту)
  • IP: Internet protocol (Інтернет-протокол)
  • SDK: Software Development Kit (комплект інструментальних засобів для розробки програмного забезпечення)
  • SQL: Structured Query Language (мова структурованих запитів)
  • UI: User Interface (призначений для користувача інтерфейс)
  • XML: Extensible Markup Language (розширювана мова розмітки)

Казуальні комп'ютерні ігри (ігри для широкого кола користувачів, в які грають від випадку до випадку) надзвичайно популярні і дуже рентабельні, що легко можна пояснити. Далеко не кожен, не залежно від віку, цікавляться інтерактивними "стрілялками" від першої особи проти полчищ ворогів, які вимагають блискавичної реакції. Іноді цікавіше пограти в ігри, в яких є час на роздуми і вироблення стратегії або для виграшу слід застосовувати кооперативну стратегію.

З точки зору розробника казуальні ігри набагато простіше для розробки, ніж графічні "стрілялки" від першої особи або спортивні ігри. Тому розробнику або групі розробників легше створити нову оригінальну гру.

У даній статті розглядаються основи створення казуальної мережевий багатокористувацької гри в "хрестики-нулики". Ігровим сервером є Web-додаток з XML-інтерфейсом, що використовує MySQL і PHP. Клієнтом є стандартне Android-додаток, що працює на Android-телефонах.

Створення серверної частини

Серверна частина використовує просту базу даних MySQL, має дві таблиці. В лістингу 1 показана схема бази даних.

Лістинг 1. db.sql

DROP TABLE IF EXISTS games; CREATE TABLE games (id INT NOT NULL AUTO_INCREMENT, primary key (id)); DROP TABLE IF EXISTS moves; CREATE TABLE moves (id INT NOT NULL AUTO_INCREMENT, game INT NOT NULL, x INT NOT NULL, y INT NOT NULL, color INT NOT NULL, primary key (id));

У реальному додатку, ймовірно, буде використовуватися таблиця users, а таблиця games буде містити ідентифікатори обох гравців. Для простоти я відмовився від такого підходу і сконцентрувався на зберіганні ігрових даних, на взаємодії між клієнтом і сервером і на створенні клієнтської частини.

Друга таблиця moves містить окремі ходи гри і складається з п'яти стовпців. Перший стовпець - це унікальний ідентифікатор ходу. Другий стовпець - ідентифікатор гри, якої належить хід. Потім йдуть позиції x і y ходу. Ці значення повинні перебувати в межах між 0 і 2, оскільки використовується ігрове поле три на три. Останнє поле - це "колір" ходу, що є цілим числом, що вказує X (хрестик) або O (нулик).

Для створення бази даних насамперед запустіть програму mysqladmin і за допомогою команди mysql виконайте сценарій db.sql, як показано нижче:

% Mysqladmin --user = root --password = foo create ttt% mysql --user = root --password = foo ttt <db.sql

Дана дія створює нову базу даних ttt, що містить схему гри в "хрестики-нулики".

Після створення схеми необхідно створити спосіб запуску гри. Для цього використовується сценарій під назвою start.php, наведений в лістингу 2 .

Лістинг 2. start.php

<? Php header ( 'Content-Type: text / xml'); $ Dd = new PDO ( 'mysql: host = localhost; dbname = ttt', 'root', ''); $ Sql ​​= 'INSERT INTO games VALUES (0)'; $ Sth = $ dd-> prepare ($ sql); $ Sth-> execute (array ()); $ Qid = $ dd-> lastInsertId (); $ Doc = new DOMDocument (); $ R = $ doc-> createElement ( "game"); $ R-> setAttribute ( 'id', $ qid); $ Doc-> appendChild ($ r); print $ doc-> saveXML (); ?>

Сценарій починається з підключення до бази даних. Потім виконується вираз INSERT для таблиці games і повертається згенерований ідентифікатор. Після цього створюється XML-документ, в тег game додається ідентифікатор і виконується експорт XML.

Цей сценарій необхідно виконати для створення гри в базі даних, тому що наше просте Android-додаток не має інтерфейсу для створення ігор. Ось код:

$ Php start.php <? Xml version = "1.0"?> <Game id = "1" /> $

Отже, у нас є перша гра. Щоб переглянути список ігор використовується сценарій games.php, наведений в лістингу 3 .

Лістинг 3. games.php

<? Php header ( 'Content-Type: text / xml'); $ Dbh = new PDO ( 'mysql: host = localhost; dbname = ttt', 'root', ''); $ Sql ​​= 'SELECT * FROM games'; $ Q = $ dbh-> prepare ($ sql); $ Q-> execute (array ()); $ Doc = new DOMDocument (); $ R = $ doc-> createElement ( "games"); $ Doc-> appendChild ($ r); foreach ($ q-> fetchAll () as $ row) {$ e = $ doc-> createElement ( "game"); $ E-> setAttribute ( 'id', $ row [ 'id']); $ R-> appendChild ($ e); } Print $ doc-> saveXML (); ?>

Цей сценарій, як і сценарій start.php, починається з підключення до бази даних. Потім запитується таблиця games для перегляду доступних ігор. Після цього створюється новий XML-документ, додається тег games, а потім теги game для кожної доступної гри.

Після запуску сценарію з командного рядка повинна відобразитися наступна інформація:

$ Php games.php <? Xml version = "1.0"?> <Games> <game id = "1" /> </ games> $

Також цей сценарій можна запустити з Web-браузера.

Чудово! Тепер, маючи інтерфейс games, можна приступити до написання серверного коду обробки ходів. Цей код починається зі створення допоміжного сценарію show_moves, що одержує поточні ходи для даної гри і експортує їх в XML. В лістингу 4 показаний PHP-код для даної допоміжної функції.

Лістинг 4. show_moves.php

<? Php function show_moves ($ dbh, $ game) {$ sql = 'SELECT * FROM moves WHERE game =?'; $ Q = $ dbh-> prepare ($ sql); $ Q-> execute (array ($ game)); $ Doc = new DOMDocument (); $ R = $ doc-> createElement ( "moves"); $ Doc-> appendChild ($ r); foreach ($ q-> fetchAll () as $ row) {$ e = $ doc-> createElement ( "move"); $ E-> setAttribute ( 'x', $ row [ 'x']); $ E-> setAttribute ( 'y', $ row [ 'y']); $ E-> setAttribute ( 'color', $ row [ 'color']); $ R-> appendChild ($ e); } Print $ doc-> saveXML (); }?>

Сценарій приймає дескриптор бази даних і ідентифікатор гри. Потім він виконує SQL-запит для отримання списку ходів. Після цього він створює XML-документ з ходами для даної гри.

Цю допоміжну функцію використовують два сценарії. Перший з них - це moves.php, який повертає поточні ходи зазначеної гри. Цей сценарій наведено в лістингу 5 .

Лістинг 5. moves.php

<? Php require_once ( 'show_moves.php'); header ( 'Content-Type: text / xml'); $ Dbh = new PDO ( 'mysql: host = localhost; dbname = ttt', 'root', ''); show_moves ($ dbh, $ _REQUEST [ 'game']); ?>

Цей простий сценарій підключає код допоміжної функції, з'єднується з базою даних і активізує функцію show_moves із зазначеним ідентифікатором гри. Щоб протестувати цей код, застосуєте команду curl для активізації сценарію на сервері з командного рядка:

$ Curl "http: //localhost/ttt/moves.php? Game = 1" <? Xml version = "1.0"?> <Moves /> $

Ще не зроблено жодного ходу, тому нічого цікавого не виводиться. Щоб виправити становище, до серверного інтерфейсу потрібно додати останній сценарій. В лістингу 6 наведено сценарій move.php.

Лістинг 6. move.php

<? Php require_once ( 'show_moves.php'); header ( 'Content-Type: text / xml'); $ Dbh = new PDO ( 'mysql: host = localhost; dbname = ttt', 'root', ''); $ Sql ​​= 'DELETE FROM moves WHERE game =? AND x =? AND y =? '; $ Sth = $ dbh-> prepare ($ sql); $ Sth-> execute (array ($ _REQUEST [ 'game'], $ _REQUEST [ 'x'], $ _REQUEST [ 'y'])); $ Sql ​​= 'INSERT INTO moves VALUES (0,?,?,?,?)'; $ Sth = $ dbh-> prepare ($ sql); $ Sth-> execute (array ($ _REQUEST [ 'game'], $ _REQUEST [ 'x'], $ _REQUEST [ 'y'], $ _REQUEST [ 'color'])); show_moves ($ dbh, $ _REQUEST [ 'game']); ?>

Цей сценарій починається з підключення допоміжної функції і з'єднання з базою даних. Потім виконуються два SQL-вирази. Перше видаляє всі ходи, які можуть конфліктувати з ходами, що відправляються в другому запиті. Друге SQL-вираз вставляє новий рядок в таблицю moves для зазначеного ходу. Потім клієнтові повертається список ходів. Ця дія усуває необхідність виконання клієнтом двох запитів при кожному ході. Пропускна здатність недешева, тому при першій-ліпшій можливості слід об'єднувати запити.

Для тестування можна виконати хід:

$ Curl "http: //localhost/ttt/move.php? Game = 1 & x = 1 & y = 2 & color = 1" <? Xml version = "1.0"?> <Moves> <move x = "1" y = "2" color = "1" /> </ moves>

Після завершення створення серверного коду можна приступити до створення Android-інтерфейсу цієї розрахованої на багато користувачів мережевої гри.

Створення Android-інтерфейсу

Перш за все встановіть Android SDK, кілька версій платформи Android і, нарешті, Eclipse і плагін Android Eclipse. На щастя, все це добре описано на сайті Android (посилання наведено в розділі ресурси ). Детальний опис налаштування середовища розробки зайняв би цілу статтю і, ймовірно, не одну.

Після настройки середовища розробки запустіть Eclipse і почніть новий Android-проект. На екрані повинна відобразитися інформація, наведена на малюнку 1 .

Малюнок 1. Створення Android-додатки в Eclipse
Створюємо мережеву багато користувачів гру в хрестики-нулики, використовуючи технології PHP, XML і комплект інструментальних засобів для розробки додатків на платформі Android   Мережеві розраховані на багато користувачів хрестики-нулики   Часто використовувані скорочення   API: Application Programming Interface (прикладний інтерфейс програмування)   HTTP: Hypertext Transfer Protocol (протокол передачі гіпертексту)   IP: Internet protocol (Інтернет-протокол)   SDK: Software Development Kit (комплект інструментальних засобів для розробки програмного забезпечення)   SQL: Structured Query Language (мова структурованих запитів)   UI: User Interface (призначений для користувача інтерфейс)   XML: Extensible Markup Language (розширювана мова розмітки)   Казуальні комп'ютерні ігри (ігри для широкого кола користувачів, в які грають від випадку до випадку) надзвичайно популярні і дуже рентабельні, що легко можна пояснити

на малюнку 1 зображений майстер проектів для Android-додатків. Введіть назву проекту, відзначте перемикач Create new project in workspace (створити новий проект в робочій області) і вкажіть місце розташування вихідного коду з елементами інтерфейсу. У списку Build Target виберіть Android platform. Для даного коду я використовую Android 2.3.1. Код досить простий, тому можна використовувати будь-яку версію за вашим вибором. Якщо в списку немає жодної платформи, необхідно завантажити та встановити одну з них, як описано в інструкціях по установці Android SDK. Попереджаю, що завантаження всіх платформ може зайняти дуже багато часу.

У розділі Properties введіть назву програми та назву пакета. Я використовував Tic Tac Toe і com.jherrington.tictactoe у відповідних полях. Потім відзначте прапорець Create Activity і введіть ім'я дії. Як ім'я дії я використовував TicTacToeActivity.

Натисніть кнопку Finish, після чого повинен відобразитися екран, показаний на малюнку 2 .

Малюнок 2. Файли проекту TicTacToe

на малюнку 2 показані файли і каталоги верхнього рівня для Android-додатки (каталоги src, gen, Android 2.3.1 і res; файли assets, AndroidManifest.xml, default.properties і proguard.cfg). Важливі елементи:

  • Каталог res, що містить ресурси.
  • Каталог src, що містить вихідний Java ™ -код.
  • Файл manifest, що містить біографічну інформацію про програму.

Спочатку змінимо файл manifest. В основному файл правильний, але в нього потрібно додати дозвіл доступу до Інтернету, щоб додаток могло виконувати запити через Інтернет. В лістингу 7 наведено готовий файл manifest.

Лістинг 7. AndroidManifest.xml

<? Xml version = "1.0" encoding = "utf-8"?> <Manifest xmlns: android = "http://schemas.android.com/apk/res/android" android: versionCode = "1" android: versionName = "1.0" package = "com.jherrington.tictactoe"> <uses-permission android: name = "android.permission.INTERNET" /> <uses-sdk android: minSdkVersion = "5" /> <application android: icon = "@ drawable / icon" android: label = "@ string / app_name"> <activity android: name = "TicTacToeActivity" android: label = "@ string / app_name"> <intent-filter> <action android: name = "android .intent.action.MAIN "/> <category android: name =" android.intent.category.LAUNCHER "/> </ intent-filter> </ activity> </ application> </ manifest>

Зроблено єдина зміна - в початок файлу доданий тег uses-permission.

Наступне завдання - розробити призначений для користувача інтерфейс. Для цього модифікуємо файл layout.xml, що знаходиться в каталозі res / layout. В лістингу 8 наведено нове вміст цього файлу.

Лістинг 8. layout.xml

<? Xml version = "1.0" encoding = "utf-8"?> <LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android" android: orientation = "vertical" android: layout_width = "fill_parent" android: layout_height = "fill_parent"> <LinearLayout android: layout_height = "wrap_content" android: layout_width = "match_parent" android: id = "@ + id / linearLayout1"> <Button android: text = "Play X" android: id = "@ + id / playx" android: layout_width = "wrap_content" android: layout_height = "wrap_content"> </ Button> <Button android: text = "Play O" android: id = "@ + id / playo "android: layout_width =" wrap_content "android: layout_height =" wrap_content "> </ Button> </ LinearLayout> <com.jherrington.tictactoe.BoardView android: id =" @ + id / bview "android: layout_width =" wrap_content " android: layout_height = "wrap_content"> </ com.jherrington.tictactoe.BoardView> </ LinearLayout>

Це проста схема. У верхній частині знаходяться дві кнопки, розташовані горизонтально поруч один з одним. Це кнопки X і O, які користувач використовує для вказівки кольору, яким грає.

Інша частина вихідного коду - це клас BoardView, що відображає ігрове поле поточної гри. Вихідний код класу BoardView приведений в лістингу 11.

Маючи схему, можна написати Java-код програми. Він починається з класу TicTacToeActivity, наведеного в лістингу 9 . Дії (activities) - це базові блоки Android-додатки. Кожна програма має одне або кілька дій, які представляють різні стани додатки. У міру проходження по додатком створюється стек дій, до яких потім можна повернутися, використовуючи кнопку "назад" мобільного телефону. Додаток TicTacToe має тільки одну дію.

Лістинг 9. TicTacToeActivity.java

package com.jherrington.tictactoe; import java.util.Timer; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.Gallery; import android.widget.LinearLayout; public class TicTacToeActivity extends Activity implements OnClickListener {@Override public void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.main); Button playx = (Button) this.findViewById (R.id.playx); playx.setOnClickListener (this); Button playo = (Button) this.findViewById (R.id.playo); playo.setOnClickListener (this); Timer timer = new Timer (); UpdateTimer ut = new UpdateTimer (); ut.boardView = (BoardView) this.findViewById (R.id.bview); timer.schedule (ut, 200, 200); } Public void onClick (View v) {BoardView board = (BoardView) this.findViewById (R.id.bview); if (v.getId () == R.id.playx) {board.setColor (2); } If (v.getId () == R.id.playo) {board.setColor (1); }}}

Дія має два методи. Перший - це метод onCreate, який створює для користувача інтерфейс, підключає обробник onClick до кнопок X і O і запускає таймер update. Цей таймер використовується для поновлення стану гри кожні 200 мілісекунд. Дана функціональність дозволяє обом гравцям бачити ходи один одного.

Оброблювач onClick встановлює поточний колір ігрового поля, грунтуючись на останній натиснутій користувачем кнопці X або O.

Клас GameService, наведений в лістингу 10 , Є singleton-класом, які представляють ігровий сервер і поточний стан даної гри.

Лістинг 10. GameService.java

package com.jherrington.tictactoe; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import android.util.Log; public class GameService {private static GameService _instance = new GameService (); public int [] [] positions = new int [] [] {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; public static GameService getInstance () {return _instance; } Private void updatePositions (Document doc) {for (int x = 0; x <3; x ++) {for (int y = 0; y <3; y ++) {positions [x] [y] = 0; }} Doc.getDocumentElement (). Normalize (); NodeList items = doc.getElementsByTagName ( "move"); for (int i = 0; i <items.getLength (); i ++) {Element me = (Element) items.item (i); int x = Integer.parseInt (me.getAttribute ( "x")); int y = Integer.parseInt (me.getAttribute ( "y")); int color = Integer.parseInt (me.getAttribute ( "color")); positions [x] [y] = color; }} Public void startGame (int game) {HttpClient httpclient = new DefaultHttpClient (); HttpPost httppost = new HttpPost ( "http://10.0.2.2/ttt/moves.php"); try {List <NameValuePair> nameValuePairs = new ArrayList <NameValuePair> (2); nameValuePairs.add (new BasicNameValuePair ( "game", Integer.toString (game))); httppost.setEntity (new UrlEncodedFormEntity (nameValuePairs)); HttpResponse response = httpclient.execute (httppost); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance (); DocumentBuilder db = dbf.newDocumentBuilder (); updatePositions (db.parse (response.getEntity (). getContent ())); } Catch (Exception e) {Log.v ( "ioexception", e.toString ()); }} Public void setPosition (int game, int x, int y, int color) {HttpClient httpclient = new DefaultHttpClient (); HttpPost httppost = new HttpPost ( "http://10.0.2.2/ttt/move.php"); positions [x] [y] = color; try {List <NameValuePair> nameValuePairs = new ArrayList <NameValuePair> (2); nameValuePairs.add (new BasicNameValuePair ( "game", Integer.toString (game))); nameValuePairs.add (new BasicNameValuePair ( "x", Integer.toString (x))); nameValuePairs.add (new BasicNameValuePair ( "y", Integer.toString (y))); nameValuePairs.add (new BasicNameValuePair ( "color", Integer.toString (color))); httppost.setEntity (new UrlEncodedFormEntity (nameValuePairs)); HttpResponse response = httpclient.execute (httppost); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance (); DocumentBuilder db = dbf.newDocumentBuilder (); updatePositions (db.parse (response.getEntity (). getContent ())); } Catch (Exception e) {Log.v ( "ioexception", e.toString ()); }}}

Це найцікавіший код в додатку. По-перше, він містить метод updatePositions, який приймає повернений із сервера XML і шукає елементи move, а потім оновлює масив positions, в якому вказано поточний набір ходів. У масиві positions міститься значення для кожної позиції на ігровому полі; нуль - це порожнє місце, 1 - це O, а 2 - це X.

Дві інші функції, startGame і setPosition, реалізують спосіб взаємодії з сервером. Метод startGame запитує у сервера поточний стан ходів і оновлює список позицій. Метод setPosition передає хід на сервер, створюючи HTTP-запит post і задаючи дані цього post-запиту на основі масиву пар ім'я-значення, які потім кодуються для передачі. Потім метод аналізує відповідь XML і оновлює список позицій.

Придивившись, можна побачити, що використовується для підключення до сервера використовується незвичайний IP-адреса. Це не localhost і не 127.0.0.1, а 10.0.2.2, який є псевдонімом машини, на якій виконується емулятор. Оскільки Android-телефон сам по собі є UNIX®-системою, він має свої власні служби на localhost. Чудеса, чи не так? Не часто настільки очевидно проявляється той факт, що це, власне, не телефон, а повноцінний поміщається на долоні комп'ютер, в якому волею випадку опинився вбудований телефон.

Отже, на чому ми зупинилися? У нас є дія (основний компонент додатка), налаштована схема користувальницького інтерфейсу і Java-код для підключення до сервера. Тепер нам необхідно намалювати ігрове поле. Цим займається клас BoardView, наведений в лістингу 11 .

Лістінг 11. BoardView.java

package com.jherrington.tictactoe; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class BoardView extends View {private int _color = 1; public void setColor (int c) {_color = c; } Public BoardView (Context context) {super (context); GameService.getInstance (). StartGame (0); } Public BoardView (Context context, AttributeSet attrs) {super (context, attrs); GameService.getInstance (). StartGame (0); } Public BoardView (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle); GameService.getInstance (). StartGame (0); } Public boolean onTouchEvent (MotionEvent event) {if (event.getAction ()! = MotionEvent.ACTION_UP) return true; int offsetX = getOffsetX (); int offsetY = getOffsetY (); int lineSize = getLineSize (); for (int x = 0; x <3; x ++) {for (int y = 0; y <3; y ++) {Rect r = new Rect ((offsetX + (x * lineSize)), (offsetY + (y * lineSize)), ((offsetX + (x * lineSize)) + lineSize), ((offsetY + (y * lineSize)) + lineSize)); if (r.contains ((int) event.getX (), (int) event.getY ())) {GameService.getInstance (). setPosition (0, x, y, _color); invalidate (); return true; }}} Return true; } Private int getSize () {return (int) ((float) ((getWidth () <getHeight ())? GetWidth (): getHeight ()) * 0.8); } Private int getOffsetX () {return (getWidth () / 2) - (getSize () / 2); } Private int getOffsetY () {return (getHeight () / 2) - (getSize () / 2); } Private int getLineSize () {return (getSize () / 3); } Protected void onDraw (Canvas canvas) {Paint paint = new Paint (); paint.setAntiAlias ​​(true); paint.setColor (Color.BLACK); canvas.drawRect (0,0, canvas.getWidth (), canvas.getHeight (), paint); int size = getSize (); int offsetX = getOffsetX (); int offsetY = getOffsetY (); int lineSize = getLineSize (); paint.setColor (Color.DKGRAY); paint.setStrokeWidth (5); for (int col = 0; col <2; col ++) {int cx = offsetX + ((col + 1) * lineSize); canvas.drawLine (cx, offsetY, cx, offsetY + size, paint); } For (int row = 0; row <2; row ++) {int cy = offsetY + ((row + 1) * lineSize); canvas.drawLine (offsetX, cy, offsetX + size, cy, paint); } Int inset = (int) ((float) lineSize * 0.1); paint.setColor (Color.WHITE); paint.setStyle (Paint.Style.STROKE); paint.setStrokeWidth (10); for (int x = 0; x <3; x ++) {for (int y = 0; y <3; y ++) {Rect r = new Rect ((offsetX + (x * lineSize)) + inset, (offsetY + (y * lineSize)) + inset, ((offsetX + (x * lineSize)) + lineSize) - inset, ((offsetY + (y * lineSize)) + lineSize) - inset); if (GameService.getInstance (). positions [x] [y] == 1) {canvas.drawCircle ((r.right + r.left) / 2, (r.bottom + r.top) / 2, (r .right - r.left) / 2, paint); } If (GameService.getInstance (). Positions [x] [y] == 2) {canvas.drawLine (r.left, r.top, r.right, r.bottom, paint); canvas.drawLine (r.left, r.bottom, r.right, r.top, paint); }}}}}

Більшу частину роботи виконує метод onTouch, який реагує на натискання користувачем конкретної клітини ігрового поля, і метод onDraw, який малює ігрове поле, використовуючи Android-механізм промальовування.

Метод onTouch використовує функції sizing для обчислення прямокутника позиції кожної клітини. Потім він викликає для прямокутника метод contains, щоб визначити, натиснув користувач клітку. Якщо так, активізується запит сервісу game для виконання ходу.

Функція onDraw використовує функції sizing як для промальовування ліній ігрового поля, так і для промальовування всіх поставлених хрестиків та нуликів. Сінглтон GameServer використовується для масиву positions, в якому зберігається поточний стан кожного квадрата ігрового поля.

Останній потрібний нам клас - UpdateTimer, який використовує сервіс game для поновлення позицій на ігровому полі з урахуванням свіжих даних. В лістингу 12 наведено вихідний код таймера.

Лістинг 12. UpdateTimer.java

package com.jherrington.tictactoe; import java.util.TimerTask; public class UpdateTimer extends TimerTask {public BoardView boardView; @Override public void run () {GameService.getInstance (). StartGame (0); boardView.post (new Runnable () {public void run () {boardView.invalidate ();}}); }}

Таймер инициализируется класом TicTacToeActivity під час запуску програми. Таймер реалізує polling-механізм. Це не найефективніший спосіб взаємодії між клієнтом і сервером, але він є найпростішим і надійним. Найбільш ефективний спосіб - використовувати версію 1.1 HTTP-протоколу для підтримки з'єднання в активному стані і реалізувати відправку сервером оновлень клієнту при здійсненні ходу. Цей підхід набагато складніше; він вимагає підтримки протоколу 1.1 і клієнтом і сервером і має обмеження на кількість з'єднань. Розгляд цього підходу виходить за рамки даної статті. Для простих демонстраційних ігор, подібних до нашої, відмінно підходить polling-механізм.

Після написання вихідного коду можна протестувати додаток. Для цього потрібно запустити емулятор. Після запуску на екрані повинна відобразитися інформація, наведена на малюнку 3.

Малюнок 3. Запуск Android-емулятора

Цей емулятор завантажує фантастичний інтерфейс "ANDROID". Після його завантаження ви повинні побачити екран запуску додатка, який ви бачите на малюнку 4 .

Малюнок 4. Емулятор запущений і готовий до роботи

Для входу в телефон перемістіть піктограму замка вправо. Ця дія відкриє домашній екран і запустить налагоджувати додаток. У нашому випадку відобразиться екран з грою, наведений на малюнку 5 .

Малюнок 5. Гра до виконання першого ходу

Залежно від стану вашого сервера ви або побачите ходи, або ні. У нашому випадку гра ще не починалася. Кнопки Play X і Play O знаходяться над ігровим полем, розташованому в центрі екрану. Натисніть кнопку Play X, а потім центральний квадрат. З'явиться екран, аналогічний наведеному на малюнку 6 .

Малюнок 6. Природно, хід хрестиком робиться в центральний квадрат

на малюнку 6 показано ігрове поле з хрестиком в центральному квадраті. Для перевірки підключення до сервера можна виконати команду curl зі сценарієм moves.php на сервері для отримання самого останнього списку ходів.

Для тестування роботи налякав натисніть Play O і виберіть кутовий квадрат, як показано на малюнку 7 .

Малюнок 7. Нулик в кутовому квадраті

Можна грати і хрестиками, і нулики. Додаток підключається до сервера для збереження стану гри в загальнодоступному місці. А завдяки таймеру update будь-який гравець може бачити ходи, зроблені іншим гравцем.

Висновок

Чи є ця гра закінченою? Звичайно ж ні. Відсутня перевірка умови перемоги, гравці можуть повторно займати одні й ті ж поля, відсутній контроль черговості ходів. Але основні технологічні блоки присутні: ігровий сервер з доступним для всіх гравців збереженим станом гри і стандартне графічне додаток на мобільному пристрої, що підключається до ігрового сервера для надання інтерфейсу гри. Ви можете використовувати цю гру в якості відправної точки для свого власного ігрового програми і зробити його таким, яким побажаєте. Просто пам'ятайте, що гра повинна бути цікавою та захоплюючою, і ви, можливо, створите конкурента Words With Friends або багато користувачів варіант "Angry Birds".

Ресурси для скачування

Схожі тими

  • Оригінал статті: Create a networked tic-tac-toe game for Android (EN).
  • сайт The Android Developer : Завантажте SDK і плагін Eclipse.
  • Eclipse : Довідкова інформація про використовувану в даній статті середовищі IDE для розробки Android-додатки. Також наведені посилання на завантаження Eclipse і плагіни.
  • Засоби розробки PHP-додатків для Eclipse . Потрібне середовище IDE для PHP? Проект Eclipse має потрібне розширення, а також інші плагіни практично для будь-яких мов.
  • Android Market : Після написання мережевий багатокористувацької Android-ігри завантажте її на сайт Android marketplace. І дайте нам знати в коментарях до даної статті.
  • сайт PHP : Краща довідкова інформація по PHP.
  • W3C : Відмінний сайт за стандартами, зокрема, за стандартами XML , Що мають відношення до даної статті.
  • Інші статті даного автора (Джек Херрингтон (Jack Herrington), developerWorks, з березня 2005 року по теперішній час): статті про Ajax, JSON, PHP, XML і інших технологіях (EN).
  • Сертифікація IBM по XML : Інформація про отримання сертифіката IBM-Certified Developer по XML і суміжних технологій.
  • Ознайомчі версії продуктів IBM. завантажте ознайомчі Версії продуктів IBM або досліджуйте в IBM SOA Sandbox інтерактивні ознайомчі версії , Щоб освоїти інструменти розробки додатків і продукти проміжного рівня сімейств DB2®, Lotus®, Rational®, Tivoli® і WebSphere®.

Підпішіть мене на ПОВІДОМЛЕННЯ до коментарів

Php <?
Php <?
Php function show_moves ($ dbh, $ game) {$ sql = 'SELECT * FROM moves WHERE game =?
Php require_once ( 'show_moves.php'); header ( 'Content-Type: text / xml'); $ Dbh = new PDO ( 'mysql: host = localhost; dbname = ttt', 'root', ''); show_moves ($ dbh, $ _REQUEST [ 'game']); ?
Php?
Game = 1" <?
Php require_once ( 'show_moves.php'); header ( 'Content-Type: text / xml'); $ Dbh = new PDO ( 'mysql: host = localhost; dbname = ttt', 'root', ''); $ Sql ​​= 'DELETE FROM moves WHERE game =?