Главная Обратная связь Поможем написать вашу работу!

Дисциплины:

Архитектура (936)
Биология (6393)
География (744)
История (25)
Компьютеры (1497)
Кулинария (2184)
Культура (3938)
Литература (5778)
Математика (5918)
Медицина (9278)
Механика (2776)
Образование (13883)
Политика (26404)
Правоведение (321)
Психология (56518)
Религия (1833)
Социология (23400)
Спорт (2350)
Строительство (17942)
Технология (5741)
Транспорт (14634)
Физика (1043)
Философия (440)
Финансы (17336)
Химия (4931)
Экология (6055)
Экономика (9200)
Электроника (7621)






Пример включения перечисления Type в пространство имен EColorChannel



Необходимые настройки для проекта

Включите генерацию файлов XML-документации и всегда держите их в актаульном состоянии.

Включите опцию, генерирующую ошибку при отсутствии документации к коду.

Соглашения по именованию

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

Сразу после объявления переменной желательно написать к ней пояснительный комментарий. Кроме того, это требует стиль Javadoc. Вы можете писать комментарии как к отдельным переменным, так и группам переменных, расположенных в нескольких строках кода, идущих подряд. Отступы между строками не обязательны.

Для именования переменных используйте следующий формат: ThisIsAGoodVariableName. Не применяйте форматы: "thisIsABadName" или "this_is_a_bad_name".

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

/** the tea weight in kilograms */

var float TeaWeight;

 

/** the number of tea leaves */

var int TeaNumber;

 

/** TRUE indicates tea is smelly */

var bool bDoesTeaStink;

 

/** non-human-readable FName for tea */

var name TeaName;

 

/** human-readable name of the tea */

var String TeaName;

К концу имен структурированных типов добавляйте имя класса:

/** Which class of tea to use */

var class<Tea> TeaClass;

 

/** The sound of pouring tea */

var Sound TeaSound;

 

/** a picture of tea */

var Texture TeaTexture;

Для классов C++ все переменные по умолчанию должны быть закрытыми (private). Делайте их общедоступными (public) только в случаях, когда необходимо взаимодействие кода на C++ со сценариями, то есть для кода, генерированного в XxxClasses.h.

Для именования процедур (функций без возвращаемого значения) вы должны использовать только глаголы, располагая их перед именами объектов. Исключением являются случаи, когда процедура вызывается из самого объекта. Во избежание неоднозначности при именовании процедур не используйте слова "Handle" и "Process".



Tea SomeT;

SteepTea(SomeT); // method names type of object processed

SomeT.Pour(); // method invoked on Tea; verb is enough

Имена функции, возвращающих значение, должны описывать возвращаемое значение; имя должно дать ясно понять, какое значение вернет функция. Это особенно важно для булевых функций. Рассмотрим следующие два метода:

function bool CheckTea(Tea t) {...} // what does TRUE mean? function bool IsTeaFresh(Tea t) {...} // name makes it clear TRUE means tea is fresh

Имена состояний и классов для удобства чтения должны начинаться с заглавной буквы. Имена классов должны быть существительными, а имена состояний - описывать состояние (например, прилагательным). Обратите внимание, что состояние никогда не используется вне класса, то есть всегда есть неявный объект.

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

void Update(FLOAT DeltaTime, UBOOL /*bForceUpdate*/);

В сценариях Unreal Script для параметров, передаваемых по ссылке, используйте префикс out_:



function PassRefs (out float out_wt, float ht, out int out_x)

Константы

При объявлении констант C++ старайтесь вместо директив компилятора применять переменные со спецификатором const.

Виртуальные функции

В производном классе при объявлении виртуальной функции, переопределяющей виртуальную функцию в родительского класса, обязательно используйте ключевое слово virtual. Хотя согласно дополнительному стандарту С++ спецификатор "virtual" наследуется, код намного яснее при явном указании ключевого слова virtual.

Исполняемые блоки

Фигурные скобки { }

Идет вечный спор о правильном расположении фигурных скобок. В Epic каждая фигурная скобка размещается в отдельной строке. Рекомендуем вам придерживаться этого правила.

Блоки if - else

При использовании if - else заключайте все исполняемые блоки в фигурные скобки. Это предотвращает возможные ошибки. Если не использовать скобки, то кто-нибудь может невольно добавить еще одну строку в блок if - else, тем самым создав трудно локализуемую ошибку исполнения. Всегда используйте фигурные скобки!

if (bHaveUnrealLicense)

{

InsertYourGameHere();

}

else

{

CallMarkRein();

}

При необходимости осуществления множества проверок используйте выражение else if. Это улучшит читаемость кода.

if (TannicAcid < 10)

{

log("Low Acid");

}

else if (TannicAcid < 100)

{

log("Medium Acid");

}

else

{

log("High Acid");

}

Отступы

При наборе кода в пределах исполняемых блоков делайте отступы. Для самих классов UnrealScript отступов делать не нужно. Для создания отступов используйте знаки табуляции, а не пробелы.

Блоки switch

Во всех блоках switch после кода, следующего за проверяемым значением, не забывайте ставить оператор break. Исключениями являются случаи, когда участок кода следующего проверяемого значения должен быть выполнен и для текущего проверяемого значения.



К каждому блоку switch добавляйте действие по умолчанию (default:), даже в тех случаях, когда действие по умолчанию не требует выполнения каких либо операций. Возможно необходимость в них появится позже.

switch (condition)

{

case 1:

--code--;

// falls through

case 2:

--code--;

break;

case 3:

--code--;

return;

case 4:

case 5:

--code--;

break;

default:

break;

}

Блок defaultproperties

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

defaultproperties

{

// variables inherited from Object

bGraphicsHacks=TRUE

 

// variables inherited from WarmBeverage

bThirsty=FALSE

 

// class variables

bTeaDrinker=TRUE

}

Булевы выражения

В коде на C++ в качестве значений логических выражений всегда используйте TRUE или FALSE. Не используйте true или false, которые могут вызвать сумасшедшие проблемы при компиляции. Не используйте 0 или 1, назначение подобных выражений будет неочевидным.

В коде сценариев UnrealScript вы должны использовать только true and false (в нижнем регистре).

Не бойтесь определить несколько локальных булевых переменных, чтобы сделать код более читабельным. Во втором примере, приведенном ниже, имена переменных делают причину вызова функции DoSomething() более понятной.

Фрагмент кода:

if ((Blah.BlahP.WindowExists.Etc && stuff) && !(Player exist && Gamestarted && player still has pawn && IsTuesday()))) { DoSomething(); }

должен быть заменен на:

local bool bLegalWindow;

local bool bPlayerDead;

 

bLegalWindow = (Blah.BlahP.WindowExists.Etc && stuff);

bPlayerDead = (Player exist && Gamestarted &&

player still has pawn && IsTuesday());

 

if ( bLegalWindow && !bPlayerDead )

{

DoSomething();

}

Обратите внимание: выражение, присваиваемое переменной bPlayerDead, разбито на две строки, а вторая срока этого выражения выровнена по отношению к первой.

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

Общие вопросы стиля:

  • Избегайте определения нескольких точек возврата из функции. Это сделает ваш код проще в обслуживании, позволит проще отслеживать алгоритм функции и облегчит отладку.
  • Никогда не передавайте структуры в функции debugf/warnf/appErrorf Применяйте * для типов FName и FString для их форматирования и вывода с использованием %s.
  • Сводите к минимуму внешние зависимости. Если код зависит от величины, имеющей определенное значение, то перед ее использованием попробуйте присвоить ей правильное значение. Инициализация в верхней части исполняемого блока переменной, не используемой в последующей сотне строк кода, создает вероятность случайного изменения ее значения. Старайтесь определять переменные как можно ближе к тому участку кода, где они используются. Исследование Беркли показало, что переменная, объявленная более, чем за 7 строк до ее использования, имеет крайне высокие шансы (> 80%) неправильного использования.
  • Длина функции. Функции не должны быть больше, чем 60 строк. Это число является произвольным, но вся функция должна поместиться на одной печатной странице. Если ваша функция получилась больше то, возможно, что ее следует реорганизовать. Во избежание снижения производительности старайтесь делать функции поменьше.
  • Сводите число предупреждений компилятора к минимуму Наличие предупреждающих сообщений компилятора означает, что с вашим кодом что-то не так. Исправляйте все участки кода, на которые жалуется компилятор, а если исправить код невозможно, то используйте директиву препроцессора #pragma.
  • Никогда не допускайте неявного преобразования FLOAT в INT. Это довольно медленная операция, которая к тому же поддерживается не всеми компиляторами. Вместо этого для преобразования из FLOAT в INT используйте функцию appTrunc(). В этом случае будет скомпилирован более быстрый код и достигнута совместимость кода с разными компиляторами.

Пространства имен C++

  • Для организации классов, функций и переменных вы можете использовать пространства имен. При этом вы должны соблюдать соответствующие правила.
  • На данный момент код Unreal не обернут в собственное пространство имен. Вы должны следить за коллизиями в глобальном пространстве имен, особенно при использовании кода сторонних разработчиков.
  • Не используйте объявления "using" в глобальном пространстве имен, за исключением пространства файлов .cpp.
  • Вы можете использовать объявления "using" внитри пространств имен или в теле функций.
  • Обратите вниматние, что если вы поместите объявление "using" внутри пространства имен, то это объявление будет распространятся на все блоки соответствующего пространства имен.
  • Использование объявления "using" в заголовочных файлах будет безопасным только при соблюдении вами вышеперечисленных правил.
  • Обратите внимание, что все объявления функций должны находиться в соответствующих пространствах имен. В противном случае вы получите ошибку компиляции.
  • Объявление множества классов и типов внутри пространства имен затрудняет их использование в глобальном пространсте имен, заставляя вас каждый раз указывать имя пространства имен перед именами соответствующих типов параметров глобальных функций.
  • С помощью объявления "using" вы можете получать доступ не только к пространству имен в целом, но и к отдельным типам используемого пространства имен (например, using Foo::FBar), но мы обычно так не поступаем.
  • Часто бывает не лишним обернуть объявления перечислений (enum) в соответствующее пространство имен (в стиле C#), например:

Пример включения перечисления Type в пространство имен EColorChannel

/**

* Defining a enumeration within a namespace to achieve C#-style enum scoping

*/

namespace EColorChannel

{

/** Declare EColorChannel::Type as the actual type for this enum */

enum Type

{

/** Red color channel */

Red,

 

/** Green color channel */

Green,

 

/** Blue color channel */

Blue

};

}

 

 

/**

* Given a color channel, returns a name string for that color

*

* @param InColorChannel The color channel to return a name for

*

* @return Name of this color channel

*/

FString GetNameForColorChannel( const EColorChannel::Type InColorChannel )

{

FString Name;

 

switch( InColorChannel )

{

case EColorChannel::Red:

Name = TEXT( "Red" );

break;

 

case EColorChannel::Green:

Name = TEXT( "Green" );

break;

 

case EColorChannel::Blue:

Name = TEXT( "Blue" );

break;

}

 

return Name;

}

Примеры:

/** * This class handles various waveform activities. It manages the waveform data * that is being played on any given gamepad at any given time. It is called by * the player controller to start/stop/pause a waveform for a given gamepad. It * is called by the UXboxViewport to get the current rumble state information * to apply that to the gamepad. It does this by evaluating the function * defined in the waveform sample data.<BR> * * Copyright: Copyright (c) 2005<BR> * Company: Epic Games Inc.<BR> */ class WaveformManager extends Object within PlayerController native transient poolable(1,0);   /** * Whether the player has disabled gamepad rumble or not (TCR C5-3). This comment is * long so it really needs the multiple lines. */ var bool bAllowsForceFeedback;   /** The currently playing waveform */ var ForceFeedbackWaveform FFWaveform;   /** Whether it was paused by the player controller or not */ var bool bIsPaused;   /** The current waveform sample being played */ var int CurrentSample;   /** The amount of time elapsed since the start of this waveform */ var float ElapsedTime;   /** The amount to scale all waveforms by (user settable) */ var float ScaleAllWaveformsBy;   /** * Sets the waveform to play for the gamepad * * @param Waveform The waveform data to play */ simulated final function PlayWaveform(ForceFeedbackWaveform Waveform) { // Zero out the current sample and duration and unpause if paused CurrentSample = 0; ElapsedTime = 0.0; bIsPaused = FALSE; // Make sure the waveform is valid if (Waveform != None && Waveform.Samples.Length > 0 && bAllowsForceFeedback ) { // Set the wave form to play FFWaveform = Waveform; } else { FFWaveform = None; } }   /** * Stops the waveform by nulling out the waveform */ simulated final function StopWaveform() { // Remove the current waveform FFWaveform = None; }   /** * Pauses/unpauses the playback of the waveform for the gamepad * * @param bPause TRUE to pause, FALSE to resume */ simulated final function PauseWaveform(optional bool bPause) { // Set the paused state for the gamepad bIsPaused = bPause; }   defaultproperties { bAllowsForceFeedback=TRUE ScaleAllWaveformsBy=1.0 }

Функции C++

/** * Run Post render for each sub camera effect and accumulate results. * By doing this we save the extra full screen pass from adding the emissive * result and we also get an extra 2 pass blur on the emissive for free. * * @param Viewport The viewport we are drawing into * @param RI The render interface used for drawing */ void UUCScreenEmissiveWithBloom::PostRender(UViewport* Viewport,FRenderInterface* RI) { guard(UUCScreenEmissiveWithBloom::PostRender);   checkSlow( EmissiveCamEffect && BloomCamEffect );   // make sure that the emissive post render does not draw its // results onto the back buffer EmissiveCamEffect->DisplayOutput = 0; EmissiveCamEffect->PostRender( Viewport, RI );   // set the result from the emissive camera effect for the // bloom camera effect to use BloomCamEffect->EmissiveResultTarget = EmissiveCamEffect->GetEmissiveResultTarget(); BloomCamEffect->PostRender( Viewport, RI );   unguard; }     /** * Increments the int variable attached in link 0, then * compares it to the int variable attached in link 1, * and fires impulses based on the comparison. */ void USeqCond_Increment::Activated() { check(VariableLinks.Num() >= 2 && "Decrement requires at least 2 variables");   // grab our two int variables INT Value1 = 0; INT Value2 = 0; TArray<INT*> IntValues1; GetIntVars( IntValues1, TEXT("Counter") ); TArray<INT*> IntValues2; GetIntVars( IntValues2, TEXT("Comparison") ); // increment all of the counter variables for (INT VarIdx = 0; VarIdx < IntValues1.Num(); VarIdx++) { *(IntValues1(VarIdx)) += IncrementAmount; Value1 += *(IntValues1(VarIdx)); } // get the actual values by adding up all linked variables for (INT VarIdx = 0; VarIdx < IntValues2.Num(); VarIdx++) { Value2 += *(IntValues2(VarIdx)); } // compare the values and set output impulse OutputLinks(Value1 <= Value2 ? 0 : 1).bHasImpulse = 1; }

Классы C++

/**

* Base class for all templated arrays. Handles allocation of dynamic arrays and

* uses an algorithm to decide how much "slack" memory to allocate to prevent

* lots of copying of data due to inefficient grow patterns.

*/

class FArray

{

public:

/**

* Allows access to the array block

*

* @return The pointer to the block of memory that makes up the array

*/

void* GetData()

{

return Data;

}

 

/**

* Validates that the specified index is within the array boundary

*

* @return TRUE if the index is valid, FALSE otherwise

*/

UBOOL IsValidIndex( INT i ) const

{

return i>=0 && i<ArrayNum;

}

 

// ...

 

protected:

/** The pointer to the block of memory representing the array */

void* Data;

/** Number of elements currently in the array */

INT ArrayNum;

/** The number of elements the array can hold without having to realloc */

INT ArrayMax;

};

Данный документ является переводом оригинального документа Coding Standards.

 


Просмотров 213

Эта страница нарушает авторские права




allrefrs.ru - 2021 год. Все права принадлежат их авторам!