Предотвратить байт обратно в 0 при увеличении более 255 - PullRequest
2 голосов
/ 30 января 2011

Я пишу приложение XNA 3.1 для класса C # / XNA, которое сейчас беру.Это очень простое вводное назначение, в котором пользователь просто меняет цвет экрана, нажимая кнопки R, G или B на клавиатуре, чтобы выбрать цветовой канал, а затем стрелки вверх и вниз, чтобы увеличить или уменьшить значение этого канала..

Если я увеличиваю байт после 255, он возвращается к 0, и наоборот для уменьшения, предположительно потому, что C # фактически преобразовывает byte в int при выполнении арифметики над ними.Однако мой профессор специально спрашивает, что, как только канал достигает своего максимального или минимального значения, он остается там, если пользователь пытается выйти за эти пределы.Я сам нашел способ исправить это, но ничего не нашел, когда искал решения этой проблемы здесь или в Google.Вот как я решил эту проблему:

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

    Color color;

    private int Red
    {
        set { color.R = NoWrapIntToByte(value); }
        get { return (int)color.R; }
    }

    private int Green
    {
        set { color.G = NoWrapIntToByte(value); }
        get { return (int)color.G; }
    }

    private int Blue
    {
        set {color.B = NoWrapIntToByte(value); }
        get { return (int)color.B; }
    }

    /// <summary>
    /// Converts an integer to a byte but doesn't wrap.
    /// </summary>
    /// <param name="x"></param>
    /// <returns></returns>
    static byte NoWrapIntToByte(int x)
    {
        if (x < Byte.MinValue)
            return Byte.MinValue;
        else if (x > Byte.MaxValue)
            return Byte.MaxValue;
        else
            return (byte)x;
    }
}

Каждый раз, когда вызывается метод Draw(), цвет, сохраненный в color, устанавливается как цвет экрана.

Просто для ясности, я понимаю, что не могу сделать что-то вроде

byte x = 256;    // compiler error

, компилятор будет жаловаться.Однако, когда пользователь нажимает стрелки вверх или вниз, этот цветной канал увеличивается или уменьшается, и если канал уменьшается ниже 0 или увеличивается выше 255, он будет перенесен.Я использовал int в качестве типа свойств канала, потому что, если я использую что-то вроде Red -= 1 или Red += 1, могут возникнуть разные ожидания, если я выйду за пределы.Если я добавлю, я ожидаю, что результирующее значение будет меньше исходного значения, и наоборот, если я уменьшу.Я использую int, потому что это позволяет мне обнаруживать это в свойстве и обрабатывать соответственно.

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

Спасибо!

Ответы [ 5 ]

4 голосов
/ 30 января 2011

Ваш ответ выглядит так, как будто он должен делать то, что вы хотите, но для этого нужно много кода.Если бы это была моя проблема, я бы, вероятно, сделал что-то более похожее на это:

static byte NoWrapIntToByte(int x)
{
    int tmp;
    tmp = Math.Max(x, 0);
    tmp = Math.Min(255, tmp);
    return (byte)tmp;
}

Спасибо @Marlon за исправление Math.Max/Min.

Спасибо @Andrew Noyes за исправление приведения..

Надеюсь, это поможет.:)

2 голосов
/ 31 января 2011

Мне кажется, что вы должны просто использовать метод "Зажим", встроенный в платформу XNA.

http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.mathhelper.clamp.aspx

Обычно, если вы хотите, чтобы значение говорилось в пределах от 0 до 255, вы просто напишите что-то вроде этого.

static byte NoWrapIntToByte(int x)
{
    return (byte)MathHelper.Clamp(x, 0, 255);
}

Это должно в значительной степениименно то, что звучит так, как будто ты ищешь.

2 голосов
/ 30 января 2011

Ваше решение работает, но в корне неверно. Вы должны были написать свою собственность следующим образом:

private int Red
{
    get { return (int)color.R; }
    set { 
        if (value < 0 || value > 255) throw new ArgumentOutOfRangeException();
        color.R = (byte)value;
    }
}

Что позволяет любому, кто использует ваш класс, включая вас, попасть в пропасть успеха. После чего вы бы нашли правильное решение, похожее на это:

private void IncrementRed_Click(object sender, EventArgs e) {
    if (this.Color.Red < 255) this.Color.Red += 1;
}

Затем вы можете еще больше улучшить это, если средство установки свойств вызывает событие PropertyChanged. Событие, которое вы можете подписать в своем пользовательском интерфейсе, чтобы установить для свойства Enabled кнопки значение false, так что для пользователя сразу становится очевидным, что нажатие кнопки больше не является полезным.

1 голос
/ 30 января 2011

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

struct NoWrapByte
{
    private byte _data;

    public NoWrapByte(byte data)
    {
        this._data = data;
    }

    public static NoWrapByte operator +(NoWrapByte a, NoWrapByte b)
    {
        if (a._data + b._data > 255)
            return new NoWrapByte((byte)255);
        else if (a._data + b._data < 0)
            return new NoWrapByte((byte)0);
        else
        return new NoWrapByte((byte)(a._data + b._data));
    }

    public static NoWrapByte operator -(NoWrapByte a, NoWrapByte b)
    {
        if (a._data - b._data > 255)
            return new NoWrapByte((byte)255);
        else if (a._data - b._data < 0)
            return new NoWrapByte((byte)0);
        else
            return new NoWrapByte((byte)(a._data - b._data));
    }

    public static implicit operator byte(NoWrapByte op)
    {
        return op._data;
    }
}
0 голосов
/ 30 января 2011

Я не думаю, что я могу остановить это от обертывания. Вы должны использовать int16 или int32. Однако вы можете использовать оператор if, чтобы проверить, будет ли результат больше 255, а затем преобразовать его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...