Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Перерисовка формы


Автор: Enteropoly 17.6.2009, 18:20
Привет всем. 

У меня такое дело. Я пишу что-то типа стратегической игры на C#, использую только GDI+. Итак, тайлы (клеточки на игровом поле) у меня имеют форму шестиугольника, с отрисовкой всей этой сетки всё нормально. Проблемы начинаются при перерисовке. 

По задумке, у меня "подсвечивается" только тот тайл, над которым находится курсор мыши. Для этого бы создан массив эти клеточек, написаны методы, с технической стороны проблем, в общем, нету. Всё работает как надо. НО! Перерисовка весит на MouseMove, поэтому получается, что с каждым движением у меня перерисовывается всё поле размером в, скажем, 1000х1000 клеток, посему, как результат, под 100% грузится процессор, что, как понятно, недопустимо.

Так вот, мне нужно перерисовывать только видимую часть поля, ту, что видно на форме, а ту, что за кадром, оставить как есть до тех пор, пока она не станет видимой. Копал Invalidate, ничего путного не нашёл. Кто что может посоветовать?


ЗЫ. Метод поиска нужной клетки для подсвечивания, по координатам, работает максимально быстро (по бинарному дереву), поиск по полю 32000х32000 проходит за 6-7 итераций. Грешу на перерисовку.



-----------
Едит:
Повесил перерисовку на таймер, но всё равно тормозит жутко. Слишком много перерисовывается всего.

Автор: Heinzz 17.6.2009, 18:38
Если каждый шестиугольничек является объектом, можно добавить ему метод
 "перерисоваться" если содержит курсор мыши
координаты мыши на всем поле вычислить проблем быть не должно

Автор: Grok 17.6.2009, 18:42
а почему Invalidate() не подходит? 
Передавать туда прямоугольник который нужно перерисовать и  должно работать нормально ....

Автор: Enteropoly 17.6.2009, 19:52
Цитата

"перерисоваться" если содержит курсор мыши

Тут суть в том, что перерисовывать всё равно нужно все клетки, а ту, над которой курсор, просто по-другому =)


Автор: Enteropoly 17.6.2009, 20:15
Воть.


Код

protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            field.DrawField(e.Graphics, firsttimeredraw);
            base.OnPaint(e);
            firsttimeredraw = false;
        }

-------------------------------------------------------

public void DrawField(Graphics g, bool firsttime)
        {
            if (firsttime)
            {
                foreach (GTile tile in tiles)
                {
                    tile.DrawTile(g);
                }
            }
            else
            {
                RedrawLastRestateTiles(g);
            }

-------------------------------------------------------

public override void DrawTile(Graphics g) //отрисовка клетки (зависит от её состояния)
        {
            switch (this.sstate)
            {
                case Globals.SelectState.Normal:
                    g.DrawPath(Pens.Black, hexagonoutline);
                    if (Globals.ConsoleVariables.TileShowHashnum)
                    {
                        g.DrawString(this.hashnum.ToString(), Globals.StringFontFormat, Brushes.Red, this.hexcenterpoint.X- 
Globals.TileIntRadius / 2, this.hexcenterpoint.Y - Globals.TileExtRadius / 4); 
                    }
                    break;
            
                  ........................



Вот как-то так. Ладно, я тут пыхнул, и понял, что суть не в Invalidate. Просто надо разработать какой-то критерий, по которому определялось бы, надо перерисовывать клетку, или нет. В общем, будем искать.  smile 

Автор: amarenkov 18.6.2009, 13:46
Enteropoly, есть несколько вопросов и несколько советов smile.

Вопросы:
1. Я так понял, у тебя не все поле сразу видно, а 100-200 клеток? А каким образом это у тебя реализуется? Есть какие-то координатные преобразования? Или ты Image по форме двигаешь smile?
2. Проекция у тебя изометрическая или чисто 2D? Другими словами, у тебя есть части, вылезающие за клетку?

Советы:
1. Делай сразу на XNA, Tao или чистом DirectX, OpenGL - много сил сэкономишь smile.
2. Перерисовывать надо не на MouseMove, а при изменении состояния, т.е. когда меняется подсвечиваемя клетка. Надо помнить на какой были и при движении мыши проверять, изменилась ли она. Если да - перерисовать.
3. Рисовать сначала стоит на Bitmap, который находится в памяти. Потом весь Bitmap рисовать на Image, а не сразу на Graphics'e Image-а.

Автор: Enteropoly 20.6.2009, 02:33
Цитата(amarenkov @ 18.6.2009,  13:46)
Enteropoly, есть несколько вопросов и несколько советов smile.

Вопросы:
1. Я так понял, у тебя не все поле сразу видно, а 100-200 клеток? А каким образом это у тебя реализуется? Есть какие-то координатные преобразования? Или ты Image по форме двигаешь smile?
2. Проекция у тебя изометрическая или чисто 2D? Другими словами, у тебя есть части, вылезающие за клетку?

Советы:
1. Делай сразу на XNA, Tao или чистом DirectX, OpenGL - много сил сэкономишь smile.
2. Перерисовывать надо не на MouseMove, а при изменении состояния, т.е. когда меняется подсвечиваемя клетка. Надо помнить на какой были и при движении мыши проверять, изменилась ли она. Если да - перерисовать.
3. Рисовать сначала стоит на Bitmap, который находится в памяти. Потом весь Bitmap рисовать на Image, а не сразу на Graphics'e Image-а.

1. 1 клетка = 1 экземпляр класса Tile. В классе реализован метод отрисовки. Всё прям напрямую через Graphics.Draw......
2. Чисто 2D.

1. С XNA знаком, но в целях как бы... ммм... повышения уровня квалификации именно в традиционном C#, хочется написать на GDI+  smile 
2. Щас уже перерисовывается по таймеру. Я как бы отвязал перерисовку от каких-то действий. Картинка меняется назависимо от происходящего, как лента в проекторе крутится постоянно, вне зависимости от того, что на ней нарисовано. А вот что на ней будет нарисовано (какие клетки надо перерисовать и как) - это у меня уже выполняет другая функция, которая как раз привязана к разным кликам, мувам и прочим событиям. Работает на ура.
3. А вот тут надо подумать =) Я ещё функцию скролла карты не реализовал и до сих пор предвкушаю долгие часы неиллюзорного секса с TranslateTransform и прочими радостями  smile 


Автор: gambit 29.6.2009, 00:02
Может конечно не поможет, но что если использовать двойную буферизацию??? Он тогда вроде как тогда использует особый метод отрисовки, что то типа отрисовывает изменившейся объект, а все остальное нет. Так решается проблема с мерцанием, но может и с нагрузкой ЦПУ, что ниб решится?

Автор: Enteropoly 29.6.2009, 17:27
Двойная буферизация ессно включена =)

Автор: gambit 29.6.2009, 23:38
Создай класс шестиугольника, загони все объекты в массив, отрисуй их все, в mouse_move повесь процедуру определения, к какому объекту принадлежат данные координаты, если координаты наехали на другой объект, то только тогда перерисовывай форму.

Автор: gambit 30.6.2009, 00:00
Криво, но общий смысл понятен.

Автор: gambit 30.6.2009, 10:15
До меня уже после дошло, в mouse move в начале можно вставить проверку с текущего ли объекта не ушла ли мышь, тогда он еще и цикл поиска гнать не будет, еще больше разгрузишь проц. А если ушла, то уже цикл поиска.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)