Actionscript 3: события пользовательского ввода не запускаются от дочерних объектов Blit Sprite - PullRequest
0 голосов
/ 01 апреля 2012

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

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

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

Игровой класс:

package Game
{
import Game.*;
import Game.Worlds.Level1.Level1;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display3D.IndexBuffer3D;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;

public class Game extends Sprite
{
    /** Hold each racquet so as to retrieve them when collision detection is needed. **/
    internal var racquetList:Vector.<Racquet>= new Vector.<Racquet>(2,true);
    /** Hold each Zwig so as to retrieve them when collision detection is needed. **/
    internal var zwigColliderList:Vector.<Collider>= new Vector.<Collider>(2,true);

    /** Object that contains the coordinates for the Twinkys in the counter. **/
    internal var twinkyScore0:Object= {firstX:727,firstY:950,secondX:710,secondY:911,
        thirdX:690,thirdY:872,fourthX:674,fourthY:840,
        fifthX:657,fifthY:808};
    internal var twinkyScore1:Object= {firstX:41,firstY:74,secondX:58,secondY:113,
        thirdX:78,thirdY:152,fourthX:94,fourthY:184,
        fifthX:111,fifthY:216};

    /** Speed decay coefficient. The closer to 1 the less speed decays. **/
    private var friction:Number= .96;
    /** Maximum speed cap for twinkys. The higher the number the grater the maximal speed. **/
    private var speedMax:Number= 10;

    /** Important positions for the placement of game elements.
     * LianaHeight is the height at which the liana on the players' HUDs is ending their zone and on which the racquet travels.
     * TwinkyHeight is the height at which the players stop controlling their Twinkys.
     * YMargin is the vertical margin for the Twinkys. Used to place them at the end of the tube when added.
     * XMargin is the horizontal margin for the Twinkys. Used to place them at the end of the tube when added. **/
    private var positions:Object= {LianaHeight:165,TwinkyHeight:265,YMargin:8.0,XMargin:200.0};

    private var _mRef:ZwigsIpad;
    Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;

    private var _Canvas:BitmapData= new BitmapData(ZwigsIpad.BORDERS.right,ZwigsIpad.BORDERS.bottom,false);
    private var _Background:Background;
    private var _HUD1:HUD;
    private var _HUD2:HUD;
    private var _Score:Score;
    private var _Zwig1:Zwig;
    private var _Zwig2:Zwig;
    private var _Racquet1:Racquet;
    private var _Racquet2:Racquet;
    private var _Twinky1:Twinky;
    private var _Twinky2:Twinky;

    /** Create the first level. It will create the stage and add the background, HUDs, Zwigs, Racquets and Twinkys, and manages the game until the end. **/
    public function Game(m:ZwigsIpad)
    {
        this._mRef= m;
        this.addEventListener(Event.ADDED_TO_STAGE,init);
    }

    private function init(e:Event):void
    {
        this.removeEventListener(Event.ADDED_TO_STAGE,init);

        // Add game canvas on which all assets are rendered
        addChild(new Bitmap(this._Canvas));

        // Get informations from Level1
        // LATER make it dependant from what level was chosen (switch case)
        this.positions.LianaHeight= Level1.LIANA_HEIGHT;
        this.positions.TwinkyHeight= Level1.TWINKY_HEIGHT;
        this.positions.YMargin= Level1.TWINKY_MARGIN_Y;
        this.positions.XMargin= Level1.TWINKY_MARGIN_X;
        this.friction= Level1.TWINKY_FRICTION;
        this.speedMax= Level1.TWINKY_SPEED_MAX;

        // Add background
        this._Background= new Background(this._Canvas,0);
        addChild(this._Background);

        // Add HUD
        this._HUD1= new HUD(this._Canvas);
        this._HUD2= new HUD(this._Canvas,true,1);
        addChild(this._HUD1);
        addChild(this._HUD2);

        // Add scoring
        this._Score= new Score(this,this._mRef);
        addChild(this._Score);

        // Add zwigs
        this._Zwig1= new Zwig(this._Canvas);
        this._Zwig2= new Zwig(this._Canvas,true,1);
        addChild(this._Zwig1);
        addChild(this._Zwig2);

        // Add zwigs' colliders to vector
        this.zwigColliderList[0]= this._Zwig1.collider;
        this.zwigColliderList[1]= this._Zwig2.collider;

        // Add racquets
        this._Racquet1= new Racquet(this.positions,this._Canvas);
        this._Racquet2= new Racquet(this.positions,this._Canvas,false,1);
        addChild(this._Racquet1);
        addChild(this._Racquet2);

        // Add racquets to vector
        this.racquetList[0]= this._Racquet1;
        this.racquetList[1]= this._Racquet2;

        // Add twinkys
        this._Twinky1= new Twinky(this,this._Score,this,this.positions,this.friction,this.speedMax,this._Canvas,0);
        this._Twinky2= new Twinky(this,this._Score,this,this.positions,this.friction,this.speedMax,this._Canvas,1,false,1);
        addChild(this._Twinky1);
        addChild(this._Twinky2);

        this.addEventListener(Event.ENTER_FRAME,renderLevel);
    }

    private function renderLevel(e:Event):void
    {
        this._Canvas.lock();

        this._Background.render();
        this._HUD1.render();
        this._HUD2.render();
        this._Score.render();
        this._Zwig1.render();
        this._Zwig2.render();
        this._Racquet1.render();
        this._Racquet2.render();
        this._Twinky1.render();
        this._Twinky2.render();

        this._Canvas.unlock();
    }
}
}

Класс Twinky:

package Game
{
import Game.Game;
import Game.Score;

import com.greensock.TweenMax;
import com.greensock.easing.*;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;

/** The Twinky is the main player controlled class. **/
internal class Twinky extends Sprite
{
    private var _mRef:Game;
    private var _sRef:Score;
    private var player:uint;

    Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
    private var _touchMoveID:int= 0;
    private var _speedX:Number= 0;
    private var _speedY:Number= 0;
    private var xOffset:Number;
    private var yOffset:Number;
    private var currentX:Number;
    private var currentY:Number;
    private var oldX:Number;
    private var oldY:Number;
    private var dragging:Boolean= false;
    private var launched:Boolean= false;
    private var _point:Point= new Point();

    private var positions:Object;
    private var friction:Number;
    private var speedMax:Number;
    private var canvas:BitmapData;
    private var isAtBottom:Boolean;
    private var skin:uint;

    private var _image:BitmapData;
    private var _idleArray:Array= new Array();
    private var i:uint= 0;

    // Yellow twinky
    [Embed (source= "Assets/Players/twinky1.png")]
    private const Twinky1idle:Class;
    private var _twinky1idleArray:Array;
    // Red twinky
    [Embed (source= "Assets/Players/twinky2.png")]
    private const Twinky2idle:Class;
    private var _twinky2idleArray:Array;

    private const twinkyWidth:uint= 64;
    private const twinkyHeight:uint= 64;

    private var t1i001:Rectangle= new Rectangle(0,0,twinkyWidth,twinkyHeight);
    private var t2i001:Rectangle= new Rectangle(0,0,twinkyWidth,twinkyHeight);

    /** Create Twinky. Twinkys must be flicked to the same colored Zwig to
     * feed it and die when they lost momentum. **/
    public function Twinky(daddy:Game,score:Score,m:Game,positions:Object,friction:Number,speedMax:Number,canvas:BitmapData,player:uint,isAtBottom:Boolean=true,skin:uint=0)
    {
        // Get score and game object reference
        this._sRef= score;
        this._mRef= daddy;

        this.positions= positions;
        this.friction= friction;
        this.speedMax= speedMax;
        this.canvas= canvas;
        this.player= player;
        this.isAtBottom= isAtBottom;
        this.skin= skin;

        this._twinky1idleArray= [t1i001];
        this._twinky2idleArray= [t2i001];

        this.addEventListener(Event.ADDED_TO_STAGE,init,false,0,true);
    }

    private function init(e:Event):void
    {
        this.removeEventListener(Event.ADDED_TO_STAGE,init);

        // Get skin
        switch (this.skin)
        {
            case 0:
                this._image= new this.Twinky1idle().bitmapData;
                this._idleArray= this._twinky1idleArray;
            break;

            case 1:
                this._image= new this.Twinky2idle().bitmapData;
                this._idleArray= this._twinky2idleArray;
            break;

            default:
                this._image= new this.Twinky1idle().bitmapData;
                this._idleArray= this._twinky1idleArray;
            break;
        }

        // Give position
        if (this.isAtBottom)
        {
            this.x= this.positions.XMargin;
            this.y= ZwigsIpad.BORDERS.bottom - this.positions.YMargin;

            // Animate entrance
            TweenMax.from(this,1,{x:this.x-70,y:this.y-12,rotation:-180,alpha:.5});
        }
        else
        {
            this.x= ZwigsIpad.BORDERS.right - this.positions.XMargin;
            this.y= this.positions.YMargin;

            // Animate entrance
            TweenMax.from(this,1,{x:this.x+70,y:this.y+12,rotation:-180,alpha:.5});
        }

        this._point.x= this.x;
        this._point.y= this.y;

        aText.appendText("\n position: "+this.x+" "+this.y);

        // Detect touched
        this.addEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
        // Always detect untouched
        this._mRef.addEventListener(TouchEvent.TOUCH_END,touchUp);
        // Always do kinetics
        this._mRef.addEventListener(Event.ENTER_FRAME,freeMove);
    }

    /** Render the Twinky at its current coordinates by redrawing it. **/
    internal function render():void
    {
        this._point.x= this.x - this._idleArray[i].width * .5;
        this._point.y= this.y - this._idleArray[i].height * .5;

        this.canvas.copyPixels(this._image,this._idleArray[0/*i*/],this._point);

        // When idle finished restart, else pursue with animation
        /*if (i==this._idleArray.length - 1)
            i= 0;
        else
            i++;*/
    }

    // TWINKY AND RACQUET DO NOT DETECT TOUCH EVENTS because the main canvas covers them
    // Start dragging when touched
    private function touchDown(e:TouchEvent):void
    {
        aText.appendText("\n Twinky touched!");

        if (this._touchMoveID != 0)
            return;

        this._touchMoveID= e.touchPointID;
        this.dragging= true;
        // Get the mouse's offset on the object
        this.xOffset= e.localX;
        this.yOffset= e.localY;

        this._mRef.addEventListener(TouchEvent.TOUCH_MOVE,touchMove);
    }

    private function touchMove(e:TouchEvent):void
    {
        if (e.touchPointID != this._touchMoveID)
            return;

        // Move twinky to where the mouse is
        this.x= e.stageX - this.xOffset;
        this.y= e.stageY - this.yOffset;

        // Don't go farther than borders
        if (this.x <= this.width * .5)
        {
            this.x= (this.width * .5) + .1;
        }

        if (this.x >= ZwigsIpad.BORDERS.right - (this.width * .5))
        {
            this.x= ZwigsIpad.BORDERS.right - (this.width * .5) - .1;
        }

        if (this.y <= this.height * .5)
        {
            this.y= (this.height * .5) + .1;
        }

        if (this.y >= ZwigsIpad.BORDERS.bottom - (this.height * .5))
        {
            this.y= ZwigsIpad.BORDERS.bottom - (this.height * .5) - .1;
        }

        // Be undraggable if zone is left
        if (this.isAtBottom)
        {
            if (this.y < (ZwigsIpad.BORDERS.bottom - this.positions.TwinkyHeight))
            {
                this._touchMoveID= 0;
                this.dragging= false;

                this._mRef.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
                return;
            }
        }
        else
        {
            if (this.y > this.positions.TwinkyHeight)
            {
                this._touchMoveID= 0;
                this.dragging= false;

                this._mRef.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
                return;
            }
        }

        // Refresh coordinates for display
        this._point.x= this.x;
        this._point.y= this.y;

        e.updateAfterEvent();
    }

    private function touchUp(e:TouchEvent):void
    {
        if (e.touchPointID != this._touchMoveID)
            return;

        this._touchMoveID= 0;
        this.dragging= false;

        this._mRef.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
    }

    private function freeMove(e:Event):void
    {
        // Be undraggable if liana crossed
        if (this.isAtBottom)
        {
            if (this.y < (ZwigsIpad.BORDERS.bottom - this.positions.TwinkyHeight))
            {
                this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
                this._mRef.removeEventListener(Event.ENTER_FRAME,touchUp);
                this.dragging= false;
                this.launched= true;
            }
        }
        else
        {
            if (this.y > this.positions.TwinkyHeight)
            {
                this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
                this._mRef.removeEventListener(Event.ENTER_FRAME,touchUp);
                this.dragging= false;
                this.launched= true;
            }
        }

        // Move the twinky and calculate its speed if player is dragging it 
        if (this.dragging)
        {
            aText.appendText("\n Twinky dragged!");
            this.oldX= currentX;
            this.oldY= currentY;
            currentX= this.x;
            currentY= this.y;

            // Calculate speed in X and Y axis
            this._speedX= this.currentX - this.oldX;
            this._speedY= this.currentY - this.oldY;

            // Cap maximal speed
            if (this._speedX > this.speedMax)
                this._speedX= this.speedMax;

            if (this._speedY > this.speedMax)
                this._speedY= this.speedMax;
        }
        // Otherwise move the twinky using its speed
        else
        {
            this.x+= this._speedX;
            this.y+= this._speedY;
        }

        // Detect collision with zwigs
        for (i= 0 ; i < this._mRef.zwigColliderList.length ; i++)
        {
            var cemp:Collider= this._mRef.zwigColliderList[i] as Collider;
            if (this.hitTestObject(cemp))
            {
                this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
                this._mRef.removeEventListener(TouchEvent.TOUCH_END,touchUp);
                this._mRef.removeEventListener(Event.ENTER_FRAME,freeMove);
                this._sRef.die(this,this.player,true,i);
                return;
            }
        }

        // Detect collision with borders: left border
        if (this.x <= this.width / 2)
        {
            // Don't go any further
            this.x= (this.width / 2) + .1;
            // Reverse speed to bounce
            this._speedX*= -1;
        }
        // Right border
        if (this.x >= ZwigsIpad.BORDERS.right - (this.width / 2))
        {
            this.x= ZwigsIpad.BORDERS.right - (this.width / 2) - .1;
            this._speedX*= -1;
        }
        // Top border
        if (this.y <= this.height / 2)
        {
            this.y= (this.height / 2) + .1;
            this._speedY*= -1;
        }
        // Bottom border
        if (this.y >= ZwigsIpad.BORDERS.bottom - (this.height / 2))
        {
            this.y= ZwigsIpad.BORDERS.bottom - (this.height / 2) - .1;
            this._speedY*= -1;
        }

        // Detect collision with racquets
        for (var i:uint= 0 ; i < this._mRef.racquetList.length ; i++)
        {
            var temp:Racquet= this._mRef.racquetList[i] as Racquet;
            if (this.hitTestObject(temp))
            {
                this._speedY*= -1;
                this.y+= this._speedY;
            }
        }

        // Speed decay
        this._speedX*= this.friction;
        this._speedY*= this.friction;

        // Set speed to 0 if speed is smaller than .5
        if (Math.abs(this._speedX) < .5) this._speedX= 0;
        if (Math.abs(this._speedY) < .5) this._speedY= 0;

        // If speed is null and it has been launched, kill twinky
        if (this._speedX == 0 && this._speedY == 0 && this.launched)
        {
            this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
            this._mRef.removeEventListener(TouchEvent.TOUCH_END,touchUp);
            this._mRef.removeEventListener(Event.ENTER_FRAME,freeMove);
            TweenMax.to(this, 1.5, {alpha:0, ease:Linear.easeNone});
            this._sRef.die(this,this.player);
            return;
        }

        // Refresh coordinates for display
        this._point.x= this.x;
        this._point.y= this.y;
    }
}
}

Класс ракетки:

package Game
{
import Game.Worlds.Level1.Level1;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.geom.Point;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;

internal class Racquet extends Sprite
{
    Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
    private var _touchMoveID:int= 0;
    private var xOffset:Number;
    private var dragging:Boolean= false;

    private var positions:Object;
    private var canvas:BitmapData;
    private var isAtBottom:Boolean;
    private var skin:uint;

    private var _image:BitmapData;
    private var _point:Point= new Point();

    // Yellow racquet
    [Embed (source= "Assets/Players/racq1.png")]
    private const Racquet1:Class;
    // Red racquet
    [Embed (source= "Assets/Players/racq2.png")]
    private const Racquet2:Class;

    public function Racquet(positions:Object,canvas:BitmapData,isAtBottom:Boolean=true,skin:uint=0)
    {
        this.positions= positions;
        this.canvas= canvas;
        this.isAtBottom= isAtBottom;
        this.skin= skin;

        this.addEventListener(Event.ADDED_TO_STAGE,init,false,0,true);
    }

    private function init(e:Event):void
    {
        this.removeEventListener(Event.ADDED_TO_STAGE,init);

        // Get skin
        switch (this.skin)
        {
            case 0:
                //this._image= new R.Racquet1().bitmapData;
                this._image= new this.Racquet1().bitmapData;
            break;

            case 1:
                //this._image= new R.Racquet2().bitmapData;
                this._image= new this.Racquet2().bitmapData;
            break;

            default:
                this._image= new this.Racquet1().bitmapData;
            break;
        }

        // Give position
        if (this.isAtBottom)
        {
            this.x= ZwigsIpad.BORDERS.centerX;
            this.y= ZwigsIpad.BORDERS.bottom - this.positions.LianaHeight;
        }
        else
        {
            this.x= ZwigsIpad.BORDERS.centerX;
            this.y= this.positions.LianaHeight;
        }

        this._point.x= this.x;
        this._point.y= this.y;

        this.addEventListener(TouchEvent.TOUCH_BEGIN,touchDown,false,0,true);
        this.parent.addEventListener(TouchEvent.TOUCH_END,touchUp,false,0,true);
    }

    internal function render():void
    {
        this._point.x= this.x - this._image.rect.width * .5;
        this._point.y= this.y - this._image.rect.height * .5;

        this.canvas.copyPixels(this._image,this._image.rect,this._point);
    }

    private function touchDown(e:TouchEvent):void
    {
        aText.appendText("\n Racquet touched!");
        if(this._touchMoveID != 0)
            return;

        this._touchMoveID= e.touchPointID;

        this.xOffset= e.localX;
        this.parent.addEventListener(TouchEvent.TOUCH_MOVE,touchMove,false,0,true);
    }

    private function touchMove(e:TouchEvent):void
    {
        if(e.touchPointID != this._touchMoveID)
            return;

        Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
        this._point.x= e.stageX - this.xOffset;

        if (this._point.x <= ZwigsIpad.BORDERS.left + (this._image.width*.5))
            this._point.x= ZwigsIpad.BORDERS.left + (this._image.width*.5);
        else if (this._point.x >= ZwigsIpad.BORDERS.right - (this._image.width*.5)) 
            this._point.x= ZwigsIpad.BORDERS.right - (this._image.width*.5);
    }

    private function touchUp(e:TouchEvent):void
    {
        if(e.touchPointID != this._touchMoveID)
            return;

        this._touchMoveID= 0;
        this.parent.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
    }
}
}

1 Ответ

2 голосов
/ 01 апреля 2012

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

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

Вы должны подумать о том, чтобы каждый спрайт содержал свою собственную графику, и все будет проще.Если производительность является серьезной проблемой, я предлагаю сначала заставить ее работать, а затем поэкспериментировать с различными стратегиями оптимизации (например, cacheAsBitmap, отсечение / прокрутка с помощью scrollRect и т. Д.)

...