【发布时间】: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 值的枚举开始;它将大大简化事情。此外,您似乎试图通过随机生成所有笔记来填充表格,这太疯狂了。你不想要随机的音符:你想要所有的音符,以随机顺序,你可以通过先填充数组然后改组来更快地获得。