Шаг 7 - Создание прототипов: PROTO и EXTERNPROTO

Идея создания прототипов является дальнейшим развитием идеи повторного использования кода. В прошлом шаге мы познакомились с методами DEF/USE, но они имеют серьезный недостаток - невозможность модификации кода. С помощью прототипов можно создавать новые типы узлов, которые помимо простого копирования кода будут иметь возможность менять его параметры, так называемые "переменные".

Вот структура определяющая новый прототип узла:

PROTO <имя_прототипа> [
     <список_полей_и_событий>
]
{
     <тело_узла>
}

Список полей и событий - это список параметров, которыми будет обладать этот узел. Про типы полей и событий читайте шаг "Шаг 5 - Типы полей и событий". Описываются поля в следующем виде:

<модификатор> <тип_поля> <имя_поля> <значение_по_умолчанию>

Эдесь под <модификатор>'ом я подразумеваю зарезервированные слова field, eventIn, и eventOut, которые указывают предназначение поля, т.е. указывают чем является поле: параметром или событием. Из суммы этих определений следует еще один модификатор - exposedField, который имеет полноценное право здесь быть. Об этом модификаторе мы раньше говорили в "Шаг 3 - Основные понятия". Давайте для примера создадим список полей:

# поле с именем NUMBER хранящее целое число, 
# по умолчанию поле принимает значение 0
field SFInt32 NUMBER 0

# поле с именем F_ARRAY хранящее массив вещественных
# чисел, по умолчанию принимает пустое значение [ ]
field MFFloat F_ARRAY []

# изменяемые поле SIZE и COLOR
exposedField SFFloat SIZE  1.0
exposedField SFColor COLOR 0 0 0

# события
eventIn  SFVec3f    MOVE     0 0 0
eventIn  SFRotation ROTATE   0 0 1 0
eventOut SFBool     ROTATING FALSE

В <тело_узла> вставляется описание объекта, создаваемого этим узлом. К примеру можно задать постоение сложной формы, параметры которой будут зависеть от конкретных значений полей этого узла. Давайте рассмотрим пример:

#VRML V2.0 utf8

# определяем прототип куба размером size,
# в позиции position и цветом color
PROTO BOX_NEW[
	field SFColor color 1 1 1
	field SFVec3f position 0 0 0
	field SFVec3f size  2 2 2
]
{
Transform {
		translation IS position
		children [
			 Shape {
				appearance Appearance {
					material Material {
						diffuseColor IS color
					}
				}
				geometry Box {
					size IS size
				}
			}
		]
	}
}

# строим сцену из предыдущего шага
# с более расширенными возможностями
Group {
	children[
		BOX_NEW { }
		BOX_NEW {
			position 2 2 -2
			size 1 1 1
			color 0 1 0
		}
		BOX_NEW { position -2 -2 2 color 1 0 0}
	]
}

Вот, что получается в результате просмотра:

7.gif (2508 b)

Как видите, теперь описание сцены из предыдущего шага стало еще более коротким, и в то же время увеличилось количество свойств у куба. Эта возможность появилась из-за использования разных значений полей узла NEW_BOX. Каждое поле данного узла присваивается реальному полю куба с помощью оператора присваивания IS (соответствующие строки кода выделены жирным шрифтом).

Другим прекрасным методом повторного использования кода является работа с внешними прототипами с помощью EXTERNPROTO. Структура определяющая внешний прототип выглядит следующим образом:

EXTERNPROTO <имя_прототипа> [
     <список_полей_и_событий>
] "<URL_прототипа>"

Это описание очень похоже на предыдущее за исключением того, что поля не имеют <значений_по_умолчанию> (они берутся из исходного файла). Осталось поговорить только о <URL_прототипа>, так как сразу не ясно, что это такое. Под URL адресом прототипа подразумевается полный или относительный адрес файла VRML, в котором находится полное описание прототипа. Причем важно то, что этот внешний файл должен полностью соблюдать структуру файла VRML, т.е. иметь заголовок. Если файл содержит только один прототип, то URL адресом прототипа будет имя файла полностью:

"proto.wrl"
или
"http://any.domen.ru/proto.wrl"

Если же этот файл содержит описание нескольких прототипов, то надо указывать имя того прототипа, описание которого будет использоваться:

"proto.wrl#PROTO1"
или
"http://any.domen.ru/proto.wrl#PROTO1"

Таким образом, если мы запишем прототип нашего куба в файл protolib.wrl, то использовать его описание внутри нашей сцены мы сможем только после его описания. Давайте рассмотрим пример:

#VRML V2.0 utf8

EXTERNPROTO BOX_NEW[
	field SFColor color
	field SFVec3f position
	field SFVec3f size
] "protolib.wrl#BOX_NEW"
Group {
	children[
		BOX_NEW { }
		BOX_NEW { position 2 2 -2 size 1 1 1 color 0 1 0}
		BOX_NEW { position -2 -2 2 color 1 0 0}
	]
}

Использование внешних прототипов еще более упрощает файл сцены. К тому же таким методом можно создавать большие библиотеки прототипов и использовать их в виртуальных мирах.


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Кузин Андрей.