Игра на QuickTiGame2d в Appcelerator Titanium. Часть 2


    В первой части данной статьи "Игра на QuickTiGame2d в Appcelerator Titanium. Часть 1" я рассказывала о некоторых моментах работы с движком, которые, на мой взгляд, будут полезны тем, кто собирается ознакомиться с этой публикацией. Сейчас я предлагаю рассмотреть создание простейшей игры на Appcelerator Titanium.

    Суть игры заключается в том, что из появляющихся букв нужно собрать слово «TITANIUM», после чего будет выведено соответствующее сообщение о победе и игра будет закончена.

    Для начала создадим файл pathsToFiles.js, в котором присвоим пути к имеющимся ресурсам:

    //menuScene
    var pngMenuBackground = "pictures/menu/background.png";
    var pngButtonNewGame = "pictures/menu/newGame.png";
    var pngButtonHelp = "pictures/menu/help.png";
    //helpScene
    var pngHelp = "pictures/help/help.png";
    var pngBackFromHelp = "pictures/help/back.png";
    //mainLoadingScene
    var pngMainBackground = "pictures/game/background.png";
    var pngBackToMenu = "pictures/game/back.png";
    var pngVictory = "pictures/game/victory.png";
    var xmlCharactersPosition = "pictures/game/charactersPosition.xml";
    //sound
    var soundClick = "sound/click.wav";
    

    Перво-наперво обратимся к файлу app.js. Создадим экран игры, подключим файлы js, с которыми будем работать, а также опишем расположение экрана для Android и iOS:

    var window = Ti.UI.createWindow({
        backgroundColor : 'black'
    });
    var quicktigame2d = require('com.googlecode.quicktigame2d');
    var game = quicktigame2d.createGameView();
    if (Titanium.Platform.osname === 'android') {
        game.orientation = Ti.UI.LANDSCAPE_LEFT;
        window.orientationModes = [Titanium.UI.LANDSCAPE_LEFT];
    } else {
        game.orientation = Ti.UI.LANDSCAPE_RIGHT;
        window.orientationModes = [Titanium.UI.LANDSCAPE_RIGHT];
    }
    Ti.include('pathsToFiles.js');
    Ti.include('helpScene.js');
    Ti.include('menuScene.js');
    Ti.include('mainScene.js');
    

    Далее рассчитаем необходимый масштаб игры для устройства, проинициализируем подгружаемые сцены, которые будут описаны ниже, добавим игровой экран в окно приложения, откроем его и запустим MenuScene.

    var WINDOW_SCALE_FACTOR_X = 1;
    var WINDOW_SCALE_FACTOR_Y = 1;
    game.addEventListener('onload', function(e) {
        var screenScale = game.size.height / 640;
        game.screen = {
            width : game.size.width / screenScale,
            height : game.size.height / screenScale
        };
        WINDOW_SCALE_FACTOR_X = game.screen.width / game.size.width;
        WINDOW_SCALE_FACTOR_Y = game.screen.height / game.size.height;
        MenuScene.init();
        HelpScene.init();
        MainScene.init();
        game.pushScene(MenuScene.scene);
        game.start();
    });
    window.add(game);
    window.open({
        fullscreen : true,
        navBarHidden : true
    });
    

    Теперь займемся созданием MenuScene для игры. Для начала непосредственно создадим её:

    var buttonMargin = 20;
    var clickSound = null;
    
    var MenuScene = {
        scene : null,
        background : null,
        buttonNewGame : null,
        buttonHelp : null,
        init : function() {
            this.scene = quicktigame2d.createScene();
    ...
        },
    };
    

    Здесь buttonMargin — это отступ, который будет использоваться далее, а clickSound — переменная для хранения звука.

    Теперь стоит добавить некоторые действия. Запускаем текущую сцену при загрузке спрайтов:

     var onloadsprite = (function(self) {
                return function(e) {
                    if (e.name == pngButtonHelp) {
                        game.startCurrentScene();
                    }
                };
    })(this);
    

    Опишем события нажатия на кпопки «New game» и «Help». При нажатии и при отпускании кнопки будет изменяться её картинкаю Также, при нажатии будет издаваться короткий звук, а при «отжатии» — сцена игры будет изменена на выбранную:

    var touchstart = (function(self) {
                return function(e) {
                    var x = e.x * WINDOW_SCALE_FACTOR_X;
                    var y = e.y * WINDOW_SCALE_FACTOR_Y;
                    if (self.buttonNewGame.contains(x, y)) {
                        self.buttonNewGame.frame = 0;
                        clickSound.play();
                    }
                    if (self.buttonHelp.contains(x, y)) {
                        self.buttonHelp.frame = 0;
                        clickSound.play();
                    }
                }
    })(this);
    
    var touchend = (function(self) {
                return function(e) {
                    var x = e.x * WINDOW_SCALE_FACTOR_X;
                    var y = e.y * WINDOW_SCALE_FACTOR_Y;
                    self.buttonNewGame.frame = 1;
                    self.buttonHelp.frame = 1;
                    if (self.buttonNewGame.contains(x, y)) {
                        game.pushScene(MainScene.scene);
                    }          
                    if (self.buttonHelp.contains(x, y)) {
                        game.pushScene(HelpScene.scene);
                    }
                };
    })(this);
    

    Теперь проинициализируем переменные и зададим координаты расположения кнопок и фона меню игры. Добавим на сцену соответствующие элементы, а так же слушателей событий:

    var activated = (function(self) {
                return function(e) {
                     if (clickSound == null) {
                        clickSound = Ti.Media.createSound({
                            url : soundClick
                        });
                    }
                    if (self.background == null) {
                        self.background = quicktigame2d.createSprite({
                            image : pngMenuBackground
                        });
                    }
                    if (self.buttonNewGame == null) {
                        self.buttonNewGame = quicktigame2d.createSpriteSheet({
                            image : pngButtonNewGame,
                            width : 275,
                            height : 100
                        });
                    }              
                    if (self.buttonHelp == null) {
                        self.buttonHelp = quicktigame2d.createSpriteSheet({
                            image : pngButtonHelp,
                            width : 275,
                            height : 100
                        });
                    }
                    self.background.x = (game.screen.width * 0.5) - (self.background.width * 0.5);
                    self.background.y = (game.screen.height * 0.5) - (self.background.height * 0.5);
    
                    self.buttonNewGame.x = (game.screen.width - self.buttonNewGame.width) / 4;
                    self.buttonNewGame.y = (game.screen.height * 0.8);
    
                    self.buttonHelp.x = (game.screen.width - self.buttonNewGame.width) / 4*3;
                    self.buttonHelp.y = self.buttonNewGame.y;
    
                    self.buttonNewGame.frame = 1;
                    self.buttonHelp.frame = 1;
                    
                    self.scene.add(self.background);
                    self.scene.add(self.buttonNewGame);
                    self.scene.add(self.buttonHelp);
    
                    game.addEventListener('touchstart', touchstart);
                    game.addEventListener('touchend', touchend);
                    self.scene.addEventListener('enterframe', enterframe);
                };
    })(this);
    

    Опишем функцию удаления всех созданных элементов (выгрузка текстур, удаление слушателей событий):

    var deactivated = (function dea(self) {
                return function(e) {
                    self.scene.remove(self.background);
                    self.background = null;
                    self.scene.remove(self.buttonNewGame);
                    self.scene.remove(self.buttonHelp);
                    self.buttonNewGame = null;
                    self.buttonHelp = null;
                    game.unloadTexture(pngButtonNewGame);
                    game.unloadTexture(pngButtonHelp);
                    game.removeEventListener('touchstart', touchstart);
                    game.removeEventListener('touchend', touchend);
                };
    })(this);
    

    Осталось только добавить слушателей событий активации/деактивации сцен и загрузки спрайтов:

          this.scene.addEventListener('activated', activated);
          this.scene.addEventListener('deactivated', deactivated);
          this.scene.addEventListener('onloadsprite', onloadsprite);
    

    Сцена меню готова. Перейдем к сцене Help. В принципе, все процессы загрузки и выгрузки элементов очень похожи, поэтому не будем повторяться и рассмотрим наиболее интересующие нас элементы. Одним из них является создание фона help:

     if (self.background == null) {
         self.background = quicktigame2d.createSprite({
              image : pngMenuBackground
          });
    }
    if (self.menuLayer == null) {
         self.menuLayer = quicktigame2d.createSprite({
              width : self.background.width,
              height : self.background.height
         });
         self.menuLayer.color(0.5, 0.5, 0.5);
         self.menuLayer.alpha = 0.78;
    
    }
    if (self.foreground == null) {
         self.foreground = quicktigame2d.createSpriteSheet({
             image : pngHelp,
             width : 960,
             height : 640
         });
    }
    

    Здесь мы подгружаем 3 слоя фона. Один из них — это слой в меню, он будет нижним. Второй фон мы устанавливаем поверх (в нем присутствует цвет и прозрачность). Третий — это слой с текстом. Определяем его как SpriteSheet, чтобы использовать для него несколько изображений.

    Опишем расположение кнопки в углу экрана относительно его размеров:

    if (game.screen.width > self.background.width) {
         self.okButton.x = self.background.x + self.background.width - self.okButton.width - buttonMargin;
         self.okButton.y = self.background.y + self.background.height - self.okButton.height - buttonMargin;
    } else {
         self.okButton.x = game.screen.width - self.okButton.width - buttonMargin;
         self.okButton.y = game.screen.height - self.okButton.height - buttonMargin;                   
    }
    

    И добавим анимацию текстового фона:

    self.foreground.animate(0, 2, 2000, -1);
    

    Теперь перейдем к созданию сцены для процесса игры. Стоит создать несколько переменых:

    var COUNT_OF_CHARACTERS = 9;
    var word = "";
    var wordTitanium = "titanium";
    

    Где COUNT_OF_CHARACTERS — это количество мест на поле для появления букв, word — собранное слово, wordTitanium — слово которое нужно собрать.

    В функцию activated добавим процесс создания массива элементов с изображениями букв:

    var xCoef = self.background.width / 4;
           var yCoef = self.background.height / 4;
           var xParam = 1;
           var yParam = 1;
           for (var i = 0; i < COUNT_OF_CHARACTERS; i++) {
                        self.characters[i] = quicktigame2d.createSpriteSheet({
                            image : xmlCharactersPosition
            });
            self.characters[i].x = self.background.x + xCoef * xParam;
            self.characters[i].y = self.background.x + yCoef * yParam;
            xParam++;
            if (xParam > 3) {
                     xParam = 1;
                     yParam++;
            }
            self.characters[i].z = 3;
            self.characters[i].hide();
            self.characters[i].index = i;
            self.characters[i].status = "waiting";
            self.characters[i].selectFrame("character0");
            self.scene.add(self.characters[i]);
            if (self.charactersTransforms[i] == null) {
                  self.charactersTransforms[i] = quicktigame2d.createTransform();
                  self.charactersTransforms[i].addEventListener('complete', oncharactersCompleted);
                  self.charactersTransforms[i].index = i;
            }
    }
    

    Здесь мы устанавливаем местоположение для каждого элемента, скрываем его, устанавливаем статус, текущее изображение. Здесь же устанавливается свой слушатель событий для каждого элемента. Слушатель для событий будет выглядить таким образом:

    var oncharactersCompleted = (function(self) {
                return function(e) {
                    var transform = e.source;
                    var choosenCharacter = self.characters[transform.index];
                    if (choosenCharacter != null) {
                        if (choosenCharacter.status == "moving") {
                            choosenCharacter.show();
                            choosenCharacter = changeStatus(choosenCharacter, transform, "living");
                        } else if (choosenCharacter.status == "living") {
                            choosenCharacter = changeStatus(choosenCharacter, transform, "dying");
                        } else if (choosenCharacter.status == "dying") {
                            choosenCharacter = changeStatus(choosenCharacter, transform, "hiding");
                        } else if (choosenCharacter.status == "hiding") {
                            transform.scale(0, 0);
                            choosenCharacter = changeStatus(choosenCharacter, transform, "queue_waiting");
                        } else if (choosenCharacter.status == "queue_waiting") {
                            choosenCharacter.hide();
                            choosenCharacter.status = "waiting";
                            transform.duration = 1000;
                            choosenCharacter.transform(transform);
                        } else if (choosenCharacter.status == "killed") {
                            transform.rotate(-360);
                            transform.scale(0, 0);
                            choosenCharacter = changeStatus(choosenCharacter, transform, "queue_waiting");
                        }
                    }
                };
    })(this);
    
    function changeStatus(choosenCharacter, transform, statuscharacter) {
                transform.duration = 2000;
                choosenCharacter.status = statuscharacter;
                choosenCharacter.transform(transform);
                return choosenCharacter;
    }
    

    Здесь в зависимости от статуса элемента с ним будут происходить разного рода действия: вращение, изменение масштаба, скрытие и появление на экране.

    Добавим метод для завершения игры, в котором мы убираем текст в уже набранном слове, а также добавляем на сцену информацию о том, что игрок выиграл, что в свою очередь вызовет слушателя событий victoryText:

    function finishActivity(self) {
                word = "";
                self.scene.add(self.victoryText);
                self.victoryTextTransform.duration = 1000;
                self.victoryText.transform(self.victoryTextTransform);
    }
    
    var onVictoryTextCompleted = (function(self) {
                return function(e) {
                    if (self.victoryTextTransform.completed) {
                        self.scene.remove(self.victoryText);
                        closeGame(self);
                    } else {
                        self.victoryTextTransform.y = game.screen.height;
                        self.victoryTextTransform.completed = true;
                        self.victoryText.transform(self.victoryTextTransform);
                    }
                };
    })(this);
    

    В enterframe следует добавить процесс смены букв в соответствующих элементах. Это будет происходить при статусе waiting: элементы будут появляться на экране со случайно созданной для них буквой.

    self.charactersTransforms[i].show();
    self.charactersTransforms[i].scale(1, 1);
    self.charactersTransforms[i].duration = 500;
    self.charactersTransforms[i].delay = 0;
    self.charactersTransforms[i].easing = quicktigame2d.ANIMATION_CURVE_CUBIC_IN;
    var face = Math.floor((randomNumber * 100) % 8);
                                    
    for (var count = 0; count < wordTitanium.length; count++) {
           if (face == count) {
                 self.characters[i] = addDataToWord(self.characters[i], self.charactersTransforms[i], "character"+count, wordTitanium[count]);
                 self.characters[i].transform(self.charactersTransforms[i]);
                 break;
            }
    } 
    

    где функция addDataToWord:

    function addDataToWord(choosenCharacter, choosenCharacterTransform, frame, symbol) {
                choosenCharacter.isMoving = false;
                choosenCharacter.faceName = frame;
                choosenCharacter.symbol = symbol;
                choosenCharacter.status = "moving";
                choosenCharacter.selectFrame(frame);
                choosenCharacterTransform.duration = 0;
                choosenCharacter.transform(choosenCharacterTransform);
                return choosenCharacter;
    }
    

    Последнее, что осталось сделать, — это прописать функцию клика по элементу:

    var dblclick = (function(self) {
                return function(e) {
                    var x = e.x * WINDOW_SCALE_FACTOR_X;
                    var y = e.y * WINDOW_SCALE_FACTOR_Y;
                    if (!self.loaded)
                        return;
                    if (!self.started)
                        return;
                    for (var i = 0; i < COUNT_OF_CHARACTERS; i++) {
                        if (self.characters[i].status != "killed") {
                            if (self.characters[i].contains(x, y)) {
                                clickSound.play();
                                self.charactersTransforms[i].rotate(360);
                                self.charactersTransforms[i].duration = 2000;
                                self.characters[i].transform(self.charactersTransforms[i]);
                                self.characters[i].status = "killed";
                                word += self.characters[i].symbol;
                                Ti.API.info(word);
                                if (wordTitanium.indexOf(word) == 0) {
                                    Ti.API.info(word + " " + wordTitanium);
                                    if(wordTitanium.length == word.length){
                                        finishActivity(self);
                                    }
                                } else {
                                    word = "";
                                }
                            }
                        }
                    }
                };
     })(this);
    

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

    Получившийся результат:









    Rus Wizards
    Компания

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 2

      0
      Интересно.
      А можно ссылку на готовую версию под андроид? или ссылки на какие-нибудь built-with-titanium игры?
      Чего можно ожидать в плане производительности — я запускал titanium приложения (kitchen sink и др.) на парочке бюджетных androidах — запускались медленно, и работали не очень быстро.
        0
        Да, конечно. Вот ссылка.
        Производительность titanium несколько ниже, чем если бы это была какая-то определенная платформа, но взамен мы получаем его кроссплатформенность.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое