Пытаюсь написать простую 2D игру. Сделано это:
public interface GameObject
{
Bitmap Picture { get; }
int OffsetX { get; }
int OffsetY { get; }
}
Здесь свойство Picture возвращает изображение, которое должно быть нарисовано для текущего объекта.
public static class Game
{
public class MapIndexer
{
public GameObject this[int x, int y]
{
get => map[y, x];
set => map[y, x] = value;
}
}
private static MapIndexer indexer;
public static MapIndexer Map
{
get => indexer ?? (indexer = new MapIndexer());
}
static GameObject[,] map = new GameObject[,]
{
{ null, null, null },
{ null, null, null },
{ null, null, null }
};
public static int MapWidth
{
get => map.GetLength(1);
}
public static int MapHeight
{
get => map.GetLength(0);
}
}
Класс Game, который содержит индексатор карт и предназначен для дальнейшей разработки. Индексация [y, x] предназначена для доступа к карте, такой как декартовы координаты, иначе я получаю перевернутые размеры. NULL в массиве — это просто наполнитель (т.е. трава в моей игре ничего не делает и нужна только для заполнения карты, поэтому не вижу смысла создавать для нее отдельный класс). Также создан простой класс Player из интерфейса GameObject, который просто возвращает изображение для рисования. А вот собственно код краски:
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int y = 0; y < Game.MapHeight; y++)
for (int x = 0; x < Game.MapWidth; x++)
{
e.Graphics.DrawImage(Properties.Resources.Grass, new Point(x * size, y * size));
if (Game.Map[x, y] is not null)
e.Graphics.DrawImage(Game.Map[x, y].Picture, new Point(x * size + Game.Map[x, y].OffsetX, y * size + Game.Map[x, y].OffsetY));
}
}
Поэтому, когда я делаю какое-то движение, я аннулирую форму и получаю следующий кадр. Для меня это выглядит странно, на самом деле это потому, что при выполнении действия картинка мигает при каждой операции перерисовки. Анимация для теста — это движение игрока, которое происходит каждые 200 мс, что немного. Итак, вопрос: как оптимизировать отрисовку, чтобы она выглядела плавно, или мой дизайн кода изначально плохой?
Что вы имеете в виду под 4. о размере?
new Point(x * size, y * size)
<- откуда берется size
и где оно определено, не определено. Это значение должно быть частью объекта, который описывает изображения, которые вы используете, а не поле в форме (или что-то еще).
Размер действительно является полем формы и используется только в этом событии рисования и больше нигде. Каждая картинка одинакового размера
Form.DoubleBuffered == true:
? Для формы вы можете включить его напрямую, для PBox он уже включен, для других элементов управления вы можете включить его в коде(..
Эффект, который вы испытываете, на самом деле не связан с производительностью. То, что вы видите, скорее всего, является эффектом очистки экрана перед перерисовкой. Вы должны изучить концепцию под названием «двойная буферизация».
Первое, что вам нужно сделать: 1. Назначьте объект
Properties.Resources.Grass
Bitmap свойству/полю вашего игрового класса.Properties.Resources
— это фабрика, поэтому вы каждый раз создаете новое изображение. Вы не хотите этого. 2. Включите двойную буферизацию на холсте, используемом для рисования, если вы этого не сделали. Используйте другой контейнер, например PictureBox (двойная буферизация включена по умолчанию), а не саму форму. 3. Сделайте недействительным только тот раздел, который нужно перерисовать. См. перегрузки методаInvalidate()
. 4. Избегайте значений, которые появляются в коде из ниоткуда, напримерsize
.