/// <summary> /// 将指定的拼图碎片与当前的拼图碎片合并。不检查两个拼图碎片是否可以被合并。 /// </summary> /// <param name="piece">要合并的拼图碎片。</param> public void Merge(JigsawPiece piece) { // 更新相邻拼图碎片信息。 foreach (JigsawPiece p in piece.neighbors) { p.neighbors.Remove(piece); p.neighbors.Add(this); } this.neighbors.UnionWith(piece.neighbors); this.neighbors.Remove(this); // 更新形状。 float sum = this.shape.Weight + piece.shape.Weight; this.offset = new Vector2((this.offset.X * this.shape.Weight + piece.offset.X * piece.shape.Weight) / sum, (offset.Y * this.shape.Weight + piece.offset.Y * piece.shape.Weight) / sum); this.shape.Merge(piece.shape); // 更新路径。 GeometryGroup newGroup = SharpDXUtility.Merge(this.originalPath, piece.originalPath); this.originalPath.Dispose(); this.originalPath = newGroup; this.CalculateMatrix(); this.UpdatePath(); if (piece.PieceType == JigsawPieceType.Border) { this.pieceType = JigsawPieceType.Border; } piece.Dispose(); }
/// <summary> /// 判断指定的拼图碎片是否可以与当前碎片合并。 /// </summary> /// <param name="piece">要判断合并的拼图碎片。</param> /// <param name="radius">允许进行吸附的半径。</param> /// <returns>是否能合并。</returns> public bool CanMerge(JigsawPiece piece, float radius) { if (piece == this) { return(true); } if (piece.rotate != this.rotate) { return(false); } // 在拼图坐标系下比较 (0, 0) 点的距离。 Vector2 point = new Vector2(); return(radius * radius >= Vector2.DistanceSquared(this.PointToJigsaw(point), piece.PointToJigsaw(point))); }
/// <summary> /// 判断指定的拼图碎片是否可以与当前碎片合并。 /// </summary> /// <param name="piece">要判断合并的拼图碎片。</param> /// <param name="radius">允许进行吸附的半径。</param> /// <returns>是否能合并。</returns> public bool CanMerge(JigsawPiece piece, float radius) { if (piece == this) { return true; } if (piece.rotate != this.rotate) { return false; } // 在拼图坐标系下比较 (0, 0) 点的距离。 Vector2 point = new Vector2(); return radius * radius >= Vector2.DistanceSquared(this.PointToJigsaw(point), piece.PointToJigsaw(point)); }
/// <summary> /// 返回指定拼图碎片的阴影位图。 /// </summary> /// <param name="piece">要获取阴影位图的拼图碎片。</param> /// <returns>指定拼图碎片的阴影位图。</returns> private Tuple<Bitmap, Vector2> GetShadow(JigsawPiece piece) { Tuple<Bitmap, Vector2> tuple; if (!shadowCache.TryGetValue(piece.OriginalPath, out tuple)) { // 移除已被释放的拼图碎片。 Geometry disposedGeom = null; if ((disposedGeom = shadowCache.Keys.FirstOrDefault(g => g.IsDisposed)) != null) { shadowCache.Remove(disposedGeom); } RectangleF bounds = piece.OriginalPath.GetBounds(); Size2 size = new Size2((int)bounds.Width + ShadowPadding * 2, (int)bounds.Height + ShadowPadding * 2); using (Bitmap1 source = DeviceManager.CreateBitmap(size)) { Bitmap1 target = DeviceManager.CreateBitmap(size); // 设置特效的输入。 shadowEffect.SetInput(0, source, true); // 阴影的偏移。 Vector2 offset = new Vector2(bounds.Left - ShadowPadding, bounds.Top - ShadowPadding); using (TransformedGeometry tGeom = new TransformedGeometry(this.DeviceContext.Factory, piece.OriginalPath, Matrix3x2.Translation(-offset.X, -offset.Y))) { // 将拼图碎片绘制到位图上。 this.DeviceContext.Target = source; this.DeviceContext.BeginDraw(); this.DeviceContext.Clear(Color.Transparent); this.DeviceContext.FillGeometry(tGeom, blackBrush); this.DeviceContext.EndDraw(); // 将添加特效后的拼图碎片绘制到位图上。 this.DeviceContext.Target = target; this.DeviceContext.BeginDraw(); this.DeviceContext.DrawImage(shadowEffect); this.DeviceContext.EndDraw(); tuple = new Tuple<Bitmap, Vector2>(target, offset); shadowCache.Add(piece.OriginalPath, tuple); } } } return tuple; }
/// <summary> /// 鼠标移动。 /// </summary> private void renderPanel_MouseMove(object sender, MouseEventArgs e) { Vector2 loc = renderPanel.PointToJigsaw(e.Location); if (isDraging) { // 拖动被选中的拼图碎片 Drag(loc); lastMousePoint = loc; } else if (isSelecting) { // 选择图片。 if (lastMousePoint.X < loc.X) { selectRect.Left = lastMousePoint.X; selectRect.Right = loc.X; } else { selectRect.Left = loc.X; selectRect.Right = lastMousePoint.X; } if (lastMousePoint.Y < loc.Y) { selectRect.Top = lastMousePoint.Y; selectRect.Bottom = loc.Y; } else { selectRect.Top = loc.Y; selectRect.Bottom = lastMousePoint.Y; } selectedPieces.Clear(); selectedPieces.AddRange(pieces.GetPiece(selectRect)); } else { // 鼠标经过时高亮拼图碎片 if (lastPiece != null) { lastPiece.State &= ~JigsawPieceState.Highlight; } lastPiece = pieces.GetPiece(loc); if (lastPiece != null && !lastPiece.Frozen) { lastPiece.State |= JigsawPieceState.Highlight; } } InvalidateAll(); }
/// <summary> /// 检查当前拼图碎片能否与其它拼图碎片合并。 /// </summary> private void CheckAnchor() { int finished = this.FinishedPercent; lastPiece = pieces.Merge(lastPiece, gameInfo.AnchorRadius); // 移除被合并的拼图碎片。 this.selectedPieces.IntersectWith(pieces); // 吸附到正确的位置。 if (gameInfo.AnchorToBackground && lastPiece.Rotate == 0) { float tx = lastPiece.Offset.X; float ty = lastPiece.Offset.Y; if ((tx * tx + ty * ty) <= gameInfo.AnchorRadius * gameInfo.AnchorRadius) { lastPiece.Frozen = true; lastPiece.Offset = new Vector2(); pieces.BringToBack(lastPiece); } } pieces.CollectInRectangle(renderPanel.JigsawRegion, this.selectedPieces); if (selectedPieces.SingleSelected) { selectedPieces.Clear(); } renderPanel.AutoMouseScroll = false; gameChanged = true; if (this.FinishedPercent != finished) { UpdateFinishedPercent(); } }
/// <summary> /// 鼠标弹起。 /// </summary> private void renderPanel_MouseUp(object sender, MouseEventArgs e) { renderPanel.Cursor = Cursors.Default; if (e.Button == MouseButtons.Left) { if (isDraging) { // 鼠标弹起,放下拼图碎片。 StopDrag(); CheckAnchor(); } else if (isSelecting) { isSelecting = false; } // 把拼图碎片放到最底层。 if (Control.ModifierKeys == Keys.Control) { if (lastPiece != null) { pieces.BringToBack(lastPiece); } } } else if (e.Button == MouseButtons.Right && gameInfo.Rotatable) { // 右键旋转 Vector2 loc = renderPanel.PointToJigsaw(e.Location); lastPiece = pieces.GetPiece(loc); if (lastPiece != null && !lastPiece.Frozen) { pieces.BringToFront(lastPiece); if (Control.ModifierKeys == Keys.Control) { lastPiece.Rotate = (lastPiece.Rotate + 270) % 360; } else { lastPiece.Rotate = (lastPiece.Rotate + 90) % 360; } CheckAnchor(); } } InvalidateAll(); }
/// <summary> /// 鼠标按下。 /// </summary> private void renderPanel_MouseDown(object sender, MouseEventArgs e) { isSelecting = false; if (e.Button == MouseButtons.Left) { lastMousePoint = renderPanel.PointToJigsaw(e.Location); lastPiece = pieces.GetPiece(lastMousePoint); if (lastPiece != null && lastPiece.Frozen) { lastPiece = null; } if (lastPiece == null) { selectedPieces.Clear(); isSelecting = true; selectRect = new RectangleF(lastMousePoint.X, lastMousePoint.Y, 0f, 0f); } else { renderPanel.Cursor = Cursors.Hand; if (!selectedPieces.Contains(lastPiece)) { // 拖动单个拼图碎片 selectedPieces.Clear(); selectedPieces.Add(lastPiece); } StartDrag(); renderPanel.AutoMouseScroll = true; } } else { selectedPieces.Clear(); } InvalidateAll(); }