LifeEXE | Unreal Engine | CG
1.95K subscribers
429 photos
546 videos
480 links
Download Telegram
Всем привет!

🔥 Новое видео на канале 🔥

План лекции следующий:
🎯 Говорим про тестовое покрытие
🎯Рассматриваем OpenCppCoverage
🎯 Пишем bat скрипт для запуска тестового покрытия
🎯 Рассматриваем форматы публикации отчета: html, cobertura
🎯 Создаем Jenkins работу для запуска тестового покрытия
🎯 Проверим макрос FORCENOINLINE

https://youtu.be/owBUien7aRs

Все ссылки из видео для удобства собрал на отдельной странице в вики

Ресурсы:
🔴LifeEXE School
🔴Группа ВКонтакте
🔴Twitter
🔴GitHub
🔴Medium

Поддержать канал:
🔴PayPal Donate
🔴Patreon

#unrealengine #ue5 #gamedev #devops #unit_tests #test_automation #TDD #test_report #test_coverage #code_coverage #unrealengine5 #ue4 #lifeexe #lifeexecode #cplusplus
🔥391👍1
🆕 Всем привет! 🆕

Минутка кода под утренний кофеёк ☕️

В UE5 появился удобный макрос для логирования — UE_LOGFMT.
Он позволяет логировать строки более гибко и безопасно.

Пример использования:
#include "Logging/StructuredLog.h"
DEFINE_LOG_CATEGORY_STATIC(LogSlasherGame, All, All);


const FString Name = "Patrick Bateman";
const bool IsDead = false;
const int32 Ammo = 10;

UE_LOGFMT(LogSlasherGame, Display,
"Name: {0}, is alive: {1}, ammo: {2}", Name, !IsDead, Ammo);


Сравнение с классическим UE_LOG:
#include "Logging/StructuredLog.h"
DEFINE_LOG_CATEGORY_STATIC(LogSlasherGame, All, All);


const FString Name = "Patrick Bateman";
const bool IsDead = false;
const int32 Ammo = 10;

UE_LOGFMT(LogSlasherGame, Display,
"Name: {0}, is alive: {1}, ammo: {2}", Name, !IsDead, Ammo);

UE_LOG(LogSlasherGame, Display,
TEXT("Name: %s, is alive: %s, ammo: %d"),
*Name, IsDead ? TEXT("false") : TEXT("true"), Ammo);


UE_LOGFMT поддерживает именованные аргументы:
#include "Logging/StructuredLog.h"
DEFINE_LOG_CATEGORY_STATIC(LogSlasherGame, All, All);


const FString Name = "Patrick Bateman";
const bool IsDead = false;
const int32 Ammo = 10;

UE_LOGFMT(LogSlasherGame, Display,
"Name: {name}, is alive: {alive}, ammo: {ammo}", Name, !IsDead, Ammo);


Результат логирования везде одинаковый:
Name: Patrick Bateman, is alive: true, ammo: 10


UE_LOGFMT использует современный подход к форматированию строк — string interpolation, подобно std::format (С++20), или анриловскому FString::Format, что обеспечивает безопасность типов (type safety) и улучшает читаемость.

Не забудьте, что для использования UE_LOGFMT необходимо подключить заголовочный файл:
#include "Logging/StructuredLog.h"


🔤🔤🔤🔤🔤🔤🔤

🤝 Поддержать:
Patreon | Boosty | PayPal

Ресурсы:
GitHub | LifeEXE School | Itch | X | Wiki | Курс по UE

#unrealengine #gamedev #lifeexe #code #cpp #code_hints #lifeexeEDU
Please open Telegram to view this post
VIEW IN TELEGRAM
50🔥11132👍158🐳1🏆1
🔼Всем привет, всем привет! 🔼

Небольшой пост о UML-диаграммах и диаграммах в целом 📉

Сам не фанат детализированных диаграмм, но иногда полезно их применять для наглядного объяснения базовых концептов и функциональности.

Популярные сервисы вроде drawio, lucidchart, miro или axivion suite, конечно, справляются с этой задачей. Однако они перегружены, и нужно приложить усилия, чтобы всё выглядело аккуратно и читабельно. Плюс некоторые фичи доступны только по подписке. Короче, удобнее на листе бумаги все накидать 😁

Но имеется один отличный минималистичный и полностью бесплатный инструмент, который может помочь с диаграммами:

🔤🔤🔤🔤🔤🔤🔤

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

classDiagram
class Character {
-string name
}

class Supervillain {
+doBadThings()
}

class WeaponComponent {
-int damage
+attack()
}

class HealthComponent {
-int health
+heal()
}

Character <|-- Supervillain : is-a
Supervillain *-- WeaponComponent : has
Supervillain *-- HealthComponent : has


Mermaid поддерживает разные типы диаграмм (не только UML):
• классов
• состояний
• последовательностей
• Ганта
• чарты
и другие.

У Mermaid имеется удобный live-редактор, в котором можно экспериментировать: https://mermaid.live

Доки отличные, все осваивается за пару часов, если знакомы с UML: https://mermaid.js.org/intro

Поддерживаются стили, так что внутренний художник будет удовлетворен 🎨

Инструмент легко интегрируется с платформами, такими как Notion, Jira, GitBook и многими другими, поскольку все рендирится на JavaScript. Загуглите, есть даже плагин для VSCode.

Плюс это ещё и open-source проект (зацените кстати их модный markdown, с интеграцией диаграмм):
https://github.com/mermaid-js/mermaid

Не хватает только кастомных координат. Хотелось бы иметь возможность двигать блоки самостоятельно. Возможно добавят со временем данную фичу. Тогда будет идеально.

В качестве бонуса есть ещё один мини сервис:
https://nomnoml.com

В вики все ссылки добавил

#lifeexe #tools #uml #code #gamedev #mermaid
Please open Telegram to view this post
VIEW IN TELEGRAM
36👍21🔥175👾3
▶️ Всем привет, всем привет! ▶️

Непостоянная рубрика: Субботний C++ 🦊

Сегодня в меню очевидный, но не всегда применяемый подход:
Immediately Invoked Lambda Expression (IILE)

🔗 Текст поста также добавил в статьи в вики

Почему const — это важно?
Неизменяемость (immutability) — залог надежного и понятного кода. Использование const там, где это возможно, помогает компилятору отлавливать ошибки и показывает намерения программиста яснее. Когда другой человек читает ваш код и видит const, снижается когнитивная нагрузка на мозг — «запоминать изменения данного значения не надо — расслабься». Const correctness является важной практикой в C++.

Проблематика
В простых случаях инициализация констант не вызывает проблем:
const int c_maxPlayers = 100;
const double c_scale = getScaleFactor() * 1.5;
const bool c_enabled = check() || FORCE_ENABLE;
const int c_healthModifier = bHealing ? 20 : 0;


Но что делать, если для вычисления значения константы требуется несколько шагов, временные переменные, циклы или условия?
float c_calculatedDamage = getBaseDamageValue();
if (targetAimed(calculatedDamage)) {
for (int i = 0; i < c_effectCount; ++i) {
calculatedDamage += getBonusDamage(i);
}
}


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

Immediately Invoked Lambda Expression (IILE)
Здесь на помощь приходит использование немедленно вызываемого лямбда-выражения (IILE). Мы определяем лямбда-функцию, которая инкапсулирует всю сложную логику инициализации, и тут же вызываем её. Результат этого вызова и присваивается нашей константе.

Как это выглядит:
const auto myLambda = [](){ return 13; }();


Скобочки форева 🤪 Последние круглые скобки () после фигурных скобок лямбды — это и есть немедленный вызов. Они заставляют лямбду выполниться прямо в месте определения. То есть мы можем проинициализировать сложный объект и сохранить константность:
const auto c_calculatedDamage = [&]() {
float tempDamage = getBaseDamageValue();
if (targetAimed(tempDamage)) {
for (int i = 0; i < c_effectCount; ++i) {
tempDamage += getBonusDamage(i);
}
}
return tempDamage;
}();


Преимущества IILE для инициализации
🟢Инкапсуляция — вся логика инициализации собрана в одном месте.
🟢Локальность — временные переменные, используемые для вычисления, не «загрязняют» внешнюю область видимости.
🟢Сonst сorrectness — позволяет объявить переменную как const (или даже constexpr, если лямбда соответствует требованиям), даже если её вычисление многоэтапное.
🟢Чистота кода — избавляет от необходимости создавать отдельные, одноразовые именованные функции.

Альтернативный синтаксис (C++17)
В C++17 можно использовать std::invoke, хотя для IILE прямой вызов () обычно предпочтительнее и понятнее:
#include <functional> 
// ...
const auto c_anotherConstant = std::invoke([] {
// ...
return 13;
});


Ссылки
🔗ES.28: Use lambdas for complex initialization, especially of const variables
🔗Article in english

🔤🔤🔤🔤🔤🔤🔤

🤝 Поддержать:
Patreon | Boosty | PayPal

Ресурсы:
GitHub | LifeEXE School | Itch | X | Wiki | Курс по UE

#cpp #tipsandtricks #code #fun #lifeexe #lifeexecode #lifeexeEDU
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8316👍9❤‍🔥2
Media is too big
VIEW IN TELEGRAM
🔝 Всем приятного вечера! 🔝

На FAB завезли топовый контент — RDR System

Проект, написанный на C++, демонстрирует интеграцию Advanced Locomotion System Refactored с возможностями Motion Matching из проекта Game Animation Sample

🔗 Скачать бесплатно с FAB

🖥 Документация

💀 Rig персонажа

📱 Шоукейс

🤘 Credits: David Pusher

#unrealengine #ue5 #fab #gamedev #gasp #als #sample #code #assets #lifeexe #lifeexecode
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥44144👍311
🔝 Всем привет! 🔝

В новом апдейте Visual Studio 2022 17.14 огненные фичи ⬇️

🔥 Unreal Engine Blueprints Debugger

Добавлена возможность отлаживать Blueprint'ы непосредственно в Visual Studio. Это позволяет просматривать стек вызовов блюпринт-функций и их локальные переменные прямо в IDE[Изображение1]

Соответствующие окна в меню Visual Studio:
Debug > Windows > Call Stack
Debug > Windows > Locals

Отлаживать так намного удобнее + время переключения между Visual Studio и Unreal Editor сократится. Это прямо кайф!

🔥 C++ Dynamic Debugging

Динамическая отладка C++ — это новая фича компилятора и IDE, которая позволяет сохранить производительность оптимизированных сборок, предоставляя при этом удобство отладки, характерное для неоптимизированных сборок.

Проблематика:
Думаю, каждый сталкивался с переменными, значения которых невозможно посмотреть под отладчиком, потому что они были оптимизированы компилятором — [Изображение2]

Как решать данную проблему?
🔤Можно полностью отключить оптимизацию компилятора — билд станет заметно «тяжелее», рантайм просядет.
🔤Можно использовать pragma optimize для куска кода, который мы не хотим оптимизировать:
#pragma optimize( "", off )
/* unoptimized code section */
int please_let_me_live_var {13};
#pragma optimize( "", on )


В Unreal Engine имеется свой парный макрос для этого:
UE_DISABLE_OPTIMIZATION
int please_let_me_live_var {13};
UE_ENABLE_OPTIMIZATION


Собственный макрос в UE обусловлен тем, что синтаксис pragma варьируется между компиляторами.

🔤Новое решение — C++ Dynamic Debugging. Фича доступна в beta-версии и работает за счет динамической деоптимизации функций, в которых вы активируете точки останова.

1. Ставим конфигурацию проекта в Release.
2. Включаем фичу в пропертях проекта [Изображении3]:
Advanced > Use C++ Dynamic Debugging > Yes
3. Результат можно видеть на [Изображении4]

🟢 Остальные обновления минорные: реализованы новые возможности C++23, некоторые автокомплиты для CMAKE и улучшения для GitHub Copilot — куда ж без него 😀

На моём канале есть видео по теме:
🔤Сборка C++ проектов. Компиляция. Ассемблер. Теория
🔤Сборка C++ проектов. Оптимизации компилятора

#visualstudio #vs #code #unrealengine #ue5 #gamedev #lifeexe #lifeexecode
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥457😱64👍21
📕 Всем привет, всем привет! 📕

Зацените чувство юмора авторов книги по C++ 1997 года от Bell Labs

🔗 Ruminations on C++: A Decade of Programming Insight and Experience

Слово ruminate в английском языке имеет два значения:
— жевать жвачку, буквально, как делают коровы 🤠
— размышлять глубоко и вдумчиво 👨‍💻

Фамилия Барбары — Му

Обложка рекурсивная: женщина на обложке (походу Барбара) читает книгу, на которой изображена она сама.

#code #book #cpp #gamedev #lifeexe #lifeexecode #humor
Please open Telegram to view this post
VIEW IN TELEGRAM
😁38👍8❤‍🔥521🤯1👌1👾11
📕 Всем привет, всем привет! 📕

В эфире рубрика выходного дня: Воскресный C++ 🦊

Numeric limits в стандарте C++ и в Unreal Engine
На Boosty и Patreon расширенная статья с множеством интерактивных примеров в Compiler Explorer


🔤🔤🔤🔤🔤🔤🔤🔤 🔤

std::numeric_limits в C++ — это стандартный шаблонный класс, который предоставляет информацию о свойствах числовых типов, например:

🔤Минимальные и максимальные значения.
🔤Точность в десятичных знаках.
🔤Специальные значения: infinity, quiet_NaN, signaling_NaN и другие.

Полная спецификация на cppreference.com

Простейший пример использования:
#include <limits>
#include <print> // C++23

int main()
{
std::println("Max int: {}", std::numeric_limits<int>::max());
std::println("Min double: {}", std::numeric_limits<double>::min());
std::println("Lowest float: {}", std::numeric_limits<float>::lowest());
std::println("Double epsilon: {}", std::numeric_limits<double>::epsilon());
return EXIT_SUCCESS;
}


Ключевые особенности
⬇️

Безопасность
🔤Использование шаблонов позволяет компилятору проверять корректность типов на этапе компиляции, предотвращая ошибки.

Вместо «магических чисел» (например, 2147483647 для int), вы используете std::numeric_limits<int>::max(). В итоге код становится более читаемым и переносимым (платформонезависимым).

Портируемость
🔤Работает с любым числовым типом — int, float, double, uint64_t, а также с пользовательскими числовыми типами, если для них существует специализация шаблона numeric_limits .

Чистота кода
🔤Сразу видно, что речь о границе типа.

Когда реально нужен ⬇️

🟢 Для инициализации переменных максимальным или минимальным значением типа. Например, при поиске минимума/максимума в массиве.
🟢 Для проверки переполнения или выхода за пределы диапазона.
🟢 Для шаблонного кода, где тип неизвестен заранее.
🟢 Спецзначения: бесконечность и NaN.

💡 Дополнительно полезно почитать про:
🔤Saturation arithmetic
🔤std::add_sat


🔤🔤🔤🔤🔤🔤 🔤🔤🔤🔤🔤🔤

В Unreal Engine имеется собственный шаблон TNumericLimits<T> — это аналог std::numeric_limits, реализованный в движке.

Заголовочный файл находится по адресу: Runtime/Core/Public/Limits.h

Применение абсолютно аналогичное, как и в стандартном C++:
#include "Math/NumericLimits.h"
#include "Logging/StructuredLog.h"

DEFINE_LOG_CATEGORY_STATIC(LogNumLimitsTest, All, All);

void NumLimitsTest()
{
const int32 MaxInt = TNumericLimits<int32>::Max();
const int32 MinInt = TNumericLimits<int32>::Min();

const float MaxFloat = TNumericLimits<float>::Max();
const float MinFloat = TNumericLimits<float>::Min();

UE_LOGFMT(LogNumLimitsTest, Display, "Int32: Min={0}, Max={1}", MinInt, MaxInt);
UE_LOGFMT(LogNumLimitsTest, Display, "Float: Min={0}, Max={1}", MinFloat, MaxFloat);
}


💡Согласно последним рекомендациям, в коде проектов под Unreal Engine можно использовать и стандартный std::numeric_limits — читаем раздел Use of standard libraries. Поэтому можно выбирать любой подходящий под вашу конкретную ситуацию шаблон.

Всем чистого кода 🤘

🔤🔤🔤🔤🔤🔤🔤

🤝 Поддержать:
Patreon | Boosty | PayPal

Ресурсы:
GitHub | X | LifeEXE School | Itch | Wiki | Курс по UE

#code #cpp #code_hints #lifeexeEDU #unrealengine #ue5 #gamedev #lifeexe #lifeexecode #best_practice #numeric_limits #clean_code
Please open Telegram to view this post
VIEW IN TELEGRAM
6🔥251610🦄22
📕 Всем привет, всем привет! 📕

В эфире рубрика выходного дня: Воскресный C++ 🦊

Написал большую статью на тему:
«Asserts в стандарте C++ и в Unreal Engine»

❗️ На Boosty и Patreon полная версия с множеством примеров!


По традиции сначала разбираем как все работает на чистом
C++, а потом смотрим, что происходит в Unreal Engine
.

🔤🔤🔤🔤🔤🔤

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

Инвариант — это условие, которое должно быть истинным всегда в определённом контексте.

Зачем нужны assertions?
🔤Раннее выявление логических ошибок
🔤Документация ожиданий внутри кода
🔤Обеспечение корректности API

Виды assertions
🔤Времени выполнения — runtime assertions
🔤Времени компиляции — compile-time assertions

🔤🔤🔤🔤🔤🔤🔤🔤 🔤

В стандартном C++ основной инструмент для реализации утверждений — это макрос препроцессора assert, определенный в заголовочном файле <cassert> :

🔤Если выражение истинно — ничего не происходит, и выполнение программы продолжается.
🔤Если выражение ложно — макрос assert выводит диагностическое сообщение в стандартный поток ошибок stderr и немедленно завершает программу путем вызова функции std::abort() ➡️

double div(double numerator, double denominator) 
{
assert(denominator != 0.0);
return numerator / denominator;
}


Стандартный макрос assert не имеет встроенного параметра для пользовательских сообщений. Однако существуют две распространенные идиомы для добавления диагностики, которая будет выведена в диагностическом сообщении в случае сбоя ➡️

assert(divisor != 0 && "Divisor cannot be 0");
assert(("Divisor cannot be 0", divisor != 0));


Распространенная ошибка при использовании assert — это включение в проверяемое выражение кода с побочными эффектами.

Проблема в том, что когда определен макрос NDEBUG, все выражение внутри assert удаляется из кода. Это может привести к тому, что логика программы в отладочной и релизной сборках будет отличаться.

⚠️ Пример того, как делать НЕЛЬЗЯ:
assert(InitializeSubsystem());


✔️ Правильный подход — всегда отделяем действие от проверки:
[[maybe_unused]] const bool bSuccess = InitializeSubsystem();
assert(bSuccess);


🔤🔤🔤🔤🔤🔤 🔤🔤🔤🔤🔤🔤

Unreal Engine расширяет стандартный макрос assert , добавляя дополнительные возможности к рантайм проверкам, Имеются следующие семейства: check, verify, ensure.

🔤🔤🔤🔤🔤

Семейство check является прямым эквивалентом стандартного assert в Unreal Engine. Сбой check указывает на критическую ошибку в программе, и выполнение немедленно останавливается ➡️

void AMyActor::CalculateJumpVelocity(AActor* JumpTarget, FVector& JumpVelocity)
{
check(JumpTarget != nullptr);
}


Остальные макросы данного семейства: check, checkf, checkSlow, checkfSlow, checkCode, checkNoEntry, checkNoReentry, checkNoRecursion, unimplemented

🔤🔤🔤🔤🔤🔤

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

Полный список макросов: verify, verifyf, verifySlow

🔤🔤🔤🔤🔤🔤

Данное семейство макросов используется для сообщения о нефатальных ошибках. Программа не завершает работу, а отправляет отчет со стеком вызовов в Crash Reporter и продолжает выполнение: ensure, ensureAlways, ensureMsgf, ensureAlwaysMsgf

🔤🔤🔤🔤🔤 🔤🔤🔤🔤

🔤Можно проверить на этапе компиляции → static_assert
🔤Критическая ошибка + нет побочных эффектов → check
🔤Критическая ошибка + есть побочные эффекты → verify
🔤Дорогая проверка только для отладки → checkSlow
🔤Некритическая ошибка, продолжаем работу → ensure
🔤Недостижимый код → checkNoEntry или unimplemented
🔤Защита от рекурсии → checkNoRecursion
🔤Защита от повторного вызова → checkNoReentry

В статье на Boosty и Patreon подробнее про каждый из макросов и static_assert


Всем чистого кода 🤘

🔤🔤🔤🔤🔤🔤🔤

🤝 Поддержать:
Patreon | Boosty | PayPal

Ресурсы:
GitHub | X | LifeEXE School | Itch | Wiki | Курс по UE

#code #cpp #code_hints #lifeexeEDU #unrealengine #ue5 #gamedev #lifeexe #lifeexecode #best_practice #assert #clean_code
Please open Telegram to view this post
VIEW IN TELEGRAM
21🔥42👍11116🦄11