public void FillLane() { if (LaneBook.Any()) { FillLane(LaneBook.First()); } }
public override void RelocateOnlyAndUpdate(Position position, LaneBook laneBook) { base.RelocateOnlyAndUpdate(position, laneBook); Air?.RelocateOnlyAndUpdate(position, laneBook); airHoldBegin?.Relocate(position); airHoldBegin?.UpdateLocation(laneBook); }
// REVIEW: この辺の生ノーツデータを手づかみで触る処理はここじゃなくてNoteBookでやったほうが安全じゃない…? private void ReverseShortNotes(List <Note> noteList, LaneBook laneBook, NoteBook noteBook) { noteList.ForEach(x => { int reverseLane = BottomRightPosition.Lane - (x.Position.Lane - TopLeftPosition.Lane + x.Size) + 1; Position newPosition = new Position(reverseLane, x.Position.Tick); x.RelocateOnlyAndUpdate(newPosition, laneBook); if (x is AirableNote airable && airable.IsAirAttached) { Air newAir = null; if (airable.Air is AirUpL) { newAir = new AirUpR(x); } else if (airable.Air is AirUpR) { newAir = new AirUpL(x); } else if (airable.Air is AirDownL) { newAir = new AirDownR(x); } else if (airable.Air is AirDownR) { newAir = new AirDownL(x); } if (newAir != null) { noteBook.DetachAirFromAirableNote(airable, out _); noteBook.AttachAirToAirableNote(airable, newAir); } } }); }
public override void Draw(Graphics g, Point drawLocation, LaneBook laneBook) { base.Draw(g, drawLocation, laneBook); var list = this.OrderBy(x => x.Position.Tick).ToList(); foreach (Note note in list) { // 画面外の場合は描画しないようにしてなるべく処理を軽くしたい if (note.Position.Tick > Status.DrawTickLast) { continue; } if (list.IndexOf(note) < list.Count - 1) { Note next = list.Next(note); // 画面外の場合は描画しないようにしてなるべく処理を軽くしたい if (next.Position.Tick < Status.DrawTickFirst) { continue; } DrawAirHoldLine(g, note, next, drawLocation, laneBook); } //クリッピングの解除を忘れないこと g.ResetClip(); note.Draw(g, drawLocation); } }
// REVIEW: この辺の生ノーツデータを手づかみで触る処理はここじゃなくてNoteBookでやったほうが安全じゃない…? public void ReverseNotes(NoteBook noteBook, LaneBook laneBook) { ReverseShortNotes(SelectedNoteList, laneBook, noteBook); SelectedLongNoteList.ForEach(x => { ReverseShortNotes(x, laneBook, noteBook); }); }
public Model() { NoteBook = new NoteBook(); ScoreBook = new ScoreBook(); LaneBook = new LaneBook(); LaneBook.UpdateNoteLocation += NoteBook.UpdateNoteLocation; MusicInfo = new MusicInfo(); }
public void Draw(Graphics g, LaneBook laneBook, Point originLocation) { if (StartPosition == null || EndPosition == null) { return; } ScoreLane futureLane = laneBook.Find( x => x.StartTick <= TopLeftPosition.Tick && TopLeftPosition.Tick <= x.EndTick); ScoreLane pastLane = laneBook.Find( x => x.StartTick <= BottomRightPosition.Tick && BottomRightPosition.Tick <= x.EndTick); int passingLanes = futureLane != null ? futureLane.Index - pastLane.Index : laneBook.Count - pastLane.Index - 1; PointF topLeft = new PointF( pastLane.LaneRect.Left + TopLeftPosition.Lane * ScoreInfo.UnitLaneWidth - originLocation.X, pastLane.LaneRect.Bottom - (TopLeftPosition.Tick - pastLane.StartTick) * ScoreInfo.UnitBeatHeight - originLocation.Y - minHeight / 2); PointF topRight = new PointF( pastLane.LaneRect.Left + (BottomRightPosition.Lane + 1) * ScoreInfo.UnitLaneWidth - originLocation.X, pastLane.LaneRect.Bottom - (TopLeftPosition.Tick - pastLane.StartTick) * ScoreInfo.UnitBeatHeight - originLocation.Y - minHeight / 2); PointF bottomLeft = new PointF( pastLane.LaneRect.Left + TopLeftPosition.Lane * ScoreInfo.UnitLaneWidth - originLocation.X, pastLane.LaneRect.Bottom - (BottomRightPosition.Tick - pastLane.StartTick) * ScoreInfo.UnitBeatHeight - originLocation.Y + minHeight / 2); PointF bottomRight = new PointF( pastLane.LaneRect.Left + (BottomRightPosition.Lane + 1) * ScoreInfo.UnitLaneWidth - originLocation.X, pastLane.LaneRect.Bottom - (BottomRightPosition.Tick - pastLane.StartTick) * ScoreInfo.UnitBeatHeight - originLocation.Y + minHeight / 2); using (GraphicsPath graphicsPath = new GraphicsPath()) { var smoothingMode = g.SmoothingMode; g.SmoothingMode = SmoothingMode.Default; var itrLane = pastLane; for (int i = 0; i <= passingLanes; ++i, itrLane = laneBook.Next(itrLane)) { graphicsPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); graphicsPath.CloseFigure(); if (itrLane.StartTick <= Status.DrawTickLast && itrLane.EndTick >= Status.DrawTickFirst) { using (Pen pen = new Pen(Color.White, 1)) { pen.DashPattern = new float[] { 4f, 4f }; RectangleF clipRect = new RectangleF( itrLane.LaneRect.X - originLocation.X, itrLane.LaneRect.Y - originLocation.Y, //HACK: 選択領域矩形が少し大きいので見切れないようにする itrLane.LaneRect.Width + 1, itrLane.LaneRect.Height + 5); g.Clip = new Region(clipRect); g.DrawPath(pen, graphicsPath); } } topLeft = topLeft.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, itrLane.LaneRect.Height); topRight = topRight.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, itrLane.LaneRect.Height); bottomLeft = bottomLeft.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, itrLane.LaneRect.Height); bottomRight = bottomRight.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, itrLane.LaneRect.Height); graphicsPath.ClearMarkers(); } g.SmoothingMode = smoothingMode; } g.ResetClip(); }
public void UpdateLocation(LaneBook laneBook) { ScoreLane lane = laneBook.Find(x => x.StartTick <= Position.Tick && Position.Tick <= x.EndTick); if (lane == null) { return; } PointF location = new PointF( lane.LaneRect.Left + Position.Lane * ScoreInfo.UnitLaneWidth, //HACK: Y座標が微妙にずれるので-1して調節する lane.HitRect.Bottom - (Position.Tick - lane.StartTick) * ScoreInfo.UnitBeatHeight - 1); RelocateOnly(location, lane.Index); }
public override void Draw(Graphics g, Point drawLocation, LaneBook laneBook) { base.Draw(g, drawLocation, laneBook); var list = this.OrderBy(x => x.Position.Tick).ToList(); foreach (Note note in list) { if (list.IndexOf(note) < list.Count - 1) { Note next = list.Next(note); DrawHoldLine(g, note, next, drawLocation, laneBook); } //クリッピングの解除を忘れないこと g.ResetClip(); note.Draw(g, drawLocation); } }
public RelocateNoteOperation( List <Note> noteList, List <LongNote> longNoteList, Position diff, LaneBook laneBook) { Invoke += () => { noteList.ForEach(x => { Position positionAfter = new Position( x.Position.Lane + diff.Lane, x.Position.Tick + diff.Tick); x.RelocateOnlyAndUpdate(positionAfter, laneBook); }); longNoteList.ForEach(x => { x.ForEach(y => { Position positionAfter = new Position( y.Position.Lane + diff.Lane, y.Position.Tick + diff.Tick); y.RelocateOnlyAndUpdate(positionAfter, laneBook); }); }); }; Undo += () => { noteList.ForEach(x => { Position positionAfter = new Position( x.Position.Lane - diff.Lane, x.Position.Tick - diff.Tick); x.RelocateOnlyAndUpdate(positionAfter, laneBook); }); longNoteList.ForEach(x => { x.ForEach(y => { Position positionAfter = new Position( y.Position.Lane - diff.Lane, y.Position.Tick - diff.Tick); y.RelocateOnlyAndUpdate(positionAfter, laneBook); }); }); }; }
/// <summary> /// 選択矩形の左上の位置が引数のpositionとなるように移動します /// </summary> /// <param name="position"></param> /// <param name="laneBook"></param> // REVIEW: この辺の生ノーツデータを手づかみで触る処理はここじゃなくてNoteBookでやったほうが安全じゃない…? public void Relocate(Position position, LaneBook laneBook) { if (StartPosition == null || EndPosition == null || position == null) { return; } Position prevStartPosition = new Position(TopLeftPosition); Position areaSize = new Position(BottomRightPosition.Lane - TopLeftPosition.Lane, TopLeftPosition.Tick - BottomRightPosition.Tick); int newStartLane = position.Lane; if (newStartLane < 0) { newStartLane = 0; } else if (newStartLane + areaSize.Lane > 15) { newStartLane = 15 - areaSize.Lane; } int newStartTick = position.Tick; if (newStartTick - areaSize.Tick < 0) { newStartTick = areaSize.Tick; } StartPosition = new Position( newStartLane, newStartTick); EndPosition = new Position( StartPosition.Lane + areaSize.Lane, StartPosition.Tick - areaSize.Tick); SelectedNoteList.ForEach(x => { Position positionDelta = x.Position - prevStartPosition; x.RelocateOnlyAndUpdate(new Position(newStartLane + positionDelta.Lane, newStartTick + positionDelta.Tick), laneBook); }); SelectedLongNoteList.ForEach(x => { x.ForEach(y => { Position positionDelta = y.Position - prevStartPosition; y.RelocateOnlyAndUpdate(new Position(newStartLane + positionDelta.Lane, newStartTick + positionDelta.Tick), laneBook); }); }); }
public RelocateNoteOperation(Note note, Position before, Position after, LaneBook laneBook) { Invoke += () => { note.Relocate(after); note.UpdateLocation(laneBook); if (note is AirableNote airable) { airable.Air?.UpdateLocation(laneBook); airable.AirHold?.UpdateLocation(laneBook); } }; Undo += () => { note.Relocate(before); note.UpdateLocation(laneBook); if (note is AirableNote airable) { airable.Air?.UpdateLocation(laneBook); airable.AirHold?.UpdateLocation(laneBook); } }; }
/// <summary> /// SlideCurveの当たり判定 /// </summary> private bool ContainsInCurve(Note past, Note curve, Note future, LaneBook laneBook, PointF locationVirtual) { int passingLanes = future.LaneIndex - past.LaneIndex; using (GraphicsPath graphicsPath = MyUtil.CreateSlideCurvePath(past, curve, future, drawOffset)) { ScoreLane lane = laneBook.Find(x => x.Contains(past)); for (int i = 0; i <= passingLanes && lane != null; ++i) { if (graphicsPath.IsVisible(locationVirtual)) { return(true); } else { graphicsPath.Translate( ScoreLane.scoreWidth + ScoreLane.Margin.Left + ScorePanel.Margin.Right + ScorePanel.Margin.Left + ScoreLane.Margin.Right, lane.HitRect.Height); lane = laneBook.Next(lane); } } } return(false); }
private static void DrawAirHoldLine(Graphics g, Note past, Note future, Point drawLocation, LaneBook laneBook) { float distance = (future.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; PointF drawOffset = new PointF(past.Width / 2f - lineWidth / 2f, LongNote.drawOffset.Y); //相対位置 PointF pastRerativeLocation = new PointF(past.Location.X - drawLocation.X, past.Location.Y - drawLocation.Y); PointF futureRerativeLocation = new PointF(future.Location.X - drawLocation.X, future.Location.Y - drawLocation.Y); int passingLanes = future.LaneIndex - past.LaneIndex; //スライドのノーツとノーツがレーンをまたがないとき if (passingLanes == 0) { PointF topLeft = futureRerativeLocation.Add(drawOffset); PointF topRight = futureRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(future.Width); PointF bottomLeft = pastRerativeLocation.Add(drawOffset); PointF bottomRight = pastRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(past.Width); using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); using (SolidBrush myBrush = new SolidBrush(lineColor)) { g.FillPath(myBrush, graphicsPath); } } } //スライドのノーツとノーツがレーンをまたぐとき else if (passingLanes >= 1) { float positionDistance = (future.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; float diffX = (future.Position.Lane - past.Position.Lane) * ScoreInfo.UnitLaneWidth; #region 最初のレーンでの描画 //ノーツfutureの位置はノーツpastの位置に2ノーツの距離を引いて表す。またTopRightの水平位置はfutureのWidthを使うことに注意 PointF topLeft = pastRerativeLocation.Add(diffX, -positionDistance).Add(drawOffset); PointF topRight = pastRerativeLocation.Add(diffX, -positionDistance).Add(-drawOffset.X, drawOffset.Y).AddX(future.Width); //以下の2つはレーンをまたがないときと同じ PointF bottomLeft = pastRerativeLocation.Add(drawOffset); PointF bottomRight = pastRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(past.Width); using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); ScoreLane scoreLane = laneBook.Find(x => x.Contains(past)); if (scoreLane != null) { RectangleF clipRect = new RectangleF( scoreLane.LaneRect.X - drawLocation.X, scoreLane.LaneRect.Y - drawLocation.Y, scoreLane.LaneRect.Width, scoreLane.LaneRect.Height); g.Clip = new Region(clipRect); } using (SolidBrush myBrush = new SolidBrush(lineColor)) { g.FillPath(myBrush, graphicsPath); } } #endregion #region 以降最後までのレーンでの描画 { ScoreLane prevLane, curLane; for (prevLane = laneBook.Find(x => x.Contains(past)), curLane = laneBook.Next(prevLane); curLane != null && laneBook.IndexOf(curLane) <= future.LaneIndex; prevLane = curLane, curLane = laneBook.Next(curLane)) { topLeft.X = curLane.LaneRect.X + future.Position.Lane * ScoreInfo.UnitLaneWidth - drawLocation.X + drawOffset.X; topLeft.Y += prevLane.LaneRect.Height; topRight.X = topLeft.X + future.Width - 2 * drawOffset.X; topRight.Y += prevLane.LaneRect.Height; bottomLeft.X = curLane.LaneRect.X + past.Position.Lane * ScoreInfo.UnitLaneWidth - drawLocation.X + drawOffset.X; bottomLeft.Y += prevLane.LaneRect.Height; bottomRight.X = bottomLeft.X + past.Width - 2 * drawOffset.X; bottomRight.Y += prevLane.LaneRect.Height; using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); RectangleF clipRect = new RectangleF(curLane.LaneRect.Location.Sub(drawLocation), curLane.LaneRect.Size); g.Clip = new Region(clipRect); using (SolidBrush myBrush = new SolidBrush(lineColor)) { g.FillPath(myBrush, graphicsPath); } } } } #endregion } }
public void SetScore(int beatNumer, int beatDenom, int barCount) { LaneBook.SetScore(ScoreBook, beatNumer, beatDenom, barCount); }
/// <summary> /// ノーツ間を繋ぐ帯の描画(ベジェ) /// </summary> private static void DrawSlideCurve(Graphics g, Note past, Note curve, Note future, Point drawLocation, LaneBook laneBook, ref RectangleF gradientRect) { if (gradientRect.Width <= 0) { gradientRect.Width = 1; } if (gradientRect.Height <= 0) { gradientRect.Height = 1; } //相対位置 PointF pastRerativeLocation = new PointF(past.Location.X - drawLocation.X, past.Location.Y - drawLocation.Y); int passingLanes = future.LaneIndex - past.LaneIndex; float positionDistanceFuture = (future.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; float positionDistanceCurve = (curve.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; float diffXFuture = (future.Position.Lane - past.Position.Lane) * ScoreInfo.UnitLaneWidth; float diffXCurve = (curve.Position.Lane - past.Position.Lane) * ScoreInfo.UnitLaneWidth; //ノーツfutureの位置はノーツpastの位置に2ノーツの距離を引いて表す。またTopRightの水平位置はfutureのWidthを使うことに注意 PointF topLeft = pastRerativeLocation.Add(diffXFuture, -positionDistanceFuture).Add(drawOffset); PointF topRight = pastRerativeLocation.Add(diffXFuture, -positionDistanceFuture).Add(-drawOffset.X, drawOffset.Y).AddX(future.Width); //以下の2つはレーンをまたがないときと同じ PointF bottomLeft = pastRerativeLocation.Add(drawOffset).AddY(deltaHeight); PointF bottomRight = pastRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(past.Width).AddY(deltaHeight); //3つのそれぞれのノーツの中心の座標 PointF topCenter = topLeft.AddX(future.Width / 2f - drawOffset.X); PointF bottomCenter = bottomLeft.AddX(past.Width / 2f - drawOffset.X); PointF curveCenter = pastRerativeLocation.Add(diffXCurve, -positionDistanceCurve).AddX(curve.Width / 2f); // //下からアンカーまでの比率 float ratio = (curveCenter.Y - bottomCenter.Y) / (topCenter.Y - bottomCenter.Y); //カーブノーツのY座標で水平にスライドを切ったときのスライド幅 float widthAnchor = (topRight.X - topLeft.X) * ratio + (bottomRight.X - bottomLeft.X) * (1 - ratio); using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddBezier(bottomLeft, curveCenter.AddX(-widthAnchor / 2f), topLeft); graphicsPath.AddLine(topLeft, topRight); graphicsPath.AddBezier(topRight, curveCenter.AddX(widthAnchor / 2f), bottomRight); graphicsPath.AddLine(bottomLeft, bottomRight); ScoreLane scoreLane = laneBook.Find(x => x.Contains(past)); RectangleF clipRect; for (int i = 0; i <= passingLanes && scoreLane != null; ++i) { if (Status.DrawTickFirst < scoreLane.EndTick && scoreLane.StartTick < Status.DrawTickLast) { clipRect = new RectangleF( scoreLane.LaneRect.X - drawLocation.X, scoreLane.LaneRect.Y - drawLocation.Y, scoreLane.LaneRect.Width, scoreLane.LaneRect.Height); g.Clip = new Region(clipRect); using (LinearGradientBrush myBrush = new LinearGradientBrush(gradientRect, baseColor, baseColor, LinearGradientMode.Vertical)) { myBrush.InterpolationColors = colorBlend; g.FillPath(myBrush, graphicsPath); } using (Pen myPen = new Pen(lineColor, 2)) { g.DrawBezier(myPen, bottomCenter, curveCenter, topCenter); } } // インクリメント bottomCenter = bottomCenter.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, scoreLane.HitRect.Height); curveCenter = curveCenter.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, scoreLane.HitRect.Height); topCenter = topCenter.Add(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, scoreLane.HitRect.Height); if (i != passingLanes) { graphicsPath.Translate(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, scoreLane.HitRect.Height); gradientRect.Y += scoreLane.HitRect.Height; scoreLane = laneBook.Next(scoreLane); } } } }
/// <summary> /// ノーツ間を繋ぐ帯の描画(直線) /// </summary> private static void DrawSlideLine(Graphics g, Note past, Note future, Point drawLocation, LaneBook laneBook, ref RectangleF gradientRect) { if (gradientRect.Width <= 0) { gradientRect.Width = 1; } if (gradientRect.Height <= 0) { gradientRect.Height = 1; } //相対位置 PointF pastRerativeLocation = new PointF(past.Location.X - drawLocation.X, past.Location.Y - drawLocation.Y); int passingLanes = future.LaneIndex - past.LaneIndex; float positionDistance = (future.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; float diffX = (future.Position.Lane - past.Position.Lane) * ScoreInfo.UnitLaneWidth; //ノーツfutureの位置はノーツpastの位置に2ノーツの距離を引いて表す。またTopRightの水平位置はfutureのWidthを使うことに注意 PointF topLeft = pastRerativeLocation.Add(diffX, -positionDistance).Add(drawOffset); PointF topRight = pastRerativeLocation.Add(diffX, -positionDistance).Add(-drawOffset.X, drawOffset.Y).AddX(future.Width); //以下の2つはレーンをまたがないときと同じ PointF bottomLeft = pastRerativeLocation.Add(drawOffset).AddY(deltaHeight); PointF bottomRight = pastRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(past.Width).AddY(deltaHeight); using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddPolygon(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); ScoreLane scoreLane = laneBook.Find(x => x.Contains(past)); RectangleF clipRect; for (int i = 0; i <= passingLanes && scoreLane != null; ++i) { if (Status.DrawTickFirst < scoreLane.EndTick && scoreLane.StartTick < Status.DrawTickLast) { clipRect = new RectangleF( scoreLane.LaneRect.X - drawLocation.X, scoreLane.LaneRect.Y - drawLocation.Y, scoreLane.LaneRect.Width, scoreLane.LaneRect.Height); g.Clip = new Region(clipRect); using (LinearGradientBrush myBrush = new LinearGradientBrush(gradientRect, baseColor, baseColor, LinearGradientMode.Vertical)) { myBrush.InterpolationColors = colorBlend; g.FillPath(myBrush, graphicsPath); } using (Pen myPen = new Pen(lineColor, 2)) { g.DrawLine( myPen, (graphicsPath.PathPoints[1].X + graphicsPath.PathPoints[2].X) / 2, graphicsPath.PathPoints[1].Y, (graphicsPath.PathPoints[0].X + graphicsPath.PathPoints[3].X) / 2, graphicsPath.PathPoints[0].Y); } } // インクリメント if (i != passingLanes) { graphicsPath.Translate(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, scoreLane.HitRect.Height); gradientRect.Y += scoreLane.HitRect.Height; scoreLane = laneBook.Next(scoreLane); } } } }
/// <summary> /// このスライドを描画します。 /// </summary> /// ノーツのリストに対して前から回して、そのノーツとそれと次のノーツまでの帯を描画し、そのノーツを描画 public override void Draw(Graphics g, Point drawLocation, LaneBook laneBook) { if (g == null) { return; } base.Draw(g, drawLocation, laneBook); var list = this.OrderBy(x => x.Position.Tick).ToList(); RectangleF gradientRect = new RectangleF(); var stepList = list.Where(x => x is SlideBegin || x is SlideTap || x is SlideEnd).ToList(); Note gradientNote, gradientNext, next, curve; foreach (Note note in list) { // 画面外の場合は描画しないようにしてなるべく処理を軽くしたい if (note.Position.Tick > Status.DrawTickLast) { continue; } if (list.IndexOf(note) < list.Count - 1 && !(note is SlideCurve)) { //スライド帯のグラデーション用矩形を設定する if (note is SlideBegin || note is SlideTap || note is SlideEnd) { gradientNote = note; gradientNext = stepList.Next(note); if (gradientNext != null) { float distance = (gradientNext.Position.Tick - gradientNote.Position.Tick) * ScoreInfo.UnitBeatHeight; //x座標と幅は適当な値を入れたけどちゃんとうごいてるっぽい?重要なのはy座標と高さ gradientRect = new RectangleF(0, gradientNote.Location.Y - distance + drawOffset.Y - drawLocation.Y, 10, distance); } } //スライド帯を描画する next = list.Next(note); if (!(next is SlideCurve)) { // 画面外の場合は描画しないようにしてなるべく処理を軽くしたい if (next.Position.Tick < Status.DrawTickFirst) { continue; } DrawSlideLine(g, note, next, drawLocation, laneBook, ref gradientRect); } else { curve = next; //SlideRelayは末尾に来ることはないし,SlideRelayが2つ以上連続に並ぶことはないという確信の元実装 //↑実際ノーツの束縛処理でそうなるような実装をしている(した) if (list.IndexOf(curve) < list.Count - 1) { next = list.Next(curve); // 画面外の場合は描画しないようにしてなるべく処理を軽くしたい if (next.Position.Tick < Status.DrawTickFirst) { continue; } DrawSlideCurve(g, note, curve, next, drawLocation, laneBook, ref gradientRect); } } } //クリッピングの解除を忘れないこと g.ResetClip(); //非表示設定のノーツは描画しないようにする if (note is SlideRelay && !Status.IsSlideRelayVisible) { continue; } if (note is SlideCurve && !Status.IsSlideCurveVisible) { continue; } note.Draw(g, drawLocation); } }
/// <summary> /// 与えられた座標がスライド帯の上に乗っているか判定します /// </summary> public bool Contains(PointF locationVirtual, LaneBook laneBook) { var list = this.OrderBy(x => x.Position.Tick).ToList(); foreach (Note note in list) { if (list.IndexOf(note) >= list.Count - 1) { break; } Note next = list.ElementAt(list.IndexOf(note) + 1); if (note is SlideCurve) { continue; } else if (next is SlideCurve) { var ret = ContainsInCurve(note, next, list.ElementAt(list.IndexOf(next) + 1), laneBook, locationVirtual); if (ret) { return(true); } } // int passingLanes = next.LaneIndex - note.LaneIndex; if (passingLanes == 0) { PointF topLeft = next.Location.Add(drawOffset); PointF topRight = next.Location.Add(-drawOffset.X, drawOffset.Y).AddX(next.Width); PointF bottomLeft = note.Location.Add(drawOffset); PointF bottomRight = note.Location.Add(-drawOffset.X, drawOffset.Y).AddX(note.Width); using (GraphicsPath hitPath = new GraphicsPath()) { hitPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); if (hitPath.IsVisible(locationVirtual)) { return(true); } } } else if (passingLanes >= 1) { float positionDistance = (next.Position.Tick - note.Position.Tick) * ScoreInfo.UnitBeatHeight; float diffX = (next.Position.Lane - note.Position.Lane) * ScoreInfo.UnitLaneWidth; #region 最初のレーンでの判定処理 PointF topLeft = note.Location.Add(drawOffset).Add(diffX, -positionDistance); PointF topRight = note.Location.Add(-drawOffset.X, drawOffset.Y).AddX(next.Width).Add(diffX, -positionDistance); PointF bottomLeft = note.Location.Add(drawOffset); PointF bottomRight = note.Location.Add(-drawOffset.X, drawOffset.Y).AddX(note.Width); using (GraphicsPath hitPath = new GraphicsPath()) { hitPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); if (hitPath.IsVisible(locationVirtual)) { return(true); } } #endregion #region 以降最後までの判定処理 ScoreLane prevLane, curLane; for (prevLane = laneBook.Find(x => x.Contains(note)), curLane = laneBook.Next(prevLane); curLane != null && laneBook.IndexOf(curLane) <= next.LaneIndex; prevLane = curLane, curLane = laneBook.Next(curLane)) { topLeft.X = curLane.LaneRect.X + next.Position.Lane * ScoreInfo.UnitLaneWidth + drawOffset.X; topLeft.Y += prevLane.LaneRect.Height; topRight.X = topLeft.X + next.Width - 2 * drawOffset.X; topRight.Y += prevLane.LaneRect.Height; bottomLeft.X = curLane.LaneRect.X + note.Position.Lane * ScoreInfo.UnitLaneWidth + drawOffset.X; bottomLeft.Y += prevLane.LaneRect.Height; bottomRight.X = bottomLeft.X + note.Width - 2 * drawOffset.X; bottomRight.Y += prevLane.LaneRect.Height; using (GraphicsPath hitPath = new GraphicsPath()) { hitPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); if (hitPath.IsVisible(locationVirtual)) { return(true); } } } #endregion } } return(false); }
private static void DrawHoldLine(Graphics g, Note past, Note future, Point drawLocation, LaneBook laneBook) { float distance = (future.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; //グラデーション矩形 //x座標と幅は適当だけど動いてるはず。重要なのはy座標と高さ RectangleF gradientRect = new RectangleF(0, past.Location.Y - distance + drawOffset.Y - drawLocation.Y, 10, distance <= 0 ? 1 : distance); //相対位置 PointF pastRerativeLocation = new PointF(past.Location.X - drawLocation.X, past.Location.Y - drawLocation.Y); int passingLanes = future.LaneIndex - past.LaneIndex; float positionDistance = (future.Position.Tick - past.Position.Tick) * ScoreInfo.UnitBeatHeight; float diffX = (future.Position.Lane - past.Position.Lane) * ScoreInfo.UnitLaneWidth; //ノーツfutureの位置はノーツpastの位置に2ノーツの距離を引いて表す。またTopRightの水平位置はfutureのWidthを使うことに注意 PointF topLeft = pastRerativeLocation.Add(diffX, -positionDistance).Add(drawOffset); PointF topRight = pastRerativeLocation.Add(diffX, -positionDistance).Add(-drawOffset.X, drawOffset.Y).AddX(future.Width); //以下の2つはレーンをまたがないときと同じ PointF bottomLeft = pastRerativeLocation.Add(drawOffset); PointF bottomRight = pastRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(past.Width); using (GraphicsPath graphicsPath = new GraphicsPath()) { graphicsPath.AddLines(new PointF[] { topLeft, bottomLeft, bottomRight, topRight }); ScoreLane scoreLane = laneBook.Find(x => x.Contains(past)); for (int i = 0; i <= passingLanes && scoreLane != null; ++i) { if (Status.DrawTickFirst < scoreLane.EndTick && scoreLane.StartTick < Status.DrawTickLast) { RectangleF clipRect = new RectangleF( scoreLane.LaneRect.X - drawLocation.X, scoreLane.LaneRect.Y - drawLocation.Y, scoreLane.LaneRect.Width, scoreLane.LaneRect.Height); g.Clip = new Region(clipRect); using (LinearGradientBrush myBrush = new LinearGradientBrush(gradientRect, baseColor, baseColor, LinearGradientMode.Vertical)) { myBrush.InterpolationColors = colorBlend; g.FillPath(myBrush, graphicsPath); } } // インクリメント if (i != passingLanes) { graphicsPath.Translate(ScoreLane.Width + ScorePanel.Margin.Left + ScorePanel.Margin.Right, scoreLane.HitRect.Height); gradientRect.Y += scoreLane.HitRect.Height; scoreLane = laneBook.Next(scoreLane); } } } }
public void InsertScoreForward(Score score, int beatNumer, int beatDenom, int barCount) { LaneBook.InsetScoreForward(ScoreBook, score, beatNumer, beatDenom, barCount); }
public void DeleteScore(Score score, int count) { LaneBook.DeleteScore(ScoreBook, score, count); }
public void DivideLane(Score score) { LaneBook.DivideLane(score); }
public void InsertScoreBackwardWithNote(Score score, int beatNumer, int beatDenom, int barCount) { LaneBook.InsertScoreBackwardWithNote(NoteBook, ScoreBook, score, beatNumer, beatDenom, barCount); }
public void FillLane(ScoreLane begin) { LaneBook.FillLane(begin); }
public virtual void RelocateOnlyAndUpdate(Position position, LaneBook laneBook) { RelocateOnly(position); UpdateLocation(laneBook); }