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

Suntea 20.05.2013 21:47

Анимация персонажа при управлении
 
Вложений: 1
Добрый день!

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

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

Код AS3:

package AS {
 
        import flash.display.MovieClip;
        import flash.events.KeyboardEvent;
        import flash.events.Event;
 
 
        public class Hero extends MovieClip {
 
                private var moveUp:Boolean;
                private var moveDown:Boolean;
                private var moveLeft:Boolean;
                private var moveRight:Boolean;
 
                private var moveUpFlag:Boolean;
                private var moveDownFlag:Boolean;
                private var moveLeftFlag:Boolean;
                private var moveRightFlag:Boolean;
 
                private var moveSpeed:uint;
 
                public function Hero() {
                        moveUp=false;
                        moveRight=false;
                        moveLeft=false;
                        moveDown=false;
 
                        moveSpeed=4;
 
                        Constants.stageRef.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedListener);
                        Constants.stageRef.addEventListener(KeyboardEvent.KEY_UP, keyReleasedListener);
                        Constants.stageRef.addEventListener(Event.ENTER_FRAME, frameListener);
 
                }
 
                private function keyPressedListener(e:KeyboardEvent){
                        var key:uint=e.keyCode;
                        if(key==87||key==38){//W or UP key
                                this.gotoAndPlay("goUp")
                                moveUp=true;                               
                        }else if(key==65||key==37){//A or LEFT key
                                this.gotoAndPlay("goLeft")
                                moveLeft=true;                               
                        }else if(key==83||key==40){//S or DOWN key
                                this.gotoAndPlay("goDown")
                                moveDown=true;                               
                        }else if(key==68||key==39){//D or RIGHT
                                this.gotoAndPlay("goRight")
                                moveRight=true;                               
                        }
 
                }
 
                private function keyReleasedListener(e:KeyboardEvent){
                        var key:uint=e.keyCode;
                        if(key==87||key==38){//W or UP key
                                this.gotoAndStop("goUp")
                                moveUp=false;
                        }else if(key==65||key==37){//A or LEFT key
                                this.gotoAndStop("goLeft")
                                moveLeft=false;
                        }else if(key==83||key==40){//S or DOWN key       
                                this.gotoAndStop("goDown")
                                moveDown=false;
                        }else if(key==68||key==39){//D or RIGHT
                                this.gotoAndStop("goRight")
                                moveRight=false;
                        }
                }
 
                private function frameListener(e:Event){
                        if(moveUp){
                                this.y-=moveSpeed;
 
                        }else if(moveLeft){
                                this.x-=moveSpeed;
 
                        }else if(moveDown){
                                this.y+=moveSpeed;
 
 
                        }else if(moveRight){
                                this.x+=moveSpeed;
 
                        }
                }
        }
 
}


Koopa 20.05.2013 22:19

То что класс наследуется от MovieClip не означает что он будет отображаться.
Либо класс не полный, либо вы хитрите.

Suntea 20.05.2013 22:23

А, что? То есть хитрю?

Koopa 20.05.2013 22:33

Класс расположен где?
P.S.Независим или в кадре?
P.S.S.Даже немного не так. Класс "привязан" к муви, а клип отображается в определённых кадрах?

FlashWizard 20.05.2013 22:41

Цитата:

Класс расположен где?
P.S.Независим или в кадре?
Koopa, как интересно вы расположите класс в кадре?

Koopa 20.05.2013 22:42

Цитата:

Сообщение от FlashWizard (Сообщение 1134087)
Koopa, как интересно вы расположите класс в кадре?

легко
Другой вопрос, зачем.

FlashWizard 20.05.2013 22:49

Цитата:

легко
У меня ошибка компиляции. Вы не путаете?
Код на кадре таймлайна преобразуется в класс. Описание класса внутри описания другого, в первый раз слышу.

C4Grey 20.05.2013 22:52

Цитата:

Проблема: при нажатии клавиш управления анимация включается, но проигрывается только один раз
Скорее всего, нужно в финальный кадр анимации для определенного направления вставить код перехода на начальный кадр этой анимации:
Код AS3:

gotoAndPlay("goDown")

Цитата:

при одновременном нажатии двух клавиш, например вверх, потом не отпуская влево, персонаж поворачивается влево и продолжает в таком положении двигаться вверх
Он делает именно то, что написано в коде - если нажать клавишу "влево", проигрывает анимацию передвижения влево. Двигается же он вверх, потому что в frameListener стоят условия выбора только одного направления, а первым проверяется именно направление вверх.
P.S.
Учиться лучше по туториалам текстовым, честно вчитываясь, теория в видео обычно воспринимается как "бла-бла-бла, а теперь пишем код".

Wolsh 20.05.2013 22:54

Цитата:

при одновременном нажатии двух клавиш, например вверх, потом не отпуская влево, персонаж поворачивается влево и продолжает в таком положении двигаться вверх.
А Вы бы как хотели?
У Вас при поступлении события от клавиатуры разбирается, какая клавиша была нажата. Но при этом условия if() вложены через else (видимо, авторы туториалов считают, что переменная может хранить сразу несколько значений ;) ). Затем каждый кадр (по событию ENTER_FRAME) происходит перемещение персонажа в зависимости от флагов влево, вправо и т.д. То есть, хотелось бы чтобы от флагОВ, но на самом деле — от флагА, поскольку if'ы снова вложены через else, то есть, если персонаж идет вверх, он уже никак не может идти влево. Кроме того, если клавишу вверх не отпустили, он вообще никуда больше идти не будет, потому что остальные варианты рассматриваются только в else ("иначе", то есть только если вверх не идем). Если хотите, чтобы перс двигался и по диагонали, уберите else. Если хотите, чтобы перс просто был повернут в ту же сторону из 4-х, в которую двигается — поворачивайте его там же, где меняете координату. Потому что сейчас происходит так: приходит одно событие от клавиатуры, затем второе — и все это на протяжении одного кадра, то есть отрисовано будет только последнее изменение состояния.
Вобщем, сначала Вам надо определиться, чего Вы ждете при нажатии двух направлений одновременно.

Idon'tKnow 20.05.2013 23:01

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

Т.е. Если нажата Вверх и вниз - пойдет вверх, влево и вниз - пойдет влево.
Т.е приоритеты :
1. up
2. left
3. down
4. right

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

Исправить этот баг - просто, просто нужно обнулять переменные ненужных нам направлений в приемнике:

Код AS3:

private function keyPressedListener(e:KeyboardEvent){
                        var key:uint=e.keyCode;
                        if(key==87||key==38){//W or UP key
                                this.gotoAndPlay("goUp");
                                moveUp = true;
                                moveRight=false;
                                moveDown = false;
                                moveLeft=false;
                        }else if(key==65||key==37){//A or LEFT key
                                this.gotoAndPlay("goLeft");
                                moveLeft = true;
                                moveUp = false;
                                moveRight=false;
                                moveDown=false;
                        }else if(key==83||key==40){//S or DOWN key
                                this.gotoAndPlay("goDown");
                                moveDown = true;
                                moveUp = false;
                                moveRight=false;
                                moveLeft=false;
                                return;
                        }else if(key==68||key==39){//D or RIGHT
                                this.gotoAndPlay("goRight");
                                moveRight = true;
                                moveUp = false;
                                moveDown=false;
                                moveLeft=false;
                        }
 
                }

Если же Вы хотите, чтобы после отпускания одной из двух клавиш Ваш персонаж продолжал движение, то Вам придется завести что-то типа переменной приоритета и менять при получении события, т.е где я менял значения переменных, там обновлять этот приоритет при получении событий, а в приемнике фрейма отталкиваться от значений :
1. Нажата ли кнопочка?
2. Если нажата, то проверять приоритет. :)

Suntea 20.05.2013 23:38

Цитата:

P.S.S.Даже немного не так. Класс "привязан" к муви, а клип отображается в определённых кадрах?
Да, если я правильно поняла. К первому сообщению прикреплен весь проект, можете посмотреть.

Цитата:

Скорее всего, нужно в финальный кадр анимации для определенного направления вставить код перехода на начальный кадр этой анимации:
так и сделано, не работает =/ анимация проигрывается однажды

Цитата:

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

Цитата:

Вобщем, сначала Вам надо определиться, чего Вы ждете при нажатии двух направлений одновременно.
Чтоб он не поворачивался :) движения по диагонали мне не надо. Я пробовала сперва "поворачивать" его именно в frameListener, но там анимация не проигрывается вообще. Хотя пспрайт двигается без этих лишних поворотов... Как из этой позиции в таком случае заставить играть анимацию?

Idon'tKnow, ваш код тоже убрал тот баг, но главной проблемы не решил - анимация все равно проигрывается один раз и все. Плюс когда клавиша отпущена, анимация движения в эту сторону как раз начинает проигрываться. Чяднт :С

Wolsh 21.05.2013 00:21

Давайте кое-что проясним.
Вот внизу окошко, в котором Вы пишете сообщения. Поставьте туда курсор и нажмите любую клавишу с буквой на клавиатуре. Не отпускайте. Что Вы видите? Событие "нажали клавишу ..." отправляется постоянно, пока нажата клавиша, с определенным интервалом. Соответственно Ваш обработчик нажатия точно так же выполняется с определенным интервалом снова и снова, пока клавиша удерживается нажатой. Не один раз при нажатии, а постоянно. Вы постоянно отправляете своего героя на начальный кадр анимации. А "проигрывается один раз" видимо лишь потому, что между первым событием при нажатии и началом серии пауза чуть больше, чем интервал самой серии (клавиатура выжидает, иначе мы бы замаялись стирать двойные-тройные буквы), и за эту паузу Ваш герой успевает сделать пару шагов))), после чего возвращается к первому кадру чаще, чем происходит переход на следующий кадр.

По этой же причине
Цитата:

Я пробовала сперва "поворачивать" его именно в frameListener, но там анимация не проигрывается вообще.
Естественно, потому что на каждый кадр герой будет возвращаться на начальный кадр своей анимации.

Добавлено через 16 минут
Можно попробовать сделать так: завести две переменных, хранящих текущее состояние героя:
Boolean идёт/стоит, и String или uint, хранящий направление.
При получении события "клавиша ... нажата" проверяете первым делом, стоит герой или идет. Соответственно две ветки условий — если стоит, то надо начать идти в заданном клавишей направлении, и записать в флаги значение true ("шагает") и это направление. А если уже идет, то надо проверить, в том ли направлении он идет, и если в том, то ничего делать не надо, а нет — значит переходим на другой ключевой кадр и записываем в нашу переменную направления это Новое направление.
При отпускании клавиши соответственно переходим на начальный кадр текущего направления и стоп. И записываем в "шагает/стоит" false.
И этими же флагами пользуемся в обработчике ентерфрейма — если стоит, ничего не делаем; если идет, то меняем координату в соответствии с направлением.

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

package AS {
 
        import flash.display.MovieClip;
        import flash.events.KeyboardEvent;
        import flash.events.Event;
 
 
        public class Hero extends MovieClip {
 
                private var moveSpeed:uint;
 
                // добавил свои флаги
                private var isMove:Boolean = false;
                private var direct:String = "goUp";
 
                public function Hero() {
                        moveSpeed=4;
 
                        Constants.stageRef.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedListener);
                        Constants.stageRef.addEventListener(KeyboardEvent.KEY_UP, keyReleasedListener);
                        Constants.stageRef.addEventListener(Event.ENTER_FRAME, frameListener);
                }
 
                private function keyPressedListener(e:KeyboardEvent){
                        var key:uint=e.keyCode;
                        var command:String;
                        if(key==87||key==38){//W or UP key
                                command = "goUp";
                        }
                        if(key==65||key==37){//A or LEFT key
                                command = "goLeft";
                        }
                        if(key==83||key==40){//S or DOWN key
                                command = "goDown"
                        }
                        if(key==68||key==39){//D or RIGHT
                                command = "goRight";
                        }
 
                        if(isMove) { // если герой уже идет
                                if(direct != command) { // если новое направление отличается
                                        this.gotoAndPlay(command);
                                }
                        } else { // если герой стоит
                                this.gotoAndPlay(command);
                        }
                        isMove = true;
                        direct = command;
                }
 
                private function keyReleasedListener(e:KeyboardEvent){
                        this.gotoAndStop(direct);
                        isMove = false;
                }
 
                private function frameListener(e:Event){
                        if(isMove){
                                if(direct == "goUp"){
                                        this.y -= moveSpeed;
                                }
                                if(direct == "goDown"){
                                        this.y += moveSpeed;
                                }
                                if(direct == "goRight"){
                                        this.x += moveSpeed;
                                }
                                if(direct == "goLeft"){
                                        this.x -= moveSpeed;
                                }
                        }
                }
        }
 
}


Suntea 21.05.2013 16:31

Wolsh, УРА все заработало! Правда, огромное спасибо, удивляюсь, как вам не влом было писать такой здоровый подробный ответ новичку, это очень приятно :)

gagaga 22.05.2013 10:40

абсолютно всё сделано не павильно


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

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