如何绘制随机 y 值的静态长度线

How to draw a static length line at random y values

我正在尝试创建一个小游戏,您必须使用 "turret" 来射击目标。目前我被困在我的目标线上。我的目标是让它以设定的 X 值生成,但每次我按下重绘按钮时它以随机的 Y 值生成。但是我的代码有问题。该线并非始终具有相同长度并以随机 Y 值生成,而是似乎以随机长度和随机 Y 值生成。如果有人能帮我找出我哪里出错了那将是完美的。

相关的变量有xTarget,yTarget(直线的第一个y值)yTargetEnd(直线的第二个y值)targetLine(行的静态长度)和 DrawLine() 方法调用 targetLine.

在我看来,我设置它的方式很有意义,但它似乎并没有达到我的预期。我尝试将 yTarget 设置为随机数,然后将 yTargetEnd 设置为 yTarget + targetLine,因此它的长度应该始终为 50,但这似乎根本不起作用?

public partial class Form1 : Form
{
    Random rnd = new Random { };
    double xEnd = 0;
    double yEnd = 0;
    double xOrigin = 30;
    double yOrigin = 450;
    double xFire;
    double yFire;
    double xTarget = 500;
    double yTarget;
    double yTargetEnd;
    double xHor = 30;
    double yHor = 350;
    double xVert = 130;
    double yVert = 450;
    double fireLine = 750;
    double lineLength = 50;
    double targetLine = 50;

    public Form1()
    {
        xEnd = xOrigin + lineLength;
        yEnd = yOrigin;
        xFire = xOrigin + fireLine;
        yFire = yOrigin;

        InitializeComponent(); 
    }

    private void LineDrawEvent(object sender, PaintEventArgs paint)
    {
        Graphics drawSurface = paint.Graphics;
        Pen turretLine = new Pen(Color.Blue);
        Pen graphHorizontal = new Pen(Color.Red);
        Pen graphVertical = new Pen(Color.Red);
        Pen firedLine = new Pen(Color.Blue);
        Pen targetLine = new Pen(Color.Black);
        float[] dashValues = { 5, 2 };
        firedLine.DashPattern = dashValues;

        drawSurface.DrawLine(graphVertical, (int)xOrigin, (int)yOrigin, (int)xHor, (int)yHor);
        drawSurface.DrawLine(graphHorizontal, (int)xOrigin, (int)yOrigin, (int)xVert, (int)yVert);
        drawSurface.DrawLine(firedLine, (int)xOrigin, (int)yOrigin, (int)xFire, (int)yFire);
        drawSurface.DrawLine(targetLine, (int)xTarget, (int)yTarget, (int)xTarget, (int)yTargetEnd);

        double angleInRadians = ConvertDegsToRads((double)trckBarAngle.Value);
        xEnd = xOrigin + lineLength * Math.Cos(angleInRadians / 2.0);
        yEnd = yOrigin - lineLength * Math.Sin(angleInRadians / 2.0);

        drawSurface.DrawLine(turretLine, (int)xOrigin, (int)yOrigin, (int)xEnd, (int)yEnd);
        this.Refresh();
    }

    private void trckBarAngle_Scroll(object sender, EventArgs e)
    {
        lblAngle.Text = "Angle is:" + Convert.ToString((double)trckBarAngle.Value / 2.0);  
    }

    private double ConvertDegsToRads(double degrees)
    {
        return degrees * (Math.PI / 180.0);
    }

    private void btnFire_Click(object sender, EventArgs e)
    {
        double angleInDegrees = trckBarAngle.Value;

        double angleInRadians = ConvertDegsToRads(angleInDegrees);
        xFire = xOrigin + fireLine * Math.Cos(angleInRadians / 2.0);
        yFire = yOrigin - fireLine * Math.Sin(angleInRadians / 2.0);
        this.Refresh();
    }

    private void btnRedraw_Click(object sender, EventArgs e)
    {
        yTargetEnd = yTarget - targetLine;
        yTarget = rnd.Next(100, 500);
    }
}

设计师生成的代码:

partial class Form1
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.lblAngle = new System.Windows.Forms.Label();
        this.trckBarAngle = new System.Windows.Forms.TrackBar();
        this.btnFire = new System.Windows.Forms.Button();
        this.btnRedraw = new System.Windows.Forms.Button();
        ((System.ComponentModel.ISupportInitialize)(this.trckBarAngle)).BeginInit();
        this.SuspendLayout();
        // 
        // lblAngle
        // 
        this.lblAngle.AutoSize = true;
        this.lblAngle.Location = new System.Drawing.Point(13, 13);
        this.lblAngle.Name = "lblAngle";
        this.lblAngle.Size = new System.Drawing.Size(46, 17);
        this.lblAngle.TabIndex = 0;
        this.lblAngle.Text = "label1";
        // 
        // trckBarAngle
        // 
        this.trckBarAngle.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
        | System.Windows.Forms.AnchorStyles.Right)));
        this.trckBarAngle.LargeChange = 10;
        this.trckBarAngle.Location = new System.Drawing.Point(732, 42);
        this.trckBarAngle.Maximum = 360;
        this.trckBarAngle.Minimum = -360;
        this.trckBarAngle.Name = "trckBarAngle";
        this.trckBarAngle.Orientation = System.Windows.Forms.Orientation.Vertical;
        this.trckBarAngle.Size = new System.Drawing.Size(56, 495);
        this.trckBarAngle.TabIndex = 1;
        this.trckBarAngle.Scroll += new System.EventHandler(this.trckBarAngle_Scroll);
        // 
        // btnFire
        // 
        this.btnFire.Location = new System.Drawing.Point(632, 13);
        this.btnFire.Name = "btnFire";
        this.btnFire.Size = new System.Drawing.Size(75, 23);
        this.btnFire.TabIndex = 2;
        this.btnFire.Text = "Fire";
        this.btnFire.UseVisualStyleBackColor = true;
        this.btnFire.Click += new System.EventHandler(this.btnFire_Click);
        // 
        // btnRedraw
        // 
        this.btnRedraw.Location = new System.Drawing.Point(713, 13);
        this.btnRedraw.Name = "btnRedraw";
        this.btnRedraw.Size = new System.Drawing.Size(75, 23);
        this.btnRedraw.TabIndex = 2;
        this.btnRedraw.Text = "Redraw";
        this.btnRedraw.UseVisualStyleBackColor = true;
        this.btnRedraw.Click += new System.EventHandler(this.btnRedraw_Click);
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(800, 549);
        this.Controls.Add(this.btnRedraw);
        this.Controls.Add(this.btnFire);
        this.Controls.Add(this.trckBarAngle);
        this.Controls.Add(this.lblAngle);
        this.Name = "Form1";
        this.Text = "Form1";
        this.Paint += new System.Windows.Forms.PaintEventHandler(this.LineDrawEvent);
        ((System.ComponentModel.ISupportInitialize)(this.trckBarAngle)).EndInit();
        this.ResumeLayout(false);
        this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.Label lblAngle;
    private System.Windows.Forms.TrackBar trckBarAngle;
    private System.Windows.Forms.Button btnFire;
    private System.Windows.Forms.Button btnRedraw;
}

基本问题归结为代码根本不符合您的预期。您写道:

I try to set yTarget to a random number and then set yTargetEnd to yTarget + targetLine

但这实际上不是代码的作用。您的代码以相反的顺序执行这两件事。因此 yTargetEnd 值始终基于 上一个 目标位置,而不是新选择的位置。

您的代码应该如下所示:

private void btnRedraw_Click(object sender, EventArgs e)
{
    yTarget = rnd.Next(100, 500);
    yTargetEnd = yTarget - targetLine;
}

即编写代码,使其符合您的规范。 :)


回答完之后,您的代码中还有一些其他重要问题需要解决:

  • 首先,您以完全错误的方式更新屏幕。您不应从 Paint 事件处理程序调用 Refresh()Update()Invalidate()。相反,你应该在某处有单独的逻辑,例如基于计时器、后台线程等处理数据状态(即您的游戏世界)的控制,并且当数据以某种方式发生变化时使相关 window 或控件无效这将需要重新绘制它们。
  • 此外,您应该尽可能使用库存 Pen 对象,如果不可能,请处理您的自定义 Pen 对象或将其存储在某个地方以供重复使用。

例如:

private static readonly Pen _firedLine =
    new Pen(Color.Blue) { DashPattern = new [] { 5f, 2f } };

private void LineDrawEvent(object sender, PaintEventArgs paint)
{
    Graphics drawSurface = paint.Graphics;
    Pen turretLine = Pens.Blue;
    Pen graphHorizontal = Pens.Red;
    Pen graphVertical = Pens.Red;
    Pen targetLine = Pens.Black;

    drawSurface.DrawLine(graphVertical, (int)xOrigin, (int)yOrigin, (int)xHor, (int)yHor);
    drawSurface.DrawLine(graphHorizontal, (int)xOrigin, (int)yOrigin, (int)xVert, (int)yVert);
    drawSurface.DrawLine(_firedLine, (int)xOrigin, (int)yOrigin, (int)xFire, (int)yFire);
    drawSurface.DrawLine(targetLine, (int)xTarget, (int)yTarget, (int)xTarget, (int)yTargetEnd);

    double angleInRadians = ConvertDegsToRads((double)trckBarAngle.Value);
    xEnd = xOrigin + lineLength * Math.Cos(angleInRadians / 2.0);
    yEnd = yOrigin - lineLength * Math.Sin(angleInRadians / 2.0);

    drawSurface.DrawLine(turretLine, (int)xOrigin, (int)yOrigin, (int)xEnd, (int)yEnd);
}