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

Ioangum 25.12.2013 23:50

Параллакс в двух направлениях
 
Доброго времени суток! Вот уже много времени бьюсь над решением задачи - всё никак не получается + в интернете подходящей информации найти не могу. Суть такова: нужно сделать эффект параллакса, но не только при изменении x и y координат, а ещё и при приближении. Это всё на примере звёздного неба. Когда по x и y таскать надо, всё получается, а вот с глубиной проблемы. Может, кто сталкивался с подобным. Буду очень признателен за совет. Спасибо

shmaser 26.12.2013 00:56

Зависит от того, как сейчас у вас реализованы параллакс слои. Это спрайты с разной координатой z, или это спрайты, которые лежат на одном уровне, но перемещение спрайта, который должен быть дальше, просто делается медленнее? Если первое, то просто гоняете z, если второе, то создать эффект приближения можно, масштабируя спрайты, которые должны быть ближе к зрителю быстрее, чем те которые должны казаться дальше. Что-то типа:
Код AS3:

private var _scaleFactor:Number //чем ближе к зрителю объект, тем больше значение scaleFactor
sprite.scaleX *= _scaleFactor
sprite.scaleY *= _scaleFactor

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

alexandrratush 26.12.2013 05:18

Цитата:

а вот с глубиной проблемы.
Какие именно проблемы?

caseyryan 26.12.2013 10:11

на вскидку такой вариант:
Дальняя картинка по размеру меньше ближней, соответственно, для дальней картинки масштабирование умножаем на ширинуДальней / ширинуБлижней
то есть, допустим ширина передней картинки 2000, а дальней 1000.
Код AS3:

var scaleFactor:Number = 2;
front.scaleX = front.scaleY = scaleFactor;
back.scaleX = back.scaleY = front.scaleX * (back.width / front.width);

Что-то типа того. Не проверял, но это первое, что пришло в голову

Ioangum 26.12.2013 16:16

Не выходит, к сожалению. Появляется какой-то сдвиг после масштабирования, и как только переходим к перетаскиванию, картинка как бы делает скачок

Akopalipsis 26.12.2013 17:31

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

public static function scalePoint(target:DisplayObject, scaleX:Number, scaleY:Number, point:Point):void
{
        var dXS:Number = (target.x - point.x) / target.scaleX;
        var dYS:Number = (target.y - point.y) / target.scaleY;
 
        target.scaleX = scaleX;
        target.scaleY = scaleY;
 
        target.x = point.x + dXS * target.scaleX;
        target.y = point.y + dYS * target.scaleY;
}


Ioangum 26.12.2013 17:40

А что тогда за точку брать для каждого конкретного слоя?

Akopalipsis 26.12.2013 17:57

Цитата:

А что тогда за точку брать для каждого конкретного слоя?
Координаты мышки.

Ioangum 26.12.2013 19:47

Вложений: 1
Может, я что-то не так делаю, но всё равно не то. Вот код основного класса Main:
Код AS3:

package  
{
        import flash.display.Sprite;
        import flash.geom.Point;
 
 
        public class Main extends Sprite
        {
                public var s:Space;
                public var stars:Vector.<Sprite> = new Vector.<Sprite>;
                private var s0: Star;
 
                private var pre_x:Number=0;
                private var pre_y:Number=0;
 
                public function Main()
                {
                        fillSky(1000, 800);
                        s = new Space(500 - 700, 400 - 500); //Располагаем посередине. 700x500 - размер swf
                        pre_x = s.x;
                        pre_y = s.y;
                        addChild(s);
                }
 
                private function fillSky(W:int, H:int) {
                        //i - слой, j - звезда в слое
                        //i=0 - слой, самый ближний к наблюдателю
                        //j - звезда, размер выбирается рандомно в пределах слоя (внутри есть свойство dist = дальность {0..100})
                        var sloy:Sprite;
                        for (var i:int = 0; i < 10; i++) {
                                sloy = new Sprite();
                                for (var j:int = 0; j < 25; j++) {
                                        s0 = new Star(Math.random() * W, Math.random() * H, Math.random() * 10+i*10);
                                        sloy.addChild(s0);
                                }
                                stars.push(sloy);
                                addChildAt(sloy,0);
                        }
                }
 
                public function moveSky():void {
 
                        //рассчитываем насколько сдвинулся Space
                        var dx:Number = s.x-pre_x;
                        var dy:Number = s.y - pre_y;
 
                        //запоминаем положение Space для вычисления разницы
                        pre_x = s.x;
                        pre_y = s.y;
 
                        //сдвигаем каждый слой соответственно его глубине
                        for (var i:int = 0; i < stars.length; i++) {
                                stars[i].x += dx / (10 - i +2); //по идее надо делать 10-i, но тогда при i=9 ,будет dx/1, что соответствует слою Space. А нужно сделать всё-таки чуть сзади
                                stars[i].y += dy / (10 - i +2);
                        }
 
                }
 
                public function scalePoint(target:Sprite, scaleX:Number, scaleY:Number, point:Point):void{
                        var dXS:Number = (target.x - point.x) / target.scaleX;
                        var dYS:Number = (target.y - point.y) / target.scaleY;
 
                        target.scaleX = scaleX;
                        target.scaleY = scaleY;
 
                        target.x = point.x + dXS * target.scaleX;
                        target.y = point.y + dYS * target.scaleY;
                }
 
                public function scaleSky(bigger:Boolean):void {
                        var p:Point;
                        for (var i:int = 0; i < stars.length; i++) {
                                p = new Point(stage.stageWidth/2, stage.stageHeight/2);
                                p = globalToLocal(p);
                                scalePoint(stars[i], s.scaleX * (1 - 1 / (10 - i +2)), s.scaleY * (1 - 1 / (10 - i +2)), p);
                        }
                }
 
        }
 
}

В классе Space ничего особенного: его можно таскать и увеличивать. Ну и всё. Но на всякий пожарный вот он:
Код AS3:

package  
{
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Point;
        import flash.geom.Rectangle;
 
        public class Space extends Sprite
        {
                public const GEN_W:int = 700; //horizontal size of swf file
                public const GEN_H:int = 500; //vertical size of swf file
                public var WW:Number = 1000; //данные о начальной высоте спейса
                public var HH:Number = 800; //данные о начальной ширине спейса
                public var scale_f:Number = 1;
 
                private var droped:Boolean = false;
 
                public function Space(XX:int, YY:int)
                {
                        x = XX;
                        y = YY;
 
                        graphics.beginFill(0x000000,0.5);
                        graphics.drawRect(0, 0, 1000, 800);
                        graphics.endFill();
 
                        graphics.beginFill(0x00FF00);
                        graphics.drawCircle(400, 300, 100);
                        graphics.endFill();
 
                        graphics.beginFill(0x00FF00);
                        graphics.drawCircle(200, 700, 50);
                        graphics.endFill();
 
                        addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
                        addEventListener(MouseEvent.MOUSE_UP, onMUp);
                        addEventListener(MouseEvent.MOUSE_WHEEL, sScale);
                        addEventListener(Event.ENTER_FRAME, EF);
                }
 
                private function onMDown(e:MouseEvent) {
                        var dx:Number = WW-stage.stageWidth;
                                var dy:Number = HH-stage.stageHeight;
                                var dragRect:Rectangle = new Rectangle(-dx,-dy, dx,dy);
                                startDrag(false, dragRect);
                                droped = true;
                }
 
                private function onMUp(e:MouseEvent) {
                        stopDrag();
                        droped = false;
                }
 
                //изменение масштаба карты
                private function sScale(e:MouseEvent):void {
                        var sc:Number = 0.95;
                        var p = new Point(GEN_W/2, GEN_H/2);
                        p = globalToLocal(p);
                        if ((e.delta < 0) && (WW*sc>=GEN_W) && (HH*sc>=GEN_H)) {
                                width *= sc;
                                height *= sc;
                                WW *= sc;
                                HH *= sc;
 
                                scale_f *= sc;
                                (parent as Main).scaleSky(false);
                        }
                        else if ((e.delta > 0) && (scale_f<5)) {
                                width /= sc;
                                height /= sc;
                                WW /= sc;
                                HH /= sc;
 
                                scale_f /= sc;
                                (parent as Main).scaleSky(true);
                        }
 
                        p = localToGlobal(p);
                        x += GEN_W/2 - p.x;
                        y += GEN_H / 2 -p.y;
 
                        if (x > 0) x = 0;
                        if (y > 0) y = 0;
                        if (x + WW < GEN_W) x = GEN_W - WW;
                        if (y + HH < GEN_H) y = GEN_H - HH;
                }
 
                private function EF(e:Event) {
                        if (droped) (parent as Main).moveSky();
                }
 
        }
 
}

Ну и класс Star - обычный шейп:
Код AS3:

package  
{
        import flash.display.Shape;
 
        public class Star extends Shape
        {
                public var dist:Number = 0; //0..100
                public var x0:int = 0;
                public var y0:int = 0;
 
                public function Star(X:Number, Y:Number, D: Number = 0)
                {
                        dist = D;
                        x0 = X;
                        y0 = Y;
                        x = X;
                        y = Y;
                        graphics.beginFill(0xFFFFFF);
                        graphics.drawCircle(0, 0,D/100+0.01);
                        graphics.endFill();
                }
 
        }
 
}


Akopalipsis 26.12.2013 21:08

Цитата:

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

Ioangum 26.12.2013 21:09

Жаль. Ну, если додумаюсь, выложу сюда )


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

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