Клон астероидов в Monogame порождает астероиды с тем же положением, вращением и направлением - PullRequest
0 голосов
/ 28 апреля 2018

РЕДАКТИРОВАТЬ: Исправлена ​​проблема. Я создал новый Рандом для каждого астероида, поэтому между ними не было достаточно времени. Но когда я прошел код вручную, было достаточно времени, чтобы не создать то же значение.

Вот код. Управляйте с помощью WASD, стреляйте с пробела и нажимайте «L», чтобы вызвать астероид.

https://github.com/Geblin/Monogame-Asteroids

Астероиды делятся на 2-3 меньших астероида при стрельбе, и это те меньшие, которые имеют одинаковые значения, хотя я даю им случайные. Я прошел через код, и кажется, что они изначально получают разные значения.

Вот класс Астероидов. Поэтому я ввожу масштаб и позицию, чтобы можно было создавать меньшие астероиды в разных позициях. Здесь выбирается случайный угол и скорость.

public Asteroid(Texture2D texture, float scale, Vector2 pos)
{
    rand = new Random();
    this.texture = texture;
    this.scale = scale;
    this.pos = pos;
    angle = degreesToRadian(rand.Next(0,360));
    direction = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
    origin = new Vector2(texture.Width / 2, texture.Height / 2);
    isVisible = true;
    sourceRectangle = new Rectangle(0, 0, texture.Width, texture.Height);
    boundingCircle = new BoundingCircle(pos, texture, scale);
    speed = (float)rand.NextDouble() * (3 - 1) + 1;           

    setupRotation();
}

public void Draw(SpriteBatch spriteBatch)
{           
    spriteBatch.Draw(texture, pos, sourceRectangle, Color.White, angle, origin, scale, SpriteEffects.None, 1f);
}

public void Update(GameTime gameTime)
{
    boundingCircle.x = pos.X;
    boundingCircle.y = pos.Y;

    pos += direction * speed;

    //Sets the asteroids bounds
    if (pos.X > 2120)
        pos.X = -200;
    else if (pos.X < -200)
        pos.X = 2120;
    if (pos.Y > 1280)
        pos.Y = -200;
    else if (pos.Y < -200)
        pos.Y = 1280;

    angle += (float)rotationDirection;
}

public float degreesToRadian(int degrees)
{
    float radian = (float)(Math.PI / 180) * degrees;
    return radian;
}

//Sets a random rotation speed and rotation direction.
public void setupRotation()
{
    rotationDirection = rand.NextDouble() * (0.01f - 0.005f) + 0.005f;

    int x = rand.Next(2);
    if (x == 1)
        rotationDirection = -rotationDirection;
}

Вот класс астероидов. Метод SetRandomSpawn предназначен для первых астероидов. Те, которые появляются за окном и смещаются внутрь. В основном классе у меня есть код, который проверяет столкновения между лазерами и астероидами, а затем порождает меньшие в той же позиции.

public AsteroidSpawner(List<Asteroid> asteroidList)
{
    rand = new Random();
    this.asteroidList = asteroidList;
}

public void LoadContent(ContentManager content)
{
    texture = content.Load<Texture2D>("Asteroid");
}

public void Draw(SpriteBatch spriteBatch)
{
    foreach (Asteroid asteroid in asteroidList)
        asteroid.Draw(spriteBatch);
}

public void Update(GameTime gameTime)
{
    UpdateAsteroids(gameTime);

    if (Keyboard.GetState().IsKeyDown(Keys.L))
        SpawnAsteroid(SetRandomSpawn(), 1f, 1);
}

public void SpawnAsteroid(Vector2 pos, float scale, int amount)
{
    for (int i = 1; i <= amount; i++)
    {
        Asteroid newAsteroid = new Asteroid(texture, scale, pos);
        asteroidList.Add(newAsteroid);
    }
}

public void UpdateAsteroids(GameTime gameTime)
{
    foreach (Asteroid asteroid in asteroidList)
    {
        asteroid.Update(gameTime);
    }

    for (int i = 0; i < asteroidList.Count; i++)
    {
        if (!asteroidList[i].isVisible)
        {
            asteroidList.RemoveAt(i);
            i--;
        }
    }
}

//Sets a random spawn outside of screen bounds
public Vector2 SetRandomSpawn()
{
    int side = rand.Next(4);

    //Each number represents a side

    switch (side)
    {
        // Left
        case 0:
            return new Vector2(2120, rand.Next(0, 1080));

        // Top
        case 1:
            return new Vector2(rand.Next(0, 1920), 1280);

        // Right
        case 2:
            return new Vector2(-200, rand.Next(0, 1080));

        //Bottom
        case 3:
            return new Vector2(rand.Next(0, 1920), -200);

        default:
            throw new ArgumentException("Incorrect CrystalTypeEnum");
    }
}

1 Ответ

0 голосов
/ 28 апреля 2018

Начальное число объекта Random основано на времени, и, поскольку спавнер создает Asteroid и, следовательно, Random в цикле, генерируемые случайные числа одинаковы.

С Документы :

Исходное значение по умолчанию выводится из системных часов и имеет конечное разрешение. В результате различные объекты Random, созданные в тесной последовательности при вызове конструктора по умолчанию, будут иметь идентичные начальные значения по умолчанию и, следовательно, будут создавать идентичные наборы случайных чисел.

Вы можете увидеть этот эффект с помощью крошечного теста:

for (var i = 0; i < 10; i++) {
    var rand = new Random();
    Console.WriteLine(rand.Next());
}

... который выводит:

1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944

Исправьте это путем повторного использования того же Random (предположим, что ваш создатель создает Asteroid, а затем устанавливает свою позицию).

...