Приложение 5: пустое

 

В данном уроке мы разберём:
1. Как создавать и обрабатывать внути-игровые окна
2. Как изменить картинку курсора
image0

Видеоверсия: no

Итак, нам потребуются создать следующие классы:
Design – дизайн
DesignWindow – дизайн окна
Window – окно
MWindows – система окон (окна)
DesignCursor – дизайн курсора
Cursor – курсор
Mouse – мышь

Каждый класс находится в отдельных файлах .h и .cpp
Я не буду объяснять элементарные вещи, которые были разобраны в предыдущих уроках.


Design – Дизайн


Дизайн – это класс для обработки определённых картинок.
Ниже представлены дизайны для окон и мышки
flyffWindows8.12

 
Для создания данного класса нам потребуется вот это

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

Далее самое интересное, как мы будем резать дизайн.
Этим у нас занимается функция designToImage()

Входные параметры:
1. Sf::Image* image1 – ссылка на картинку дизайна, которую будем резать.
2. sf::Image* image2 – ссылка на картинку, в которую будем вставлять часть дизайна
3. int numCellWidth – номер ячейки по ширине
4. int numCellHeight – номер ячейки по высоте
5. int sideCell – размеры ячейки
Данная функция обрезает картинку примерно так
image06Внутренний алгоритм поручаю понять самостоятельно.
Немножко о методах sf::Image можно найти тут.
Перед использованием данной функции убедитесь что у вас имеются картинки image1 и image2.
Исходный код класса Design приложен к статье или можно найти вот тут.

Далее мы рассмотрим классы DesignCursor и DesignWindow.


DesignCursor – Дизайн Курсора


В этом классе мы просто укажем как нам резать дизайны курсоров.
Важным моментом является то, что сначала нужно заполнить вектор vecImage пустыми картинками, а потом уже создавать дизайн курсора.

И собственно конструктор


DesignWindow – Дизайн Окна


Аналог класса DesignCursor Только для окон.

А в этом классе я захотел разделить конструктор и загрузку.

Тут есть небольшая хитрость.
Если в правом столбце нет картинок, то они берутся из левого, и разворачиваются по горизонтали.
Так-же если дизайна с таким filename не существует, то функция не будет его обрабатывать, а возвратит false, что очень важно.
Почему я заполняю vecImage именно в таком порядке, объясню когда будем разбирать класс Window.


Window – Окно


Очень сложный класс. Постараюсь разобрать все аспекты и очень кратко.

Нам потребуются 2 вспомогательные структуры:
1. winSave – служит для хранения позиции и размеров окна
2. winSprite – аналог sf::Sprite с доп.методами и параметрами. Хранит в себе 9 спрайтов для рисования окна.

Наше окно имеет координаты нахождения и размеры текущие, и предельные.

Так-же наше окно имеет флажки

С помощью них можно сделать такие фишки как:
– Не выходить за края окна Программы.
– Нельзя изменять размеры  (Пример: панель инвентаря)
– Можно изменять размеры (Приме: окно переписки)
– Запретить передвигать окно (Пример: мини-карта)
– и т.д.
Ещё нам потребуется номер текущего дизайна, это если приспичит менять дизайн окна в процессе программы (например в настройках); и непонятный параметр высоты.

А так-же 3 вектора

Всё вместе это будет выглядеть как

Сначала рассмотрим структуры.


winSprite


В vecWinSprite расположено 9 экземпляров winSprite.
каждый winSptite содержит sf::Sprite, который содержит один из этих кусочков окна
image08winSprite расположены в vecWinSprite в следующем порядке
image09Помните я вам обещал рассказать почему загрузка происходит именно таким образом? Так вот, если начать рисовать окно с конца вектора, то можно избежать некоторых сбоев в прорисовке окна.
winSprire
w, h – начальная ширина и высота (совпадают с w  и h image0)
wc и wh – текущие ширина и высота
dx и dy – смещение относительно позиции окна
image0 – изначальная картинка
image – текущая картинка
image07Все методы довольно простые кроме одного, это




Попробуем разобраться

…………….
Мы должны как-то создавать окно и задавать его размеры и свойства.
Для этого будем использовать конструкторы. В будущем надо вынести в отдельные функции.

или

Функция data() сами знаете для чего используется

Я пока не делал ориентацию на максимальный размер окна, так что по 0 .

 

..


Функция main


Перед нами файл main.cpp

Нам потребуются дополнительные классы. Допустим они у нас уже есть, мы их подключили к проекту и используем.

Чтобы отображать много окон в 1 приложении нам нужен некий класс, который будет содержат в себе все окна и обрабатывать их, и им будет MWindows. Допустим он у нас уже имеется.

Наши действия:
1. Создаём экземпляр класса MWindows
2. Выбираем файл дизайна, у меня это будет “flyff/flyff.png”.
(Можете сделать свой дизайн в Paint.net)

Далее нам потребуется класс мыши. Допустим он у нас уже имеется.
Наши действия:
1. Создаём экземпляр класса мышь
2. Привязываем мышь к окну Программы (обязательно)
3. Устанавливаем дизайн курсора “aero/aero.png”
4. Устанавливаем картинку курсора – стрелочку
5. Скрываем стандартный курсор

Далее создаём экземпляр класса клавиатуры (его настраивать не надо)

Далее нам надо как-то создавать окна.
Наложим на клавиши 1 или 2 обработчики событий клавиатуры.
Нам потребуется класс окна, допустим он у нас уже имеется.

Наши действия, если было нажатие на кнопку:
1. Создаём экземпляр класса окна и задаём ему параметры
150 – ширина окна
150 – высота окна
true – можно ли перемещать окно (не работает)
false – можно ли окну выходить за пределы окна Программы (работает только влево и вверх)
true – можно ли изменять размеры окна
2. перемещаем окно на 300 по Y
3. Устанавливаем дизайн окна который был выбран в начале
4. Добавляем окно в систему окон MWindows

Далее у нас идёт поведение мыши, которое обновляет координаты мыши

Далее,
Наша система окон имеет поведение ориентируемое на мышь, так что обработаем его

Далее мы рисуем систему окон и курсор мыши на экране

И повторяем всё заново.

В конце программы не забываем удалить созданное нами (аля Тарас Бульба)

Теперь мы рассмотрим, что же у нас таит в себе Система окон MWindows


II. MWindows


 

MWindows.h и MWindow.cpp в конце статьи или вот тут.
Начнём рассмотрение с тех функций, которые мы вызывали в пункте I.


1. MWindows(void)


Вызывается функция data() задающая начальную информацию.


2. void add(Window* window)


Добавляет окно в vecWindow

 

Каждое окно содержит ссылку на вектор vecInt класса MWindows, т.е. ссылку на вектор, в котором хранятся координаты окна и мыши в момент нажатия ЛКМ.


3. void behavior(Mouse* mouse)


 

Разбор полётов:
Общий вид функции

Разберём всё по порядку


case 0


Что происходит в программе когда мышь не нажата?
Когда мышь не нажата, может изменятьcя картинка курсора, если он зайдёт в зону растяжения и собственно всё.

Итак, проходим по всем окнам

Нам бы надо найти окно, на которое зашла мышка.
Специально для этого у каждого окна существует функция check1(&x, &y) которая принимает ссылки на координаты мыши и возвращает true, если эти координаты принадлежат данному окну.
image01

Если мы нашли окно, на которое зашла мышка, то нам надо запомнить номер этого окна и выйти из цикла. (номер запишем в iNum)
Если не написать break, то данная конструкция возьмёт самое нижнее окно, на которое наведён курсор, что не есть гуд.

Далее:
А что если мышка сейчас не на окне? Тогда картинку изменять не надо.

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

image1
Для проверки входимости в зоны растяжения у каждого окна существует функция check3(&x, &y), которая возвращает 0-7 если мышка находится в зонах растягивания и -1 если нет.image02
Почему именно так? позже объясню.

Добавляем установку курсора в соответствии с полученным значением zzz

В остальных случаях либо зона перемещения, либо никакой.
Я решил что в зонах перемещения курсор тоже будет менять картинку.
Обычный курсор тоже нужно устанавливать!

В итоге это будет выглядеть вот так:


case 1


Что происходит в программе когда нажимается ЛКМ.
В нашем случае возможны 3 варианта:
– ничего
– начало изменений координат окна
– начало изменения размеров окна
Итак, давайте выясним это!

Перебираем окна

Проверим, было ли нажатие на 1 из окон

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

Далее нам необходимо чтобы окно, по которому мы кликнули поместилось на передний план.
Выглядеть это будет следующим образом
image04
Функция sort1(int) этим и занимается

Это выглядит примерно так
image05После сортировки выделенное окно становиться в vecImage[0]

Теперь на всякий случай сохраним размеры окна с помощью функции save();

Дальше нам нужно проверить, был ли клик по зоне растяжения или по зоне перетаскивания.
Для этого добавим следующие строчки

думаю, тут и так всё понятно. Обрабатываем оба случая входа в зону и помечаем флажком если положительный вход в зону.
Так-же после всего этого нам нужно выйти из цикла поиска окон, иначе функция продолжит перебирать окна, что не есть правильно.

В итоге у нас будет что-то вроде этого


case 2


Что происходит в программе когда зажата ЛКМ.
В нашем случае возможны 3 ситуации:
– ничего
– было нажатие в зону перетаскивания, надо перемещать окно
– было нажатие в зоне растяжения, надо растягивать окно
Для этого мы в case 1 использовали flag2 и flag3.

Сначала мы проверим, будет растяжение, и если его не будет, то проверим, будет ли перемещение.

Допустим у каждого окна уже есть функция растягивания и перемещения,
В нашем случае это

и

Они за нас всё сделает, Отлично! ООП великолепно!
В итоге мы получим

Компактно, не правда ли?


case 3


Что происходит когда мышка отпускается?
Окна прекращает перетаскиваться или растягиваться и собственно всё.
В нашем случае мы просто обнуляем флаги.

Собственно, это пока всё с поведением системы окон.


void draw(sf::RenderWindow* window)


Рисует во входящем окне все окна с конца в начало вектора.
Таким образом организоывваеться правильное отображение окон.

Архив будет приложен в будущем.
..

 
Буду благодарен, если поделитесь: