【问题标题】:TypeError 1009 and muting sound in AS3类型错误 1009 和 AS3 中的静音
【发布时间】:2017-09-06 04:56:00
【问题描述】:

真的对此很陌生,所以,如果有一些我不知何故错过的明显解决方案,我真的很抱歉,但是哦,好吧......
我正在制作游戏,我正在尝试制作角色选择菜单。每个角色都会有同一首歌曲的唯一版本(具有相同的 bps),因此当您“悬停”其中一个选项时,角色的歌曲会播放而其他歌曲会静音(不会暂停或停止,所以以免失去歌曲所有版本之间的同步)...
现在,我试图只为其中一首歌曲进行编程,然后在我弄清楚后重复其他歌曲的方法。
所以...
我究竟做错了什么?

代码如下:

package {

import flash.display.MovieClip;
import flash.events.Event; 
import flash.media.SoundTransform;
import flash.media.Sound;
import flash.media.SoundChannel; 
import flash.media.SoundMixer; 

public class MainThing extends MovieClip {
    private var soulcounting: Number = 1;
    private var Muting: Boolean = false;
    private var snd:Sound = new Sound();

    public function MainThing() {
        snd.load(new URLRequest("SOUL1.mp3"));
        stage.addEventListener(Event.ENTER_FRAME, FrameHandler);
        }

    private function FrameHandler(event: Event): void {
        if (Object(root).currentFrame == 2) {
            var channel:SoundChannel = snd.play(0,1);
            channel.soundTransform = new SoundTransform(1,0);
            /*the soulcounting number is determined by a keyboard function...  
            I didn't deem it necessary to be included in here,  
            as I don't think it is part of the problem.*/
            if (soulcounting == 1) {
                Object(root).SOULS.gotoAndStop(1);
                Muting = false;
                }

            if (soulcounting == 2) {
                Object(root).SOULS.gotoAndStop(2);
                Muting = true;
                }

            if (soulcounting == 3) {
                Object(root).SOULS.gotoAndStop(3);
                Muting = true;
                }

            if (soulcounting == 4) {
                Object(root).SOULS.gotoAndStop(4);
                Muting = true;
                }

            if (soulcounting == 5) {
                Object(root).SOULS.gotoAndStop(5);
                Muting = true;
                }

            if (soulcounting == 6) {
                Object(root).SOULS.gotoAndStop(6);
                Muting = true;
                }

            if(Muting){
                setVolume(channel);
                }

            if(!Muting){
                setVolume(channel, 1);
                }
            } 

    private function setVolume (Soundchannel:SoundChannel, volume:Number=0) {
        var trans:SoundTransform = Soundchannel.soundTransform;
        trans.volume = volume;
        Soundchannel.soundTransform = trans;
        }
    }
}

(如果我尝试预览 swf,一切正常,直到我到达第二帧,其中输出开始重复 TypeError:错误 #1009:无法访问空对象引用的属性或方法。 在 MainThing/FrameHandler())
TypeError #1009 似乎是一个非常常见的错误,但我所阅读的内容并没有真正帮助我解决这个问题......对不起,如果这里已经有解决方案,我只是没有足够的搜索...... .
提前致谢!

【问题讨论】:

  • Object(root) 应该是什么意思?如果是舞台上的某个 MovieClip,为什么不给那个 MC 一个 instance name,然后在代码中使用 if (myMCName.currentFrame == 2) 定位它?
  • 对象(根)是舞台。
  • 规则 #1... 永远不要让舞台使用多个帧(对于卡通片可以,但对于应用程序则不行)。取而代之的是制作一个大(舞台大小)MovieClip 作为容器,然后将所有旧舞台帧剪切/粘贴到其中。如果您将容器称为(实例名称)为 contMC 那么您的代码可以说 if (contMC.currentFrame == 2) 等...
  • 我仍然需要调用 Object(root).contMC,因为我正在使用 .as 文件。除非我添加指向 MovieClip 的链接,但这只会让它变得更加复杂,因为我必须使用 addChild 函数......我不知道在舞台上不使用多个帧(显示我的经验),它会导致性能问题吗?
  • 不,它避免了访问舞台项目和变量等问题。作为测试绘制一个小盒子形状(矩形,没有轮廓,只是填充颜色)然后右键单击并选择转换为 MClip。现在在 properties (ctrl+F3) 中只需将 box 放在实例名称部分。按 Enter 确认更改,然后按 ctrl+s 保存。将框 MC 拖到左侧作为起点.. 在您的函数 MainThing 中输入代码 box.x += 100.. 通过 ctrl+shift+enter 进行测试... 框是否移动到与放在舞台上不同的位置?跨度>

标签: actionscript-3 audio volume soundchannel


【解决方案1】:

请在调试模式下运行您的 swf,并向我们提供导致错误的行号。不知道是什么导致了问题,也不知道你想做什么,但为什么你会这样重复自己?甚至很难阅读。你也可以这样做:

public class MainThing extends MovieClip {
    private var soulcounting: Number = 1;
    private var Muting: Boolean = false;
    private var snd:Sound = new Sound();

    public function MainThing() {
        snd.load(new URLRequest("SOUL1.mp3"));
        stage.addEventListener(Event.ENTER_FRAME, FrameHandler);
    }

    private function FrameHandler(event: Event): void {
        if (Object(root).currentFrame != 2) return;
        var channel:SoundChannel = snd.play(0,1);
        channel.soundTransform = new SoundTransform(1,0);
        /*the soulcounting number is determined by a keyboard function...  
        I didn't deem it necessary to be included in here,  
        as I don't think it is part of the problem.*/
        SOULS.gotoAndStop(soulcounting);
        Muting = soulcounting != 1;
        setVolume(channel, Number(!Muting));
    } 

    private function setVolume (sch:SoundChannel, volume:Number=0) {
        var trans:SoundTransform = sch.soundTransform;
        trans.volume = volume;
        sch.soundTransform = trans;
    }

}

而且效率会更高。

【讨论】:

  • 我不是在重复自己吗?有 6 个选项,因此如果选择其中一个,MovieClip 必须转到 6 个帧……很抱歉,我不清楚这一点。我将所有内容都放在 if 中,因为我还有其他阶段框架的其他语句......也许我应该将它们放在单独的函数中,但是......我稍后会检查。 (我会尝试调试模式)。
  • 显然,这是我代码中的第 114 行,或者:channel.soundTransform = new SoundTransform(1,0);
  • 您在这里尝试访问的唯一内容,因此唯一可以为空的内容是channel。以及您从snd.play(); 获得的频道,如果您转到文档 - play(),您将阅读 如果您没有声卡或可用的声道用完,此方法将返回 null。一次可用的最大声道数为 32。 我们假设您有声卡,因此您必须调用 play() 超过 32 次。现在看起来很明显,因为您已将帧侦听器绑定到舞台。
  • 如何在不创建更多声道的情况下更新声道的音量?
  • 和你现在做的完全一样 - trans.volume。只是不要在帧事件中开始声音......
【解决方案2】:

感谢 Pawel Audionysos 和 VC.One 帮助我解决了我的问题。 我解决了!我没有使用SoundTransform.volume 函数,而是使用SoundChannel.position 和一个变量来“保存”上一首歌曲停止的位置,以便下一首歌曲将从该点开始: 如果有人感兴趣,这是代码:

package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.media.SoundTransform;
import flash.media.Sound;
import flash.media.SoundChannel; 
import flash.media.SoundMixer; 
import flash.net.URLLoader;
import flash.net.URLRequest;

public class MainThing extends MovieClip {
    private var bool:Boolean = false;
    private var snd1:Sound = new Sound();
    private var snd2:Sound = new Sound();
    private var snd3:Sound = new Sound();
    private var snd4:Sound = new Sound();
    private var snd5:Sound = new Sound();
    private var snd6:Sound = new Sound();
    private var channel1:SoundChannel = new SoundChannel();
    private var channel2:SoundChannel = new SoundChannel();
    private var channel3:SoundChannel = new SoundChannel();
    private var channel4:SoundChannel = new SoundChannel();
    private var channel5:SoundChannel = new SoundChannel();
    private var channel6:SoundChannel = new SoundChannel();
    private var songtime:Number = 0;
    private var NoSongHasBeenPlayedYet:Boolean = true;
    private var comesfromnothing:Boolean = true;
    private var comesfrom1:Boolean = false;
    private var comesfrom2:Boolean = false;
    private var comesfrom3:Boolean = false;
    private var comesfrom4:Boolean = false;
    private var comesfrom5:Boolean = false;
    private var comesfrom6:Boolean = false;

    public function MainThing() {
        snd1.load(new URLRequest("SOUL1.mp3"));
        snd2.load(new URLRequest("SOUL2.mp3"));
        snd3.load(new URLRequest("SOUL3.mp3"));
        snd4.load(new URLRequest("SOUL4.mp3"));
        snd5.load(new URLRequest("SOUL5.mp3"));
        snd6.load(new URLRequest("SOUL6.mp3"));
        stage.addEventListener(KeyboardEvent.KEY_DOWN, MenuButtons);

        stage.addEventListener(Event.ENTER_FRAME, FrameHandler);
    }
    private function FrameHandler(event: Event): void {
        if (Object(root).currentFrame == 2) {
            //I ommitted the part of the changes to the MovieClip's frames
            //the music function is called here... It didn't work anywhere else.
            Music();
            }
        } 
    private function Music():void{
        if(NoSongHasBeenPlayedYet){
            //this part happens either when the frame has just changed, or when the "songtime" variable has surpassed the audio length.
            comesfromnothing = true;
            channel1 = snd1.play(0,100);
            channel2 = snd2.play(0,100);
            channel3 = snd3.play(0,100);
            channel4 = snd4.play(0,100);
            channel5 = snd5.play(0,100);
            channel6 = snd6.play(0,100);
            NoSongHasBeenPlayedYet = false;
            bool = false;

            }
        if(!bool && songtime < 15150){
            switch(soulcounting){
                //In the original, there are 6 cases, for each song. I didn't put all of them in here because they are mostly the same, just with different numbers.
                case 1:
                    if(comesfromnothing){
                        trace(songtime);
                        songtime = channel2.position;
                        channel1.stop();
                        channel2.stop();
                        channel3.stop();
                        channel4.stop();
                        channel5.stop();
                        channel6.stop();
                        channel1 = snd1.play(songtime,100);
                        songtime = channel1.position;   
                        //the bool variable is there so that it doesn't create a new SoundChannel at every frame    
                        bool = true;
                        comesfromnothing = false;
                        comesfrom1 = true;

                    }
                    if(comesfrom2){
                        trace(songtime);
                        songtime = channel2.position;
                        channel1.stop();
                        channel2.stop();
                        channel1 = snd1.play(songtime,100);
                        songtime = channel1.position;       
                        bool = true;
                        comesfrom1 = true;
                        comesfrom2 = false;

                    }
                    if(comesfrom3){
                        trace(songtime);
                        songtime = channel3.position;
                        channel1.stop();
                        channel3.stop();
                        channel1 = snd1.play(songtime,100);
                        songtime = channel1.position;       
                        bool = true;
                        comesfrom1 = true;
                        comesfrom3 = false;
                    }
                    if(comesfrom4){
                        trace(songtime);
                        songtime = channel4.position;
                        channel1.stop();
                        channel4.stop();
                        channel1 = snd1.play(songtime,100);
                        songtime = channel1.position;       
                        bool = true;
                        comesfrom1 = true;
                        comesfrom3 = false;
                    }
                break;
            if(channel1.position  > 15100){
                trace(songtime);
                songtime = 0;
                channel1.stop();
                channel2.stop();
                channel3.stop();
                channel4.stop();
                channel5.stop();
                channel6.stop();
                NoSongHasBeenPlayedYet = true;

            }
        }
        public function MenuButtons(event: KeyboardEvent): void {
            if (Object(root).currentFrame == 2) {

            //this is the part of the controls, the bool is set to false so each time you press a botton, the audio can change.
            if (Keyboard.LEFT == event.keyCode && soulcounting != 1 && soulcounting != 4 && !Keyboardpressed) {
                soulcounting -= 1;
                bool = false;
                Keyboardpressed = true;} 
            else if (Keyboard.LEFT == event.keyCode && (soulcounting == 1 || soulcounting == 4) && !Keyboardpressed) {
                soulcounting += 2;
                bool = false;
                Keyboardpressed = true;} 
            else if (Keyboard.RIGHT == event.keyCode && soulcounting != 3 && soulcounting != 6 && !Keyboardpressed) {
                soulcounting += 1;
                bool = false;
                Keyboardpressed = true;} 
            else if (Keyboard.RIGHT == event.keyCode && (soulcounting == 3 || soulcounting == 6) && !Keyboardpressed) {
                soulcounting -= 2;
                bool = false;
                Keyboardpressed = true;} 
            else if ((Keyboard.UP == event.keyCode || Keyboard.DOWN == event.keyCode) && soulcounting > 3 && !Keyboardpressed) {
                soulcounting -= 3;
                bool = false;
                Keyboardpressed = true;} 
            else if ((Keyboard.DOWN == event.keyCode || Keyboard.UP == event.keyCode) && soulcounting < 4 && !Keyboardpressed) {
                soulcounting += 3;
                bool = false;
                Keyboardpressed = true;
                }
            }
        }
    }

【讨论】:

  • 很高兴你让它工作了,但你的编程方式并不好。一次启动所有声音然后在每种可能的情况下暂停不同的单个声音是不好的。想象一下,现在有 50 个字符,而不是 6 个字符。 1. 由于 32 复音的限制,它不会起作用 2. 你需要有 50 个 if 块并且在每个 49 个 channelX.stop() 调用中。如果您使用一种情况,还有什么是 switch 构造?什么是布尔值?很难为其他人弄清楚这一点。
  • 检查 this answer 可能会了解如何设计它。
  • 我明白你的意思,我会试着看看我怎样才能让它更有效率。原程序一共有6个case,除了歌曲的编号发生变化外,所有的case都和这里的case一样:channel1在case 1,channel2在case 2等等。“bool”就是我为阻止程序每帧创建一个新频道而制作的一个变量……我想它可以称为“SongChannelHasBeenCreated”……但是“bool”更短,我还没有使用那个名字…… . 很抱歉造成混乱...这确实表明我是新手,不是吗?
  • 注意新手的错误。我记得我在编写 rubic 立方体的 2d 投影时的第一个项目。我认为添加第 3 级嵌套循环会很复杂,并且“我只有几个案例”......最终得到 4K 行代码,而今天我可能会在 200 行内完成此操作。 :) 想想什么是重复的,什么是你可以重复使用的。例如。你不需要在声明时创建new SoundChannel();,这是没有意义的。相反,只需在开头说private var channel1:SoundChannel;,channel1 将是null,因此您可以检查该事实以确定您是否已经开始播放声音。
  • 另外,您在帧侦听器上调用music() 的原因是什么?据我了解,您只想更改鼠标动作的音乐。那你为什么不把它放在那里呢?
猜你喜欢
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-20
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多