Создание игр типа казино. Часть первая : Рулетка (Рулеточные столы)
Вот наконец то мы и подобрались к самой рулетке. Постараюсь максимально понятно описать как это все создается. Кода будет минимум, потому что читать мой быдло-код в данном случае не рекомендуется, уверяю вас, вы напишите быдло код не хуже ) К сожалению красивую реализацию для стола сделать очень сложно, я лично выходов лучше, чем будет показано дальше не нашел.
И так.
1. Скиним и рисуем точки.
По фотке хорошо видно ( специально для себя рисовал радугу, чтобы было видно где что ) какие точки у нас задействованы, пересечения и т.п. , клетки сооотв отмечены желтым ( 20% прозрачность ) , это самые большие точки. Поверьте мне это очень геморное дело рисовать все это Но пришлось. У нас есть 2 стола - левый называется RACE, а правый, ну пускай, просто BIG_TABLE ( хотя по-моему какое то кашерное название есть ).
И так, по именованию точек я сделал так :
точки на BIG - a1 , a4_5 , a4_5_7_8 , a4_5_6 , ared , ablack и т.п.
точки на RACE - e1....e36 , evoisins и т.д.
В скине соотв 2 больших клипа левый и правый столы, внутри которых мини клипы-точки. Добавили их на сцену и поехали хардкодить... ))
СНачала приведу код только переменных , уже начинает кружить голову
public class TableBigNavigator extends EventDispatcher { private static var _listener:EventDispatcher; private static const _TB:MovieClip = SkinManager.getTableBigInstance(); private static const _RC:MovieClip = SkinManager.getTableRaceInstance(); private static const _CO:Array = SkinManager.getCoinsArray(); private static const _cancel:MovieClip = SkinManager.getCancelButton(); private static const _repeat:MovieClip = SkinManager.getRepeatButton(); private static const _glass:MovieClip = SkinManager.getGlass(); private static var _timer:Timer = new Timer(10000); // glass Timer private static const _REDS:Array = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]; private static const _BLACKS:Array = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35]; private static const _1ST12:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; private static const _2ND12:Array = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; private static const _3RD12:Array = [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36]; private static const _EVEN:Array = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36]; private static const _ODD:Array = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35]; private static const _1_18:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]; private static const _19_36:Array = [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36]; private static const _2TO1_1:Array = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34]; private static const _2TO1_2:Array = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35]; private static const _2TO1_3:Array = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36]; private static const _BLACK_SP:Array = [8, 11, 10, 13, 17, 20, 26, 28, 29, 31]; private static const _RED_SP:Array = [9, 12, 16, 18, 19, 21, 27, 30]; private static const _VOISINS:Array = [0, 2, 3, 4, 7, 12, 15, 18, 19, 21, 22, 25, 28, 26, 29, 32, 35]; private static const _TIERS:Array = [5, 8, 10, 11, 13, 16, 23, 24, 27, 30, 33, 36]; private static const _ORPHELINS:Array = [1, 6, 9, 14, 17, 20, 31, 34]; private static const _RACE:Array = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26]; private static const _BSP:Array = ["8_11", "10_11", "10_13", "17_20", "26_29", "28_29", "28_31"]; private static const _RSP:Array = ['9_12', '18_21', '16_19', '27_30']; private static const _RTI:Array = ['5_8', '10_11', '13_16', '23_24', '27_30', '33_36']; private static const _VOI:Array = ['0_2_3', '4_7', '12_15', '18_21', '19_22', '25_26_28_29', '32_35']; private static const _ORP:Array = ['1', '6_9', '14_17', '17_20', '31_34']; private static var _currentBet:String = ''; private static var _betbuffer:int = 1; private static var _process:Array = []; private static var _serverCodeArray:Array = []; private static var _codeIndex:int = 0; private static var _tempCoin:MovieClip = null; private static var _tempChild:MovieClip = null; private static var _serverBetCode:String = null; private static var _nominalObject:Object = { }; private static var _tempNominal:Object = { }; private static var _tempNominalRace:Object = { };
Однако думаю это очень полезная инфа, тут расписаны все константы, которые мне лично пришлось просчитывать и проверять.
Далее обычным циклом вешаю стандартное поведение для точек столика
private function _setToAllMouseHandler():void { var child:MovieClip; for (var i:int = 0; i < _TB.numChildren ; i++) { child = _TB.getChildAt(i) as MovieClip; child.addEventListener(MouseEvent.MOUSE_OVER , onOver); child.addEventListener(MouseEvent.MOUSE_OUT , onOut); child.addEventListener(MouseEvent.CLICK , onClick); child.buttonMode = true; } for (i = 0; i < _RC.numChildren; i++) { child = _RC.getChildAt(i) as MovieClip; child.addEventListener(MouseEvent.MOUSE_OVER , onOver); child.addEventListener(MouseEvent.MOUSE_OUT , onOut); child.addEventListener(MouseEvent.CLICK , onClick); child.buttonMode = true; } }
private function onOver(e:MouseEvent):void { var str:String = e.currentTarget.name; // например a1_2_4 var slice:String = e.currentTarget.name.slice(0, 1); var a:Array = []; str = str.slice(1); // 1_2_4 a = str.split('_'); // 1,2,4 if ( isNaN(a[0]) ) e.currentTarget.alpha = 0.6; // сразу подсвечиваем кнопки типа red , black else if (slice == 'e') a = getRaceArray(a[0]); // для RACE своя тактика, поговорим чуть позже manageProcess(a); }
Давай те посмотрим , что же там происходит хардкодного --
-- вообщем нам главное получить массив точек, которые надо подсветить, кейсим для этого по нашим константам.
private function manageProcess(a:Array):void { switch (a[0]) { case '1st12' : allOver ( _1ST12 ); break; case '2nd12' : allOver ( _2ND12 ); break; case '3rd12' : allOver ( _3RD12 ); break; case 'even' : allOver ( _EVEN ); break; case 'odd' : allOver ( _ODD ); break; case '1from18' : allOver ( _1_18 ); break; case '19from36' : allOver ( _19_36 ); break; case '2to11' : allOver ( _2TO1_1 ); break; case '2to12' : allOver ( _2TO1_2 ); break; case '2to13' : allOver ( _2TO1_3 ); break; case 'red' : allOver ( _REDS ); break; case 'black' : allOver ( _BLACKS ); break; case 'blackr' : allOver ( _BLACK_SP ); break; case 'redr' : allOver ( _RED_SP ); break; case 'voisins' : allOver ( _VOISINS ); break; case 'tiers' : allOver ( _TIERS ); break; case 'orphelins' : allOver ( _ORPHELINS ); break; default: allOver(a); } } // ну а далее подсвечиваем их private function allOver(a:Array):void { _process = a; // запомним последний массив точек, авось пригодится потом) var b:Boolean = a.length == 5; // только при RACE кол-во значений может быть более 4 for (var i:int = 0; i < a.length ; i++) { _TB['a' + a[i]].alpha = 0.6; if(b) _RC['e' + a[i]].alpha = 0.6; } }
Перейдем к RACE. Как было описано выше для рейс реализуется специальный массив.
* описывать почему так работает это нет смысла, кто будет этим заниматься, сначала поиграется на какой нить демо-рулетке и увидит как работают столы.
И так о спец массиве....
ВНИМАНИЕ ТАК КАК НАПИСАНО НИЖЕ НЕ ПИШИТЕ НИКОГДА, ЭТО ПРОСТО ПРИМЕР )))))))))
private function getRaceArray(c:String):Array { var a:Array = []; var l:int = _RACE.length; for (var i:int = 0 ; i < l; i++) { if (_RACE[i] == c ) { a[0] = _RACE[i]; a[1] = _RACE[i+1]; a[2] = _RACE[i+2]; a[3] = _RACE[i-1]; a[4] = _RACE[i-2]; if (a[1] == undefined && a[2] == undefined) a[1] = 0 , a[2] = 32; else if (a[1] == undefined ) a[1] = 26; else if (a[2] == undefined ) a[2] = 0; else if (a[3] == undefined && a[4] == undefined ) a[3] = 26 , a[4] = 3; else if (a[4] == undefined ) a[4] = 26; } } return a; }
Установка фишек осуществляется довольно просто
private function setSimpleCoin(child:MovieClip):void { // где child есть точка if (_currentBet == '') return; // если фишка не выбрана ничего не делаем var coin:Coin = new Coin(); coin.x = child.x + child.width / 2 - coin.width / 2; coin.y = child.y + child.height / 2 - coin.height / 2; coin.buffer = _betbuffer; // фишек 10, они различаются по цветам, устанавливаю нужную coin.code = _serverBetCode; // держу на фишке некий код, нужный для взаимодействия с сервером _TB.addChild(coin); var t:String = ''; var n:Number = Number(_currentBet); // ставка должна быть числовой типа 1000 чтобы сервер нормально ее провел, поэтому удаляем всякие килобаксы и миллионы if ( n >= 1000 && n <= 999999.99 ) t = n / 1000 + 'k'; else if ( n >= 1000000 ) t = n / 1000000 + 'm'; else t = _currentBet; coin.text = t; // сеттер для номинала фишки }
private function setRaceCoin( child:MovieClip ):void { var a:Array = []; var s:String = child.name.slice(1); switch (s) { case 'redr' : a = _RSP; break; case 'blackr' : a = _BSP; break; case 'tiers' : a = _RTI; break; case 'orphelins' : a = _ORP; break; case 'voisins' : a = _VOI; break; default: a = _process; break; } for (var i:int = 0; i < a.length; i++) setSimpleCoin ( _TB['a' + a[i]] ); }
Ну вот и все - сделали наши столы, осталось описать сервер, отмену ставки, повтор ставки, но думаю вы это и сами сможете написать.
Сейчас у нас проблемы с сервером, поэтому картиночку или ссылочку , чтобы потыкать пока дать не могу, как только заработает, сразу суда выложу ссылку.
Всем спасибо.
В след статье мы поговорим о сборке всего этого, о некоторых нюансах , хитростях и т.д, а так же рассмотрим передачу параметров в игру и взаимодействие со сторонними приложениями.
Всего комментариев 38
Комментарии
17.01.2012 02:01 | |
Забудь, что это твой код. Попробуй его прочитать, как новый разработчик. Псих. С бензопилой.
|
|
Обновил(-а) Котяра 17.01.2012 в 02:18
|
17.01.2012 02:08 | |
Ну.... не посмотрев КАК именно будут и должны столы работать, о функционале кода сказать сложно...
|
17.01.2012 02:11 | |
Обновил(-а) Котяра 17.01.2012 в 02:14
|
17.01.2012 02:38 | |
Мда... с реплейсом все выглядет еще хуже... Чтож сложного сменить расцветку кода на форуме? Делов то в движке 5 минут, а особенно пхп убивает напрочь
|
17.01.2012 04:23 | |
Цитата:
как тут реплейс сделать через поиск
|
17.01.2012 13:51 | |
Цитата:
ВНИМАНИЕ ТАК КАК НАПИСАНО НИЖЕ НЕ ПИШИТЕ НИКОГДА, ЭТО ПРОСТО ПРИМЕР )))))))))
|
17.01.2012 17:55 | |
Усидчиво жду статью про саму рулетку :о). Очень интересна реализация вращения самой рулетки и движения шарика шарика.
|
17.01.2012 20:11 | |
Gbee к сожалению такой статьи не будет. У нас новое слово в онлайн-казино, тоесть идея инновационная - вместо программной рулетки у нас будет живая
|
17.01.2012 20:12 | |
Однако elder - первый в посте, говорил , что занимался рулеткой. Предлогаю скооперироваться и добавить часть статьи от него, если он делал шарик и кручение
|
17.01.2012 20:15 | |
Цитата:
У нас новое слово в онлайн-казино, тоесть идея инновационная - вместо программной рулетки у нас будет живая
|
17.01.2012 20:53 | |
Котяра нука расскажи подробнее? Я сомневаюсь, что есть такого плана казино онлайн как у нас
|
17.01.2012 20:58 | |
из соображений безопасности решение о том куда упал шарик должен принимать сервер, а не безумная физическая симуляция на стороне клиента, поэтому печкой занимается сервер, а клиент только делает вид что шарик сам туда упал
сервер знает кто проиграл а кто нет еще до того как барабан начал вращаться, и сервер, кстати, запросто может мухлевать |
|
Обновил(-а) artcraft 17.01.2012 в 21:01
|
17.01.2012 21:01 | |
Спасибо, кэп :о)
Я и не говорил, что клиент будет решать, тем более за столом несколько человек. |
17.01.2012 22:08 | |
Цитата:
У нас новое слово в онлайн-казино, тоесть идея инновационная - вместо программной рулетки у нас будет живая
|
17.01.2012 22:56 | |
Ещё раз повторяю - это неинтересно никому, а гемору больше. Красивая векторная флэшрулетка и проверка честности по MD5 лучше.
|
17.01.2012 22:57 | |
Ну совтсвенно мне пофигу, может быть и так, как выйдет будет видно, главное чтобы заказчик башлял, а там по барабану
|
17.01.2012 23:21 | |
Цитата:
главное чтобы заказчик башлял, а там по барабану
|
17.01.2012 23:27 | |
А причем тут интересно кому это или нет, если интересно мне? Если бы небыло эстетики я бы этим не занимался меньше чем за 100К в месяц
|
19.01.2012 17:08 | |
Цитата:
главное чтобы заказчик башлял, а там по барабану
|
19.01.2012 19:00 | |
Hauts - флеш это вторая работа моя просто. поэтому - это как хобби, как развлечение, а если развлечение скучное, тогда пускай за него хотябы платят
|
20.01.2012 04:00 | |
Dub4ek вы первый кто решился возразить по факту кода. Спасибо вам, покажите ваш пример, я не вижу тут другой реализации, через eventPhase как вы сказали
|
20.01.2012 05:06 | |
Саша, ну как же можно не знать?
private function _setToAllMouseHandler():void { /** * Отключаем интерактивность слоя, чтобы * реагировали только дети. Этого можно и * не делать, но тогда надо будет проверять- * - не является ли приемником события сам _RC */ _RC.mouseEnabled = false; _RC.mouseChildren = true; //так по умолчанию, но на всякий случай... ///и далее _RC.addEventListener(MouseEvent.MOUSE_OVER , onOver); _RC.addEventListener(MouseEvent.MOUSE_OUT , onOut); _RC.addEventListener(MouseEvent.CLICK , onClick); } //пример обработчика private function onOver(e:MouseEvent):void { MovieClip(e.target).someClassField; //псевдокод } |
|
Обновил(-а) fish_r 20.01.2012 в 05:15
|
20.01.2012 05:08 | |
(касается кода выше, не хочу редактировать сообщение, ибо буэ ) )
Такой подход не всегда оправдан, например, нужно чтобы объект получив событие отписался от его получения, это сложно реализовать в "перехвате". Можно сделать родительский класс и события обрабатывать в нем, а целевой класс, естественно, его расширит. и buttonMode лучше в |
|
Обновил(-а) fish_r 20.01.2012 в 05:41
|
23.01.2012 14:51 | |
Не в укор, а на заметку: ничего плохого в нарциссизме, графомании и высокомерном пафосе нет. Но весь эффект портится невысокой удобочитаемостью.
|
Последние записи от in4core
- Система диалогов, создаем подобие old School типа Fallout. (07.05.2014)
- MVC в игорной индустрии (27.11.2012)
- Якорь мне .... ))) Или History API (06.11.2012)
- FSD - учим php/sql (28.06.2012)
- I4Logger - простой и компактный логгер (06.05.2012)