示例#1
0
        /// <summary>
        /// Draws a curve between startCoordinate and endCoordinate of movement according to the max offset,
        /// specified by amp. Drawn using a sine function with rotation
        /// Note that both Positions and slope have length of number of intervals + 1. This is for drawing purpose only.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="bpm"></param>
        /// <param name="amp"></param>
        public Function(Movement movement, int bpm, float amp)
        {
            this.movement = movement;
            Size = (int)((movement.endBeat - movement.startBeat + 1) / (float)bpm * 60 / INTERVAL_TIME) * 8;
            Positions = new Vector2[Size + 1];

            // Change coordinates so that (0,0) is bottom left
            // Original start and ending positions specified by XML
            Vector2 oStartPos = new Vector2(movement.startCoordinate.X, movement.startCoordinate.Y);
            Vector2 oEndPos = new Vector2(movement.endCoordinate.X, movement.endCoordinate.Y);
            shiftPos = oStartPos;
            endPos = oEndPos - shiftPos;

            if (amp == 0)
            {
                isStraightLine = true;
                Position();
            }
            else
            {
                Vector2 endPosPrime = new Vector2(Vector2.Distance(oStartPos, oEndPos), 0);
                Vector2 midPosPrime = new Vector2(endPosPrime.X / 2, 2 * amp);

                // Rotation angle
                double theta = Math.Atan((oEndPos.Y - oStartPos.Y) / (oEndPos.X - oStartPos.X));
                if (oEndPos.X < oStartPos.X) theta += Math.PI;

                double midPosX = Math.Cos(theta) * midPosPrime.X - Math.Sin(theta) * midPosPrime.Y;
                double midPosY = Math.Sin(theta) * midPosPrime.X + Math.Cos(theta) * midPosPrime.Y;
                midPos = new Vector2((float)midPosX, (float)midPosY);

                Position();

            }
        }
示例#2
0
 private bool Expired(Movement m)
 {
     return m.fadeBeat < current_beat;
 }
示例#3
0
        public override void Update(GameTime gameTime)
        {
            if (CountDownDone() && !watch.IsRunning)
            {
                Start();
            }

            if (satisfaction.maxAge == 0 )
            {
                if (!failed)
                {
                    MediaPlayer.Stop();
                    distorted.Stop();
                    MediaPlayer.IsMuted = false;
                    MediaPlayer.Play(LevelFail);
                }
                failed = true;
            }
            else
            {
                satisfaction.Update(gameTime);

                // Adjusts volume
                Keys key = gameState.Input.Key;
                if (key != Keys.None)
                {
                    if (key == Keys.A)
                    {
                        volume = MathHelper.Clamp(volume + 1, 1, 10);
                    }
                    else if (key == Keys.Z)
                    {
                        volume = MathHelper.Clamp(volume - 1, 1, 10);
                    }

                    scaledVol = (float)(0.524 * Math.Pow(Math.E, volume / 10) - 0.425); // exponential scale
                    if (MediaPlayer.IsMuted) distorted.Volume = scaledVol;
                    else MediaPlayer.Volume = scaledVol;
                }

                //watch = watch.Add(gameTime.ElapsedGameTime);

                current_beat = beat_sum + (int)Math.Round((float)watch.ElapsedMilliseconds / beatTime);
                bool newMovement = false;
                if (current_beat > last_beat) // new beat
                {

                    last_beat = current_beat;

                    if (current_act != null && current_act.endBeat < current_beat)
                    {
                        current_act = null;

                    }
                    LinkedListNode<Movement> checkMove = actionList.First;

                    drawSet.RemoveWhere(Expired);

                    while (checkMove != null)
                    {

                        if (checkMove.Value.showBeat == current_beat)
                        {
                            drawSet.Add(checkMove.Value);
                            checkMove = checkMove.Next;
                        }
                        else if (checkMove.Value.showBeat > current_beat) break;
                        else checkMove = checkMove.Next;
                    }

                    do
                    {

                        // check and remove the head of the list
                        if (actionList.First != null && actionList.First.Value.startBeat == current_beat)
                        {
                            current_act = actionList.First.Value;
                            if (current_act.myType != Movement.Types.Control)
                            {
                                actionList.RemoveFirst();
                                c++;
                                newMovement = true;
                            }
                            else
                            {
                                beat_sum = current_beat;
                                accumulated_ms = accumulated_ms + (int)watch.ElapsedMilliseconds;
                                beatTime = 60000 / current_act.BPM;
                                actionList.RemoveFirst();
                                watch.Restart();
                            }
                        }
                        else break;
                    } while (true);

                    if (current_act != null)
                    {
                        Movement.Types type = current_act.myType;
                        float score = moveEval.Accuracy(current_act, buffer, gameTime);

                        gainedScore = (int)(score * 10);
                       // comboOn = moveEval.CurrentMovement !=null && moveEval.CurrentMovement.myType == Movement.Types.Wave ? gainedScore > 0 : true;

                        // Adjusts age of satisfaction queue
                        if (gainedScore < 0)
                        {
                            if (moveEval.CurrentMovement.myType == Movement.Types.Wave ) failCount++;
                            if (satisfaction.maxAge < 5) satisfaction.maxAge = 0;
                            else satisfaction.maxAge = Math.Max(4, satisfaction.maxAge - AGE_DECR);
                            if (failCount == 3 && current_act.myType == Movement.Types.Wave)
                            {
                                Random rand = new Random();
                                BrokenStrings[rand.Next(3)].Play();
                            }
                            else
                            {
                                if (failCount >= 5)
                                {
                                    MediaPlayer.IsMuted = true;
                                    distorted.Volume = scaledVol;
                                }
                            }

                        }
                        else
                        {
                            failCount = 0;
                            satisfaction.maxAge = Math.Min(SatisfactionQueue.MAX_AGE, satisfaction.maxAge + AGE_INCR);
                            MediaPlayer.IsMuted = false;
                            distorted.Volume = 0.0f;
                        }

                        moveEval.Update(current_act, score, (newMovement || actionList.Count == 0), gameTime, this);
                        /* Keep the combo on if it is now Wave and the most recent gainedScore is greater than 0 (i.e. success continues),
                         * or if combo is on before a Shake phase is entered,
                         * otherwise break the combo. */
                       // comboOn = !(gainedScore < 0 && type == Movement.Types.Wave /* and last is also wave */);
                        comboOn = gainedScore > 3 || (comboOn && gainedScore == 0);
                        /** Add to combo count if it is now Wave and combo is on,
                         * else if it is now Wave but combo is broken, reset count to 0,
                         * else if combo is on but a Shape or Noop phase is entered, keep the count until next Wave. */
                        comboCount = comboOn && moveEval.CurrentMovement.myType == Movement.Types.Wave ? comboCount + 1 : (type == Movement.Types.Wave ? 0 : comboCount);
                        if (comboCount > maxCombo) maxCombo = comboCount;
                        //  if (actionList.First != null) // prevents score from endlessly increasing

                        /** Add gainedScore to current_score.
                         * If there is a combo and the most recent score is non-negative (e.g. Shaking is succuessful), also add the current combo count to the score */
                        if (actionList.Count != 0) current_score += (gainedScore + (comboCount > 1 && gainedScore > 0 ? comboCount : 0));
                        current_score = Math.Max(0, current_score);

                        if (newMovement) { buffer.Clear();  }
                    }
                }
            }

            if (actionList.Count == 0 || failed)
            {
                untilClapping++;
                if (untilClapping == 150) ended = true;
                if (!failed && untilClapping == 150)
                {
                    if (current_score < 1000)
                    {
                        SmallApplause.Play();
                    }
                    else
                    {
                        LargeApplause.Play();
                    }
                }
                backToMenu++;
            }
            if (backToMenu >= 420)
            {
                //UnloadContent(); // doesn't seem to work, i.e. memory usage does not decrease
                if (!failed)
                {
                    gameState.Score = current_score;
                    gameState.Combo = (maxCombo > 1 ? maxCombo : 0);

                    gameState.UpdateStats();
                }
                else
                {
                    gameState.Score = -1;
                    gameState.Combo = -1;
                }
                gameState.CurrentScreen = gameState.PreviousScreen;
            }
        }
        /**
        public bool Timing(InputBuffer inputs, Point p, bool start)
        {
            if (inputs.Count != 0)
            {
                Vector2 coords = new Vector2(p.X, GameEngine.HEIGHT - p.Y);
                Vector2 pos = (start ? inputs[0].Position : inputs[inputs.Count - 1].Position);
                //  Console.WriteLine("coords is " + coords);
                //  Console.WriteLine("pos is " + pos);
                //  Console.WriteLine("difference in pos is " + Vector2.Distance(coords, pos)+"\n");
                return Vector2.Distance(coords, pos) <= 100;
            }
            else
            {
                return false;
            }
        } */
        /*Returns a floating number 0 to 1 which indicates how well the input is matching the movement */
        public float Accuracy(Movement m, InputBuffer inputs, GameTime t)
        {
            int totalInput = inputs.Count;
            int correct = 0;
            if (CurrentMovement != null)
            {
                switch (CurrentMovement.myType)
                {
                    case Movement.Types.Noop:
                        return (totalInput > 20 ? -0.5f : 0.0f);
                    case Movement.Types.Shake:
                        if (totalInput < 20)
                        {
                            return 0.0f;
                        }
                        else
                        {
                            foreach (InputState state in inputs)
                            {
                                if (Math.Abs(state.Acceleration.X) > ACC_THRESHOLD || Math.Abs(state.Acceleration.Y) > ACC_THRESHOLD)
                                {
                                    correct++;
                                }
                            }
                            return (float)correct / totalInput / 2;
                        }
                    case Movement.Types.Wave:
                        if (totalInput < 5)
                        {
                            return -0.3f;
                        }
                        else
                        {
                            Vector2 startPos = new Vector2(CurrentMovement.startCoordinate.X, CurrentMovement.startCoordinate.Y);
                            Vector2 endPos = new Vector2(CurrentMovement.endCoordinate.X, CurrentMovement.endCoordinate.Y);
                            float DIST_THRESHOLD = 0.55f * Vector2.Distance(startPos, endPos);

                            Vector2[] slopes = CurrentMovement.f.Slope(totalInput - 1);
                            float errorSum = 0.0f;
                            float dist = Vector2.Distance(inputs[totalInput - 1].Position, inputs[0].Position);

                            if (dist >= DIST_THRESHOLD)
                            {
                                for (int i = 1; i < totalInput; i++)
                                {
                                    Vector2 normVel = Vector2.Normalize(inputs[i].Velocity);
                                    Vector2 slope = slopes[i];
                                    errorSum += (normVel.X - slope.X) * (normVel.X - slope.X) + (normVel.Y - slope.Y) * (normVel.Y - slope.Y);
                                }
                                float rmsError = (float)Math.Sqrt((double)errorSum / (double)(totalInput - 1));
                                float accuracy = (1 - rmsError * MAGIC_WAVE_THRESHOLD);
                                return (accuracy > FAIL_THRESHOLD ? accuracy : -0.3f);
                            }
                            else
                            {
                                return -0.3f;
                            }
                        }
                    default:
                        return 0.0f;
                }
            }
            else
            {
                return 0.0f;
            }
        }
 public MovementEvaluator(Movement m)
 {
     CurrentMovement = m;
 }
 public void Update(Movement m, float score, bool newMovement, GameTime t, PlayLevel level)
 {
     if (newMovement) // current movement is over, set state accordingly
     {
         //Debug.WriteLine("NEW MOVEMENT!");
         // send score back to Movement
         if (CurrentMovement != null)
         {
             if (score < FAIL_THRESHOLD)
             {
                 CurrentMovement.setState(Movement.States.Fail);
             }
             else if (score >= FAIL_THRESHOLD)
             {
                 CurrentMovement.setState(Movement.States.Succeed);
             }
             else // no op
             {
                 CurrentMovement.setState(Movement.States.None);
             }
         }
         CurrentMovement = m; // update movement
     }
 }