Как сделать так, чтобы классы, не относящиеся к классу документов, «знали» о компонентах сцены во Flash AS3? - PullRequest
0 голосов
/ 03 декабря 2010

Я работаю над текстовой приключенческой игрой, в которой на сцене всегда будет по крайней мере несколько компонентов (текстовая область для повествования и ввода текста для ввода пользователя). Поэтому я создал эти компоненты статически с помощью среды разработки Flash WYSIWYG. Я дал им имена экземпляров "myTA" и "myTI" соответственно. Мне удалось заставить мой основной класс (класс документа для сцены) взаимодействовать с ними (динамически добавлять текст по одному символу за раз, как пишущая машинка во время выполнения), но другие классы в том же пакете, похоже, не способны распознавать сценические составляющие. Ниже приведен соответствующий код:

Случай A, в котором все происходит в основном классе:

package { 
    public class Main extends MovieClip { 
      public var myTA:TextArea; 
      var displayedChar:String = new String(); 
      var textToWrite:String = new String(); 
      var i:int = 0; var intervalId:uint; 
      var done:int = 0; 

      public function Main { 
       setUpTA(); 
      } 

      public function setUpTA(){ 
       myTA.text = "" + playAtInterval("Hello Player!"); 
      }         

      public function writeCharsSlowly(){     
        textToWrite = arguments[0];     
        displayedChar=textToWrite.substring(i,i+1); 
        myTA.appendText(displayedChar);                             
        i++;     
        if (i == textToWrite.length) {         
          done = 1;         
          clearInterval(intervalId);     
        }             
      }                 

      public function playAtInterval(theText:String) {                
        i = 0;              
        intervalId = setInterval(writeCharsSlowly, 100, theText);           
      }  
    } 
}

Случай B, где Main вызывает второй класс TypeWriter для обработки печати на пишущей машинке:

Main:

package { 
    public class Main extends MovieClip { 
      public var myTA:TextArea; 
      public var myTI:TextInput; 
      var str:String = new String(); 

      public function Main{ 
        testTypeWriter(); 
      } 

      public function testTypeWriter(){ 
        typeW.playAtInterval("Hello Player");
        typeW.addEventListener(MouseEvent.CLICK,testTypeWriter2);
        typeW.addEventListener(KeyboardEvent.KEY_DOWN,inputEngine2) 
        addChild(typeW); 
      } 

      public function testTypeWriter2(event:MouseEvent){ 
        if (myTI.text == "a") {   
          typeW.playAtInterval("yo");  
        } else {   
          typeW.playAtInterval("Greetings, I am a test...");  
        }             
        addChild(typeW); 
      } 

      public function inputEngine2(event:KeyboardEvent){ 
        str = String.fromCharCode(event.charCode); 
        myTI.appendText(str); 
      }

TypeWriter:

package { 
    public class TypeWriter extends MovieClip { 
      public var myTI:TextInput; 
      public var myTA:TextArea; 
      var i:int = 0; 
      var done:int = 0; 
      var intervalId:uint; 
      var displayedChar:String = new String(); 
      var textToWrite:String = new String(); 

      public function TypeWriter(){ 
        ///nothing here 
      } 

      public function writeCharsSlowly(){     
        textToWrite = arguments[0];     
        displayedChar = textToWrite.substring(i,i+1);
        myTA.appendText(displayedChar);                             
        i++;     
        if (i == textToWrite.length) {         
          done = 1;         
          clearInterval(intervalId);     
        }             
      }                 

      public function playAtInterval(theText:String) {                
        i = 0;              
        intervalId = setInterval(writeCharsSlowly, 100, theText);           
      }  
    } 
}

Случай A работает, но в случае B Flash выдает ошибку «Ошибка № 1009: не удается получить доступ к свойству или методу пустой ссылки на объект» и отмечает первую строку в TypeWriter, где я пытаюсь работать с myTA, как проблема.

как я могу сделать другие классы, кроме класса документа, "осведомленными" о существующих компонентах этапа?

Спасибо

CCJ

Ответы [ 5 ]

1 голос
/ 03 декабря 2010

Я бы порекомендовал шаблон локатора службы для этого.Самый наивный подход - создать класс ресурсов, который содержит общедоступные статические переменные.Затем в своем классе документов вы назначаете экземпляры рабочей области соответствующей статической переменной в классе ресурсов.Тогда вы можете просто получить доступ к этим компонентам сцены в любом месте.

var someTextArea = Resource.TA; //probably should rename to something more meaningful

Для чего-то более изобретательного, вам следует прочитать статью, на которую я ссылался.

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

РЕДАКТИРОВАТЬ:

Просто чтобы сделатьэто немного яснее, я подумал, что добавлю немного кода:)

Класс ресурса

package
{
    //TODO imports
    public class Resource
    {
        public static var TA:TextArea;
        public static var TI:TextInput;
    }
}

Класс документа

//....setup function
Resource.TA = myTA; //myTA is the name of the instance on stage
Resource.TI = myTI;

класс Foo

Resource.TA.x = 100;
//or
_myClassMemberVariable = Resource.TA;
_myClassMemberVariable.x = 100;
0 голосов
/ 03 декабря 2010

Просто чтобы было ясно.Когда вы пишете сцену, вы на самом деле имеете в виду класс документа для вашего флэш-документа.Этап - это класс, к которому имеет доступ каждый экземпляр, добавленный в список отображения.

Я бы передал текстовые поля в классы, которые должны их обновить.

var tw : Typewriter = new Typewriter();
    tw.inputField = myTI;
    tw.textArea = myTA;

Или

var tw : Typewriter = new Typewriter(myTI, myTA);
0 голосов
/ 03 декабря 2010

Действительно ли myTA и myTI находятся на сцене во время создания или они добавляются динамически?

В первом случае просто добавьте имя экземпляра для каждого.Затем добавьте переменную в каждый класс

var main_mc : Main = root as Main; <p>You can then access the instances via <code>main_mc.myTA и main_mc.myTI (при условии, что это имена экземпляров, которые вы выбрали), и все должно быть типобезопасным.

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

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

Если честно, вы смешиваете свой дисплей с логикой.Читайте о MVC и PureMVC в частности.С хорошим дизайном все может быть обработано сообщениями, и экземплярам не нужны прямые ссылки друг на друга.IIRC, книга Мука по AS3, имеет главу о MVC (но это может быть его книга по AS2).

0 голосов
/ 03 декабря 2010

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

В зависимости от структуры вашей игры, вы можете создать MovieClip с вашими TextFields и связать их с классом Typewriter, или просто создать класс для TextFields и использовать Events для изменения текстового содержимого.

Вы используете внешние классы, поэтому нет смысла хранить какую-либо логику внутри Flash CS.

0 голосов
/ 03 декабря 2010

Я думаю, что некоторые инъекции зависимостей решат эту проблему.Когда вы создаете экземпляр класса Typewriter, передайте ссылки на myTA и myTI.Например:

public function Main{ 
    testTypeWriter(this.myTA, this.myTI); 
} 

Тогда ваш конструктор Typewriter должен выглядеть следующим образом:

public function TypeWriter(ta:TextArea, ti:TextArea){ 
    this.myTA = ta;
    this.myTI = ti;
  } 

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

Редактировать

Некоторая дополнительная информация, которая может помочь вам в будущем: вы можете получить доступ к элементам сцены черезкорневой объект.Но это работает только с объектами, которые были добавлены в список отображения.Допустим, что Typewriter представляет объект в списке отображения, вы можете затем получить доступ к myTA следующим образом:

MovieClip(root).myTA

(Измените MovieClip на Sprite, если это то, что расширяет ваш класс документа).

Однако, поскольку кажется, что Typewriter не добавляется в список отображения, я рекомендую использовать мое первое предложение по внедрению зависимости.

Также проверьте эту страницу , он предполагает использование CasaLib для доступа к сцене из любого объекта.Лично я не пробовал, вот почему это в конце здесь; -)

...