Blueprint best practices

General Tips

Working in the Blueprint Editor

When working in the Blueprint Editor, there are a few tricks you can use to find the nodes that you want to use, as well as nodes and comments you’ve already created.

  • Use the Search button in the Blueprint Editor when you’re looking for something in an existing Blueprint, whether it’s a variable, function, or comment. It searches
    all Blueprints, even unloaded ones, if you uncheck the Find in Current Blueprint only box, so it can help you track down just where you implemented something.

  • The context menu only shows nodes that you can connect to the pin you dragged from (e.g. when you drag from a light, it shows you functions relevant to the light).When you’re trying to discover all the possible functionality available to act on a variable or component, just browse through the context menu and see what is available.

  • Whether you’re in the context menu or the palette, the search bar can be very helpful. We tag functions with lots of keywords to help you find what you’re looking for, even if you don’t know what it’s called!

Setting Up Your Graph

While everyone has their own graph setup preferences, here are a few tips that can help you keep things organized and easy to follow:

  • Keep things tidy from the get go! It’s much harder to clean up after you’ve made a bunch of code than to work clean as you go.

  • If you find yourself using the same set of nodes more than twice in a graph, consider making it a function or a macro so you can reuse it.

  • You can stack nodes with their context, because it keeps things more spatially compact. For example, if you have a reference to a light, then you access its point light component, you
    can stack those two nodes one on top of the other, and think of them as a single block.

  • Use comments
    often! Also, don’t forget that you can change the color of comment boxes, for extra help identifying sections of your graph.

Use-case: API versioning¶

Blueprints can be very useful for API versioning, where one blueprint may point
at /v1/<routes>, and another pointing at /v2/<routes>.

When a blueprint is initialised, it can take an optional version argument,
which will be prepended to all routes defined on the blueprint. This feature
can be used to implement our API versioning scheme.

# blueprints.py
from sanic.response import text
from sanic import Blueprint

blueprint_v1 = Blueprint('v1', url_prefix='/api', version="v1")
blueprint_v2 = Blueprint('v2', url_prefix='/api', version="v2")

@blueprint_v1.route('/')
async def api_v1_root(request):
    return text('Welcome to version 1 of our documentation')

@blueprint_v2.route('/')
async def api_v2_root(request):
    return text('Welcome to version 2 of our documentation')

When we register our blueprints on the app, the routes /v1/api and /v2/api will now
point to
the individual blueprints, which allows the creation of sub-sites
for each API version.

Packages

This repository contains multiple projects in the directory that fall into 3 categories:

Applications

These are hosted on GitHub Pages as static web applications:

  • – Documentation site at blueprintjs.com/docs
  • – Landing page at blueprintjs.com

These are used as development playground environments:

table-dev-app – demo page that supports manual testing of all table features

Build tooling

These packages define development dependencies and contain build configuration. They adhere to the standard NPM package layout, which allows us to keep clear API boundaries for build configuration and isolate groups of . They are published to NPM in order to allow other Blueprint-related projects to use this infrastructure outside this monorepo.

Blueprint Class

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

В этом случае нажатие кнопки активирует событие внутри Blueprint, отвечающего за дверь, в результате чего она открывается.  Но двери также можно с легкостью активировать с помощью другого типа Blueprint или с помощью Level Blueprint-последовательности. Благодаря самозаполняющейся природе Blueprints, их можно создать, просто набросав  в уровни, и они будут прекрасно работать с минимумом настроек. Также это значит, что редактирование  Blueprint, который используется в проекте, приведет к полному обновлению всех его структур.

Data-Only Blueprint

A Data-Only Blueprint is a Blueprint Class that contains only the code (in the form of node graphs), variables, and components
inherited from its parent. These allow those inherited properties to be tweaked and modified, but no new elements can be added.
These are essentially a replacement for archetypes and can be used to allow designers to tweak properties or set items with variations.

Data-Only Blueprint are edited in a compact property editor, but can also be «converted» to full Blueprints by simply adding code,
variables, or components using the full Blueprint Editor.

Class Defaults can be accessed at runtime for data-only Blueprints through the GetClassDefaults Blueprint node. Please see the Get Class Defaults
for more information.

Перезапуск игры

  1. Сбрасывать состояние игрока. Это включает в себя и скрытие кнопки перезапуска с экрана.
  2. Повторно создавать туннели. Таким образом игрок стартует с начала туннеля.

Сброс игрока

BP_PlayerRestartGame

  1. Set Is Dead присваивает IsDead значение false. Это снова включает возможность движения вперёд.
  2. Remove From Parent удаляет с экрана RestartWidget
  3. Set Input Mode Game Only снова включает возможность управления в игре, чтобы игрок мог перемещаться
  4. Set Show Mouse Cursor скрывает курсор мыши

Повторное создание туннелей

CompileBP_PlayerBP_TunnelSpawnerSpawnInitialTunnelsSequenceEntryThen 1ForLoop
Примечание:Sequence
Then 0SequenceGet All Actors of Class

Обработка нажатий на кнопку

CompileBP_TunnelSpawnerUIДважды щёлкнитеWBP_RestartRestartButtonEventsкнопкуOnClicked
On Clicked (RestartButton)RestartButton

  1. Get Owning Player Pawn возвращает Pawn, которым в текущий момент управляет игрок
  2. Cast to BP_Player проверяет, принадлежит ли Pawn к классу BP_Player
  3. Если это так, то он вызывает функцию RestartGame. Эта функция сбрасывает игрока и скрывает кнопку перезапуска.
  4. Get All Actors of Class и Get возвращает BP_TunnelSpawner и вызывает SpawnInitialTunnels. Эта функция удаляет все существующие туннели и спаунит новые.

Примечание:BP_TunnelSpawnerBP_TunnelWBP_RestartCompilePlay

Шаблоны для страницы админ-панели и авторизации

Теперь давайте
добавим первые шаблоны для нашей панели администратора. Я специально для
демонстрации сделаю другое оформление и пропишу новый базовый шаблон. В
каталоге templates/admin добавлю файл base_admin.html, который будет
иметь следующий вид:

<!DOCTYPE html>
<html>
<head>
<link type="text/css" href="{{ url_for('.static', filename='css/styles.css')}}" rel="stylesheet" />
<title>{{ title }}</title>
</head>
<body>
{% if menu -%}
         <ul class="mainmenu">
         {% for p in menu %}
         <li><a href="{{ url_for(p.url) }}">{{p.title}}</a></li>
         {% endfor %}
         </ul>
         <div class="clear"></div>
{%- endif -%}
<div class="content">
{% block content -%}
{% endblock %}
</div>
</body>
</html>

Здесь все, опять
же, достаточно очевидно

Обратите внимание, для обращения к каталогу static первый параметр
функции. url_for(‘.static’,
filename=’css/styles.css’)

url_for(‘.static’,
filename=’css/styles.css’)

записан с точкой
вначале. Эта точка будет указывать брать каталог static из подкаталога admin, то есть,
сформируется следующий путь:

admin/static/css/styles.css

Далее, в шаблоне
идет отображение меню, если оно передается в шаблон и записан именованный блок content для добавления
информации в дочерних шаблонах. И первый такой шаблон будет login.html со следующим
содержимым:

{% extends 'admin/base_admin.html' %}
 
{% block content %}
{{ super() }}
<div id="login" class="wnd_dlg_back login_wnd">
<div class="login">
         <p class="title">Админ-панель</p>
{% for cat, msg in get_flashed_messages(True) %}
<div class="flash {{cat}}">{{msg}}</div>
{% endfor %}
         <form action="" method="post">
                   <label class="form-label">Логин: </label><input type="text" name="user" />
                   <label class="form-label">Пароль: </label><input type="password" name="psw" />
                   <p align="center"><input class="login_button" type="submit" value="Войти">
         </form>
</div>
</div>
{% endblock %}

Мы здесь
отображаем форму авторизации, где пользователь вводит логин/пароль.

А шаблон index.html будет пока
пустой:

{% extends 'admin/base_admin.html' %}
 
{% block content %}
{{ super() }}
{% endblock %}

Далее, нам нужно прописать стили оформления. Они представлены
в файле

admin/static/css/styles.css

(подробнее см. в файле проекта).

И перед первым
пробным тестированием, изменим обработчик главной страницы админ-панели:

@admin.route('/')
def index():
    if not isLogged():
        return redirect(url_for('.login'))
 
    return render_template('admin/index.html', menu=menu, title='Админ-панель')

Вначале идет
проверка: если пользователь не авторизован, то он перенаправляется на страницу
авторизации. Иначе, будет отображена панель администратора. Здесь в шаблон ‘admin/index.html’ передаются два
параметра: menu и title. И для menu пропишем
следующую коллекцию:

menu = {'url': '.index', 'title': 'Панель'},
        {'url': '.logout', 'title': 'Выйти'}

Все, теперь при
запуске, мы увидим окно авторизации и, вводя admin/12345, перейдем
в панель администратора.

Видео по теме

Flask #1: Что это такое? Простое WSGI-приложение

Flask #2: Использование шаблонов страниц сайта

Flask #3: Контекст приложения и контекст запроса

Flask #4: Функция url_for и переменные URL-адреса

Flask #5: Подключение внешних ресурсов и работа с формами

Flask #6: Мгновенные сообщения — flash, get_flashed_messages

Flask #7: Декоратор errorhandler, функции redirect и abort

Flask #8: Создание БД, установление и разрыв соединения при запросах

Flask #9: Добавление и отображение статей из БД

Flask #10: Способ представления полноценных HTML-страниц на сервере

Flask #11: Формирование ответа сервера, декораторы перехвата запроса

Flask #12: Порядок работы с cookies (куками)

Flask #13: Порядок работы с сессиями (session)

Flask #14: Регистрация пользователей и шифрование паролей

Flask #15: Авторизация пользователей на сайте через Flask-Login

Flask #16: Улучшение процесса авторизации (Flask-Login)

Flask #17: Загрузка файлов на сервер и сохранение в БД

Flask #18: Применение WTForms для работы с формами сайта

Flask #19: Обработка ошибок во Flask-WTF

Flask #20: Blueprint — что это такое, где и как использовать

Flask #21: Blueprint — подключение к БД и работа с ней

Flask #22: Flask-SQLAlchemy — установка, создание таблиц, добавление записей

Flask #23: Операции с таблицами через Flask-SQLAlchemy

Parent Classes

There are several different types of Blueprints that you can create, however before doing so you will need to specify the Parent Class in which the Blueprint will be based.
Selecting a Parent Class allows you to inherit properties from the Parent to use in the Blueprint you are creating.

Below are the most common Parent Classes used when creating a new Blueprint:

Class Type

Description

Actor

An Actor is an object that can be placed or spawned in the world.

Pawn

A Pawn is an Actor that can be «possessed» and receive input from a Controller.

Character

A Character is a Pawn that includes the ability to walk, run, jump, and more.

PlayerController

A Player Controller is an Actor responsible for controlling a Pawn used by the player.

Game Mode

A Game Mode defines the game being played, its rules, scoring, and other faces of the game type.

While the above are the most common, all existing classes can be used as the Parent Class for a new Blueprint (even other Blueprint Classes).

For example, say you created an Actor Blueprint called Animals and in it provided some script that all animals share such as Hunger, Thirst, Energy, or whatever script you wanted. Then you created another Blueprint called Dogs and selected your Animals Blueprint Class as the Parent Class; you can then provide specific functionality that applies to only dogs within the Dogs Blueprint such as Play Fetch or Roll Over while inheriting the functionality that all animals share from the Animals Blueprint.

Depending upon the method used to create a Blueprint Class
, a Parent Class may already be assigned upon creation.

Создание декоратора

прекращенияEnemyBlackboardBT_Muffinнажмите правой клавишей мышиSequenceAdd Decorator\Blackboard
BlackboardBlackboard KeyEnemy
EnemySequenceObserver Aborts

Использование Observer Aborts

  1. Self: этот параметр позволяет поддереву атаки прекратить собственное выполнение, когда Enemy становится недействительным. Это может случиться, когда Enemy умирает до завершения поддерева атаки.
  2. Lower Priority: этот параметр позволяет прекращать выполнение деревьев с более низким приоритетом при задании Enemy. Поскольку поддерево случайного движения расположено после атаки, оно имеет меньший приоритет.

Observer AbortsBoth

  1. Selector запускает поддерево атаки, если задан Enemy
  2. Если он задан, то Pawn будет двигаться и поворачиваться в сторону врага
  3. Затем он выполнит атаку
  4. Наконец, Pawn будет ждать две секунды
  1. Selector запускает поддерево случайного движения, если поддерево атаки завершается неудачно. В нашем случае оно завершается неудачно, если не задан Enemy.
  2. BTService_SetRandomLocation генерирует случайную точку
  3. Pawn движется в сгенерированную точку
  4. Затем он ждёт пять секунд

BT_MuffinPlay

Определение подделки

Определяя подлинность колодок Blue Print особое внимание следует уделять мелким деталям. Так, например, каждая колодка упаковывается в плотный полиэтилен

На поверхности коробки не должно наблюдаться дефектов полиграфии.

После изъятия колодок необходимо их визуально осмотреть. Начинать следует с фрикционного материала. На нем не должно наблюдаться:

  • вздутий;
  • неравномерного цвета;
  • раковин;
  • крупных вкраплений;
  • прослоек;
  • трещин и прочих механических дефектов.

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

Создание туннелей в точке спауна

CompileBP_TunnelSpawnerBP_TunnelSpawnPointсамого дальнего
SpawnTunnelНажмите правой клавишей мышиReturn ValueSpawn Actor From ClassPromote to VariableNewestTunnel
SpawnTunnelAtSpawnPoint
SpawnPointBP_TunnelBP_TunnelSpawnerBP_TunnelSpawner

Создание ссылки на спаунер туннелей

CompileSpawnTunnelAtSpawnPointBP_TunnelTunnelSpawnerVariable TypeBP_TunnelSpawner\Object Reference
CompileBP_TunnelSpawnerSpawnTunnel
BP_TunnelSpawnerBP_TunnelSpawnerTriggerZone

Скриптинг зоны триггера

CompileBP_Tunnelнажмите правой клавишейTriggerZoneAdd Event\Add OnComponentBeginOverlap
ActorTriggerZoneActorTriggerZoneПеретащитеOther Actorлевую клавишу мышиCast to BP_Player
Примечание:концеTriggerZoneCast to BP_PlayerOther ActorCast to BP_Player

  1. Когда Actor касается TriggerZone, выполняется нод On Component Begin Overlap (TriggerZone)
  2. Нод Cast to BP_Player проверяет, является ли касающийся актор игроком
  3. Если это игрок, то BP_TunnelSpawner создаст новый туннель. Его местоположение будет находится в компоненте SpawnPoint последнего созданного туннеля.
  4. Поскольку старый туннель уже не нужен, игра удаляет его с помощью нода DestroyActor

CompilePlayвыглядят

О материалах

материал

Что такое «материал»?

  • Base Color: цвет или текстуру поверхности. Используется для добавления детализации и вариаций цвета.
  • Metallic: насколько металлическим выглядит материал. В общем случае, чисто металлический объект имеет максимальное значение Metallic, а ткань — значение 0.
  • Specular: управляет блеском неметаллических поверхностей. Например, керамика будет обладать высоким значением Specular, в отличие от глины.
  • Roughness: поверхность с максимальной roughness (шероховатостью) не будет иметь никакого блеска. Используется для таких поверхностей, как камень и дерево.

Редактор материалов (Material Editor)

  1. Graph: в этой панели содержатся все ноды (узлы) и нод Result. Перемещаться по панели можно, удерживая правую клавишу мыши и двигая мышью. Масштабирование выполняется прокруткой колёсика мыши.
  2. Details: здесь отображаются свойства выбранного нода. Если нод не выбран, то здесь отображаются свойства материала.
  3. Viewport: содержит меш предварительного просмотра, представляющий материал. Поворачивать камеру можно, удерживая левую клавишу и двигая мышь. Масштабирование выполняется прокруткой колёсика мыши.
  4. Palette: список всех нодов, доступных для вашего материала.

Добавление текстур

текстураBanana_Texture.jpgTextureSampleTextureSampleлевую клавишу мышиперетащив
TextureSampleраскрывающийся списокTexture
Banana_Texture
Resultлевую клавишу мышибеломTextureSampleПеретащитеBase ColorResult
Apply

Class Variables vs. Local Variables

When you’re working in your Blueprint, you have the ability to add variables
using the My Blueprint

  1. When you’re inside a function though, you’ll see an additional section of the My Blueprint tab for Local Variables.

Local variables are scoped, which means that they only exist where you define them. So, a local variable in a function is only visible to that function, and not to other functions, or the
Event Graph. This helps to reduce clutter for things that are only relevant within the context of that function. You can consider local variables a «scratch pad» to work with in a function. You
can use them to help perform what the function needs to, but they get tossed away after the function has completed.

Class variables are for things that you are potentially going to be interested in accessing from multiple places in the Blueprint. So, things like references to meshes or other components, or variables
that need to be public so you can access them from other Blueprints, should be class variables. They’re the things you don’t want to forget about after you use them.

Маршрутизация в Blueprint

Перейдем в
модуль admin.py и пропишем
декоратор route:

@admin.route('/')
def index():
    return "admin"

Смотрите, мы
вызываем route для admin, а не app, как это делали
в основном приложении. Тем самым указываем, что корневая (главная) страница –
это страница Blueprint, а не
приложения app. Причем, адрес
этого URL определяется по
правилу:

домен/<url_prefix>/<URL-blueprint>

и в нашем случае
будет выглядеть так:

http://127.0.0.1:5000/admin/

то есть, это
главная страница админ-панели, а не сайта. И благодаря префиксу, указанному при
регистрации этого эскиза, мы можем не беспокоиться о дублировании URL в нашем модуле.

Авторизация в админ-панели

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

@admin.route('/login', methods="POST", "GET")
def login():
    if request.method == "POST":
        if request.form'user' == "admin" and request.form'psw' == "12345":
            login_admin()
            return redirect(url_for('.index'))
        else:
            flash("Неверная пара логин/пароль", "error")
 
    return render_template('admin/login.html', title='Админ-панель')

Здесь все
достаточно просто и очевидно. Сначала проверяем, что пришли данные по POST-запросу, затем,
проверяем правильность логина и пароля и при истинности условий, выполняем
авторизацию с помощью функции login_admin, которую
пропишем чуть позже. Далее, делается перенаправление на главную страницу
админ-панели, а иначе – формируется мгновенное сообщение «Неверная пара
логин/пароль». В конце возврашается шаблон ‘admin/login.html’ с заголовком ‘Админ-панель’.

Обратите
внимание, как здесь записан параметр в функции

url_for(‘.index’)

Перед index указана точка.
Эта точка означает, что функцию-представления index следует брать
для текущего Blueprint, а не глобальную
из приложения. Если убрать точку, то будет возвращен URL-адрес главной
страницы сайта, а не панели администратора. Как вариант, функцию url_for можно еще
вызвать и так:

url_for(‘admin.index’)

Здесь admin – это имя Blueprint, а не название
файла admin.py. Например, если
изменить имя эскиза на bp, то придется уже прописывать:

url_for(bp.index’)

Но, в данном
случае, это избыточная запись и, кроме того, идет жесткая привязка к имени Blueprint. Поэтому, я в
дальнейшем буду писать просто точку.

Итак,
возвращаясь к обработчику login, добавим функцию login_admin в модуль admin.py:

def login_admin():
    session'admin_logged' = 1

Мы здесь просто
в сессии создаем и сохраняем запись ‘admin_logged’ со значением
1. И в дальнейшем будем полагать, если она существует, то пользователь зашел в
админ-панель.

Некоторые из вас
могут задаться вопросом: почему бы нам здесь не использовать рассмотренный
ранее модуль Flask-Login? Дело в том,
что нельзя создать еще один его экземпляр в рамках одного приложения. А Blueprint – это лишь
дополнение, расширение, но не самостоятельная программа. Конечно, мы могли бы
передать ссылку на Flask-Login в наш модуль admin и как то его
использовать, но тогда теряется концепция независимости и модульности Blueprint. И наша
реализация будет ничем не лучше обычного дополнительного вспомогательного
класса, записанного в отдельном файле проекта. Поэтому, я авторизацию сделал
через сессии.

Давайте здесь же
рядом объявим еще две вспомогательные функции:

def isLogged():
    return True if session.get('admin_logged') else False
 
def logout_admin():
    session.pop('admin_logged', None)

Первая
проверяет: авторизован ли администратор, а вторая – удаляет из сессии запись об
авторизации и будет использоваться при выходе из админ-панели. И сразу пропишем
функцию представления logout:

@admin.route('/logout', methods="POST", "GET")
def logout():
    if not isLogged():
        return redirect(url_for('.login'))
 
    logout_admin()
 
    return redirect(url_for('.login'))

Почему у нас появилась отдельная строка «возможные ошибки и их решения»?

Обращали ли вы внимание на то, что часто хороший сервис — это невидимый сервис. Пользователя все устраивает, вы решаете его задачи

Но как только происходит сбой — вас замечают, начинают звонить, писать, оставлять гневные отзывы в интернете

Знакомая ситуация? Избежать ошибок совсем нельзя, вот почему так важно знать все тонкие места и иметь быстрые решения для таких ситуаций

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

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

В рамках Service Blueprint мы отметили эти моменты в специальной строке, чтобы видеть что происходит и на каких этапах пользовательского сценария. Дальше, основываясь на этой картине сервиса, мы сгенерировали идеи о том, как помочь сотрудникам создавать позитивные впечатления от услуги у пользователей «здесь и сейчас».

Что у нас получилось можно узнать на нашем сайте в развернутой истории о кейсе RED: lab-w.com/cases/red

Braking Parts Specialised for Asian Vehicles

Going beyond the full selection of dry braking components for All-Makes, Blue Print – as a specialist for parts for Asian vehicles – has the complete solution for the remainder of the braking range for Asian applications.

There are currently more than 3,200 parts in the braking range alone – covering over 70,000 applications – giving you an unrivalled breadth and depth of coverage for Asian vehicles.

From fitting kits for brake pads to ABS sensors, Blue Print is Your One Stop Shop for Your Asian Vehicle Braking Needs!

To get more information about the full Blue Print braking range for Asian vehicles, visit our online catalogue at partsfinder.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *