Search code examples
c#winformsmousedown

Mouse down between two pieces of a puzzle


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 part of the puzzle piece, i want to verify if there is any piece behind that one, and if so, start the mousemove of that other piece, got it?

I am also able to recognize if the mousedown was over the image, or if it happens in the transparent part of the puzzle piece. My problem is to get the best way to pass the mouse event to the piece behind.

Many Thanks in advance.

UPDATE 1

The following is the class for the puzzle piece:

class Peça : DrawingArea
{
    private Point _Offset = Point.Empty;
    public Image imagem
    {
        get;
        set;
    }


    protected override void OnDraw()
    {
        Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
        this.graphics.DrawImage(imagem, location);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (_Offset != Point.Empty)
        {
            Point newlocation = this.Location;
            newlocation.X += e.X - _Offset.X;
            newlocation.Y += e.Y - _Offset.Y;
            this.Location = newlocation;
        }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        _Offset = Point.Empty;
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        Down(e);
        //Console.WriteLine(color.ToString());
    }

    public void Down(MouseEventArgs e)
    {
        Bitmap b = new Bitmap(imagem);
        Color? color = null;
        try
        {
            color = b.GetPixel(e.X, e.Y);
            if (color.Value.A != 0 && color != null)
            {
                if (e.Button == MouseButtons.Left)
                {
                    _Offset = new Point(e.X, e.Y);
                    this.BringToFront();
                }
            }
        }
        catch {
             }
    }
} 

The following code, is my DrawingArea (Panel) that i create in order to work with transparency:

abstract public class DrawingArea : Panel
{
    protected Graphics graphics;
    abstract protected void OnDraw();

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT

            return cp;
        }
    }

    public DrawingArea()
    {

    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {

    }

    protected override void OnPaint(PaintEventArgs e)
    {

        this.graphics = e.Graphics;


        this.graphics.TextRenderingHint =
            System.Drawing.Text.TextRenderingHint.AntiAlias;
        this.graphics.InterpolationMode =
            System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
        this.graphics.PixelOffsetMode =
            System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        this.graphics.SmoothingMode =
            System.Drawing.Drawing2D.SmoothingMode.HighQuality;


        OnDraw();
    } 
}

And you can also see my Form code:

 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;       
            return handleParam;
        }
    }
}

Those are my pieces, and when i touch the transparent space in the first piece, i want to pick up the second one and move it on mouseMouse instead of doing nothing...

It looks like this:

enter image description here

Apologize my bad english.

UPDATE 2

I think i am getting very close to the solution, but something strange happens now, when i touch the piece behind another one, it disappear... What am i doing wrong?

SOME CODE UPDATES

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 void Move(MouseEventArgs e)
    {
        if (_Offset != Point.Empty)
        {
            Point newlocation = this.Location;
            newlocation.X += e.X - _Offset.X;
            newlocation.Y += e.Y - _Offset.Y;
            this.Location = newlocation;
        }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        _Offset = Point.Empty;
        movable = false;
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        Down(e);
        //Console.WriteLine(color.ToString());
    }

    public Boolean Down(MouseEventArgs e, bool propaga=true)
    {
        Form parentForm = (this.Parent as Form);
        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)
            {
                if (e.Button == MouseButtons.Left)
                {
                    _Offset = new Point(e.X, e.Y);
                    this.BringToFront();
                    flag = true;
                    movable = true;
                }
            }
            else
            {
                if(propaga)
                (this.Parent as Form1).propagaEvento(this, e);
                flag = false;

            }
            return flag; 
        }
        catch {
            return flag; }
    }
}

Form1:

public partial class Form1 : Form
{
    private List<Peça> peças;
    private Point _Offset = Point.Empty;
    public Form1()
    {
        InitializeComponent();

        peças = new List<Peça>();
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
        criaListaPecas();
        associaEventosPecas();      
    }

    private void associaEventosPecas()
    {
        foreach (Peça p in peças)
        {
            p.MouseMove += Form1_MouseMove;
        }
    }

    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);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;       
            return handleParam;
        }
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        label1.Text = e.Location.ToString();
        gereMovimento(e);
    }

    private void gereMovimento(MouseEventArgs e)
    {
        foreach (Peça p in peças)
        {
            if (p.movable)
            {
                p.Move(e);
            }
        }
    }

    internal void propagaEvento(Peça peça, MouseEventArgs e)
    {
        foreach (Peça p in peças)
        {
            if (p != peça)
            {
                if (p.Down(e, false))
                    break;
            }
        }
    }
}

Thanks in advance again :)


Solution

  • 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 ;)