【问题标题】:Flash CS5 Displaying Different "screens" on the stage as movieclipsFlash CS5 在舞台上显示不同的“屏幕”作为影片剪辑
【发布时间】:2011-08-02 21:26:49
【问题描述】:

this thread 提升到一个新的水平,现在制作一个 Main.as 类来显示我的游戏的不同“屏幕”。目前我只有一个名为 ControlPanel 的屏幕,但这最终将有多个级别(每个级别将是一个单独的屏幕)和一个级别选择屏幕等。所以在这一点上,我正在失去对如何让事物进入舞台的控制权(换句话说......它变得非常厚,有多个层次,这个菜鸟的大脑正在超载哈哈)。

首先,我使用了舞台上默认的所有图形(按钮、灯光、仪表、乐谱文本等)并创建了一个名为 ControlPanel 的新元件 (MovieClip) 并勾选了“导出”对于 ActionScript”,类名为 ControlPanel。所以现在我的游戏 fla 阶段是黑色的,我将它的文档类设为 Main.as。看起来像这样:

public class Main extends MovieClip {

    public var controlPanel:ControlPanel;

    public function Main() {
        addEventListener(Event.ADDED_TO_STAGE, added);
    }

    private function added(evt:Event):void {
        removeEventListener(Event.ADDED_TO_STAGE, added);

        controlPanel = new ControlPanel(this);
        addChild(controlPanel);
    }
}

运行它非常有效,因为我的控制面板屏幕直接弹出到屏幕上。当然,所有按钮都还没有工作,但这是下一步。所以我将旧的 Game.as 修改为现在称为 ControlPanel 并如下所示:

public class ControlPanel extends MovieClip {
    private var docRef:Main;

    private var _player:Player;
    private var _controller:Controller;

    public function ControlPanel($docRef:Main):void {
        this.docRef = $docRef;

        addEventListener(Event.ADDED_TO_STAGE, added);
    }

    private function added(evt:Event):void {
        removeEventListener(Event.ADDED_TO_STAGE, added);

        _player = new Player(docRef);
        _controller = new Controller(_player, docRef);

        addChild(_player);
    }

现在这是添加我的 Player 类和我的 Controller 类。它们基本上具有相似的构成,所以我将在这里展示 Player.as 类:

public class Player extends MovieClip {
    private var docRef:Main;
    private var _lights:uint;

    public function Player($docRef:Main):void {
        this.docRef = $docRef;

        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }

    private function lightsOut():void {
        switch(_lights) {
        case 1:
        docRef.controlPanel.greenLight1.visible=false;
        break;
        case 2:
        docRef.controlPanel.greenLight2.visible=false;//works
        break;
        case 3:
        docRef.controlPanel.greenLight3.visible=false;//works
        break;
        }
    }

问题是,现在我尝试测试它,我不再看到以前看到的控制面板图形,但我现在收到错误消息:

TypeError:错误 #1009:无法访问空对象引用的属性或方法。 在控制面板() 在主/添加()

我还注释掉了 Main 中的 controlPanel 行,只是做了一个 trace(this);它返回了

[对象主]

不应该是object Stage之类的吗?以前没试过,所以不知道以前是什么。我这里哪里出错了?

更新:好的,所以我的 Controller 不仅像 Player 类,而且可能需要舞台和视图的实例?好吧,这是我为控制器和一些所需的事件侦听器准备的:

public class Controller extends MovieClip {
    private var _model:Object;
    private var _dHandle:Object;
    private var panelView:ControlPanelView; //started playing with this idea but maybe that is the wrong way to go?? Stick with docRef here? or both?

    public function Controller(model:Object, dHandle:Object, $view:ControlPanelView):void {
        this._model = model;
        this._dHandle = dHandle;
        this.panelView = $view;

        docRef.stage.addEventListener(KeyboardEvent.KEY_DOWN, processKeyDown);
        docRef.stage.addEventListener(MouseEvent.MOUSE_DOWN, processMouseDown);
        docRef.ControlPanelView.fireButton.addEventListener(MouseEvent.CLICK, processFirePress);
        docRef.ControlPanelView.cWButton.addEventListener(MouseEvent.CLICK, processCWPress);
        docRef.ControlPanelView.cCWButton.addEventListener(MouseEvent.CLICK, processCCWPress);

如您所见,这是一个在 docRef 和 View 理念之间撕裂的大杂烩。我需要为我的鼠标和键盘监听器访问舞台,但我还需要访问 ControlPanelView 符号中的按钮。我需要在这里传递视图和 docRef 吗?如何保持对舞台和 ControlPanelView 图形的访问权限?

【问题讨论】:

  • 跟踪是正确的,它说你有一个 Main 类型的对象,它是你的类。您现在真的需要 Player 接收对您的文档类的引用,还是只需要对 ControlPanel 的引用?在这种情况下两者都应该工作,但后者更容易阅读。
  • 等一下,我有这个权利吗,你有一个库项目设置为'export for actionscript',你称之为ControlPanel,你还有一个.as文件,其中包含一个类名为ControlPanel?
  • 检查库中的符号链接。还要检查您的包名称是否与库中的内容匹配。
  • 是的,我将所有图形放入名为 ControlPanel 的符号中,当我单击 Export for ActionScript 时,它只是使用了 ControlPanel 的默认名称,所以我离开了它。然后我需要控制它,所以我认为它已经被创建了,为什么不把一些真实的代码放进去。所以我将 Game.as 更改为现在的 ControlPanel.as。是的,我还创建了保存新 ControlPanel 的变量,称为小写 controlPanel。也许只是太多了,我需要更改为 cPanel 之类的东西?或者我不能让我的符号和控制类具有相同的名称吗?

标签: flash actionscript-3 flash-cs5


【解决方案1】:

您不能从库和具有相同名称的类文件中导出某些内容。当您将库项目设置为“Export for ActionScript”时,Flash 会创建一个具有该名称的类来表示该对象,因此您自己创建一个同名的类会导致冲突。

对于如何继续,您有两种选择:

继承

您可以使用为 ControlPanel 创建的类作为库中符号的代码库。要做到这一点,首先给它一个不同的名字,比如ControlPanelBase。然后您可以将其指定为符号的基类。您可以在 IDE 中通过进入符号属性并将基类从 flash.display.MovieClip 更改为 ControlPanelBase(或您选择的任何名称)来执行此操作。单击绿色小勾以确保找到该类,然后单击“确定”。

现在,当您使用 new ControlPanel(this) 表示法创建新的 ControlPanel 时,它将创建一个使用图形的对象,以及来自基类的代码。因为您是继承的,所以您需要将所有出现的单词 private 更改为 protected 以允许任何后代类看到它们。

分离视图

这是我的偏好,因为当您停止将 IDE 用于生成资产包之外的任何事情时,您可以避免在更改代码时重新编译资产。

将库符号的名称更改为更具描述性的名称,例如 ControlPanelView。现在,当您使用 new ControlPanel(this) 创建 ControlPanel 时,它不会附加任何图形,因此您需要自己执行此操作:

public class ControlPanel extends MovieClip {
    private var docRef:Main;

    private var _player:Player;
    private var _controller:Controller;

    public var view:ControlPanelView; //note that this is public

    public function ControlPanel($docRef:Main):void {
        this.docRef = $docRef;

        addEventListener(Event.ADDED_TO_STAGE, added);
    }

    private function added(evt:Event):void {
        removeEventListener(Event.ADDED_TO_STAGE, added);

        view = addChild(new ControlPanelView()) as ControlPanelView; //add the graphics

        _player = new Player(docRef);
        _controller = new Controller(_player, docRef);

        addChild(_player);
    }
}

现在,要从 Player 内部访问这些灯光,您会说

docRef.controlPanel.view.greenLight1.visible=false;

您可以看到这变得有点拗口,但为了缩短它,您可以在创建播放器时传递对 ControlPanel 而不是 Main 的引用,或者实际上您可以传递对视图的引用(如果是)您需要与之交谈的一切。

在控制面板中:

_player = new Player(view);

新的播放器类:

public class Player extends MovieClip {
    private var panelView:ControlPanelView;
    private var _lights:uint;

    public function Player($view:ControlPanelView):void {
        this.panelView = $view;

        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }

    private function lightsOut():void {
        switch(_lights) {
        case 1:
        panelView.greenLight1.visible=false;
        break;
        case 2:
        panelView.greenLight2.visible=false;//works
        break;
        case 3:
        panelView.greenLight3.visible=false;//works
        break;
        }
    }
}

关于您的更新,请记住您的 Main 类和 stage 不是一回事。每个显示对象都有一个stage 属性,它们都指向同一个对象。这意味着要将您的听众添加到舞台上,Main.stageview.stagethis.stage 之间没有区别(假设控制器在舞台上)。所以你的控制器可能看起来像这样:

public class Controller extends EventDispatcher {
    private var _model:Player;
    private var panelView:ControlPanelView;

    public function Controller($model:Player, $view:ControlPanelView):void {
        this._model = $model;
        this.panelView = $view;

        panelView.stage.addEventListener(KeyboardEvent.KEY_DOWN, processKeyDown);
        panelView.stage.addEventListener(MouseEvent.MOUSE_DOWN, processMouseDown);
        panelView.fireButton.addEventListener(MouseEvent.CLICK, processFirePress);
        panelView.cWButton.addEventListener(MouseEvent.CLICK, processCWPress);
        panelView.cCWButton.addEventListener(MouseEvent.CLICK, processCCWPress);
    }
}

在 ControlPanel 中,您可以这样创建它:

_controller = new Controller(_player, view);

请注意,我还让您的控制器扩展 EventDispatcher 而不是 MovieClip。从您需要的最低限度的类扩展是一种很好的做法,所以如果它永远不会出现在舞台上但它会发出事件,那么 EventDispatcher 是最低限度的。如果它永远不需要派发事件,只需向其他人添加侦听器,那么它就不需要扩展任何东西。

基本上,仅当您需要时间线功能或您的类将成为库中某些内容的基类时才扩展 MovieClip。对于任何其他标准显示对象,您应该扩展SpriteShape,如果您打算添加孩子,则前者,如果您只打算绘制矢量图形,则后者。如果您的对象永远不会出现在显示树上,则通常您需要扩展 EventDispatcher 或根本不需要扩展。

【讨论】:

  • 好吧,我的控制器比我想象的要复杂。我在原始帖子的底部添加了一些代码。很抱歉我是个皮塔饼,但我真的非常感谢您提供的所有帮助。
  • @FlashNoob468 - 我已经处理了你的更新。希望这能解决问题。
  • 好吧,我对舞台一无所知。这实际上清除了很多我刚刚接受的以某种方式工作的事情。但是....我将所有内容都更改为新系统,我又回到了我开始使用TypeError: Error #1009: Cannot access a property or method of a null object reference. at ControlPanel() at Main/added() 的位置,我应该仍然在 Main 中添加 ControlPanel 还是现在应该添加 ControlPanelView?现在我的 main 看起来仍然像上面列出的原始版本。
  • 您从 Flash 导出的影片剪辑的类名是什么?
  • 只是为了确保我看到的和你问的一样,当我转到我在库中创建的 ControlPanelView 符号的属性时,你正在谈论课堂空白对吗?我强迫它成为 ControlPanelView。我应该把它留在 ControlPanel 上吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-14
  • 2014-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多