Brian_TheLion Ответов: 2

Получая ошибку при следовании за репетитором, может ли кто-нибудь, пожалуйста, помочь мне.


Я следую за репетитором, чтобы создать игру, но я получаю ошибку в этой строке

для (int i = 0; i < звезды.Длина /2; i++)

C# говорит мне, что звезды равны нулю.

Ошибка System.NullReferenceException: ‘ссылка на объект не установлена на экземпляр объекта’.

Я проверил код и не вижу никакой разницы между моим кодом и вашим кодом. Может быть, есть что-то, что мне нужно сделать с формой, чтобы остановить эту ошибку.

Код включен.
Обратите внимание, что код не является полным, но это не мешает ему выдавать мне ошибку при компиляции кода.

Brian_TheLion

Я использую последнюю версию Visual Studio, и учебник предназначен для #7 Visual Studio, так что, возможно, это причина ошибки или есть что-то, что мне нужно было сделать, чего не хватает в учебнике. Я проверил свой код с кодом в учебнике, но это то же самое.



Надеюсь, ты мне поможешь.

Что я уже пробовал:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WMPLib;

namespace SpaceShooter
{
    public partial class Form1 : Form
    {
        WindowsMediaPlayer gameMedia;
        WindowsMediaPlayer shootgMedia;
        
        PictureBox[] stars;
        PictureBox[] munitions;  //gun fire at enemy
        int backgroundspeed;
        int playerSpeed;
        int munitionsSpeed;
       
        
        Random rnd;
        public Form1()
        {
            InitializeComponent();
        }
       //window_Load methoid
        private void Form1_Load(object sender, EventArgs e)
        {
            backgroundspeed = 4;
            playerSpeed = 4;
            munitionsSpeed = 20;
            munitions = new PictureBox[3];
          
            //Load images
            Image munition = Image.FromFile(@"asserts\munitation.png");

            for(int i = 0; i < munitions.Length; i++)
            {
                munitions[i] = new PictureBox();
                munitions[i].Size = new Size(8, 8);
                munitions[i].Image = munition;
                munitions[i].SizeMode = PictureBoxSizeMode.Zoom;
                munitions[i].BorderStyle = BorderStyle.None;
                this.Controls.Add(munitions[i]);
            }

            //Create WMP
            gameMedia = new WindowsMediaPlayer();
            shootgMedia = new WindowsMediaPlayer();
          

            //Load all songs
            gameMedia.URL = "songs\\GameSong.mp3";
            shootgMedia.URL = "songs\\shoot.mp3";

            //Setup Songs settings
            gameMedia.settings.setMode("loop", true);
            gameMedia.settings.volume = 5;
            shootgMedia.settings.volume = 1;

            stars = new PictureBox[10];
            rnd = new Random();

            for (int i = 0; i < stars.Length; i++)
            {
                stars[i] = new PictureBox();
                {
                    stars[i].BorderStyle = BorderStyle.None;
                    stars[i].Location = new Point(rnd.Next(20, 580), rnd.Next(-10, 400));
                }
                if (i % 2 == 1)
                {
                    stars[i].Size = new Size(2, 2);
                    stars[i].BackColor = Color.Wheat;
                }
                else
                {
                    stars[i].Size = new Size(3, 3);
                    stars[i].BackColor = Color.DarkGray;
                }
                this.Controls.Add(stars[i]);
            }

            gameMedia.controls.play();    //might be correct place for this

        }
        //Move Game Timer_Tick
        private void MoveBgTimer_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < stars.Length /2; i++)   //ERROR on this line. stars = null
            {
                stars[i].Top += backgroundspeed;   

                if (stars[i].Top >= this.Height)
                {
                    stars[i].Top = -stars[i].Height;
                }
            }
            
            for (int i = stars.Length /2; i <stars.Length; i++)
            {
                stars[i].Top += backgroundspeed - 2;
                if (stars[i].Top >= this.Height)
                {
                    stars[i].Top = -stars[i].Height;
                }
            }
        }

        private void LeftMoveTimer_Tick(object sender, EventArgs e)
        {
            if(Player.Left > 10)
            {
                Player.Left -= playerSpeed;
            }
        }

        private void RightMoveTimer_Tick(object sender, EventArgs e)
        {
            if (Player.Right <580)
            {
                Player.Left += playerSpeed;
            }
        }

        private void DownMoveTimer_Tick(object sender, EventArgs e)
        {
            if (Player.Top <400)
            {
                Player.Top += playerSpeed;
            }
        }

        private void UpMoveTimer_Tick(object sender, EventArgs e)
        {
            if (Player.Top >10)
            {
                Player.Top -= playerSpeed;
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Right)
            {
                RightMoveTimer.Start();
            }
            if (e.KeyCode == Keys.Left)
            {
                LeftMoveTimer.Start();
            }
            if (e.KeyCode == Keys.Down)
            {
                DownMoveTimer.Start();
            }
            if (e.KeyCode == Keys.Up)
            {
                UpMoveTimer.Start();
            }
        }

        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
           RightMoveTimer.Stop();
           LeftMoveTimer.Stop();
           DownMoveTimer.Stop();
           UpMoveTimer.Stop();
        }

        private void MoveMunitionTimer_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < munitions.Length; i++)
            {
                if (munitions[i].Top > 0)
                {
                    munitions[i].Visible = true;
                    munitions[i].Top -= munitionsSpeed;
                }
                else
                {
                    munitions[i].Visible = false;
                    munitions[i].Location = new Point(Player.Location.X + 20, Player.Location.Y + 30);
                }
            }
        }
    }
}

2 Ответов

Рейтинг:
2

TheRealSteveJudge

Проблема заключается в вашем таймере.

MoveBgTimer_Tick

Этот таймер, по-видимому, настроен как Enabled = True в конструкторе.
Поэтому он сразу же активируется после запуска приложения.
Затем обработчик событий обращается к массиву звезд перед его инициализацией.
Вы должны установить Enabled = False в конструкторе и установить Enabled = True в конце конструктора.
Form1_Load
обработчик событий.


Рейтинг:
2

Afzaal Ahmad Zeeshan

Цитата:
Ошибка System.NullReferenceException: ‘ссылка на объект не установлена на экземпляр объекта’.
Это одна из самых основных проблем, с которыми сталкиваются разработчики. Это значит, что вы забыли сделать new для ваших данных. Это может быть ваш код или код в библиотеке, и вы забыли вызвать какой-то метод инициализации.

Внутри вашего кода проблема заключается в следующем,
for (int i = 0; i < stars.Length /2; i++)
Таким образом, это означает, что вы забыли инициализировать значение для звезд. Если вы посмотрите на код, то увидите, что вы оставили поле неинициализированным,
public partial class Form1 : Form
{
    WindowsMediaPlayer gameMedia;
    WindowsMediaPlayer shootgMedia;
    
    PictureBox[] stars; // <-- here
Существует простой способ решить эту проблему, просто инициализируйте значение для звезд либо в конструкторе, либо вы можете сделать это в отдельном методе, когда вы знаете значение для массива.
public Form1()
{
    InitializeComponent();

    // Here
    stars = new PictureBox[10]; // 10 hardcoded elements, each null.
}
Это подводит нас к другой проблеме в C#, что массивы имеют фиксированные размеры. И они не могут вместить больше, чем их размер, и всегда будут потреблять точный размер в памяти. Вот где он находится List<PictureBox> типы пригодятся.

Если вы можете изменить код, я настоятельно рекомендую использовать List<T> вместо массива.
.net - Array versus List<T>: Когда и что использовать? - переполнение стека[^]
Список<T> класса (System.Коллекции.Общая) | Майкрософт Документы[^]

Еще одна вещь, я заметил, что вы делаете то же самое, что я рекомендовал в Form1_Load метод,
stars = new PictureBox[10];
rnd = new Random();

for (int i = 0; i < stars.Length; i++)
{
Было бы здорово, если бы вы могли спокойно продолжить выполнение кода. Подобный этому,
if(stars != null) {
    for (int i = 0; i < stars.Length; i++) {
        // Code here.
    }
}
Это может предотвратить исключения нулевой ссылки в коде.

Редактировать
Если вы хотите показать звезды, даже когда они равны нулю, просто сделайте это:
if(stars == null) {
   stars = new PictureBox[10];
}

// Your code here...


Brian_TheLion

Спасибо за вашу помощь.
Я попробовал поместить 'starts = new PictureBox[10];' под код InitializeComponet();
но теперь мы получаем аналогичную ошибку на этой линии
начинается[i].Top += backgroundspeed;
однако установка MoveBhTimer в null решила эту проблему.
Компилятор говорит мне, что звезды равны нулю.
У меня были подобные ошибки для части боеприпасов кода и сделал те же исправления, но теперь при запуске программы ничего не происходит. Я должен видеть звезды, движущиеся в небе, и иметь возможность перемещать свой космический корабль на экране.

Любая дополнительная помощь будет приветствоваться, спасибо.

Afzaal Ahmad Zeeshan

В этом случае, когда доступ к полям не может быть определен, вы можете использовать if...else блоки для предотвращения этих исключений.

Это также показывает, что код не покрывается тестами должным образом.

Brian_TheLion

Спасибо за вашу помощь.
Я попробовал if (stars !=null) {..} но это блокирует код от происходящего, что приводит к тому, что звезды не отображаются.
Странно, что это работает для репетитора...может быть, что-то связано с различными версиями Visual Studio, поскольку он использует #7. Я думаю, что у меня все еще есть #7 visual studio, так что я мог бы попробовать его с помощью этой версии.

Afzaal Ahmad Zeeshan

Было бы здорово, если бы вы могли проверить с преподавателем и сказать им, что не так с кодом.

Я обновил ответ и добавил объяснение для использования кода, а также для преодоления проблемы нулевого указателя. Пожалуйста, смотрите последний раздел в ответе.

Brian_TheLion

Мне интересно, должен ли я иметь picturebox на форме для отображения звезд, так как этого не было в учебнике.

Brian_TheLion

Я понял, в чем проблема. Form1_Load не выполнялся. Таким образом, любой код под Form1_Load не действовал, что означает, что многие вещи не были загружены в начале игры.
Я добавил: "Это.load += Form1_Load' в разделе public Form1()

Я думаю, что главная проблема заключается в том, что в последней версии Visual Studio некоторые значения по умолчанию, такие как Form1_load, были отключены, так как в прошлом код Form1_load автоматически возбуждался при компиляции программы.