c# - 使用 WinForms 连续绘制椭圆同时保留矩形

标签 c# winforms oop graphics abstract-class

我正在做关于 WinForms、继承、接口(interface)和抽象类的书中的练习。练习是创建几个沿随机方向移动的球,并让形状像盒子一样的障碍物与球相互作用。

enter image description here

书中的思路是,有一个 Ball 类和另一个名为 Engine 的类来处理椭圆的创建。我的工作是制造障碍物并让它们与球互动。

这是要求

All obstacles should be treated the same w.r.t. the engine; perhaps by using an interface. Do not use fully abstract classes

All obstacles should share as much code as possible, but only code that makes sense to share; use abstract classes if necessary to avoid inheriting methods that do not make sense or empty methods.

BallEngine,给定的类。

位置:

public class Position
    {
        public float X, Y;

        public Position(float x, float y)
        {
            X = x; Y = y;
        }
    }

向量:

public class Vector
{
    public float X, Y;

    public Vector(float x, float y)
    {
        X = x; Y = y;
    }
}

:

public class Ball
    {
        static Pen Pen = new Pen(Color.Black);

        Position Position;
        Vector Speed;

        float Radius;

        static Random Random = new Random();

        public Ball(float x, float y, float radius)
        {
            Position = new Position(x,y);
            var xd = Random.Next(1, 6);
            var yd = Random.Next(1, 6);
            if (Random.Next(0, 2) == 0) xd = -xd;
            if (Random.Next(0, 2) == 0) yd = -yd;

            Speed = new Vector(xd,yd);
            Radius = radius;
        }

        public void Draw(Graphics g)
        {
            g.DrawEllipse(Pen,Position.X - Radius, Position.Y - Radius, 2 * Radius, 2 * Radius);
        }

        public void Move()
        {
            Position.X += Speed.X;
            Position.Y += Speed.Y;
        }

    }

引擎:

public class Engine
    {
        MainForm Form = new MainForm();
        Timer Timer = new Timer();
        List<Ball> Balls = new List<Ball>();
        Redbox RBox = new Redbox(); //My added code 
        Random Random = new Random();


        public void Run()
        {
            Form.Paint += Draw;
            Timer.Tick += TimerEventHandler;
            Timer.Interval = 1000/25;
            Timer.Start();

            Application.Run(Form);
        }

        private void Form_Paint(object sender, PaintEventArgs e)
        {
            throw new NotImplementedException();
        }

        void TimerEventHandler(Object obj, EventArgs args)
        {
            if (Random.Next(100) < 25)
            {
                var ball = new Ball(400, 300, 10);
                Balls.Add(ball);
            }

            foreach (var ball in Balls)
            {
                ball.Move();
            }

            Form.Refresh();
        }

        void Draw(Object obj, PaintEventArgs args)
        {
            foreach (var ball in Balls)
            {
                ball.Draw(args.Graphics);
            }
            RBox.Draw(args.Graphics); //Testing 
        }
    }

这是我创建的界面:

interface IObstacles
{
    void Draw(Graphics g);
}

class Redbox : IObstacles
{
    public void Draw(Graphics g)
    {
        Pen Pen = new Pen(Color.Red);
        Random Random = new Random();
        Position Position = new Position(Random.Next(100, 700), Random.Next(100, 700));

        var width = Random.Next(30, 100);
        var height = Random.Next(30, 100);

        g.DrawRectangle(Pen, Position.X , Position.Y, width, height);

    }
}

我一直想弄清楚如何绘制我的一个(目前)矩形而不每次都刷新它。我可能听起来像个白痴,但我是相当新的。我得到的结果是相同的矩形以相同的刻度出现和消失。我还注意到 Ball 类在列表中创建并存储了新的“球”,但由于我的接口(interface)实现,我认为我不能这样做。我正在为所有 Obstacles 创建界面,因为它们相同但形状不同。我的实现可能有误,但至少对我来说这听起来合乎逻辑。

任何帮助将不胜感激,因为我是 C# 的新手。

最佳答案

使用 Jimi's建议 :

事实证明他是对的 Draw 中声明的随机性这不是正确的解决方案,就像他所说的那样,每次都会用随机重新绘制障碍 position .这一切都通过将它们移到外面来解决我还修改了类,以便可以选择绘制框的位置。

我发布了答案,以便其他偶然发现这个问题的人可以看看我是如何解决我的问题的,感谢 Jimi's解决方案。

接口(interface):

interface IObstacles
{
    void Draw(Graphics g);
}

class Redbox : IObstacles
{
    Pen Pen = new Pen(Color.Red);

    Random Random = new Random();
    Position Position;

    float width;
    float height;

    public Redbox(float x, float y)
    {
        Position = new Position(x, y);

        width = Random.Next(30, 100);
        height = Random.Next(30, 100);
    }


    public void Draw(Graphics g)
    {
        g.DrawRectangle(Pen, Position.X , Position.Y, width, height);
    }
}

引擎:

public class Engine
{
    MainForm Form = new MainForm();
    Timer Timer = new Timer();
    List<Ball> Balls = new List<Ball>();

    List<IObstacles> RBox = new List<IObstacles>(); 

    Random Random = new Random();


    public void Run()
    {
        Form.Paint += Draw;
        Timer.Tick += TimerEventHandler;
        Timer.Interval = 1000/25;
        Timer.Start();

        Application.Run(Form);
    }

    private void Form_Paint(object sender, PaintEventArgs e)
    {
        throw new NotImplementedException();
    }

    void TimerEventHandler(Object obj, EventArgs args)
    {
        
        if (Random.Next(100) < 25)
        {
            var ball = new Ball(400, 300, 10);
            Balls.Add(ball);
        }

        if (RBox.Count() < 2) 
        {
            RBox.Add(new Redbox(100 * Random.Next(1, 8), 100 * Random.Next(0, 6)));
        }
        foreach (var ball in Balls)
        {
            ball.Move();
        }

        Form.Refresh();
    }

    void Draw(Object obj, PaintEventArgs args)
    {
        foreach (var ball in Balls)
        {
            ball.Draw(args.Graphics);
        }

        foreach (var rbox in RBox)
        {
            rbox.Draw(args.Graphics);
        }
    }
}

如果还有任何问题或建议有人想补充,请随时发表评论。

关于c# - 使用 WinForms 连续绘制椭圆同时保留矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74778602/

相关文章:

c# - 使用正则表达式获取每个反斜杠之间的字符串

c# - 如何将 sonarqube 与 visual studio 解决方案集成

c# - 使用 SqlBulkCopy 和 C# 自动添加 SQL 日期时间

c# - 从图像文件创建视频?

c# - 在 C# 中动态创建的用户控件

c# - 在 C# winform 的文本框中使用另一种语言

c# - 计算winforms TextBox控件中显示行数的最准确方法

c# - 状态设计模式的功能等价物

PHP 优化这是正确的吗?

PHP:无法声明类,因为名称已在使用中