Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 19 сообщений
Cообщения с меткой

игровой сайт - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Игра «Слова из слова». Продолжение

Воскресенье, 19 Марта 2017 г. 17:33 (ссылка)

Прошлым летом я публиковал статью о моем небольшом учебном проекте-игре "Слова из слова", написанном на JavaScript. Время идет и, я надеюсь, идет не напрасно. Постепенно набираясь знаний, я решил расширить идею и начать создание некого подобия интернет-площадки, которая объединит тематические игры со словами на одном ресурсе. Под катом ссылка на рабочий прототип проекта.

wordsgames.by





О проекте



Игровой сайт «Игры со словами» представляет собой платформу для размещения игр соответствующей тематики.

Зарегистрированные игроки имеют доступ к имеющимся на ресурсе играм, а также участвуют в рейтинге, формируемом на основе игрового уровня пользователя. Опыт набирается в результате прохождения различных игр и выполнения определенных задач.



Ссылка на репозиторий GitHub: https://github.com/Ghivan/wordsgames

Ссылка на рабочий прототип платформы: https://wordsgames.by/login/



Инструменты создания



Фронтэнд — Typescript, SCSS, Bootstrap, JQuery.

Бэкэнд — PHP 7, MySQL.



База данных



Схема базы данных

database schema



База данных состоит из шести таблиц:




  1. Глобальные таблицы ресурса:


    • dictionary — толковый словарь;

    • players — данные о зарегистрированных игроках;

    • games — описание игр;


  2. Таблицы игры "Слова из слова":


    • wfw_levels — информация об этапах;

    • wfw_scoreTable — очки (в будущем также и достижения) игрока ;

    • wfw_levelsPassed — информация о прохождении этапов.




Таблицы players, wfw_levelsPassed и wfw_scoreTable связаны через id игрока. Таблицы wfw_levels и wfw_levelsPassed связаны через поле word (сделано для того, чтобы можно было менять порядок уровня на обновляя записи о прохождении).

У каждого игрока есть игровой уровень (дань RPG), общий для ресурса. Количество опыта, необходимое для перехода на следующий уровень, рассчитывается по формуле геометрической прогрессии. За определение уровня игрока отвечает пользовательская функция в СУБД, а данные обновляются посредством триггера.



Функция и триггер
DELIMITER $$

CREATE FUNCTION `countExp`(`lvl` INT) RETURNS int(11)
NO SQL
SQL SECURITY INVOKER
COMMENT 'Подсчитывает необходимое количество опыта для уровня'
BEGIN
DECLARE exp int;
SET exp = FLOOR(1000 * (POW(1.1, lvl) - 1));
RETURN exp;
END$$

DELIMITER ;
-- Триггер, определяющий уровень игрока:
DELIMITER //
CREATE TRIGGER `lvlCount` BEFORE UPDATE ON `players`
FOR EACH ROW BEGIN
IF (NEW.exp <> OLD.exp AND NEW.exp > 0) THEN
IF NEW.exp >= countExp(NEW.`level`) THEN
WHILE NEW.exp >= countExp(NEW.`level`)
DO
set NEW.level = NEW.level + 1;
END WHILE;
ELSEIF NEW.exp < countExp(NEW.`level` - 1) THEN
WHILE NEW.exp < countExp(NEW.`level` - 1)
DO
set NEW.level = NEW.level - 1;
END WHILE;
END IF;
END IF;
END
//
DELIMITER ;


Соединение с базой данных из PHP



За соединение с базой отвечает статический класс:



Класс DB
class DB
{
private static $dbc = null;

protected static function getConnection()
{

if (!self::$dbc){
try {
self::$dbc = new PDO("mysql:host=".HOST.";dbname=".DB_NAME.";charset=UTF8", DB_USER, DB_PASSWORD);
} catch (Throwable $e) {
ErrorLogger::logException($e);
return null;
}
}
return self::$dbc;
}
}


В дальнейшем для получения информации используются классы наследники. Пример одного из классов под спойлером.



Получение информации об играх
class DBGamesGlobalInfo extends DB
{
private static $queries = array(
'globalInfo' => 'SELECT id, name, rules, status, author, path FROM games'
);

static function getGlobalInfo(){
try {
$stmt = parent::getConnection()->prepare(self::$queries['globalInfo']);
if (!$stmt->execute()){
ErrorLogger::logFailedDBRequest($stmt->errorInfo(), $stmt->queryString,__LINE__, __FILE__);
$message = 'Ошибка запроса информации об играх';
throw new Exception($message);
}
return $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e){
ErrorLogger::logException($e);
return null;
}
}
}


Авторизация



В настоящий момент для авторизации используется обычная сессия, куда записывается id зарегистрированного пользователя. В ближайшем будущем планирую посмотреть иные варианты готовых решений, но так как проект носит учебный характер пока везде использовал свои костыли.



Авторизация
class Authorization
{
public static function check(){
if (session_status() !== PHP_SESSION_ACTIVE){
session_start();
}
return (isset($_SESSION['pl_id'])) ? true : false;
}
public static function logIn($playerId){
if (!defined('LOGIN_SCRIPT') || LOGIN_SCRIPT !== '/login/server_scenarios/index.php') return false;

if (session_status() !== PHP_SESSION_ACTIVE){
session_start();
}
$_SESSION['pl_id'] = $playerId;
return (isset($_SESSION['pl_id'])) ? true : false;
}

public static function logOut(){
if (session_status() !== PHP_SESSION_ACTIVE){
session_start();
}
unset($_SESSION['pl_id']);
unset($_SESSION['cur_level']);
}

public static function getAuthorizedPlayerId(){
if (session_status() !== PHP_SESSION_ACTIVE){
session_start();
}
return isset($_SESSION['pl_id']) ? $_SESSION['pl_id'] : null;
}
}


Игра "Слова из слова"



Кратко напомню правила: Необходимо составлять слова из показанного на экране слова. Слово должно быть нарицательным именем существительным в единственном числе. Уменьшительно-ласкательные формы, а также сокращения не принимаются. Минимальная длина слова — 3 буквы. Для перехода на следующий этап необходимо отгадать не менее 30% вариантов слов текущего.



Вид игрового поля

Word from word



Взаимодействие с сервером происходит посредством Ajax.



Скелет игрового поля до инициализации


Ваш аватар

Игрок


Вернуться в личный кабинет




Этап: 0

Очки: 0




Слов отгадано: 0/0




Карта этапов





Подсказки









Первая звезда
Вторая звезда
Третья звезда















Помощь





















Стереть букву

Стереть все слово


















Подсказка



















Далее подгружаем данные о прогрессе пользователя.



Клиентский код инициализации
class Controller{
private model: Model;
private view: View;
private freezeState: boolean = false;

constructor(){
this.view = new View();
this.model = new Model(this.onReceiveInitialData.bind(this), this.onError.bind(this));

$(document).on('tipClick',this.useTip.bind(this));
$(document).on('lvlBtnClick',this.changeLevel.bind(this));
$(document).on('letterClick', this.onLetterClick.bind(this));
$(document).on('foundWordClick',this.getWordDefinition.bind(this));
$(document).on('keydown', this.keyControls.bind(this));

$('#clear-letter-btn').on('click', this.removeLastLetter.bind(this));
$('#clear-word-btn').on('click', this.clearUserInput.bind(this));
}
..........
}

class Model{
readonly tipsCost = {
holeWord: 250,
wordDefinition: 100
};
private login: string;
private avatar: string;
private level: number;
private totalLevelsNumber: number;
private levelsPassedNumber: number;
private levelWord: string;
private wordVariants: Array;
private foundWords: Array;
private score: number;
private userWord: string = '';
private missions: {
1: boolean,
2: boolean,
3: boolean
};
private missionUnique;
private dictionary = {};

constructor(success: ()=> any, error: (message: string)=>any, lvl?: number){
let that = this;
$.ajax({
url: 'server_scenarios/index.php',
type: 'post',
data: {
'action': 'getInitialInfo',
'lvl' : (lvl) ? lvl : null
},
success: function (data) {
if (data.state){
that.initialize(data);
success();
} else {
error(data.message);
}
},
error: function(){
error('Ошибка соединения с сервером');
}
})
}

public initialize(data: ServerAnswerInitialData){
this.login = data.login;
this.avatar = data.avatar;
this.level = parseInt(data.level);
this.totalLevelsNumber = parseInt(data.totalLevelsNumber);
this.levelsPassedNumber = parseInt(data.levelsPassedNumber);
this.levelWord = data.levelWord;
this.wordVariants = data.wordVariants;
this.foundWords = data.foundWords;
this.score = parseInt(data.score);
this.missions = data.missions;
this.missionUnique = data.missionUnique;
}
........
}

class View{
private playerInfo: PlayerInfo;
private gamefield: Gamefield;
public loader: Loader;
constructor(){
this.loader = new Loader();
this.playerInfo = new PlayerInfo();
this.gamefield = new Gamefield();
}

public initializePlayerInfoBox(data: UserInfoData){
this.playerInfo.setNewAvatar(data.avatar);
this.playerInfo.setLoginLabel(data.login);
this.playerInfo.setLevelLabel(data.level.toString());
this.playerInfo.setScoreLabel(data.score);
this.playerInfo.setFoundWordsLabel(data.foundWordsNumber.toString());
this.playerInfo.setTotalWordsLabel(data.totalWordsNumber.toString());
this.playerInfo.setProgressBar(data.foundWordsNumber, data.totalWordsNumber);
this.playerInfo.createLevelMap(data.totalLevelsNumber, data.level, data.levelsPassedNumber);
if (data.tipsState.wordDefinition){
this.playerInfo.enableTip('wordDefinition');
}
if (data.tipsState.holeWord){
this.playerInfo.enableTip('holeWord');
}
}

public initializeGameField(data: GamefieldData){
for (let prop in data.missions){
if (data.missions.hasOwnProperty(prop)){
(data.missions[prop]) ? this.showCompleteMissionStateIcon(parseInt(prop)): this.showIncompleteMissionStateIcon(parseInt(prop));
}
}
this.updateUserInputWord();
this.gamefield.printMainWordLetters(data.levelMainWord);

this.gamefield.clearFoundWordsBox();
if (data.foundWords){
for (let i = 0; i < data.foundWords.length; i++){
this.addFoundWord(data.foundWords[i]);
}
}
this.gamefield.setUniqueMissionTitle(data.missionUnique);
}
....
}


Серверный код инициализации
if (!defined('PLAYER_ID') || !defined('CURRENT_LEVEL')) exit();
header('Content-Type: application/json');

$playerGlobalInfo = DBPlayerGlobalInfo::getGlobalInfo(PLAYER_ID);
$playerProgressInfo = DBPlayerProgress::getProgressOnLvl(PLAYER_ID, CURRENT_LEVEL);
$levelInfo = DBGameInfo::getLevelInfo(CURRENT_LEVEL);

echo json_encode(array(
'state' => true,
'login' => $playerGlobalInfo['login'],
'avatar' => file_exists($_SERVER['DOCUMENT_ROOT'] . $playerGlobalInfo['avatar']) ? $playerGlobalInfo['avatar'] : '/_app_files/players_avatars/no_avatar.png',
'level' => CURRENT_LEVEL,
'totalLevelsNumber' => DBGameInfo::getLevelsQuantity(),
'levelsPassedNumber' => DBPlayerProgress::getPassedLvlQuantity(PLAYER_ID),
'levelWord' => $levelInfo['word'],
'wordVariants' => $levelInfo['wordVariants'],
'foundWords' => (empty($playerProgressInfo['foundWords'])) ? array() : $playerProgressInfo['foundWords'],
'score' => DBPlayerProgress::getScore(PLAYER_ID),
'missions' => array(
1 => (boolean) $playerProgressInfo['star1status'],
2 => (boolean) $playerProgressInfo['star2status'],
3 => (boolean) $playerProgressInfo['star3status']
),
'missionUnique' => $levelInfo['missionUnique']
));


Для того, чтобы избегать постоянных запросов к серверу и базе данных, в модели после инициализации хранятся найденные слова и варианты возможных слов для текущего этапа. В настоящее время они хранятся в открытом виде и доступны искушенному пользователю, который сможет залезть сначала в скрипт, а потом в консоль и увидеть все 100% слов. Поэтому буду рад, если кто подскажет в какую сторону копать, чтобы избежать этого варианта.



Проверка слова, вводимого игроком



Слово уровня представляет собой набор div'ов с одной буквой внутри. По нажатию на букву выполняется проверка активности буквы, если она не выбрана, то добавляется к набираемому слову и, как только длина слова станет больше либо равна, то оно отправляется на проверку наличия в словаре. Далее, когда проверка пройдена успешна, слова отправляется на сервер для подсчета очков и занесения в базу данных.

В случае, когда буква была выбрана, то проверяется ее положение в слове. Если крайняя — стирается, если нет — ничего не происходит.

Обработчик клика приведен ниже.



Обработчика клика по букве
onLetterClick(e: CustomEvent): void{
if (this.freezeState) return;
this.freeze();
let letter = e.detail,
userWord = this.model.getUserInputWord();
if (!letter.hasClass('active')){
userWord += letter.text();
letter.data('order', userWord.length);
this.view.setActiveLetterState(letter);
this.view.updateUserInputWord(userWord);
this.model.updateUserInputWord(userWord);
if (userWord.length >= 3){
this.model.checkUserWord(userWord, this.onAlreadyFoundWord.bind(this), this.onNewFoundWord.bind(this), );
}
} else {
if (letter.data().order === userWord.length){
letter.data('order', 0);
userWord = userWord.substr(0, userWord.length-1);
this.view.removeActiveLetterState(letter);
this.view.updateUserInputWord(userWord);
this.model.updateUserInputWord(userWord);
}
}
}


Отправка найденного слова на сервер
checkUserWord(word: string, onAlreadyFound: (word) => any, onNewFound:(data: ServerAnswerCheckWord)=>any){
let model = this;

if (this.foundWords.indexOf(word) > -1){
onAlreadyFound(word);
return;
}
if (this.wordVariants.indexOf(word) > -1){
$.ajax({
url: 'server_scenarios/index.php',
type: 'post',
data: {
'action': 'checkWord',
'userWord' : word
},
success: function (data) {
if (data.state){
model.score = data.score;
model.foundWords = data.foundWords;
let level_status = false;
if ((data.lvl_status) && (model.totalLevelsNumber >= (model.level + 1))){
level_status = true;
}

onNewFound({
word: data.word,
score: data.score,
experience: data.experience,
points: data.points,
missions: data.missions,
foundWordsNumber: data.foundWords.length,
lvl_status: level_status
});
}
}
})
}
}


Серверный код обработки найденного слова
if (!defined('PLAYER_ID') || !defined('CURRENT_LEVEL') || empty($_POST['userWord'])) exit;
header('Content-Type: application/json');

$checker = new AddingWordChecker(PLAYER_ID,CURRENT_LEVEL,$_POST['userWord']);

echo json_encode(
$checker->getChangedData()
);

class AddingWordChecker
{
const POINTS_PER_LETTER = 4;
const EXPERIENCE_PER_WORD = 1;

const POINTS_FOR_LEVEL_COMPLETE = 150;
const EXPERIENCE_FOR_LEVEL_COMPLETE = 20;

const POINTS_FOR_FIRST_STAR = 1000;
const EXPERIENCE_FOR_FIRST_STAR = 50;

const POINTS_FOR_SECOND_STAR = 500;
const EXPERIENCE_FOR_SECOND_STAR = 30;

const POINTS_FOR_THIRD_STAR = 10000;
const EXPERIENCE_FOR_THIRD_STAR = 250;

const PERCENT_FOUND_FOR_LEVEL_COMPLETE = 0.3;
const PERCENT_FOUND_FOR_FIRST_STAR = 0.4;
const PERCENT_FOUND_FOR_THIRD_STAR = 1;

private $playerId;
private $state = false;
private $gameLevel;
private $levelStatus;
private $wordToCheck;
private $wordVariants;
private $foundWords;
private $star1status;
private $star2status;
private $star3status;
private $changedData = array();

function __construct($playerId, $gameLevel, $wordToCheck)
{
$wordToCheck = strip_tags($wordToCheck);

$this->playerId = $playerId;
$this->gameLevel = $gameLevel;
$this->wordVariants = DBGameInfo::getWordVariantsOnLvl(CURRENT_LEVEL);

$playerProgress = DBPlayerProgress::getProgressOnLvl($playerId, $gameLevel);
$this->levelStatus = $playerProgress['lvl_status'];
$this->foundWords = (empty($playerProgress['foundWords'])) ? array() : $playerProgress['foundWords'];
$this->star1status = $playerProgress['star1status'];
$this->star2status = $playerProgress['star2status'];
$this->star3status = $playerProgress['star3status'];

$this->wordToCheck = $wordToCheck;

if (!$this->checkWord()){
$this->changedData['state'] = false;
$this->changedData['message'] = 'Неверное слово';
return;
}

$this->addWord();
}

public function getChangedData(){
$this->changedData['state'] = $this->state;
$this->changedData['score'] = DBPlayerProgress::getScore($this->playerId);
$this->changedData['word'] = $this->wordToCheck;
return $this->changedData;
}

private function checkWord(){
if ((array_search($this->wordToCheck, $this->foundWords) !== false) ||
(array_search($this->wordToCheck, $this->wordVariants) === false)) {
$this->state = false;
} else {
$this->state = true;
}
return $this->state;
}

private function addWord(){
if (!$this->state) return;

array_push($this->foundWords, $this->wordToCheck);
DBPlayerProgress::updateFoundWords($this->playerId, $this->gameLevel, $this->foundWords);
$this->changedData['foundWords'] = $this->foundWords;

$this->calculatePointsForWordLength();
$this->checkLvlStatus();
$this->checkMissions();
DBPlayerProgress::augmentScore($this->playerId, $this->changedData['points']);
DBPlayerGlobalInfo::augmentExperience($this->playerId, $this->changedData['experience']);
}

private function addPoints($points){
if (isset($this->changedData['points'])){
$this->changedData['points'] += $points;
} else {
$this->changedData['points'] = $points;
}
}

private function addExperience($experience){
if (isset($this->changedData['experience'])){
$this->changedData['experience'] += $experience;
} else {
$this->changedData['experience'] = $experience;
}
}

private function calculatePointsForWordLength(){
$wordLength = mb_strlen($this->wordToCheck);
$points = $wordLength * $this::POINTS_PER_LETTER;
$experience = $this::EXPERIENCE_PER_WORD;
switch ($wordLength){
case (($wordLength > 3) && ($wordLength <= 5)):
$points *= 1.1;
$experience *= 2;
break;
case (($wordLength > 5) && ($wordLength <= 7)):
$points *= 1.2;
$experience *= 3;
break;
case (($wordLength > 7) && ($wordLength <= 9)):
$points *= 1.3;
$experience *= 4;
break;
case ($wordLength >= 10):
$points *= 2;
$experience *= 10;
break;
}

$this->addPoints(floor($points));
$this->addExperience(floor($experience));
}

private function checkLvlStatus(){
if ((!$this->levelStatus) &&
(count($this->foundWords) >= count($this->wordVariants)* $this::PERCENT_FOUND_FOR_LEVEL_COMPLETE)){
$this->levelStatus = true;
DBPlayerProgress::completeLevel($this->playerId, $this->gameLevel);
$this->changedData['lvl_status'] = $this->levelStatus;

$this->addPoints($this::POINTS_FOR_LEVEL_COMPLETE);
$this->addExperience($this::EXPERIENCE_FOR_LEVEL_COMPLETE);
}
}

private function checkMissions(){
$this->changedData['missions'] = array();
$this->checkFirstStarMission();
$this->checkSecondStarMission();
$this->checkThirdStarMission();
}

private function checkFirstStarMission(){
if ($this->star1status) return;
if (count($this->foundWords) >= count($this->wordVariants)* $this::PERCENT_FOUND_FOR_FIRST_STAR){
$this->star1status = true;
DBPlayerProgress::setCompleteStatusOnMission($this->playerId, $this->gameLevel, 1);
$this->changedData['missions']['star1status'] = $this->star1status;

$this->addPoints($this::POINTS_FOR_FIRST_STAR);
$this->addExperience($this::EXPERIENCE_FOR_FIRST_STAR);
}
}

private function checkSecondStarMission(){
if ($this->star2status) return;
$uniqueMission = DBGameInfo::getUniqueMission($this->gameLevel);
$letter = array_keys($uniqueMission)[0];
$quantity = array_values($uniqueMission)[0];
$pattern = '/^'.$letter.'+/u';
$matches = preg_grep($pattern, $this->foundWords);
if (count($matches) >= $quantity){
$this->star2status = true;
DBPlayerProgress::setCompleteStatusOnMission($this->playerId, $this->gameLevel, 2);
$this->changedData['missions']['star2status'] = $this->star2status;

$this->addPoints($this::POINTS_FOR_SECOND_STAR);
$this->addExperience($this::EXPERIENCE_FOR_SECOND_STAR);
}
}

private function checkThirdStarMission(){
if ($this->star3status) return;
if (count($this->foundWords) >= count($this->wordVariants)* $this::PERCENT_FOUND_FOR_THIRD_STAR){
$this->star3status = true;
DBPlayerProgress::setCompleteStatusOnMission($this->playerId, $this->gameLevel, 3);
$this->changedData['missions']['star3status'] = $this->star3status;

$this->addPoints($this::POINTS_FOR_THIRD_STAR);
$this->addExperience($this::EXPERIENCE_FOR_THIRD_STAR);
}
}
}


Заключение



Вот, собственно, и вкратце о моем проекте. Если кого-то заинтересуют подробности, с радостью отвечу. Буду благодарен за любые конструктивные замечания, а еще больше за совет, что и где нужно подучить, чтобы можно было превратить прототип платформы в полноценный работоспособный проект.



@Гуманитарий, который хочет стать технарем


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/324282/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Аноним

Среда, 01 Декабря 1970 г. 03:00 (ссылка)

Комментарии ()КомментироватьВ цитатник или сообщество
Sonya_kot

Игровой сайт

Суббота, 17 Января 2015 г. 05:53 (ссылка)

Metal Bulet (248x248, 138Kb)
Даже люди, которые покупают компьютер исключительно для работы или учебы, все равно иногда не прочь развеяться и расслабиться, поиграв в современные компьютерные игры. Сейчас их существует просто неисчислимое множество - сотни, тысячи приложений созданы для того, чтобы подарить Вам интересное и увлекательное времяпровождение.
Причем для этого не обязательно что-то качать и устанавливать - на http://igraiseichas.ru/ можно играть в онлайн-режиме. Заходим, выбираем игру из списка - и сразу же приступаем! А список, кстати, весьма и весьма обширный - здесь есть и ММОРПГ, и шутеры, и стратегии, и фэнтези. В общем, каждый посетитель сможет подыскать что-нибудь увлекательное и интересное.

Метки:   Комментарии (1)КомментироватьВ цитатник или сообщество
Трииночка

Возьмите на заметку! Новая подача салата "Селедка под шубой"

Понедельник, 15 Декабря 2014 г. 18:42 (ссылка)


Возьмите на заметку! Новая подача салата "Селедка под шубой"





"Сельдь под шубой", наш любимый салат на Новогоднем столе..., после "Оливье", конечно. Недавно узнала, что салат можно подавать с хлебом, как закуску, лучше, где-нибудь на природе.



 А, еще салат можно приготовить в силиконовой форме, получится очень красиво!

Читать далее...
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Desert_Man

Лучшие игры головоломки

Понедельник, 04 Февраля 2013 г. 13:40 (ссылка)


Я уже не первый раз замечаю, что в выходные дни по телевизору ничего интересного не показывают. Так было и вчера, а поскольку погода на улице ужасная, я решил развлекаться в интернете. Нашел сайт с компьютерными игрушками. Время пролетело незаметно и увлекательно. Хочу и своим читателям несколько слов рассказать про  bibigames.ru. На сайте представлены игры разного направления и жанра. Выбор огромный. Лучшие игры головоломки заставят работать любые головы! Я, например, засиделся в этой категории надолго. Мы как то отвыкли решать логические задачки, а здесь пришлось посоображать и когда удавалось решить головоломку, то, честно сказать, было приятно, еще не совсем отупел.



На сайте есть и другие категории игр как известные так и новенькие. Лучшие игры с поиском предметов онлайн обычно нравятся детям. Они, кстати хорошо развивают наблюдательность, внимание, да и усидчивость. Плюс ко всему ребенок учиться обращаться с компьютером. Так что на этом сайте можно провести увлекательно и с пользой довольно много времени. Возможно кому то этот сайт скрасит ненастный день, как вчера мне!


Метки:   Комментарии (2)КомментироватьВ цитатник или сообщество
леонид_старцев

Игровой сайт

Воскресенье, 21 Февраля 2010 г. 18:36 (ссылка)

Это цитата сообщения vados2384 Оригинальное сообщение

Игровой сайт




 Отличная база для любителей игр. Есть возможность выбрать мини-игру онлайн  любого направления.  Найти игру по вкусу не заставит больших трудностей. Настоятельно советую посетить...

Метки:   Комментарии (1)КомментироватьВ цитатник или сообщество
ma_zaika

Займемся созданием игровой империи... занимательно.

Понедельник, 09 Февраля 2009 г. 10:58 (ссылка)








Читайте ma_zaika ma_zaika

Как создать империю?



 








Игровой сайт

 


Интересно наверняка, да еще и прибыльно стать одним из хозяв игровой империи? Думаю, что согласятся многие. Как же оздать вою? Америку конечно же открыть не в моих силах, а рассказать что уже возможно и успешно применяется - помогу и расскажу. Сразу оговорюсь, я не открою Америки, а лишь структурирую уже имеющуюся информацию, дополню своей и очень постараюсь сделать это грамотно. Информация ориентирована на новичков, но окажется интересной и заядлым манимейкерам.



Рецепт приготовления игрового сайта - 1 порция.


ДалеЕ >>
Комментарии (13)КомментироватьВ цитатник или сообщество

Следующие 30  »

<игровой сайт - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda