This is a documentation for Board Game Arena: play board games online !

Туториал реверси

Извор: Board Game Arena
Пређи на навигацију Пређи на претрагу

Интродуцтион

Усинг тхис туториал, yоу цан буилд а цомплете wоркинг гаме он БГА енвиронмент: Реверси гаме.

Бефоре реадинг тхис туториал, yоу муст:

  • Реад тхе овералл пресентатионс оф тхе БГА Фрамеwорк (сее хере).
  • Кноw тхе рулес оф Реверси.
  • Кноw тхе лангуагес усед он БГА: ПХП, СQЛ, ХТМЛ, ЦСС, Јавасцрипт.

Цреате yоур фирст гаме

Wитх тхе инитиал скелетон оф цоде провидед инитиаллy, yоу цан алреадy старт а гаме фром тхе БГА Студио. Фор ноw, wе аре гоинг то wорк wитх 1 плаyер онлy. Мост оф тхе тиме тхис ис симплер то процеед wитх онлy оне плаyер дуринг тхе еарлy пхасе оф девелопмент оф yоур гаме, ас ит'с еасy анд фаст то старт/стоп гамес.

Тхус, yоу цан старт а "Реверси" гаме, анд арриве он а воид, емптy гаме. Yеах.

Лет ит лоок лике Реверси

Ит ис алwаyс а гоод идеа то старт wитх а литтле бит оф грапхиц wорк. Wхy? Бецаусе тхис хелпс то фигуре оут хоw тхе финал гаме wилл бе, анд иссуес тхат маy аппеар латер.

Бе царефул дуринг десигнинг тхе лаyоут оф yоур гаме: yоу муст алwаyс кееп ин минд тхат плаyерс wитх а 1024пx сцреен wидтх муст бе абле то плаy. Усуаллy, ит меанс тхат тхе wидтх оф тхе плаy ареа цан бе 750пx (ин тхе wорст цасе).

Фор Реверси, ит'с уселесс то хаве а 750x750пx боард - муцх тоо биг, со wе цхоосе тхис оне wхицх фит перфецтлy (536x528):

Боард.јпг

Ноте тхат wе аре усинг а јпг филе. Јпг аре лигхтер тхан пнг, тхен фастер то лоад. Латер wе аре гоинг то усе ПНГс фор дисцс фор транспаренцy пурпосе.

Ноw, лет'с маке ит аппеарс он оур гаме:

  • уплоад боард.јпг ин yоур "имг/" дирецторy.
  • едит "реверси_реверси.тпл" то адд а 'див' фор yоур боард:
<div id="board">
</div>
  • едит yоур реверси.цсс филе то трансформ ит инто а висибле боард:
#board {
   width: 536px;
   height: 528px;
   background-image: url('../../img/reversi/board.jpg');
}

Рефресх yоур паге. Хере'с yоур боард:

Реверси1.јпг

Маке тхе сqуарес аппеарс

Ноw, wхат wе неед ис то цреате соме инвисибле ХТМЛ елементс wхен сqуарес аре. Тхесе елементс wилл бе усед ас поситион референцес фор wидтх&блацк дисцс. Обвиоуслy, wе неед 64 сqуарес. То авоид wритинг 64 'див' елементс он оур темплате, wе аре гоинг то усе тхе "блоцк" феатуре.

Лет'с модифy оур темплате лике тхис:

 <div id="board">
    <!-- BEGIN square -->
        <div id="square_{X}_{Y}" class="square" style="left: {LEFT}px; top: {TOP}px;"></div>
    <!-- END square -->
 </div>

Ас yоу цан сее, wе цреатед а "сqуаре" блоцк, wитх 4 вариабле елементс: X, Y, ЛЕФТ анд ТОП. Обвиоуслy, wе аре гоинг то усе тхис блоцк 64 тимес дуринг паге лоад.

Лет'с до ит ин оур "реверси.виеw.пхп" филе:

        $this->page->begin_block( "reversi_reversi", "square" );
        
        $hor_scale = 64.8;
        $ver_scale = 64.4;
        for( $x=1; $x<=8; $x++ )
        {
            for( $y=1; $y<=8; $y++ )
            {
                $this->page->insert_block( "square", array(
                    'X' => $x,
                    'Y' => $y,
                    'LEFT' => round( ($x-1)*$hor_scale+10 ),
                    'TOP' => round( ($y-1)*$ver_scale+7 )
                ) );
            }        
        }

Ноте: ас yоу цан сее, сqуарес ин оур "боард.јпг" филес доес нот хаве ан еxацт wидтх/хеигхт ин пиxел, анд тхат'с тхе реасон wе аре усинг флоатинг поинт нумберс хере.

Ноw, то финисх оур wорк анд цхецк иф еверyтхинг wоркс фине, wе аре гоинг то стyле оур сqуаре а литтле бит ин оур ЦСС стyлесхеет:

#board {
    width: 536px;
    height: 528px;
    background-image: url('../../img/reversi/board.jpg');
    position: relative;
}

.square {
    width: 56px;
    height: 56px;
    position: absolute;
    background-color: red;
}

Еxпланатионс:

  • Wитх "поситион: релативе" он боард, wе енсуре сqуаре елементс аре поситионед релативелy то боард.
  • Фор тхе тест, wе усе а ред бацкгроунд цолор фор тхе сqуаре. Тхис ис а усефул тип то фигуре оут иф еверyтхинг ис фине wитх инвисибле елементс.

Лет'с рефресх анд цхецк оур оур (беаутифул) сqуарес:

Реверси2.јпг

Тхе дисцс

Ноw, оур боард ис реадy то рецеиве соме дисц токенс!

Ат фирст, wе интродуце а неw 'див' елемент ас а цхилд оф "боард" то хост алл тхесе токенс (ин оур темплате):

    <!-- END square -->
    
    <div id="tokens">
    </div>
</div>

Тхен, лет'с интродуце а неw пиеце оф арт wитх тхе дисцс. Wе неед соме транспаренцy хере со wе аре усинг а пнг филе:

Токенс.пнг

Импортант: wе аре усинг ОНЕ филе фор ботх дисцс. Ит'с реаллy импортант тхат yоу усе а минимум нумбер оф грапхиц филес фор yоур гаме wитх тхис "ЦСС сприте" тецхниqуе, бецаусе ит макес тхе гаме лоадинг фастер анд море релиабле. Реад море абоут ЦСС спритес.

Ноw, лет'с сепарате тхе дисц wитх соме ЦСС стуфф:

.token {
    width: 56px;
    height: 56px;
    position: absolute;
    background-image: url('../../img/reversi/tokens.png');
}
.tokencolor_ffffff { background-position: 0px 0px;   }
.tokencolor_000000 { background-position: -56px 0px;   }

Wитх тхис ЦСС цоде, ис wе апплy тхе цлассес "токен" анд "токенцолор_фффффф" то а див елемент, wе гот а wхите токен. Yеах.

Ноте тхе "поситион: абсолуте" wхицх аллоw ус то поситион токенс он тхе боард анд маке тхем "слиде" то тхеир поситионс.

Ноw, лет'с маке а фирст токен аппеарс он оур боард. Дисц токенс аре нот висибле ат тхе бегиннинг оф тхе гаме: тхеy аппеар дyнамицаллy дуринг тхе гаме. Фор тхис реасон, wе аре гоинг то маке тхем аппеар фром оур Јавасцрипт цоде, wитх а БГА Фрамеwорк тецхниqуе цаллед "ЈС темплате".

Ин оур темплате филе (реверси_реверси.тпл), лет'с цреате тхе пиеце оф ХТМЛ неедед то дисплаy оур токен:

<script type="text/javascript">

// Templates

var jstpl_disc='<div class="disc disccolor_${color}" id="disc_${xy}"></div>';

</script>

Ноте: wе алреадy цреатед тхе "темплатес" сецтион фор yоу ин тхе гаме скелетон.

Ас yоу цан сее, wе дефинед а ЈС темплате намед "јстпл_дисц" wитх а пиеце оф ХТМЛ анд тwо вариаблес: тхе цолор оф тхе токен анд итс x/y цоординатес. Ноте тхат тхе сyнтаx оф тхе аргумент ис дифферент фор темплате блоцк вариаблес (брацкетс) анд ЈС темплате вариаблес (доллар анд брацкетс).

Ноw, лет'с цреате а метход ин оур Јавасцрипт цоде тхат wилл маке а токен аппеар он тхе боард, усинг тхис темплате:

        addTokenOnBoard: function( x, y, player )
        {
            dojo.place( this.format_block( 'jstpl_token', {
                xy: x+''+y,
                color: this.gamedatas.players[ player ].color
            } ) , 'tokens' );
            
            this.placeOnObject( 'token_'+x+''+y, 'overall_player_board_'+player );
            this.slideToObject( 'token_'+x+''+y, 'square_'+x+'_'+y ).play();
        },

Ат фирст, wитх "дојо.плаце" анд "тхис.формат_блоцк" метходс, wе цреате а ХТМЛ пиеце оф цоде анд инсерт ит ас а неw цхилд оф "токенс" див елемент.

Тхен, wитх БГА "тхис.плацеОнОбјецт" метход, wе плаце тхис елемент овер тхе панел оф соме плаyер. Иммедиателy афтер, усинг БГА "тхис.слидетоОбјецт" метход, wе маке тхе дисц слиде то тхе "сqуаре" елемент, итс финал дестинатион.

Ноте: дон'т форгет то цалл тхе "плаy()", отхерwисе тхе токен ремаинс ат итс оригинал лоцатион.

Ноте: ноте тхат дуринг алл тхе процесс, тхе парент оф тхе неw дисц ХТМЛ елемент wилл ремаин "токенс". плацеОнОбјецт анд слидеТоОбјецт метходс аре онлy мовинг тхе поситион оф елементс он сцреен, анд тхеy аре нот модифyинг тхе ХТМЛ трее.

Ноw, то тест иф еверyтхинг wоркс фине, јуст цалл "аддТокенОнБоард( 2, 2, <yоур_плаyер_ид> )" ин yоур "сетуп" Јавасцрипт метход, анд релоад тхе паге. А токен схоулд аппеар анд слиде иммедиателy то итс поситион, лике тхис:

Реверси3.јпг

Тхе датабасе

Wе дид мост оф тхе цлиент-сиде программинг, со лет'с хаве а лоок он тхе отхер сиде ноw.

То десигн тхе датабасе модел оф оур гаме, тхе бест тхинг то до ис то фоллоw тхе "Го то гаме датабасе" линк ат тхе боттом оф оур гаме, то аццесс тхе датабасе дирецтлy wитх а ПхпМyАдмин инстанце.

Тхен, yоу цан цреате тхе таблес yоу неед фор yоур табле (до нот ремове еxистинг таблес!), анд репорт еверy СQЛ цомманд усед ин yоур "дбмодел.сqл" филе.

Реверси4.јпг

Тхе датабасе модел оф Реверси ис верy симпле: јуст оне табле wитх тхе сqуарес оф тхе боард. Ин оур дбмодел.сqл, wе хаве тхис:

CREATE TABLE IF NOT EXISTS `board` (
  `board_x` smallint(5) unsigned NOT NULL,
  `board_y` smallint(5) unsigned NOT NULL,
  `board_player` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`board_x`,`board_y`)
) ENGINE=InnoDB;

Ноw, а неw датабасе wитх а "боард" табле wилл бе цреатед еацх тиме wе старт а Реверси гаме. Тхис ис wхy афтер модифyинг оур дбмодел.сqл ит'с а гоод тиме то стоп & старт агаин оур гаме.

Сетуп тхе инитиал гаме поситион

Тхе "сетупНеwГаме" метход оф оур реверси.гаме.пхп ис цаллед дуринг инитиал сетуп: тхис ис тхе плаце то инитиализе оур дата анд то плаце тхе инитиал токенс он тхе боард (инитиаллy, тхере аре 4 токенс он тхе боард).

Лет'с до тхис:

        // Init the board
        $sql = "INSERT INTO board (board_x,board_y,board_player) VALUES ";
        $sql_values = array();
        for( $x=1; $x<=8; $x++ )
        {
            for( $y=1; $y<=8; $y++ )
            {
                $token_value = "NULL";
                if( ($x==4 && $y==4) || ($x==5 && $y==5) )  // Initial positions of white player
                    $token_value = "'$whiteplayer_id'";
                else if( ($x==4 && $y==5) || ($x==5 && $y==4) )  // Initial positions of black player
                    $token_value = "'$blackplayer_id'";
                    
                $sql_values[] = "('$x','$y',$token_value)";
            }
        }
        $sql .= implode( $sql_values, ',' );
        self::DbQuery( $sql );
        
        
        // Active first player
        self::activeNextPlayer();  

Ас yоу цан сее, wе цреате оне датабасе ентрy фор еацх сqуаре, wитх а "НУЛЛ" валуе wхицх меан "емптy сqуаре". Оф цоурсе, фор 4 специфиц сqуарес, wе плаце ан инитиал токен.

Ат тхе енд, wе ацтиве тхе фирст плаyер то маке ит ацтиве ат тхе бегиннинг оф тхе гаме.

Ноw, wе неед то маке тхесе токенс аппеарс он тхе цлиент сиде. То ацхиеве тхис, тхе фирст степ ис то ретурн тхе токен поситионс wитх оур "гетАллДатас" ПХП метход (цаллед дуринг еацх паге релоад):

        // Get reversi board token
        $result['board'] = self::getObjectListFromDB( "SELECT board_x x, board_y y, board_player player
                                                       FROM board
                                                       WHERE board_player IS NOT NULL" );

Ас yоу цан сее, wе аре усинг тхе БГА фрамеwорк "гетОбјецтЛистФромДБ" метход тхат формат тхе ресулт оф тхис СQЛ qуерy ин а ПХП арраy wитх x, y анд плаyер аттрибуте.

Тхе ласт тхинг wе неед то до ис то процесс тхис арраy он цлиент сиде, анд плаце а дисц токен он тхе боард фор еацх арраy итем. Оф цоурсе, wе аре доинг тхис ис оур Јавасцрипт "сетуп" метход:

            for( var i in gamedatas.board )
            {
                var square = gamedatas.board[i];
                
                if( square.player !== null )
                {
                    this.addTokenOnBoard( square.x, square.y, square.player );
                }
            }

Ас yоу цан сее, оур "боард" ентрy цреатед ин "гетАллДатас" цан бе усед хере ас "гамедатас.боард" ин оур Јавасцрипт. Wе аре усинг оур превиоуслy девелопед "аддТокенОнБоард" метход.

Релоад... анд хере wе аре:

Реверси5.јпг

Ит стартс то смелл Реверси хере...

Тхе гаме стате мацхине

Ноw, лет'с стоп оур гаме агаин, бецаусе wе аре гоинг то старт тхе цоре гаме логиц.

Yоу алреадy реад тхе "Фоцус он БГА гаме стате мацхине", со yоу кноw тхат тхис ис тхе хеарт оф yоур гаме логиц. Фор реверси гаме, ит'с верy симпле алтхоугх. Хере'с а диаграм оф оур гаме стате мацхине фор Реверси:

Реверси6.јпг

Анд хере'с оур "статс.инц.пхп", аццординг то тхис диаграм:

$machinestates = array(

    1 => array(
        "name" => "gameSetup",
        "description" => clienttranslate("Game setup"),
        "type" => "manager",
        "action" => "stGameSetup",
        "transitions" => array( "" => 10 )
    ),
    
    10 => array(
        "name" => "playerTurn",
		"description" => clienttranslate('${actplayer} must play a disc'),
		"descriptionmyturn" => clienttranslate('${you} must play a disc'),
        "type" => "activeplayer",
        "args" => "argPlayerTurn",
        "possibleactions" => array( 'playDisc' ),
        "transitions" => array( "playDisc" => 11, "zombiePass" => 11 )
    ),
    
    11 => array(
        "name" => "nextPlayer",
        "type" => "game",
        "action" => "stNextPlayer",
        "updateGameProgression" => true,        
        "transitions" => array( "nextTurn" => 10, "cantPlay" => 11, "endGame" => 99 )
    ),
   
    99 => array(
        "name" => "gameEnd",
        "description" => clienttranslate("End of game"),
        "type" => "manager",
        "action" => "stGameEnd",
        "args" => "argGameEnd"
    )

);

Ноw, лет'с цреате ин оур реверси.гаме.пхп филе тхе метходс тхат аре децларед ин тхис гаме статес десцриптион филе:

  • аргПлаyерТурн
  • стНеxтПлаyер

... анд старт а неw Реверси гаме.

Ас yоу цан сее он тхе сцреен цаптуре абове, тхе БГА фрамеwорк макес тхе гаме јумп то оур фирст гаме стате "плаyерТурн" ригхт афтер тхе инитиал сетуп. Тхат'с wхy тхе статус бар цонтаинс тхе десцриптион оф плаyерТурн стате ("XXXX муст плаy а дисц"):

Реверси7.јпг

Тхе рулес

Ноw, wхат wе wоулд лике то до ис то индицате то тхе цуррент плаyер wхере ит ис аллоwед то плаy. Тхе идеа ис то буилд а "гетПоссиблеМовес" ПХП метход тхат ретурн а лист оф цоординатес wхере ит ис аллоwед то плаy. Тхис метход wилл бе усед ин партицулар:

  • Ас wе јуст саид, то хелп тхе плаyер то сее wхере хе цан плаy.
  • Wхен тхе плаyер плаy, то цхецк иф хе хас тхе ригхт то плаy хере.

Тхис ис пуре ПХП программинг хере, анд тхере'с но специал тхингс фром тхе БГА фрамеwорк тхат цан бе усед. Тхис ис wхy wе wон'т го инто детаилс хере. Тхе овералл идеа ис:

  • Цреате а "гетТурнедОверДисцс(x,y)" метход тхат ретурн цоординатес оф дисцс тхат wоулд бе турнед овер иф а токен wоулд бе плаyед ат x,y.
  • Лооп тхроугх алл фрее сqуарес оф тхе боард, цалл тхе "гетТурнедОверДисцс" метход он еацх оф тхем. Иф ат леаст 1 токен ис турнед овер, тхис ис а валид мове.

Оне импортант тхинг то кееп ин минд ис тхе фоллоwинг: макинг а датабасе qуерy ис слоw, со плеасе дон'т лоад тхе ентире гаме боард wитх а СQЛ qуерy мултипле тиме. Ин оур имплементатион, wе лоад тхе ентире боард онце ат тхе бегиннинг оф "гетПоссиблеМовес", анд тхен пасс тхе боард ас ан аргумент то алл метходс.

Иф yоу wант то лоок инто детаилс, плеасе лоок ат тхе "утилитy метход" сецтионс оф реверси.гаме.пхп.