/// <summary> /// いまのところSlideカーブでの当たり判定用パスを作るためのみに使う /// 汎用性を高めればDrawSlideCurveメソッドとかをスッキリできそう /// </summary> /// <param name="past"></param> /// <param name="curve"></param> /// <param name="future"></param> /// <param name="drawOffset"></param> /// <returns></returns> public static GraphicsPath CreateSlideCurvePath(Note past, Note curve, Note future, PointF drawOffset) { GraphicsPath graphicsPath = new GraphicsPath(); PointF pastRerativeLocation = new PointF(past.Location.X, past.Location.Y); 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); PointF bottomRight = pastRerativeLocation.Add(-drawOffset.X, drawOffset.Y).AddX(past.Width); //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); // graphicsPath.AddBezier(bottomLeft, curveCenter.AddX(-widthAnchor / 2f), topLeft); graphicsPath.AddLine(topLeft, topRight); graphicsPath.AddBezier(topRight, curveCenter.AddX(widthAnchor / 2f), bottomRight); graphicsPath.AddLine(bottomLeft, bottomRight); return(graphicsPath); }
/// <summary> /// 真上向きAirのGraphicsPathを返します /// </summary> /// <returns></returns> protected virtual GraphicsPath GetAirPath(Point drawLocation) { GraphicsPath graphicsPath = new GraphicsPath(); PointF baseLocation = Location.Add(-drawLocation.X, -drawLocation.Y); PointF topCenter = baseLocation.AddX(Width / 2f).AddY(borderWidth).Add(drawOffset); PointF topRight = topCenter.AddX(Width / 2f - (Size - 1) * widthRatio).AddY(airHeight - airLineHeight - borderWidth); PointF topLeft = topCenter.AddX(-(Width / 2f - (Size - 1) * widthRatio)).AddY(airHeight - airLineHeight - borderWidth); PointF bottomCenter = topCenter.AddY(airLineHeight - borderWidth); PointF bottomRight = topRight.AddY(airLineHeight - borderWidth); PointF bottomLeft = topLeft.AddY(airLineHeight - borderWidth); graphicsPath.AddLines(new PointF[] { topCenter, topRight, bottomRight, bottomCenter, bottomLeft, topLeft }); graphicsPath.CloseFigure(); return(graphicsPath); }
/// <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); } } } }