Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Как правильно сделать "переключатель" для игровых экранов? (http://www.flasher.ru/forum/showthread.php?t=212903)

Azrael 24.05.2016 19:37

Как правильно сделать "переключатель" для игровых экранов?
 
1 экран - меню
2 экран - выбор персонажа
3 экран - выбор снаряжения
4 экран - игра

Скажите как правильно работать с экранами, может есть какой то урок на эту тему. Мне приходит в голову каждый экран создать классом на базе sprite, и из меню по onClick делать addChild(например 2 экран). Далее я выбрал персонажа и опять же по onClick что я делаю? Как правильно удалить себя со сцены и добавить следующий?

faraday 24.05.2016 19:41

синглтон Layers с методами showChar, showGame, showMenu в данном случае пожалуй самый удобный вариант

undefined 24.05.2016 20:02

либо экраны имплементят интерфейс IShowable с методами show/hide + класс StageMediator,хранящий ссылку на stage/root и добавляющий экраны когда надо.

Azrael 26.05.2016 18:17

Цитата:

Сообщение от undefined (Сообщение 1194288)
либо экраны имплементят интерфейс IShowable с методами show/hide + класс StageMediator,хранящий ссылку на stage/root и добавляющий экраны когда надо.

А можно чуть более подробнее.

Если в main.as написать функцию которая будет делать addChild и removeChild по переданому ей параметру, а параметром будет выступать класс экрана. То как в AS передавать этот класс функции?

undefined 26.05.2016 19:19

в as есть класс Class,но лучше его не использовать т.к. с его помощью можно передать в функцию все что угодно.Правильнее будет завести класс или интерфейс Showable от которого и наследовать все экраны и передавать не класс, а экземпляр класса.

Azrael 26.05.2016 19:59

Цитата:

Сообщение от undefined (Сообщение 1194316)
в as есть класс Class,но лучше его не использовать т.к. с его помощью можно передать в функцию все что угодно.

Можно пример как передать класс Menu с помощью Class?

Цитата:

Сообщение от undefined (Сообщение 1194316)
Правильнее будет завести класс или интерфейс Showable от которого и наследовать все экраны и передавать не класс, а экземпляр класса.

Мне не понятно как передавать классы или экземпляры классов в функцию, я пока тока разбираюсь с AS. Пример можно.

undefined 26.05.2016 20:52

передача класса в метод:
Код AS3:

private function someMethod(someClass:Class) {
..
}
someMethod(Object);

Передача экземпляра класса:
Код AS3:

private function someMethod(screen:Showable) {
..
}
var myScreen:Showable=new MyScreen();// класс MyScreen наследует/имплементирует класс/интерфейс Showable
someMethod(myScreen);


Azrael 27.05.2016 22:19

Цитата:

Сообщение от undefined (Сообщение 1194319)
передача класса в метод:
Код AS3:

private function someMethod(someClass:Class) {
..
}
someMethod(Object);


Код AS3:

package
{
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.display.*;
 
        public class Main extends Sprite
        {       
                var MenuScreen:Menu = new Menu();
 
                public function Main():void
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                private function init(e:Event = null):void
                {
                        ShowScreen(MenuScreen);
                }
                public function ShowScreen(Screen:Class)
                {
                        addChild(Screen);
                }
        }
}

Выдает ошибку Implicit coercion of a value of type Menu to an unrelated type Class. Что не так сделал?


Цитата:

Сообщение от undefined (Сообщение 1194319)
Передача экземпляра класса:
Код AS3:

private function someMethod(screen:Showable) {
..
}
var myScreen:Showable=new MyScreen();// класс MyScreen наследует/имплементирует класс/интерфейс Showable
someMethod(myScreen);


А зачем нужно наследовать/имплементировать? Нельзя просто в функцию передавать параметр который нужно и который функция будет делать addChild?

undefined 28.05.2016 13:33

у тебя классическая путаница понятий класс/экземпляр класса.Советую таки почитать что-нибудь по ооп чтоб не плавать в терминологии(хоть мука того же самого).Например что делает эта строка:
Код AS3:

var MenuScreen:Menu = new Menu();

1)Создает переменную с именем MenuScreen, которая может содержать ссылку на экземпляр класса Menu.Альтернативно можно сказать может содержать ссылку на экземпляр объекта типа Menu.Слова "класс" и "тип данных" в большинстве случаев взаимозаменяемые, также как "экземпляр класса N"/"объект типа N".
2)Создается экземпляр\объект класса/типа Menu(new Menu()), ссылка на свежесозданный объект кладется в переменную MenuScreen.
Короче класс - это просто описание типа данных(какую информацию он содержит и что может с ней делать).Экземпляр класса - то, что получается в результате работы оператора new.Т.е. классов обычно немного, а объекты могут штамповаться сотнями.
Дальше
Цитата:

Выдает ошибку Implicit coercion of a value of type Menu to an unrelated type Class. Что не так сделал?
Это потому что ты спрашивал как тебе передать класс в метод(в as для этого есть специальный тип данных Class),а ты туда передаешь экземпляр класса Menu.Если совсем не хочется запариваться - пиши
Код AS3:

public function ShowScreen(Screen:Menu)

Т.е. метод ожидает что ему дадут на вход ссылку на объект типа Menu.
Цитата:

А зачем нужно наследовать/имплементировать?
Наверно это пока рано.

Azrael 28.05.2016 14:42

Цитата:

Сообщение от undefined (Сообщение 1194349)
Наверно это пока рано.

Наследовать надо что бы можно было передать разные экземпляры (разные экраны) разных классов? То есть если остальные экраны будут расширять Menu я смогу и их передавть в:

Код AS1/AS2:

public function ShowScreen(Screen:Menu)

?

Спасибо за развернутый ответ!

undefined 28.05.2016 15:01

Цитата:

Наследовать надо что бы можно было передать разные экземпляры (разные экраны) разных классов? То есть если остальные экраны будут расширять Menu я смогу и их передавть в:
Да, но лучше сделать один суперкласс для всех экранов и от него наследовать и Menu и все остальные экраны.В этом случае если захочется, например, сделать чтоб экраны появлялись с какой-нибудь анимацией достаточно будет код появления/исчезания дописать в этот суперкласс и все наследники автоматически унаследуют логику появления/исчезновения.И в будущем весь функционал, общий для всех экранов можно будет пихать в суперкласс.
Обычно в название суперклассов используют слово Base.Например BaseScreen. Сигнатуру ShowScreen в этом случае естественно надо будет сменить на
Код AS3:

public function ShowScreen(Screen:BaseScreen)


Azrael 28.05.2016 19:41

Цитата:

Сообщение от undefined (Сообщение 1194357)
Да, но лучше сделать один суперкласс для всех экранов и от него наследовать и Menu и все остальные экраны.В этом случае если захочется, например, сделать чтоб экраны появлялись с какой-нибудь анимацией достаточно будет код появления/исчезания дописать в этот суперкласс и все наследники автоматически унаследуют логику появления/исчезновения.И в будущем весь функционал, общий для всех экранов можно будет пихать в суперкласс.
Обычно в название суперклассов используют слово Base.Например BaseScreen. Сигнатуру ShowScreen в этом случае естественно надо будет сменить на
Код AS3:

public function ShowScreen(Screen:BaseScreen)


А этот Base класс не абстрактный класс случаем получается?
А какой класс отвечает за функцию show/hide?

undefined 28.05.2016 20:50

Цитата:

А этот Base класс не абстрактный класс случаем получается?
в плане того, что его экземпляры не создаются - да он абстрактный.
В плане что он не содержит реализацию своих методов - нет, это обычный класс.
Вообще в AS нет абстрактных классов, но есть интерфейсы(полностью абстрактные классы).
Цитата:

А какой класс отвечает за функцию show/hide?
Цитата:

В этом случае если захочется, например, сделать чтоб экраны появлялись с какой-нибудь анимацией достаточно будет код появления/исчезания дописать в этот суперкласс и все наследники автоматически унаследуют логику появления/исчезновения

Azrael 29.05.2016 16:50

Вызов HideScreen выдает ошибку "[Fault] exception, information=ArgumentError: Error #2025: Предоставленный DisplayObject должен быть дочерним элементом вызывающего объекта."

Вы говорили про хранение ссылки на stage...

Класс документа -
Код AS1/AS2:

package
{
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.display.*;
 
        public class Main extends Base
        {       
                var MenuScreen:Menu = new Menu();
 
                public function Main():void
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                private function init(e:Event = null):void
                {
                        ShowScreen(MenuScreen);
                }       
        }
}

Код AS1/AS2:

package 
{
        import flash.display.Sprite;
 
        public class Base extends Sprite
        {
 
                public function Base()
                {
                        super();
                }
                function ShowScreen(Screen:Base)
                {
                        addChild(Screen);
                }
                function HideScreen()
                {
                        removeChild(this);
                }
        }
}

Код AS1/AS2:

package 
{
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.system.fscommand;
        import flash.text.*;
 
        public class Menu extends Base
        {
                var btn_play:MyButtonClass = new MyButtonClass();
 
                public function Menu()
                {
                        super();
 
                        btn_play.name = "btn_PLAY";
                        btn_play.label = "Play";
                        btn_play.addEventListener(MouseEvent.CLICK, btnMouseHandle);
                        addChild(btn_play).y = 50;
                        btn_play.x = 80                                               
 
                }
 
                function btnMouseHandle(e:MouseEvent):void               
                {                                       
                        switch(e.target.name)
                                {
                                        case "btn_PLAY":
                                                HideScreen(); // Вот тут ошибка
                                                break;
                                        case "btn_OPTIONS":
                                                break;
                                        case "btn_INSTRUCTIONS":
                                                break;
                                        case "btn_ABOUT":
                                                break;
                                        case "btn_EXIT":
                                                break;
                                }
                }
        }
}

Получилось удалит добавив parent.removeChilde(this), но правильно ли так делать?

undefined 29.05.2016 17:27

ты не понял идею.Методы show/hide нужны чтоб выполнить некое действие при добавлении экрана в дисплей лист(воспроизвести анимацию появления например). добавлять/удалять их должен документ класс, который и хранит ссылку на стейдж. Сами экраны никуда себя добавлять не должны, поэтому им ссылку на стейдж иметь необязательно.Если никаких действий при появлении делать не требуется - наследуй все экраны от Sprite и не парься.

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

Azrael 29.05.2016 19:31

Цитата:

Сообщение от undefined (Сообщение 1194403)
Сами экраны никуда себя добавлять не должны, поэтому им ссылку на стейдж иметь необязательно.

Мой вопрос был как раз об этом. Есть экран с меню, нажали "Играть" - как правильно будет удалить меню со сцены и отобразить экран "Играть" который в свою очередь имеет еще несколько промежуточных экранов "Выбор персонажа", "Выбор локации" и т.д.

Все экраны это классы, при необходимости отобразить след. экран как и откуда (из экземпляра текущего экрана?) удалять/добавлять со сцены?

undefined 29.05.2016 19:42

после "нажали играть" экран посылает событие что пора сменить экран.Кто-то, у кого есть доступ к стейджу ловит это событие (в твоем случае это документ класс, но это может быть кто угодно) и решает что делать дальше какой экран скрыть, а какой показать.

Azrael 29.05.2016 19:51

Цитата:

Сообщение от undefined (Сообщение 1194406)
после "нажали играть" экран посылает событие что пора сменить экран.Кто-то, у кого есть доступ к стейджу ловит это событие (в твоем случае это документ класс, но это может быть кто угодно) и решает что делать дальше какой экран скрыть, а какой показать.

А если использовать?

Код AS1/AS2:

this.stage.addChild(NextScreen);
parent.removeChild(this);


undefined 29.05.2016 20:23

На что ссылается this в этом коде?

Azrael 29.05.2016 21:40

Этот код у меня в обработчике onClick одной из кнопок меню, если я правильно понимаю, он ссылается на экземпляр класса в котором эта кнопка находится.

undefined 29.05.2016 21:50

в таком случае в этом коде не много смысла.Если у экрана есть ссылка на стейдж -this.stage, значит он уже туда добавлен и добавлять его снова имеет смысл только чтоб быстро переместить его поверх всего, что уже есть на стейдже.Все это сильно напоминает г****код.
Еще раз - экран не должен сам добавлять себя никуда.Может статься, что добавлять его надо будет не на стейдж, а в какой-нибудь контейнер.Экран должен оповестить ответственного что его надо показать .Аналогично в нужный момент он должен оповестить что пора его скрыть.

neonoviiwolf 30.05.2016 00:21

хм, я решил подобный вопрос иначе, мож поможет. У меня все классы(кроме одного) имеют ссылку на stage, дабы не морочиться кто кого должен добавлять. А дабы не писать спагетти, то у каждого класса есть список моих событий (своих наделал), на что и как реагировать. Нажал человек кнопку "play" кнопка отправило событие "NEW_PLAY". Все классы, которые должны как либо среагировать, подписаны на это событие и выполняют свой код. В итоге все классы общаются друг с другом только через события, зависимости минимальны, фактически можно отключать целые ветки кода и все будет работать, так же удобно включать новые классы, в одном месте общем написал this.addChild(new MyClass), что добавить его на сцену и всё, остальная логика реализуется внутри класса(ов)

undefined 30.05.2016 09:04

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

Azrael 30.05.2016 10:15

Цитата:

Сообщение от undefined (Сообщение 1194410)
в таком случае в этом коде не много смысла.Если у экрана есть ссылка на стейдж -this.stage, значит он уже туда добавлен и добавлять его снова имеет смысл только чтоб быстро переместить его поверх всего, что уже есть на стейдже.Все это сильно напоминает г****код.
Еще раз - экран не должен сам добавлять себя никуда.Может статься, что добавлять его надо будет не на стейдж, а в какой-нибудь контейнер.Экран должен оповестить ответственного что его надо показать .Аналогично в нужный момент он должен оповестить что пора его скрыть.

Да ссылка на stage у него есть, она собственно будет у всех экранов, игра простая состоит из 4 экранов которые по-очереди добавляются на stage (добавили 1, нажали next = убрали 1 добавили 2, во втором нажали next = убрали 2 добавили 3, в третьем нажали next = убрали 3 добавили 4) В этом случае если у меня не предусмотрен "обратный ход" предыдущий код верен?

По поводу ссылки - в main мне надо сделать так да?

Код AS3:

public static stage:Stage;
 
function Main()
{
Main.stage = stage;
}

И отвественный уже будет добавлять экран таким образом:

Код AS3:

Main.stage.addChild(Screen);


undefined 30.05.2016 13:45

если не планируешь код сильно расширять - пиши как удобнее.
Цитата:

По поводу ссылки - в main мне надо сделать так да?
Если Main - документ класс в этом нет необходимости т.к. у него и так всегда есть ссылка на стейдж -
this.stage.

Azrael 30.05.2016 20:58

Цитата:

Сообщение от undefined (Сообщение 1194419)
Если Main - документ класс в этом нет необходимости т.к. у него и так всегда есть ссылка на стейдж -
this.stage.

Если буду делать другой проект и по вашему совету через ответственного, ему нужна будет такая ссылка?

undefined 30.05.2016 21:33

Цитата:

Если Main - документ класс в этом нет необходимости т.к. у него и так всегда есть ссылка на стейдж - this.stage.
Если он не документ-класс хранить ссылку на корневой DO допустимо.
на форуме часто рекомендуют не цеплять ничего на стейдж, а все пихать в рут, т.к. стейдж не является DisplayObjectContainer и поэтому некоторые плюхи для него недоступны.Рут по большому счету тоже не является, но он допускает приведение к DisplayObjectContainer.

Wolsh 31.05.2016 08:46

Цитата:

на форуме часто рекомендуют не цеплять ничего на стейдж, а все пихать в рут, т.к. стейдж не является DisplayObjectContainer
Если бы Stage не был DisplayObjectContainer, вам бы и не удалось ничего туда "пихать". Но Stage не является частью вашего приложения. Это контейнер, В КОТОРОМ находится ваше приложение (загруженный плеером ролик).
Цитата:

Рут по большому счету тоже не является, но он допускает приведение к DisplayObjectContainer.
Рут является DisplayObjectContainer просто по-определению. Не будь он контейнером, ему не стать рутом.

undefined 31.05.2016 12:09

Цитата:

Если бы Stage не был DisplayObjectContainer, вам бы и не удалось ничего туда "пихать". Но Stage не является частью вашего приложения. Это контейнер, В КОТОРОМ находится ваше приложение (загруженный плеером ролик).
Согласен тут был не прав.
Цитата:

Рут является DisplayObjectContainer просто по-определению. Не будь он контейнером, ему не стать рутом.
А вот тут не все так просто.Например
Код AS3:

trace(root is DisplayObjectContainer);//true
trace(root.tabEnabled);// compile time error(Error: Access of possibly undefined property tabEnabled through a reference with static type flash.display:DisplayObject.)
trace((root as DisplayObjectContainer).tabChildren);//без ошибок

хотя tabEnabled - родное свойство DisplayObjectContainer'а.
Т.е. рут по меньшей мере не обычный DOC.

Добавлено через 26 минут
Код AS3:

trace(root.getChildAt(0));

аналогично ошибка компиляции

ObOs 31.05.2016 12:58

Цитата:

Сообщение от undefined (Сообщение 1194440)
Согласен тут был не прав.

А вот тут не все так просто.Например
Код AS3:

trace(root is DisplayObjectContainer);//true
trace(root.tabEnabled);// compile time error(Error: Access of possibly undefined property tabEnabled through a reference with static type flash.display:DisplayObject.)
trace((root as DisplayObjectContainer).tabChildren);//без ошибок

хотя tabEnabled - родное свойство DisplayObjectContainer'а.
Т.е. рут по меньшей мере не обычный DOC.

Добавлено через 26 минут
Код AS3:

trace(root.getChildAt(0));

аналогично ошибка компиляции

А если дождаться добавления на сцену?;)

alatar 31.05.2016 14:05

Цитата:

Сообщение от undefined (Сообщение 1194440)
хотя tabEnabled - родное свойство DisplayObjectContainer'а.
Код AS3:

trace(root.getChildAt(0));

аналогично ошибка компиляции

Ммм... А чего вы, собственно, ожидали?
Цитата:

root:DisplayObject [только для чтения]

undefined 31.05.2016 14:27

ObOs, если ты прочтешь внимательнее,то увидишь такие слова:
Цитата:

ошибка компиляции
Цитата:

compile time error(Error: Access of possibly undefined property tabEnabled through a reference with static type flash.display:DisplayObject.)
Это значит, что ошибка выскакивает на этапе компиляции.

Добавлено через 2 минуты
Цитата:

Ммм... А чего вы, собственно, ожидали?
Так какого типа рут то?

alatar 31.05.2016 14:30

DisplayObject

undefined 31.05.2016 14:33

как можно DisplayObject привести к DisplayObjectContainer?

alatar 31.05.2016 14:38

Что вы имеете ввиду?
Код AS3:

var container:DisplayObjectContainer =root as DisplayObjectContainer;
if (container)
{
 //enjoy
}


undefined 31.05.2016 14:42

т.е. фактически рут - это DOC,просто внутри приложения его зачем-то приводят к DO?Странная логика.

ObOs 31.05.2016 15:43

Цитата:

Сообщение от undefined (Сообщение 1194450)
ObOs, если ты прочтешь внимательнее,то увидишь такие слова:

Да, что ошибка на этапе компиляции я упустил. Думал что у тебя root - null в это время.

Тогда мне тоже не понятно почему

Код AS3:

trace(root is DisplayObjectContainer);//true

а

Код AS3:

trace(root.getChildAt(0));//ошибка


undefined 31.05.2016 15:56

это приведение вверх по иерархии.Сам рут - DisplayObjectContainer,но ссылка на него описана как var root:DisplayObject.Поэтому сам он DO, но допускает приведение к DOC.Зачем так сделано - загадка.

Добавлено через 2 минуты
ПС:Кто в курсе как эти смайлы отключить?

ObOs 31.05.2016 16:04

Цитата:

Сообщение от undefined (Сообщение 1194458)
это приведение вверх по иерархии.Сам рут - DisplayObjectContainer,но ссылка на него описана как var root:DisplayObject.Поэтому сам он DO, но допускает приведение к DOC.Зачем так сделано - загадка.

А, кажется догоняю. Что-то типа:
Код AS3:

        public class SomeSprite extends Sprite
        {
 
                public function SomeSprite()
                {
 
                }
        }
        var sprite:DisplayObject = new SomeSprite();
        trace(sprite.tabEnabled);//Ошибка
        trace((sprite as DisplayObjectContainer).tabEnabled);//Все ОК

Тогда действительно не понятно почему его не сделать типом DOC

Wolsh 31.05.2016 17:53

Цитата:

ПС:Кто в курсе как эти смайлы отключить?
Ставить пробел между двоеточием и D ;)
Геттер .root возвращает (имеет) тип DisplayObject. Поэтому компилятор не даст вам вызвать у свойства .root методы и свойства ДОК. Но, вроде, все знают, что рут это экземпляр Документ-класса, а им может быть только наследник DisplayObjectContainer.
Зачем такая фишка с .root, я тоже не знаю. С этими ДО и ДОК итак много всякого неочевидного. Взять тот же ТекстФилд, который явно ДОК, ибо в него можно загружать картинки и тп, но он никогда не сознается. И даже простенький Shape внутри содержит слои, что легко заметить, нарисовав несколько завершенных фигур с заливкой друг над другом, и поменяв затем альфу всему шейпу — каждый слой станет полупрозрачным "самостоятельно", то есть под верхней фигурой будет просвечивать нижняя.
Зато Stage гордо именует себя контейнером, хотя не поддерживает половину его свойств.


Часовой пояс GMT +4, время: 12:19.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.