【问题标题】:Random Generator Code?随机生成器代码?
【发布时间】:2014-12-28 20:25:40
【问题描述】:

我正在尝试让此代码生成一个包含唯一随机音符的数组。它将根据给定的参数记下并为其分配一个偶然的符号,并可能显示为平坦或尖锐的对应物。例如,如果随机生成器说音符“A”是平的,它就有可能显示为 A♭ 或 G♯。

现在,我还没有处理半步音符(例如C♭变成B♯等),但这主要是因为第一部分不起作用。我现在遇到的问题是我正在使用的代码似乎无法始终如一地工作。它有时会正确翻译笔记并将它们弄乱。也没有系统性的错误模式,至少不是我试图破译的。

我为此使用 XNA 在屏幕上显示注释,但真正的问题在于数据。我正在使用我制作的Note 课程。

这是我正在使用的代码:

首先是Note 类:

 public class Note
    {
        public enum Notes
        {
            A = 0,
            B = 1,
            C = 2,
            D = 3,
            E = 4,
            F = 5,
            G = 6
        }
        public Notes noteLetter { get; private set; }
        public Notes translatedLetter { get; private set; }
        public bool isFlat { get; private set; }
        public bool showSharp { get; private set; }

        private const int NOTE_COUNT = 7;

        /// <summary>
        /// Creates a Note
        /// </summary>
        /// <param name="note">The basic note</param>
        /// <param name="flat">Is the note flat?</param>
        /// <param name="sharp">Will be shown as it's sharp counterpart?</param>
        public Note(Notes note, bool flat, bool sharp)
        {
            noteLetter = note;
            isFlat = flat;
            showSharp = sharp;

            if (isFlat && showSharp)
            {
                int hashCode = (int)noteLetter;
                translatedLetter = (Notes)((hashCode + NOTE_COUNT - 1) % NOTE_COUNT);
            }
            else
            {
                translatedLetter = noteLetter;
                showSharp = isFlat;
            }

        }
    }

然后是 Game1.cs 文件:

 public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        KeyboardState KeyBState, prevKeybState;

        Texture2D sprite;

        Rectangle noteSource;
        Rectangle accSource;

        const int ACCIDENTAL_START_X = 840;

        const int BORDER_OFFSET = 12;

        Vector2 notePosition;

        SpriteFont font;

        /// <summary>
        /// The array of notes, row/column format
        /// </summary>
        Note[,] box;

        const int ROW_SIZE = 3, COLUMN_SIZE = 4;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            box = new Note[ROW_SIZE, COLUMN_SIZE];
            noteSource = new Rectangle(0, 0, 120, 120);
            accSource = new Rectangle(ACCIDENTAL_START_X, 0, 50, 50);

            notePosition = Vector2.Zero;
        }


        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            MakeTable();

            base.Initialize();
        }


        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            sprite = Content.Load<Texture2D>("Note Pieces2");
            font = Content.Load<SpriteFont>("font");
            // TODO: use this.Content to load your game content here
        }


        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }


        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            KeyBState = Keyboard.GetState();

            if (KeyBState.IsKeyDown(Keys.Escape))
                this.Exit();

            if (KeyBState.IsKeyDown(Keys.Space) && prevKeybState.IsKeyUp(Keys.Space))
                MakeTable();

            // TODO: Add your update logic here
            prevKeybState = KeyBState;
            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            spriteBatch.Begin();
            for (int r = 0; r < ROW_SIZE; r++)
            {
                for (int c = 0; c < COLUMN_SIZE; c++)
                {
                    Note temp = box[r, c];
                    notePosition.Y = r * noteSource.Width + (r * BORDER_OFFSET);
                    notePosition.X = c * noteSource.Height + (c * BORDER_OFFSET);
                    noteSource.X = temp.translatedLetter.GetHashCode() * noteSource.Width;

                    spriteBatch.Draw(sprite, notePosition, noteSource, Color.White);

                    notePosition.X += noteSource.Width / 2;
                    notePosition.Y += 7;

                    spriteBatch.DrawString(font,
                        temp.noteLetter.ToString() +
                        (temp.isFlat ? "b " : "  ") +
                        temp.translatedLetter +
                        (temp.showSharp ? "#" : ""), notePosition, Color.Black);

                    notePosition.X -= noteSource.Width / 2;
                    notePosition.Y -= 7;

                    if (temp.isFlat)
                    {
                        notePosition.X += 63;
                        notePosition.Y += 63;

                        accSource.X = ACCIDENTAL_START_X;
                        accSource.Y = 0;
                        if (temp.showSharp)
                        {
                            accSource.X += (temp.translatedLetter.GetHashCode() % 2) * (accSource.Width * 2);
                            accSource.Y += ((int)(temp.translatedLetter.GetHashCode() / 2)) * accSource.Height;
                            spriteBatch.Draw(sprite, notePosition, accSource, Color.White);
                        }
                        /*
                    else
                    {
                        accSource.X += (temp.translatedLetter.GetHashCode() % 2) * (accSource.Width * 2) + accSource.Width;
                        accSource.Y += ((int)(temp.translatedLetter.GetHashCode() / 2)) * accSource.Height;
                        spriteBatch.Draw(sprite, notePosition, accSource, Color.White);
                    }
                    */
                    }

                }
            }
            spriteBatch.End();
            base.Draw(gameTime);
        }

        /// <summary>
        /// Makes a new random table of notes
        /// </summary>
        private void MakeTable()
        {
            //make everything null
            for (int r = 0; r < ROW_SIZE; r++)
            {
                for (int c = 0; c < COLUMN_SIZE; c++)
                {
                    box[r, c] = null;
                }
            }

            //then start
            Random rand = new Random();
            for (int i = 0; i < 12; i++)
            {
                bool isUnique;
                bool noteEntered;

                do
                {
                    Note newNote = new Note((Note.Notes)rand.Next(0, 7),
                                rand.Next(0, 2) == 0 ? true : false,
                                rand.Next(0, 2) == 0 ? true : false);

                    isUnique = true;
                    noteEntered = false;
                    //Check to see if there exists a note like this
                    for (int r = 0; r < ROW_SIZE; r++)
                    {
                        for (int c = 0; c < COLUMN_SIZE; c++)
                        {
                            Note temp = box[r, c];
                            if (noteEntered || !isUnique)
                                continue;
                            else if (temp != null &&
                                temp.noteLetter == newNote.noteLetter &&
                                temp.isFlat == newNote.isFlat)
                            {
                                isUnique = false;
                            }
                            else if (temp == null)
                            {
                                box[r, c] = newNote;
                                noteEntered = true;
                            }

                        }
                    }
                } while (!isUnique);
            }
        }
    }

运行一切的主要代码是MakeTable() 方法,但我把一切都放进去以防万一其他地方出现问题。据我所知,除了图形库之外,我没有使用任何与 XNA 框架相关的库,这会导致出错。我正在使用 CodePlex 重建的 XNA。我知道他们仍在做一些事情,但这应该不是问题。有人可以帮我解决这个问题吗?

【问题讨论】:

  • 为什么你的枚举没有指定整数值?那个演员可能是个问题。
  • note类报错:调用GetHashCode会产生随机数,不要这样做。另一个错误:note 类及其构造函数中的布尔值过多,但在当前逻辑下,它们将始终具有相同的值(如果它们不相同,则 showSharp=isFlat 赋值使它们相等)。这个问题最有问题的部分是您应该告诉我们实际结果与预期结果。我真的不知道你在这里想要达到什么目的,我也不懂音符。
  • 一次一个。我不知道 GetHashCode() 是个问题。我以前用过,到现在都没有这个问题。但是,我愿意停止使用它。至于 showSharp 和 isFlat:我对两者都有原因。以防万一你不知道,尖锐和平坦并不像正负一样起作用;共有三个值:锐利、自然(没有锐利或平坦)和平坦。除了彼此相距半步的自然键之外,每个音符都有可能成为这些值中的任何一个。在这些情况下,它们的相对锐度和平坦度转化为彼此。待定
  • 在其他情况下,一个键的升号与下一个键的降号相同(例如 C# = Db)。将所有这些放在一起,您可以拥有十二种不同的音符。这就是为什么我的二维数组是 4X3。每个人都应该在里面有一个不同的音符。但是,它们应该是随机放置的,并由空格键控制,以便我每次按下它都可以制作一个新表。当整个表格被填充时,它应该在适当的时候和任何地方使用音符的尖锐版本、平坦版本或自然版本以某种方式表示每个键。它没有这样做。
  • 如果您使用的是标准的西方 12 音调音半音阶(也就是说,您正在考虑 C# 与 Db 的音符相同),并且您还没有考虑键,那么为什么首先从 8 值枚举开始?从一个 12 值的枚举开始;它将大大简化事情。此外,您似乎试图通过随机生成所有笔记来填充表格,这太疯狂了。你不想要随机的音符:你想要所有的音符,以随机顺序,你可以通过先填充数组然后改组来更快地获得。

标签: c# random xna


【解决方案1】:

我现在想通了。我接受了 Lee Daniel Crocker 的建议,并修复了我的程序。我创建了一个 12 值的枚举,并编辑了 MakeTable() 方法,以便它从不同的集合中提取每个音符并将它们随机输入另一个数组。此外,我修复了我的图片,以便我可以更轻松地绘制它。事后看来,即使是也不知道我为什么要这么做。

顺便说一句,我将MakeTable() 移到Note 类中,以便更容易编写MakeTable()

这是我的代码:

首先,Note

    /// <summary>
    /// A musical note
    /// </summary>
    public class Note
    {
        public enum Notes
        {
            Ab = 10,
            A = 0,
            Bb = 11,
            B = 1,
            C = 2,
            Db = 13,
            D = 3,
            Eb = 14,
            E = 4,
            F = 5,
            Gb = 16,
            G = 6
        }
        /// <summary>
        /// This holds the notes with accidentals
        /// </summary>
        public Notes noteLetter { get; private set; }
        /// <summary>
        /// this holds the note without any accidentals
        /// </summary>
        public Notes naturalLetter { get; private set; }
        /// <summary>
        /// Holds the value of the note if showsharp is true
        /// </summary>
        public Notes translatedLetter { get; private set; }
        /// <summary>
        /// Denotes whether or not the note will represented
        /// as its sharp counterpart, its prerequisite being
        /// that it was flat in the first place
        /// </summary>
        public bool showSharp { get; private set; }

        /// <summary>
        /// Creates a Note
        /// </summary>
        /// <param name="note">The basic note</param>
        /// <param name="sharp">Will be shown as it's sharp counterpart?</param>
        public Note(Notes note, bool sharp)
        {
            noteLetter = note;
            switch(noteLetter)
            {
                case Notes.Ab:
                    naturalLetter = Notes.A;
                    translatedLetter = Notes.G;
                    break;
                case Notes.Bb:
                    naturalLetter = Notes.B;
                    translatedLetter = Notes.A;
                    break;
                case Notes.Db:
                    naturalLetter = Notes.D;
                    translatedLetter = Notes.C;
                    break;
                case Notes.Eb:
                    naturalLetter = Notes.E;
                    translatedLetter = Notes.D;
                    break;
                case Notes.Gb:
                    naturalLetter = Notes.G;
                    translatedLetter = Notes.F;
                    break;
                default:
                    naturalLetter = noteLetter;
                    break;
            }
            showSharp = sharp;

            if (showSharp)
            {
                switch (noteLetter)
                {
                    case Notes.A:
                    case Notes.B:
                    case Notes.C:
                    case Notes.D:
                    case Notes.E:
                    case Notes.F:
                    case Notes.G:
                        showSharp = false;
                        break;
                }
            }

        }

        /// <summary>
        /// Will make a random table of Note objects
        /// </summary>
        /// <param name="table">the array in which to place the Note objects</param>
        public static void MakeTable(out Note[,] table)
        {
            Note[,] temp = new Note[3, 4];

            Random rand = new Random();

            temp[0, 0] = new Note(Notes.Ab, (rand.Next(0, 2) == 0 ? true : false));
            temp[0, 1] = new Note(Notes.A, (rand.Next(0, 2) == 0 ? true : false));
            temp[0, 2] = new Note(Notes.Bb, (rand.Next(0, 2) == 0 ? true : false));
            temp[0, 3] = new Note(Notes.B, (rand.Next(0, 2) == 0 ? true : false));
            temp[1, 0] = new Note(Notes.C, (rand.Next(0, 2) == 0 ? true : false));
            temp[1, 1] = new Note(Notes.Db, (rand.Next(0, 2) == 0 ? true : false));
            temp[1, 2] = new Note(Notes.D, (rand.Next(0, 2) == 0 ? true : false));
            temp[1, 3] = new Note(Notes.Eb, (rand.Next(0, 2) == 0 ? true : false));
            temp[2, 0] = new Note(Notes.E, (rand.Next(0, 2) == 0 ? true : false));
            temp[2, 1] = new Note(Notes.F, (rand.Next(0, 2) == 0 ? true : false));
            temp[2, 2] = new Note(Notes.Gb, (rand.Next(0, 2) == 0 ? true : false));
            temp[2, 3] = new Note(Notes.G, (rand.Next(0, 2) == 0 ? true : false));

            table = new Note[3, 4];

            for (int i = 0; i < 12; i++)
            {
                int row;
                int col;

                row = rand.Next(0, 3);
                col = rand.Next(0, 4);

                while (table[row, col] != null)
                {
                    //Randomly choose if either the row or column will be incremented
                    bool useRow = (rand.Next(0, 2) == 0 ? true : false);

                    //then increment one of them
                    if (useRow)
                    {
                        row = (row + 1) % 3;
                    }
                    else
                    {
                        col = (col + 1) % 4;
                    }
                }

                //Place notes in the empty registers
                if (table[row, col] == null)
                {
                    table[row, col] = temp[(int)(i / 4), i % 4];
                }
            }
        }
    }

还有Game1:

/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    KeyboardState KeyBState, prevKeybState;

    Texture2D sprite;

    Rectangle noteSource;
    Rectangle accSource;

    const int ACCIDENTAL_START_X = 840;

    const int BORDER_OFFSET = 12;

    Vector2 notePosition;

    SpriteFont font;

    /// <summary>
    /// The array of notes, row/column format
    /// </summary>
    Note[,] box;

    const int ROW_SIZE = 3, COLUMN_SIZE = 4;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";

        box = new Note[ROW_SIZE, COLUMN_SIZE];
        noteSource = new Rectangle(0, 0, 120, 120);
        accSource = new Rectangle(ACCIDENTAL_START_X, 0, 50, 50);

        notePosition = Vector2.Zero;
    }

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        Note.MakeTable(out box);

        base.Initialize();
    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
        sprite = Content.Load<Texture2D>("Note Pieces2");
        font = Content.Load<SpriteFont>("font");
        // TODO: use this.Content to load your game content here
    }

    /// <summary>
    /// UnloadContent will be called once per game and is the place to unload
    /// all content.
    /// </summary>
    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        KeyBState = Keyboard.GetState();

        if (KeyBState.IsKeyDown(Keys.Escape))
            this.Exit();

        if (KeyBState.IsKeyDown(Keys.Space) && prevKeybState.IsKeyUp(Keys.Space))
            Note.MakeTable(out box);

        // TODO: Add your update logic here
        prevKeybState = KeyBState;
        base.Update(gameTime);
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        // TODO: Add your drawing code here
        spriteBatch.Begin();
        for (int r = 0; r < ROW_SIZE; r++)
        {
            for (int c = 0; c < COLUMN_SIZE; c++)
            {
                Note temp = box[r, c];
                notePosition.Y = r * noteSource.Width + ((r + 1) * BORDER_OFFSET);
                notePosition.X = c * noteSource.Height + ((c + 1) * BORDER_OFFSET);
                noteSource.X = (temp.showSharp ? (int)temp.translatedLetter : (int)temp.naturalLetter) * noteSource.Width;

                spriteBatch.Draw(sprite, notePosition, noteSource, Color.White);

                notePosition.X += noteSource.Width / 2;
                notePosition.Y += 7;

                spriteBatch.DrawString(font,
                    temp.noteLetter.ToString() + " " +
                    (temp.showSharp ? "#" : ""), notePosition, Color.Black);

                notePosition.X -= noteSource.Width / 2;
                notePosition.Y -= 7;

                switch (temp.noteLetter)
                {
                    case Note.Notes.Ab:
                    case Note.Notes.Bb:
                    case Note.Notes.Db:
                    case Note.Notes.Eb:
                    case Note.Notes.Gb:
                        notePosition.X += 63;
                        notePosition.Y += 63;

                        int accOffset = 0;
                        if (temp.showSharp)
                        {
                            accSource.X = (int)temp.translatedLetter * noteSource.Width;
                        }
                        else
                        {
                            accSource.X = (int)temp.naturalLetter * noteSource.Width;
                            accOffset = accSource.Width;
                        }

                        accSource.X += accOffset;
                        accSource.Y = noteSource.Height;
                        spriteBatch.Draw(sprite, notePosition, accSource, Color.White);
                        break;
                }

            }
        }
        spriteBatch.End();
        base.Draw(gameTime);
      }
    }

【讨论】:

    猜你喜欢
    • 2016-02-16
    • 2011-08-19
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    相关资源
    最近更新 更多