Пример #1
0
 public void Pause(int channel = -1)
 {
     if (channel == MusicChannel)
     {
         SDL_mixer.Mix_PauseMusic();
     }
     else
     {
         SDL_mixer.Mix_Pause(channel);
     }
 }
Пример #2
0
        public override void Update(FPoint pos)
        {
            lastPos = pos;
            List <int> cleanup = new List <int>();

            foreach (var it in playback)
            {
                int      channel = it.Key;
                Playback play    = it.Value;
                if (play.Finished)
                {
                    cleanup.Add(channel);
                    continue;
                }
                if (play.Location.X == 0 && play.Location.Y == 0)
                {
                    continue;
                }
                float v = CalcDist(pos, play.Location) / soundFallOff;
                if (play.Loop)
                {
                    if (v < 1.0f && play.Paused)
                    {
                        SDL_mixer.Mix_Resume(channel);
                        play.Paused = false;
                    }
                    else if (v > 1.0f && !play.Paused)
                    {
                        SDL_mixer.Mix_Pause(channel);
                        play.Paused = true;
                        continue;
                    }
                }
                v = Math.Min(Math.Max(v, 0.0f), 1.0f);
                byte dist = (byte)(255.0f * v);
                SetChannelPosition(channel, 0, dist);
            }
            while (cleanup.Count > 0)
            {
                int channel = cleanup[0];
                cleanup.RemoveAt(0);
                if (playback.TryGetValue(channel, out Playback play))
                {
                    playback.Remove(channel);
                    if (channels.TryGetValue(play.VirtualChannel, out int vcit))
                    {
                        channels.Remove(play.VirtualChannel);
                    }
                }
            }
        }
Пример #3
0
 public override void PauseAll()
 {
     SDL_mixer.Mix_Pause(-1);
     SDL_mixer.Mix_PauseMusic();
 }
Пример #4
0
        /**
         * Used to start the GUI event loop using the SDL window to poll for events. When an event is
         * received, the keyboard state is read and the OnTick event is fired. After the event completes
         * a frame and/or audio can be rendered/played based on the values set in the OnTick event args.
         *
         * This is a BLOCKING call; the event loop will continue to be polled until (1) the user uses
         * the platform specific key combination or GUI action to close the window or (2) the OnTick
         * event arguments has ShouldQuit set to true.
         */
        public void StartLoop()
        {
            // Used to keep track of the time elapsed in each loop iteration. This is used to
            // notify the OnTick handlers so they can update their simulation, as well as throttle
            // the update loop to targetTicskHz if needed.
            var stopwatch = new Stopwatch();

            // Structure used to pass data to and from the OnTick handlers. We initialize it once
            // outside of the loop to avoid eating a ton of memory putting GC into a tailspin.
            var tickEventArgs = new GUITickEventArgs();

            // The SDL event polled for in each iteration of the loop.
            SDL.SDL_Event sdlEvent;

            while (true)
            {
                stopwatch.Restart();

                tickEventArgs.KeyDown     = null;
                tickEventArgs.ShouldBreak = false;

                while (SDL.SDL_PollEvent(out sdlEvent) != 0)
                {
                    switch (sdlEvent.type)
                    {
                    // e.g. Command + Q, ALT+F4, or clicking X...
                    case SDL.SDL_EventType.SDL_QUIT:
                        // Break out of the SDL event loop, which will close the program.
                        return;

                    case SDL.SDL_EventType.SDL_KEYDOWN:
                        tickEventArgs.KeyDown = sdlEvent.key.keysym.sym;
                        UpdateKeys(tickEventArgs, sdlEvent.key.keysym.sym, true);

                        // If the break/pause or 9 key is pressed, set a flag indicating the
                        // emulator's should activate the interactive debugger.
                        if (sdlEvent.key.keysym.sym == SDL.SDL_Keycode.SDLK_PAUSE ||
                            sdlEvent.key.keysym.sym == SDL.SDL_Keycode.SDLK_9)
                        {
                            tickEventArgs.ShouldBreak = true;
                        }

                        break;

                    case SDL.SDL_EventType.SDL_KEYUP:
                        UpdateKeys(tickEventArgs, sdlEvent.key.keysym.sym, false);
                        break;
                    }
                }

                // Update the event arguments that will be sent with the event handler.

                tickEventArgs.ShouldRender     = false;
                tickEventArgs.ShouldPlaySounds = false;
                tickEventArgs.SoundEffects.Clear();

                // Delegate out to the event handler so work can be done.
                if (OnTick != null)
                {
                    OnTick(tickEventArgs);
                }

                // We only want to re-render if the frame buffer has changed since last time because
                // the SDL_RenderPresent method is relatively expensive.
                if (tickEventArgs.ShouldRender && tickEventArgs.FrameBuffer != null)
                {
                    // Render screen from the updated the frame buffer.
                    // NOTE: The electron beam scans from left to right, starting in the upper left corner
                    // of the CRT when it is in 4:3 (landscape), which is how the framebuffer is stored.
                    // However, since the CRT in the cabinet is rotated left (-90 degrees) to show the game
                    // in 3:4 (portrait) we need to perform the rotation of points below by starting in the
                    // bottom left corner of the window and drawing upwards, ending on the top right.

                    // Clear the screen.
                    SDL.SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 0);
                    SDL.SDL_RenderClear(_renderer);

                    var bits = new System.Collections.BitArray(tickEventArgs.FrameBuffer);

                    var x = 0;
                    var y = SpaceInvaders.RESOLUTION_WIDTH - 1;

                    for (var i = 0; i < bits.Length; i++)
                    {
                        if (bits[i])
                        {
                            // The CRT is black/white and the framebuffer is 1-bit per pixel.
                            // A transparent overlay added "colors" to areas of the CRT. These
                            // are the approximate y locations of each area/color of the overlay:

                            if (y >= 182 && y <= 223)
                            {
                                SDL.SDL_SetRenderDrawColor(_renderer, 0, 255, 0, 255); // Green - player and shields
                            }
                            else if (y >= 33 && y <= 55)
                            {
                                SDL.SDL_SetRenderDrawColor(_renderer, 255, 0, 0, 255); // Red - UFO
                            }
                            else
                            {
                                SDL.SDL_SetRenderDrawColor(_renderer, 255, 255, 255, 255); // White - Everything else
                            }
                            SDL.SDL_RenderDrawPoint(_renderer, x, y);
                        }

                        y--;

                        if (y == -1)
                        {
                            y = SpaceInvaders.RESOLUTION_WIDTH - 1;
                            x++;
                        }

                        if (x == SpaceInvaders.RESOLUTION_HEIGHT)
                        {
                            break;
                        }
                    }

                    SDL.SDL_RenderPresent(_renderer);
                }

                // Handle playing sound effects.
                if (soundEffects != null &&
                    tickEventArgs.ShouldPlaySounds &&
                    tickEventArgs.SoundEffects != null)
                {
                    foreach (var sfx in tickEventArgs.SoundEffects)
                    {
                        var pointer = soundEffects[sfx];

                        // Result of Mix_PlayChannel, which indicates the channel the sound is playing on.
                        // -1 indicates an error.
                        var playChannelResult = -1;

                        switch (sfx)
                        {
                        // The UFO sound effect loops until the UFO disappears or is destroyed.
                        case SoundEffect.UFO_Start:
                            playChannelResult = SDL_mixer.Mix_PlayChannel(AUDIO_CHANNEL_UFO, pointer, AUDIO_INFINITE_LOOP);
                            break;

                        case SoundEffect.UFO_Stop:
                        {
                            SDL_mixer.Mix_Pause(AUDIO_CHANNEL_UFO);

                            // Mix_Pause doesn't return a channel or error code. Ensure we don't leave as -1.
                            playChannelResult = AUDIO_CHANNEL_UFO;

                            break;
                        }

                        case SoundEffect.InvaderMove1:
                        case SoundEffect.InvaderMove2:
                        case SoundEffect.InvaderMove3:
                        case SoundEffect.InvaderMove4:
                            playChannelResult = SDL_mixer.Mix_PlayChannel(AUDIO_CHANNEL_INVADER_MOVEMENT, pointer, AUDIO_NO_LOOP);
                            break;

                        default:
                            playChannelResult = SDL_mixer.Mix_PlayChannel(AUDIO_CHANNEL_COMMON, pointer, AUDIO_NO_LOOP);
                            break;
                        }

                        if (playChannelResult == -1)
                        {
                            Console.WriteLine("Error playing sound effect {0}. SDL Error: {1}", sfx, SDL.SDL_GetError());
                        }
                    }
                }

                // See if we need to delay to keep locked to ~ targetTicskHz.

                if (stopwatch.Elapsed.TotalMilliseconds < (1000 / _targetTicksHz))
                {
                    var delay = (1000 / _targetTicksHz) - stopwatch.Elapsed.TotalMilliseconds;
                    SDL.SDL_Delay((uint)delay);
                }

                // If the event handler indicated we should quit, then stop.
                if (tickEventArgs.ShouldQuit)
                {
                    return;
                }
            }
        }