예제 #1
0
        [Test] public void RemoveAtFast()
        {
            RawList <int> list = new RawList <int> {
                0, 1, 2, 3, 4, 5, 6, 7, 8, 9
            };

            list.RemoveAtFast(9);
            CollectionAssert.AreEqual(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, list);

            list.RemoveAtFast(0);
            CollectionAssert.AreEqual(new int[] { 8, 1, 2, 3, 4, 5, 6, 7 }, list);

            list.RemoveAtFast(3);
            CollectionAssert.AreEqual(new int[] { 8, 1, 2, 7, 4, 5, 6 }, list);

            list.RemoveAtFast(6);
            list.RemoveAtFast(5);
            list.RemoveAtFast(4);
            list.RemoveAtFast(3);
            CollectionAssert.AreEqual(new int[] { 8, 1, 2 }, list);

            list.RemoveAtFast(0);
            list.RemoveAtFast(0);
            CollectionAssert.AreEqual(new int[] { 1 }, list);

            list.RemoveAtFast(0);
            CollectionAssert.AreEqual(new int[0], list);
        }
예제 #2
0
        private void UpdateDebris(float timeMult)
        {
            for (int i = 0; i < debrisList.Count; i++)
            {
                ref DestructibleDebris debris = ref debrisList.Data[i];

                debris.Time -= timeMult;
                if (debris.Scale <= 0f || debris.Alpha <= 0f)
                {
                    debrisList.RemoveAtFast(i);
                    i--;
                    continue;
                }
                if (debris.Time <= 0f)
                {
                    debris.AlphaSpeed = -MathF.Min(0.02f, debris.Alpha);
                }

                if (debris.CollisionAction != DebrisCollisionAction.None)
                {
                    // Debris should collide with tilemap
                    float  nx     = debris.Pos.X + debris.Speed.X * timeMult;
                    float  ny     = debris.Pos.Y + debris.Speed.Y * timeMult;
                    Hitbox hitbox = new Hitbox(nx - 1, ny - 1, nx + 1, ny + 1);
                    if (IsTileEmpty(ref hitbox, true))
                    {
                        // Nothing...
                    }
                    else if (debris.CollisionAction == DebrisCollisionAction.Disappear)
                    {
                        debris.ScaleSpeed   = -0.02f;
                        debris.AlphaSpeed   = -0.006f;
                        debris.Speed        = Vector2.Zero;
                        debris.Acceleration = Vector2.Zero;
                    }
                    else
                    {
                        // Place us to the ground only if no horizontal movement was
                        // involved (this prevents speeds resetting if the actor
                        // collides with a wall from the side while in the air)
                        hitbox = new Hitbox(nx - 1, debris.Pos.Y - 1, nx + 1, debris.Pos.Y + 1);
                        if (IsTileEmpty(ref hitbox, true))
                        {
                            if (debris.Speed.Y > 0f)
                            {
                                debris.Speed.Y = -(0.8f /*elasticity*/ * debris.Speed.Y);
                                //OnHitFloorHook();
                            }
                            else
                            {
                                debris.Speed.Y = 0;
                                //OnHitCeilingHook();
                            }
                        }

                        // If the actor didn't move all the way horizontally,
                        // it hit a wall (or was already touching it)
                        hitbox = new Hitbox(debris.Pos.X - 1, ny - 1, debris.Pos.X + 1, ny + 1);
                        if (IsTileEmpty(ref hitbox, true))
                        {
                            debris.Speed.X    = -(0.8f /*elasticity*/ * debris.Speed.X);
                            debris.AngleSpeed = -(0.8f /*elasticity*/ * debris.AngleSpeed);
                            //OnHitWallHook();
                        }
                    }
                }

                debris.Pos.X += debris.Speed.X * timeMult;
                debris.Pos.Y += debris.Speed.Y * timeMult;

                if (debris.Acceleration.X != 0f)
                {
                    debris.Speed.X = MathF.Min(debris.Speed.X + debris.Acceleration.X * timeMult, 10f);
                }
                if (debris.Acceleration.Y != 0f)
                {
                    debris.Speed.Y = MathF.Min(debris.Speed.Y + debris.Acceleration.Y * timeMult, 10f);
                }

                debris.Scale += debris.ScaleSpeed * timeMult;
                debris.Angle += debris.AngleSpeed * timeMult;
                debris.Alpha += debris.AlphaSpeed * timeMult;
            }
예제 #3
0
        private void ThreadStreamFunc()
        {
            short[] buffer = new short[bufferSizeSamples];

            Stopwatch watch = new Stopwatch();

            watch.Restart();

            while (!streamWorkerEnd)
            {
                // Process even number of samples (both channels of interleaved stereo)
                // Fill only small part of the main buffer to lower the latency
                // Latency is already quite high on Android
                int samplesPlayed = masterTrack.PlaybackHeadPosition * 2;
                int samplesNeeded = ((samplesPlayed + bufferSizeSamples - samplesWritten) / 12) & ~1;

                for (int j = 0; j < streamWorkerQueue.Count; j++)
                {
                    NativeAudioSource source = streamWorkerQueue[j];

                    // Mix samples into the main buffer
                    int bufferPos = 0;
                    while (bufferPos < samplesNeeded && source.QueuedBuffers.Count > 0)
                    {
                        int     bufferIndex = source.QueuedBuffers.Peek();
                        ref int playbackPos = ref source.QueuedBuffersPos[bufferIndex];

                        NativeAudioBuffer sourceBuffer = source.AvailableBuffers[bufferIndex];
                        int samplesInBuffer            = MathF.Min(sourceBuffer.Length - playbackPos, samplesNeeded - bufferPos);
                        //int samplesInBuffer = MathF.Min((int)((sourceBuffer.Length - playbackPos) / source.LastState.Pitch), samplesNeeded - bufferPos);
                        if (!mute)
                        {
                            //if (MathF.Abs(1f - source.LastState.Pitch) < 0.01f) {
                            for (int i = 0; i < samplesInBuffer; i += 2)
                            {
                                int sampleLeft  = buffer[bufferPos] + (short)(sourceBuffer.InternalBuffer[playbackPos + i] * source.VolumeLeft);
                                int sampleRight = buffer[bufferPos + 1] + (short)(sourceBuffer.InternalBuffer[playbackPos + i + 1] * source.VolumeRight);

                                // Fast check to prevent clipping
                                if (MathF.Abs(sampleLeft) < short.MaxValue &&
                                    MathF.Abs(sampleRight) < short.MaxValue)
                                {
                                    buffer[bufferPos]     = (short)sampleLeft;
                                    buffer[bufferPos + 1] = (short)sampleRight;
                                }

                                bufferPos += 2;
                            }
                            //} else {
                            //    // ToDo: Check this pitch changing...
                            //    for (int i = 0; i < samplesInBuffer; i += 2) {

                            //        float io = playbackPos + (int)(i * source.LastState.Pitch);

                            //        short sample11 = sourceBuffer.InternalBuffer[(int)io];
                            //        short sample12 = sourceBuffer.InternalBuffer[MathF.Min((int)io + 2, sourceBuffer.Length - 2)];

                            //        short sampleLeft = (short)((sample11 + (sample12 - sample11) * (io % 1f)) * source.VolumeLeft);

                            //        short sample21 = sourceBuffer.InternalBuffer[MathF.Min((int)io + 1, sourceBuffer.Length - 1)];
                            //        short sample22 = sourceBuffer.InternalBuffer[MathF.Min((int)io + 3, sourceBuffer.Length - 1)];
                            //        short sampleRight = (short)((sample21 + (sample22 - sample21) * (io % 1f)) * source.VolumeRight);

                            //        // Fast check to prevent clipping
                            //        // ToDo: Do this better somehow...
                            //        if (MathF.Abs(buffer[bufferPos] + sampleLeft) < short.MaxValue &&
                            //            MathF.Abs(buffer[bufferPos + 1] + sampleRight) < short.MaxValue) {
                            //            buffer[bufferPos] += sampleLeft;
                            //            buffer[bufferPos + 1] += sampleRight;
                            //        }

                            //        bufferPos += 2;
                            //    }
                            //}
                        }
                        playbackPos += samplesInBuffer;
                        //playbackPos += (int)(samplesInBuffer * source.LastState.Pitch);

                        if (playbackPos >= sourceBuffer.Length)
                        {
                            playbackPos = NativeAudioSource.UnqueuedBuffer;
                            source.QueuedBuffers.Dequeue();
                        }
                    }

                    // Perform the necessary streaming operations on the audio source, and remove it when requested
                    if (source.IsStreamed)
                    {
                        // Try to stream new data
                        if (source.IsStopped || !source.PerformStreaming())
                        {
                            // End of stream, remove from queue
                            streamWorkerQueue.RemoveAtFast(j);
                            j--;
                        }
                    }
                    else
                    {
                        if (source.QueuedBuffers.Count == 0)
                        {
                            if (source.LastState.Looped)
                            {
                                // Enqueue sample again if looping is turned on
                                source.QueuedBuffers.Enqueue(0);
                                source.QueuedBuffersPos[0] = 0;
                            }
                            else
                            {
                                // End of sample array, remove from queue
                                streamWorkerQueue.RemoveAtFast(j);
                                j--;
                            }
                        }
                    }
                }

                // Write used part of the main buffer to Android's Audio Track
                masterTrack.Write(buffer, 0, samplesNeeded);
                samplesWritten += samplesNeeded;

                // Erase buffer to be ready for next batch
                for (int i = 0; i < samplesNeeded; i++)
                {
                    buffer[i] = 0;
                }

                // After each roundtrip, sleep a little, don't keep the processor busy for no reason
                watch.Stop();
                int roundtripTime = (int)watch.ElapsedMilliseconds;
                if (roundtripTime <= 1)
                {
                    streamWorkerQueueEvent.WaitOne(16);
                }
                watch.Restart();
            }