Форум 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=215681)

deepNoise 18.12.2018 05:20

Эффект печати текста
 
Вложений: 1
Нашёл урок по эффекту печати текста на Ютьюбе: https://youtu.be/rjCo0w3u2cg
Помогите усовершенствовать мой исходник.
Мне нужно, чтобы при нажатии клавиши переходило на другой кадр и в поле печатался другой текст.
Я в AS 3.0 плохо разбираюсь, поэтому просто пересоздал функцию и переменные с другими именами(добавил двойку в названия). Может это как то проще можно сделать?
Нужно что то вроде выбора вариантов ответа как в RPG, чтобы при нажатии клавиши A, B, C выбирался определённый вариант ответа и печатался определённый текст.
Так же подскажите, как можно изменить скорость печати текста.

Жень Шень 18.12.2018 17:18

Лучше сделать в одном кадре:
(ждёт нажатия клавиши А,В или С)

Код AS3:

stop();
 
var myStringArray:Array=[];
myStringArray[0]="1 Вариант 1\nПроверка текста\nЕщё проверка текста";
myStringArray[1]="2 Вариант 2\nПроверка текста\nЕщё проверка текста";
myStringArray[2]="3 Вариант 3\nПроверка текста\nЕщё проверка текста";
var myString:String;
var myArray=[];
 
addEventListener(Event.ENTER_FRAME, frameLooper);
 
function frameLooper(event:Event):void {
    if (myArray.length>0) {
        tf.appendText(myArray.shift());
    } else {
        removeEventListener(Event.ENTER_FRAME, frameLooper);
    }
}
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
 
function on_keyDown(e:KeyboardEvent):void {
    removeEventListener(Event.ENTER_FRAME, frameLooper);
    if (e.keyCode==65) {//A
        tf.text="";
        myString=myStringArray[0];
    } else if (e.keyCode == 66) {//B
        tf.text="";
        myString=myStringArray[1];
    } else if (e.keyCode == 67) {//C
        tf.text="";
        myString=myStringArray[2];
    }
    if (e.keyCode==65||e.keyCode==66||e.keyCode==67) {
        myArray=myString.split("");
        addEventListener(Event.ENTER_FRAME, frameLooper);
    }
}


deepNoise 18.12.2018 20:48

Спасибо, всё работает)
А что означает строчка tf.text=""; ? Это для того, чтобы сделать поле пустым?

Я заменил A, B, C на 1, 2, 3, чтобы было проще выбирать.
А возможно как то поместить текстовое поле в отдельный клип, разбить там всё по кадрам, и чтобы в каждом кадре был отдельный текст, который должен печататься при переходе на этот кадр? Т.е. чтобы текст для печати брался не из скрипта, а из самого текстового поля.

И возможно ли изменить скорость печати текста?

Жень Шень 18.12.2018 22:03

1.
tf.text=""; - очищает поле перед выводом нового текста, если нажать другую клавишу (А,В,С или как вы переделали 1…3 или вооще другую).
2.
Код AS3:

function on_keyDown(e:KeyboardEvent):void {
      removeEventListener(Event.ENTER_FRAME, frameLooper);

Здесь removeEventListener нужен по той же причине – остановить обработчик события.
3.
Чтобы текст брался из текстового поля «ИмяТекстовогоПоля», достаточно написать:
Код AS3:

myString = ИмяТекстовогоПоля.text;

4.
Чтобы замедлить скорость печать просто уменьшите fps ролика.

deepNoise 19.12.2018 05:07

Цитата:

Чтобы замедлить скорость печать просто уменьшите fps ролика.
А по другому нельзя как нибудь сделать? Например, можно ли как то событие Event.ENTER_FRAME преобразовать в переменную и вычесть из этой переменной какое нибудь значение?
Т.е. можно ли задать переменную, которая будет равна скорости печати? Например её значение может быть скорость fps минус какое нибудь число?

Bletraut 19.12.2018 13:18

Цитата:

А по другому нельзя как нибудь сделать?
Можно, для этого нужно поставить таймер. Переменная delay это скорость печати в миллисекундах

Код AS3:

stop();
 
var myStringArray:Array=[];
myStringArray[0]="1 Вариант 1\nПроверка текста\nЕщё проверка текста";
myStringArray[1]="2 Вариант 2\nПроверка текста\nЕщё проверка текста";
myStringArray[2]="3 Вариант 3\nПроверка текста\nЕщё проверка текста";
var myString:String;
var myArray=[];
 
var delay:int = 500;
var timer1:Timer = new Timer(delay);
timer1.addEventListener("timer", frameLooper);
timer1.start();
 
function frameLooper(event:TimerEvent):void {
    if (myArray.length>0) {
        tf.appendText(myArray.shift());
    } else {
        timer.stop();
    }
}
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
 
function on_keyDown(e:KeyboardEvent):void {
    timer1.stop();
    if (e.keyCode==65) {//A
        tf.text="";
        myString=myStringArray[0];
    } else if (e.keyCode == 66) {//B
        tf.text="";
        myString=myStringArray[1];
    } else if (e.keyCode == 67) {//C
        tf.text="";
        myString=myStringArray[2];
    }
    if (e.keyCode==65||e.keyCode==66||e.keyCode==67) {
        myArray=myString.split("");
        timer1.start();
    }
}


deepNoise 19.12.2018 15:27

Вложений: 1
Bletraut У меня почему то не работает. Выдаёт ошибку "Обращение несуществующего свойства timer."
Вы это тестили?

Жень Шень
Цитата:

Чтобы текст брался из текстового поля «ИмяТекстовогоПоля», достаточно написать:

Код AS3:

myString = ИмяТекстовогоПоля.text;


Попробовал сделать вот так:
Код AS3:

stop();
 
var myStringArray:Array=[];
//myStringArray[0]="1 Вариант 1\nПроверка текста\nЕщё проверка текста";
//myStringArray[1]="2 Вариант 2\nПроверка текста\nЕщё проверка текста";
//myStringArray[2]="3 Вариант 3\nПроверка текста\nЕщё проверка текста";
var myString:String;
var myArray=[];
 
addEventListener(Event.ENTER_FRAME, frameLooper);
 
function frameLooper(event:Event):void {
    if (myArray.length>0) {
        dialogs.tf.appendText(myArray.shift());
    } else {
        removeEventListener(Event.ENTER_FRAME, frameLooper);
    }
}
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
 
function on_keyDown(e:KeyboardEvent):void {
    removeEventListener(Event.ENTER_FRAME, frameLooper);
    if (e.keyCode==49) {//1
            dialogs.gotoAndStop(1);
        dialogs.tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 50) {//2
            dialogs.gotoAndStop(2);
        dialogs.tf.text="";
        myString=myStringArray[1];
    } else if (e.keyCode == 51) {//3
            dialogs.gotoAndStop(3);
        dialogs.tf.text="";
        myString=dialogs.tf.text;
    }
    if (e.keyCode==49||e.keyCode==50||e.keyCode==51) {
        myArray=myString.split("");
        addEventListener(Event.ENTER_FRAME, frameLooper);
    }
        trace("Код нажатой клавиши: " + e.keyCode);
}

Почему то не работает. Что нужно исправить?

Жень Шень 19.12.2018 23:56

Вложений: 1
textTypingEffect - пример с ENTER_FRAME.
textTypingEffect2 - пример с таймером.
Не понял, для чего брать текст с кадров клипа и печатать в режиме машинки в другое текстовое поле.
В примерах просто показал как брать с текстового поля и "посылать на печать" в другое текстовое поле.
Советую чётко продумать структуры своего шедевра: цель, последовательность действий программы и пользователя, итог работы кода и т.д.
Успеха.

deepNoise 20.12.2018 01:57

Цитата:

Не понял, для чего брать текст с кадров клипа и печатать в режиме машинки в другое текстовое поле.
Я хотел не с одного поля в другое, а просто одно поле, в которое напечатать текст вручную в исходнике, и он появится с эффектом печати при запуске мувика) В поле печатать, чтобы было нагляднее, сразу был виден результат.
Хотя и так тоже сойдёт, просто можно поле из которого берётся текст за экран поставить.
А для чего можно использовать: можно сделать просто тест с эффектом печати, или интерактивную новеллу, или RPG с диалогами, да много чего)

Последний вопрос: переменная delay ведь отвечает за скорость? Я пытался изменить её для установления скорости печати для каждого варианта, но скорость почему то не меняется.

Код AS3:

stop();
var myString:String;
var myArray=[];
var delay:int = 100; //typing speed
var timer1:Timer = new Timer(delay);
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
timer1.addEventListener("timer", frameLooper);
 
timer1.start();
 
function frameLooper(event:TimerEvent):void {
    if (myArray.length>0) {
        answer_tf.appendText(myArray.shift());
    } else {
        timer1.stop();
    }
}
 
function on_keyDown(e:KeyboardEvent):void {
        timer1.stop();
    if (e.keyCode==49) {//1
            delay = 10;
            dialogs.gotoAndStop(1);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 50) {//2
            delay = 50;
            dialogs.gotoAndStop(2);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 51) {//3
            delay = 100;
            dialogs.gotoAndStop(3);
        answer_tf.text="";
        myString=dialogs.tf.text;
    }
    if (e.keyCode==49||e.keyCode==50||e.keyCode==51) {
        myArray=myString.split("");
        timer1.start();
 
    }
}


Swer 20.12.2018 11:36

Код AS3:

if (e.keyCode==49||e.keyCode==50||e.keyCode==51) {
        myArray=myString.split("");
        timer1.delay = delay;
        timer1.start();
 
 }


Жень Шень 20.12.2018 14:29

Цитата:

Сообщение от deepNoise (Сообщение 1206215)
Я хотел не с одного поля в другое, а просто одно поле, в которое напечатать текст вручную в исходнике, и он появится с эффектом печати при запуске мувика)

После компиляции это будет стринговая константа - те же яйца, только в профиль, то есть первый вариант с массивом.
Может надо (я вангую) вопрос и на него печатать ответ, то это надо организовать два массива: один с вопросами, другой с ответами. По одному индексу выбирать вопрос/ответ. Где-то так. Но это вам решать.

deepNoise 30.12.2018 06:39

Вложений: 1
Подскажите как сделать, чтобы текст из поля печатался со всеми переносами строк? А то сейчас он печатается в одну строку без переносов.

Код AS3:

stop();
var myString:String;
var myArray=[];
var delay:int = 100;
var timer1:Timer = new Timer(delay);
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
timer1.addEventListener("timer", frameLooper);
 
timer1.start();
 
function frameLooper(event:TimerEvent):void {
    if (myArray.length>0) {
        answer_tf.appendText(myArray.shift());
    } else {
        timer1.stop();
    }
}
 
function on_keyDown(e:KeyboardEvent):void {
        timer1.stop();
    if (e.keyCode==49) {//1
            delay=20; //скорость печати
            dialogs.gotoAndStop(1);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 50) {//2
            delay=20; //скорость печати
            dialogs.gotoAndStop(2);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 51) {//3
            delay=20; //скорость печати
            dialogs.gotoAndStop(3);
        answer_tf.text="";
        myString=dialogs.tf.text;
        } else if (e.keyCode == 52) {//4
            delay=20; //скорость печати
            dialogs.gotoAndStop(4);
        answer_tf.text="";
        myString=dialogs.tf.text;
    }
    if (e.keyCode==49||e.keyCode==50||e.keyCode==51||e.keyCode==52) {
        myArray=myString.split("");
                timer1.delay = delay;
        timer1.start();
    }
}


Swer 30.12.2018 19:22

Код AS3:

//answer_tf.width  = 500; 
//answer_tf.height = 500; 
answer_tf.wordWrap = true; // перенос по словам - если нужно
answer_tf.multiline  = true;

Еще можно знак "\n" в тексте ставить.
Код AS3:

answer_tf.appendText( "Hellow \n world" );


deepNoise 30.12.2018 23:24

Код AS3:

answer_tf.wordWrap = true; // перенос по словам - если нужно
answer_tf.multiline  = true;

А куда именно это нужно поставить?
Пробовал после answer_tf.appendText(myArray.shift()); ставить и в функцию нажатия клавиши, но почему то текст продолжает печататься без переносов.
А способ с \n наверно подходит только, если текст берётся из скрипта, а не из текстового поля.

Swer 31.12.2018 09:08

Можно попробовать так :
- кликаешь на нужное текстовое окно
- справа сверху есть ярлыки properties и library - выбираешь properties
- ищешь paragraph там есть поле behavior - устанавливаешь multiline.
У меня работает.

Мне кажется сначала надо продумать структуру, я не читал но может быть тебе поможет -
http://www.flasher.ru/forum/blog.php?b=691

Наверное переменная myArray лишняя.
Код AS3:

stop();
var myString:String = "";
var delay:int = 100;
var timer1:Timer = new Timer(delay);
var nextCharIndex:int = 0;
var lengthString:int = 0;
 
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
timer1.addEventListener("timer", frameLooper);
 
timer1.start();
 
function frameLooper(event:TimerEvent):void {
    if ( nextCharIndex < lengthString ) {
        answer_tf.appendText( myString.charAt( nextCharIndex ) );
                ++nextCharIndex;
    } else {
        timer1.stop();
    }
}
 
function on_keyDown(e:KeyboardEvent):void {
        timer1.stop();
    if (e.keyCode==49) {//1
            delay=20; //скорость печати
            dialogs.gotoAndStop(1);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 50) {//2
            delay=20; //скорость печати
            dialogs.gotoAndStop(2);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 51) {//3
            delay=20; //скорость печати
            dialogs.gotoAndStop(3);
        answer_tf.text="";
        myString=dialogs.tf.text;
        } else if (e.keyCode == 52) {//4
            delay=20; //скорость печати
            dialogs.gotoAndStop(4);
        answer_tf.text="";
        myString=dialogs.tf.text;
    }
    if (e.keyCode==49||e.keyCode==50||e.keyCode==51||e.keyCode==52) {
                nextCharIndex = 0;
                lengthString = myString.length;
                timer1.delay = delay;
        timer1.start();
    }
}


deepNoise 31.12.2018 15:04

Цитата:

Мне кажется сначала надо продумать структуру, я не читал но может быть тебе поможет -
http://www.flasher.ru/forum/blog.php?b=691
Я в AS 3.0 то почти не разбираюсь, а тут ещё какое то XML. Почитал, не понял что такое id в каждой строке и lock="false".
Да и варианты ответа у меня нужно выбирать именно нажатием клавиши, а не мышью, а то бы я просто много кнопок наделал да и всё)
Думаю попробую сделать через переменные и if.

Жень Шень 31.12.2018 21:49

Цитата:

Сообщение от deepNoise (Сообщение 1206239)
А куда именно это нужно поставить?

Никуда ничего не надо вставлять. Просто надо "отловить" символ переноса строки 13 и вместо него подсунуть стринг "\n". Вот весь код первого кадра:
Код AS3:

stop();
var myString:String;
var myArray=[];
var delay:int=100;
var timer1:Timer=new Timer(delay);
var first_symbol:String;
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
timer1.addEventListener("timer", frameLooper);
 
timer1.start();
 
function frameLooper(event:TimerEvent):void {
    if (myArray.length>0) {
        first_symbol=myArray.shift();
        //trace(first_symbol, first_symbol.charCodeAt());
        if (first_symbol.charCodeAt() == 13){
            answer_tf.appendText("\n");
        } else {
            answer_tf.appendText(first_symbol);
        }
    } else {
        timer1.stop();
    }
}
 
function on_keyDown(e:KeyboardEvent):void {
    timer1.stop();
    if (e.keyCode==49) {//1
        delay=20;//скорость печати
        dialogs.gotoAndStop(1);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 50) {//2
        delay=20;//скорость печати
        dialogs.gotoAndStop(2);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 51) {//3
        delay=20;//скорость печати
        dialogs.gotoAndStop(3);
        answer_tf.text="";
        myString=dialogs.tf.text;
    } else if (e.keyCode == 52) {//4
        delay=20;//скорость печати
        dialogs.gotoAndStop(4);
        answer_tf.text="";
        myString=dialogs.tf.text;
    }
    if (e.keyCode==49||e.keyCode==50||e.keyCode==51||e.keyCode==52) {
        myArray=myString.split("");
        timer1.delay=delay;
        timer1.start();
    }
}

Обрати внимание на новую переменную first_symbol. Это и есть очередной допечатываемый символ. Вот его и анализирует
Код AS3:

if (first_symbol.charCodeAt() == 13){
...


Swer 01.01.2019 19:35

Цитата:

Сообщение от Жень Шень (Сообщение 1206248)
Просто надо "отловить" символ переноса строки

Если символ переноса есть в тексте, то почему он не применяется ?

Жень Шень 02.01.2019 01:13

Символ "Возврат каретки" имеет ASCII код 13.
Метод appendText(newText:String) добавляет строку, указанную параметром newText, в конец текста в текстовом поле. То есть по сути ничего не добавит в случае с символом ASCII 13. Надо сделать ещё "Перевод каретки" - ASCII код 10.
А этот код:

Код AS3:

answer_tf.appendText("\n");

можно заменить таким кодом:
Код AS3:

answer_tf.appendText(String.fromCharCode(10));

Всё бы прекрасно работало без всех этих премудростей (я про метод appendText и "ловлю" переноса строки, если был бы такой код:
Код AS3:

answer_tf.text = answer_tf.text + first_symbol;

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

Swer 02.01.2019 09:45

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

answer_tf.text = "";
answer_tf.appendText( myString );

Наверное проблема именно в посимвольной передачи.

Жень Шень 02.01.2019 11:37

Мне кажется дело в методе appendText. Он обрабатывает стринговый аргумент и стыкует его к уже имеющемуся тексту. Когда же ему скармливают символ "Возврат каретки", то он его внутри себя выполняет и в результате получается пустая строка. Когда же методу передают строковую переменную с символом 13 внутри текста, то он таки делает перенос строки, по сути вставляя и "возврат каретки" и "перевод каретки".
Попробуйте "допечатывать" по два символа за раз и код символа 13 не пропадает!
Другого объяснения не могу дать. Может гуру флеша прольют свет на сие.

RedHead90 02.01.2019 12:50

Что-то вы тут перемудрили.
1. Зачем таймер стартует сразу же, если при первом же срабатывании он останавливается?
2. Зачем таймер останавливается в начале слушателя on_keyDown? (попробуйте нажать любую не назначенную клавишу во время анимации печати)
3. Опять же, к чему эта копи-паста внутри if else if? К тому же в конце проверка кода клавиши дублируется. У вас на 4 кнопки одно действие, значит и проверка должна быть только одна.


Я бы сделал как-то так

Код AS3:

import flash.ui.Keyboard;
 
stop();
 
var keysMap:Object = {}; //код клавиши : номер кадра;
keysMap[Keyboard.NUMBER_1] = 1;
keysMap[Keyboard.NUMBER_2] = 2;
keysMap[Keyboard.NUMBER_3] = 3;
keysMap[Keyboard.NUMBER_4] = 4;
 
var timer1:Timer=new Timer(20);
timer1.addEventListener(TimerEvent.TIMER, frameLooper);
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
 
var text:String = "";
var currentSymbol:int = 0;
var pattern:RegExp = new RegExp(String.fromCharCode(13), "g"); //регулярка, ищущая все возвраты каретки в строке
var repl:String = String.fromCharCode(10); //символ переноса \n
 
function frameLooper(event:TimerEvent):void {
    if (currentSymbol < text.length) {
        answer_tf.appendText(text.charAt(currentSymbol++));
    } else {
        timer1.stop();
    }
}
 
function on_keyDown(e:KeyboardEvent):void {
        if (keysMap.hasOwnProperty(e.keyCode)) {
                answer_tf.text="";
                dialogs.gotoAndStop(keysMap[e.keyCode]);
                text = dialogs.tf.text.replace(pattern, repl);
                currentSymbol = 0;
        timer1.start();
        }
}

А вообще это все баловство и ничего вменяемого с таким подходом не получиться.

Жень Шень 02.01.2019 13:56

По первому пункту - в начальной версии у автора печатался какой-то текст (не помню уже что, но типа "нажмите клавишу А,B,C,D). Так и остался старт таймера. Замечание принимается.
По второму пункту - тоже принимается замечание. В моей редакции просто проверку на используемые клавиши надо перенести повыше и удалить повторяющий код. Результат должен быть таким:
Код AS3:

function on_keyDown(e:KeyboardEvent):void {
    if (e.keyCode==49||e.keyCode==50||e.keyCode==51||e.keyCode==52) {
        timer1.stop();
        if (e.keyCode==49) {
            delay=10;
            dialogs.gotoAndStop(1);
        } else if (e.keyCode == 50) {
            delay=15;
            dialogs.gotoAndStop(2);
        } else if (e.keyCode == 51) {
            delay=20;
            dialogs.gotoAndStop(3);
        } else if (e.keyCode == 52) {
            delay=25;
            dialogs.gotoAndStop(4);
        }
        answer_tf.text="";
        myString=dialogs.tf.text;
        myArray=myString.split("");
        timer1.delay=delay;
        timer1.start();
    }
}

По-третьему пункту - автор хотел чтобы скорость таймера была разной в зависимости от нажатой клавиши (delay=20;//скорость печати). Просто в последних редакций кода на этом не заостряли внимание и delay была одинаковой. Поэтому был оставлен ранее используемый блок "if else if". В вашем случае к объекту keysMap надо добавить ещё одно свойство и устанавливать delay для каждой из назначенных клавиш.
В целом ваши замечания правильные и рациональны, но учитывая, что автор в АС3 плохо ещё разбирается, то логика работы "его замыслов" для него более понятна в данном изложении. Впрочем это ему судить и принимать решение. :umnik2:

RedHead90 02.01.2019 15:16

@Жень Шень, то, что автор плохо разбирается как раз и стало причиной, почему я "докопался" до его кода. Лучше уж сразу указать на эти типичные ошибки, чтобы в будущем ему было проще обходить такие грабли стороной.

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

Ну и по поводу
Цитата:

Сообщение от Жень Шень (Сообщение 1206256)
удалить повторяющий код.

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

Код:

если (нажата нужная клавиша) {
    изменить задержку;
    перейти в соответствующий кадр.
} иначе если (нажата другая нужная клавиша) {
    изменить задержку;
    перейти в соответствующий кадр.
} иначе если (нажата другая нужная клавиша) {
    изменить задержку;
    перейти в соответствующий кадр.
} иначе если (нажата другая нужная клавиша) {
    изменить задержку;
    перейти в соответствующий кадр.
}

Повторение на лицо. А если вариантов будет не 4, а хотя бы 10? Тут каждый блок выполняет одну и туже функцию, а-ля
Код:

setDelayAndFrame(delay:Int, frame:Int):Void;
поэтому можно и нужно избавляться от всей этой кучи проверок.

Лучше уж, как ты и заметил, держать все это дело в keysMap
Код AS3:

keysMap[Keyboard.NUMBER_1] = {frame:1, delay:20};

Код AS3:

dialogs.gotoAndStop(keysMap[e.keyCode]['frame']);
timer1.delay = keysMap[e.keyCode]['delay'];


Жень Шень 02.01.2019 19:14

@RedHead90, повторюсь: "замечания правильные и рациональны". Осталось автору досконально разобраться с объектом, ну и заодно с регуляркой. Лично я вник и воспользовался ей на втором году пользования АС. Регулярные выражения удобная вещь, недаром им посвящены целые книги.:D:rtfm:

deepNoise 04.01.2019 17:33

Код AS3:

import flash.ui.Keyboard;
 
stop();
 
var keysMap:Object = {};//код клавиши : номер кадра;
keysMap[Keyboard.NUMBER_1] = 1;
keysMap[Keyboard.NUMBER_2] = 2;
keysMap[Keyboard.NUMBER_3] = 3;
keysMap[Keyboard.NUMBER_4] = 4;
 
var timer1:Timer = new Timer(delay);
timer1.addEventListener(TimerEvent.TIMER, frameLooper);
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, on_keyDown);
 
var text:String = "";
var currentSymbol:int = 0;
var pattern:RegExp = new RegExp(String.fromCharCode(13),"g");//регулярка, ищущая все возвраты каретки в строке
var repl:String = String.fromCharCode(10);//символ переноса \n
var way = "1";//переменная порядка ветки событий
var wayX = way;//переменная текущего значения ветки
var delay:int = 100; //скорость печати
 
 
timer1.start();
 
function frameLooper(event:TimerEvent):void
{
        if (currentSymbol < text.length)
        {
                answer_tf.appendText(text.charAt(currentSymbol++));
        }
        else
        {
                timer1.stop();
        }
}
 
function on_keyDown(e:KeyboardEvent):void
{
                if (way == wayX)
        {//назначения порядкого номера ветки событий
                if (e.keyCode == 49)
                {//1
                        way = wayX+"-1";
                }
                else if (e.keyCode == 50)
                {//2
                        way = wayX+"-2";
                }
                else if (e.keyCode == 51)
                {//3
                        way = wayX+"-3";
                }
                else if (e.keyCode == 52)
                {//4
                        way = wayX+"-4";
                }
                wayX=way;
                trace("way="+way);
        }
 
        if(way == "1-1"){
                delay=20;
        }else if(way == "1-2"){
                delay=40;
        }else if(way == "1-3"){
                delay=60;
        }else if(way == "1-4"){
                delay=80;
        }
 
        if (keysMap.hasOwnProperty(e.keyCode))
        {
                answer_tf.text = "";
                way1.gotoAndStop(keysMap[e.keyCode]);
                text = way1.tf.text.replace(pattern,repl);
                currentSymbol = 0;
                timer1.delay = delay;
                timer1.start();
        }
 
}

В общем я задал переменную way, которая отслеживает текущую ветку события в игре.
Для каждой ветки я задал свою скорость печати.
Клип dialogs переименовал в way1. Теперь буду плодить клипы с названиями текущих веток событий:
way1-1, way1-2, way1-3 и т.д., в которых будут по кадрам выставлены варианты для переходов к последующим веткам. Таким образом собираюсь сделать разветвлённую сеть дерева событий для игры.

Сейчас скорость печати задаётся конкретно для каждой ветки. А можно как то задать скорость печати и время паузы с помощью символов в тексте, как это делалось ранее для переносов символом /n? Например, если будет написано:
Цитата:

/sВы пошли налево./speed=40/pause=1,5 /sКуда теперь?/speed=20

/s1. Пойти налево. 3. Пойти вверх.
2. Пойти направо. 4. Пойти вниз. /speed=0
то это будет означать, что "Вы пошли налево" будет печататься с delay=40, "Куда теперь?" c delay=20, а после "Вы пошли налево" будет пауза 1,5 секунды.

"1. Пойти налево. 3. Пойти вверх. 2. Пойти направо. 4. Пойти вниз." соответственно будут печататься без задержки, то есть моментально. Как это можно реализовать?

RedHead90 04.01.2019 20:18

@deepNoise,
1. Тебе нужно написать парсер строк. В кадрах такие вещи не делают.
2. Тебе нужна вменяемая система, управляющая вариантами дейтсвий. Сейчас все построено так, что для каждого вопроса должно быть задано 4 варианта ответов - ни больше ни меньше. Захочешь сделать больше или меньше и все сразу пойдет по... В общем, в кадрах такие вещи не делают.
3. Брать текст из клипов - это вообще бред. И это бред вдвойне, учитывая, что сами клипы вообще по сути не используются.
4. Даже для самого простейшего текстового квеста тебе нужно иметь хотя бы начальный багаж знаний в используемом языке и ООП. С наскоку такие вещи не делают. Прочти хотя бы руководство по AS3 Колина Мука. После него и сам язык поймешь и в ООП вникнешь и тебе уже не захочется возвращаться к коду в кадрах. Даже учитывая то, что flash похоронили (это не точно), AS3 как ЯП очень хорош для новичков. После него легко сможешь изучить любой другой ООП язык.


P.S. Чисто из спортивного интереса на коленке набросал, но далее развиваться тем же путем не рекомендую
Код AS3:

 
var SPEED_TAG:String = 'speed';
var PAUSE_TAG:String = 'pause';
 
var pauseTimer:Timer=new Timer(20, 1);
pauseTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onPauseComplete);
 
function frameLooper(event:TimerEvent = null):void {
    if (currentSymbol < text.length) {
                var tag:Array = getTag(text, currentSymbol);
 
                while (tag != null) {
                        execTag(tag);
                        currentSymbol += tag[2];
                        tag = getTag(text, currentSymbol);
                }
 
                var symbol:String = text.charAt(currentSymbol++);
        answer_tf.appendText(symbol);
 
                //тупо костыль, вызывающий слушатель frameLooper повторно, если текст надо вывести без задержек
                if (timer1.delay == 0) {
                        frameLooper();
                }
 
    } else {
        timer1.stop();
    }
}
 
function onPauseComplete(event:TimerEvent):void {
        if (currentSymbol < text.length) {
                timer1.start();
        }
}
 
//если в указанной позиции установлен тэг, вернет массив [имя тэга, значение, кол-во непечатаемых символов]
//массив передается как есть в метод execTag
//если тэга в позиции нет, вернет null
function getTag(text:String, pos:int):Array {
        if (text.charAt(pos) == '<') {
                var endIdx:int = text.indexOf('/>', pos);
                var tag:String = text.substring(pos + 1, endIdx);
                var tagLenght:int = tag.length + 3;
                var removeWhitespacesRex:RegExp =  /[\s\r\n\u00A0]+/gim;//регулярка для удаления всего лишнего из строки тега(пробелы, переносы)
                tag = tag.replace(removeWhitespacesRex, '');
                var result:Array = tag.split('=');
                result.push(tagLenght);
                return result;
        }
        return null;
}
 
 
function execTag(tag:Array):void {
        switch (tag[0]) {
                case SPEED_TAG : {
                        timer1.delay = tag[1];
                        break;
                }
                case PAUSE_TAG : {
                        timer1.stop();
                        pauseTimer.delay = tag[1];
                        pauseTimer.start();
                        break;
                }
                default : throw 'Неизвестный тэг ' + tag[0];
        }
}

Строки должны быть такого вида:

<speed=40/>Вы пошли налево.<pause=1500/><speed=20/> Куда теперь?<speed=0/>
1. Пойти налево. 3. Пойти вверх.
2. Пойти направо. 4. Пойти вниз.

deepNoise 04.01.2019 22:45

Вложений: 1
Цитата:

Тебе нужно написать парсер строк. В кадрах такие вещи не делают.
Я даже не знаю, что это такое) Зачем делать по другому, если всё работает?
Цитата:

Сейчас все построено так, что для каждого вопроса должно быть задано 4 варианта ответов - ни больше ни меньше.
Я просто добавил keysMap[Keyboard.NUMBER_5] = 5; и ещё один кадр в клипе, получилось уже пять вариантов ответов.
Цитата:

Брать текст из клипов - это вообще бред. И это бред вдвойне, учитывая, что сами клипы вообще по сути не используются.
Ну, эти клипы будут ещё содержать картинки и анимации. А по кадрам разбито, чтобы было легче ориентироваться.
Цитата:

Даже для самого простейшего текстового квеста тебе нужно иметь хотя бы начальный багаж знаний в используемом языке и ООП.
Я раньше изучал AS2.0, но после его перехода на версию 3.0 для меня это стал тёмный лес. Изучать заново и перестраиваться под новую версию уже не было ни желания ни времени. А основы я знаю, иначе как бы я понимал переменные и условия с if)

Цитата:

Чисто из спортивного интереса на коленке набросал
Спасибо, всё работает)
Теперь у меня вопрос, можно ли задать имя клипа с помощью значения переменной?
То есть есть такая строка:
Код AS3:

way1.gotoAndStop(keysMap[e.keyCode]);

И нужно, чтобы вместо way1 стояло значение переменной way. По логике это должно выглядеть как то так:
Код AS3:

("way"+way).gotoAndStop(keysMap[e.keyCode]);

но видимо это неправильное выражение.

RedHead90 05.01.2019 00:47

Цитата:

Сообщение от deepNoise (Сообщение 1206268)
Зачем делать по другому, если всё работает?

А зачем люди придумали канализацию, если и кусты неплохо работают? Зачем ты вообще на AS3 перешел, если всё это и на AS2 можно реализовать?

Цитата:

Сообщение от deepNoise (Сообщение 1206268)
Я просто добавил keysMap[Keyboard.NUMBER_5] = 5; и ещё один кадр в клипе, получилось уже пять вариантов ответов.

А с теми клипами, где 4 варианта что теперь будет? Они же тоже станут реагировать на нажатие 5-ки, но 5-го кадра у них нет.

Цитата:

Сообщение от deepNoise (Сообщение 1206268)
А основы я знаю, иначе как бы я понимал переменные и условия с if)

Ничего ты не знаешь, Джон Сноу deepNoise. Переменные и условия - это даже не вершина айсберга. Если бы ты знал основы, то этой темы не существовало бы. Без желания учиться и перестраиваться ты далеко не уедешь. Сейчас, пока ты ставишь перед собой простые задачи, ты можешь прийти на форум и дождаться, когда тебе дадут готовое решение, чтобы тупо скопировать его в свой проект, даже не понимая в итоге до конца, как вся эта копи-паста работает. Дальше ты захочешь сделать что-то более сложное и интересное, но на форумах тебе уже никто не поможет, потому-что никто не будет тратить свои силы и время на такие вещи.

Цитата:

Сообщение от deepNoise (Сообщение 1206268)
можно ли задать имя клипа с помощью значения переменной?

https://help.adobe.com/ru_RU/FlashPl...tChildByName()

deepNoise 07.01.2019 02:07

Почитал справку и ничего не понял. Кажется там о том, как создавать дочерние и родительские клипы, но не как создать имя клипа с переменной.
Попробовал так:
Код AS3:

var wayClip:MovieClip = new MovieClip();
wayClip.name = 'way'+way;
 
wayClip.gotoAndStop(keysMap[e.keyCode]);
text = wayClip.tf.text.replace(pattern,repl);

Выдаёт такую ошибку:
Цитата:

TypeError: Error #1010: Термин не определен и не имеет свойств.
at textQuestV2_fla::MainTimeline/on_keyDown()
Как сделать правильно?

Bletraut 07.01.2019 14:07

Цитата:

Сообщение от deepNoise (Сообщение 1206270)
Почитал справку и ничего не понял. Кажется там о том, как создавать дочерние и родительские клипы, но не как создать имя клипа с переменной.
Попробовал так:
Код AS3:

var wayClip:MovieClip = new MovieClip();
wayClip.name = 'way'+way;
 
wayClip.gotoAndStop(keysMap[e.keyCode]);
text = wayClip.tf.text.replace(pattern,repl);

Выдаёт такую ошибку:
Как сделать правильно?

Данная ошибка в этом коде не может возникнуть, проблема в функции on_keyDown(), предположительно wayClip не добавлен в список отображения

Swer 07.01.2019 17:54

Чтобы достать свой MovieClip из библиотеки, его нужно создать. Чтобы создать нужно присвоить ему имя класса,
потом можно поместить в список отображения.
Когда назначишь имя класса можно его создать так
Код AS3:

var nameClass = "way"+way;
var mc:MovieClip = new (getDefinitionByName( nameClass ) as Class)();
addChild( mc );

Но лучше сделать функцию
Код AS3:

//var wayClip:MovieClip = getWayByIndex( way );
//addChild( wayClip );
function getWayByIndex( n:int ):MovieClip{
        var mc:MovieClip;
        switch( n ){
                case( 0 ):  mc = new Way();    break;
                case( 1 ):  mc = new Way1();  break;
                case( 2 ):  mc = new Way2();  break;
                case( 3 ):  mc = new Way3();  break;
                case( 4 ):  mc = new Way4();  break;
                default:    mc = new Way();    break;
        }
        return mc;
}

В этом видео показано присвоение класса MovieClip'у в библиотеке
https://www.youtube.com/watch?time_c...&v=e0tLVbAvDew

deepNoise 08.01.2019 01:20

Цитата:

Чтобы достать свой MovieClip из библиотеки, его нужно создать.
Я совсем забыл, что клип со следующими вариантами действий нужно ещё загрузить на сцену. В AS 2.0 была какая то команда, которая грузила клип из библиотеки в клип на сцене, кажется называлась loadMovieClip. А как это сделать в AS 3.0? Посмотрел в хелпе, не нашёл ничего напоминающего loadMovieClip.
addChild() судя по уроку просто создаёт экземпляр клипа на сцене. Это не совсем то, что нужно. Если делать так, то придётся ещё как то удалять старый клип с прошлыми вариантами ответов.
Как загрузить клип из библиотеки в клип на сцене в AS 3.0?

Swer Я попробовал скопипастить твою функцию, у меня выдаёт ошибку "вызов предположительно неопределённого метода Way1, 2, 3...".

Наверно нужно ещё раз прояснить, что я пытаюсь сделать, чтобы не было вопросов) У меня в библиотеке будут клипы с именами way1-1, way1-2, way 1-3 и т.д., в каждом из которых будут по четыре кадра с четырьмя(или более) вариантами действий. Число после "way" в названии клипа означает порядковый номер ветки событий в игре, которому соответствует переменная way.
В клипе way1 есть четыре варианта действий. При выборе каждого варианта должен грузится клип way1-1, way1-2, way1-3 или way1-4 соответственно. Новый клип должен заменить way1, когда закончится печататься текст выбранного варианта действия.
Затем в way1-1 будут ещё четыре варианта действий, которые будут грузить клипы way1-1-1, way1-1-2, way1-1-3, way1-1-4 соответственно, и т.д. с другими ветками и вариантами.
Поэтому я и пытаюсь сделать имя клипа из "way" и переменной way, чтобы получить универсальное имя для загрузки следующего клипа и действий с текущим.

Swer 08.01.2019 15:43

Где-то спрашивали - "как в as3 достать MovieClip из библиотеки ", если не ошибаюсь ответ был примерно таким - " as3 это не as2 достать MovieClip по имени не получиться, только через присвоение класса этому MovieClip ".
Система диалогов по моему это сложная штука, поэтому без классов не обойтись.
У тебя непонятная структура, к примеру я сейчас на ветке 1-2-5-4-3, нажал 4 значит я должен попасть на
1-2-5-4-3-4 . Но если добавить условие , допустим я нажал 4 - это значит я выбрал "перепрыгнуть через яму"
, проверяется моя удача - если удачлив - один путь, если нет - другой . Как ты это сделаешь ?
Наверное должен быть класс, который содержит текст - описание, картинку или анимацию, массив ответов и
функцию, которая обрабатывает выбранный ответ.

ZackMercury 08.01.2019 16:21

Цитата:

addChild() судя по уроку просто создаёт экземпляр клипа на сцене.
Ошибочное предположение, он ничего не создаёт.
Цитата:

В AS 2.0
Там много чего было, однако языки совершенно разные, непохожие друг на друга, так и структура.
AS2 был чем-то вроде примитивного инструмента для расширения задач анимации, вроде GML в гейм-мейкере.
AS3 - это уже полноценный, более-менее современный высокоуровневый объектно-ориентированный язык программирования, который устроен иначе и который нужно изучать с нуля, начиная с основ ООП и программирования в целом, а не делая предположения и сравнивая его с игрушкой, от задач которой он изошёл. Здесь всё гораздо серьёзнее.

Swer 08.01.2019 20:19

Вложений: 1
Написал небольшой пример с классами, разобраться сложно, но это лучше чем ничего.:)

deepNoise 08.01.2019 20:39

Цитата:

У тебя непонятная структура, к примеру я сейчас на ветке 1-2-5-4-3, нажал 4 значит я должен попасть на
1-2-5-4-3-4 . Но если добавить условие , допустим я нажал 4 - это значит я выбрал "перепрыгнуть через яму"
, проверяется моя удача - если удачлив - один путь, если нет - другой . Как ты это сделаешь ?
Ну у меня же будет не РПГ, а скорее интерактивная новелла со множеством ответвлений) Никакой удачи там проверятся не будет, просто на одно действие один результат.

Цитата:

Написал небольшой пример с классами, разобраться сложно, но это лучше чем ничего.
Да, что то уж слишком всё сложно и непонятно. Все скрипты теперь вне основного файла, и в них полно выражений, которых я не знаю. Наверно зря я взялся за AS 3.0, надо было пробовать в AS 2.0. Правда тогда придётся думать, как сделать эффект печати в этой версии скриптов.
Вот бы такую программу, где можно было бы просто написать все варианты действий и их результаты, а не копаться в коде. Что нибудь вроде конструктора диалоговой системы. Если кто нибудь знает такую программу, посоветуйте, а то я совсем запутался.
Может стоит гейм-мейкер попробовать, попроще будет. Но всё равно опять придётся учится.

Swer 08.01.2019 20:55

Вроде как в Rpg Maker есть диалоговая система, но я не уверен - не использовал.
Первый попавшийся пример -https://www.youtube.com/watch?v=d5WyKWLVloM


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

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