Mouse down between two pieces of a puzzle

前端 未结 3 816
时光说笑
时光说笑 2021-01-28 18:30

I am building a puzzle game in winforms, and i want to recognize the mousedown over any piece, and move it with the mousemove. The issue is that when i touch the transparent par

相关标签:
3条回答
  • 2021-01-28 18:51

    In general, keep a list of all your puzzle piece controls, sorted top down. When you get a mouse down event on one piece, check the transparency at that point, if it it not transparent handle the event on that piece. If it is transparent forward the event to the next piece down in your list (directly calling the event handler is probably the easiest way). Keep doing this until you either find a non transparent point, or run out of pieces.

    UPDATE Here is a link to a project showing an example of how to do this in pure GDI. https://drive.google.com/file/d/0B42fIyGTLNv3WlJwNGVRN2txTGs/edit?usp=sharing

    0 讨论(0)
  • 2021-01-28 18:54

    Pieces can be represent as:

    public class Piece
    {
        public Point Location {get; set;}
        public int Z {get; set;}
        public int ID {get; set;} // to be bound to control or a control itself?
        public Image Image {get; set;} // texture?
        public DockStyle PlusArea {get; set;}
        public DockStyle MinusArea {get; set;}  // can be None
        ...
    
        public bool HitTest(Point point)
        {
            // assuming all of same size
            if((new Rectangle(Location, new Size(...)).Contains(point))
            {
                switch(MinusArea)
                {
                    case Top:
                        if((new Rectangle(...)).Contains(point))
                            return false;
                    ...
                }
            }
            switch(MinusArea)
            {
                case Top:
                    if((new Rectangle(...)).Contains(point))
                        return true;
                ...
            }
            return false;
        }
    

    Then puzzle is

    public class Puzzle
    {
        public List<Piece> Pieces {get; set;}
    
        public void Draw(Graphics graphics)
        {
            // draw all pictures with respect to z order
        }
    
        public Piece HitTest(Point point)
        {
            ... // hittest all pieces, return highest z-order or null
        }
    }
    

    It is not a complete solution, but should give you idea.

    Basically:

    • In mouse event you call Figure.HitTest() to get figure to start moving (that's what you need).
    • You draw everything into owner drawn control by calling Figure.Draw().
    • Obviously, drag-n-drop operations are calling Invalidate().
    • You may have special flag to indicate figure being dragged and draw it differently (with shadows, a bit offsetted to simulate it's pulled over other pieces, etc).
    • Each figure is represented as rectangle and PlusArea or MinusArea (don't know how to call them better, it's this extra or missing area of piece connectors), this is simplification, you can improve it.
    0 讨论(0)
  • 2021-01-28 18:56

    SOLVED :)

    i have figured it out... Here's the code to anybody how needs (I have made it right now, so the code is not clean yet):

    Piece Class:

    class Peça : DrawingArea
    {
        private Point _Offset = Point.Empty;
        public Boolean movable = false;
    
        public Image imagem
        {
            get;
            set;
        }
    
        protected override void OnDraw()
        {
            Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
            this.graphics.DrawImage(imagem, location);
        }
    
        public Boolean Down(Point e, bool propaga = true)
        {
            Bitmap b = new Bitmap(imagem);
            Color? color = null;
            Boolean flag = false;
            try
            {
                color = b.GetPixel(e.X, e.Y);
                if (color.Value.A != 0 && color != null)
                {
                   flag = true;
                }
                else
                {
                    flag = false;
                }
                return flag;
            }
            catch
            {
                return flag;
            }
        }
    }
    

    Form1:

    public partial class Form1 : Form
    {
        private List<Peça> peças;
        private Point _Offset = Point.Empty;
        private Peça peça1, peça2, peça3, peça4;
        private bool canMove;
        private Peça atual;
        private bool other=false;
        public Form1()
        {
            FormBorderStyle = FormBorderStyle.None;
            WindowState = FormWindowState.Maximized;
            InitializeComponent();
    
            atual = new Peça();
    
            peça1 = new Peça();
            peça2 = new Peça();
            peça3 = new Peça();
            peça4 = new Peça();
            peça1.imagem = Properties.Resources._4p1_1;
            peça2.imagem = Properties.Resources._4p1_2;
            peça3.imagem = Properties.Resources._4p1_3;
            peça4.imagem = Properties.Resources._4p1_4;
    
            peças = new List<Peça>();
    
            peça1.Name = "peça1";
            peça2.Name = "peça2";
            peça3.Name = "peça3";
            peça4.Name = "peça4";
    
            this.Controls.Add(peça1);
            this.Controls.Add(peça2);
            this.Controls.Add(peça3);
            this.Controls.Add(peça4);
    
            criaListaPecas();
    
            foreach (Peça p in peças)
            {
                p.Size = new Size(p.imagem.Width, p.imagem.Height);
            }
    
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
    
            associaEventosPecas();
            canMove = false;
        }
    
        private void associaEventosPecas()
        {
            foreach (Peça p in peças)
            {
                p.MouseMove += Form1_MouseMove;
                p.MouseDown += Form1_MouseDown;
                p.MouseUp += Form1_MouseUp;
            }
        }
    
        private void criaListaPecas()
        {
            peças.Clear();
            foreach (Control p in this.Controls)
            {
                if (p.GetType() == typeof(Peça))
                    peças.Add((Peça)p);
            }
            Console.WriteLine(peças[0].Name);
            Console.WriteLine(peças[1].Name);
            Console.WriteLine(peças[2].Name);
            Console.WriteLine(peças[3].Name);
        }
    
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams handleParam = base.CreateParams;
                handleParam.ExStyle |= 0x02000000;
                return handleParam;
            }
        }
    
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (sender.GetType().Equals(typeof(Peça)))
            {
                label1.Text = new Point(e.Location.X + (sender as Peça).Location.X, e.Location.Y + (sender as Peça).Location.Y).ToString();
            }
            else
            label1.Text = e.Location.ToString();
            gereMovimento(sender, e);
        }
    
        private void gereMovimento(object sender, MouseEventArgs e)
        {
            if (canMove)
            {
                if (other)
                {
                    Point p = atual.PointToClient(new Point(e.X + (sender as Peça).Location.X, e.Y + (sender as Peça).Location.Y));
    
                    Point newlocation = atual.Location;
                    newlocation.X += p.X - _Offset.X;
                    newlocation.Y += p.Y - _Offset.Y;
                    atual.Location = newlocation;
                }
                else
                {
                    Point newlocation = atual.Location;
                    newlocation.X += e.X - _Offset.X;
                    newlocation.Y += e.Y - _Offset.Y;
                    atual.Location = newlocation;
                }
            }
        }
    
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (sender.GetType().Equals(typeof(Peça)) && e.Button == MouseButtons.Left)
            {
                atual = sender as Peça;
                atual.BringToFront();
                criaListaPecas();
                if (atual.Down(e.Location))
                {
                    _Offset = new Point(e.X, e.Y);
                    canMove = true;
                    other = false;
                }
                else
                {
                    Console.WriteLine(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)));
                    Console.WriteLine(atual.Location);
                    Point p = new Point(); 
                    if (peças[1].ClientRectangle.Contains(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
                        && peças[1].Down(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
                    {
                        p = peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
                        atual = peças[1];
                        atual.BringToFront();
                        criaListaPecas();
                        _Offset = p;
                        canMove = true;
                        other = true;
                    }
                    else if (peças[2].ClientRectangle.Contains(peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
                        && peças[2].Down(peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
                    {
                        p = peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
                        atual = peças[2];
                        atual.BringToFront();
                        criaListaPecas();
                        _Offset = p;
                        canMove = true;
                        other = true;
                    }
                    else if (peças[3].ClientRectangle.Contains(peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
                        && peças[3].Down(peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
                    {
                        p = peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
                        atual = peças[3];
                        atual.BringToFront();
                        criaListaPecas();
                        _Offset = p;
                        canMove = true;
                        other = true;
                    }
                }
            }
        }
    
        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            canMove = false;
        }
    }
    

    Apologize the repeated and confused code, but as i said, i have made it seconds ago, and did not clean the code yet ;)

    0 讨论(0)
提交回复
热议问题