8 (800) 551-30-75
info@appfox.ru
Since 2008
8 (800) 551-30-75
Почта:
 info@appfox.ru
8 (800) 551-30-75 info@appfox.ru

Оптимизация является очень важным этапом при разработке игры. Каждая игра нуждается в оптимизации. Игра RiverRaft - это сложный симулятор сплава по рекам и целевая платформа это Android, где не у всех есть достаточно мощные устройства. В игре присутствует динамическая вода. Объект который моделирует поведение воды в игре, повторяя его физику. Так же скрипт, который моделирует изменение меша плоскости, эмулируя волны. Скрипт, который отвечает за физику плавающего объекта по волнам.

И так, приступим. Первый же метод – это избавление от лишних вычислений в методе Update. Так как Update выполняет просчет каждый кадр и это слишком часто для сложных вычислений, что само по себе влечет уменьшение качества кадров в секунду.

Рассмотрим это все на примере скрипта Floating Object. Здесь большую часть значений мы вычисляем в методе Start. И сохраняем их в памяти. Тем самым мы избавляемся от нежелательного «деления каждый кадр».

void Start()
{
objectVolume = this.rigidbody.mass / this.density;
voxelsCountForEachAxis = Mathf.RoundToInt(1f / this.normalizedVoxelSize);

_bounds = this.collider.bounds;
voxelHeight = _bounds.size.y * this.normalizedVoxelSize;
voxelHeightHalf = voxelHeight * 0.5f;
voxelOneHeightDel = (float)1 / (float)voxelHeight;
}
protected virtual void FixedUpdate()
{
if (this.water != null && this.voxels.Length > 0)
{
CalculateMaxBuoyancyForce();

float submergedVolume = 0f;
for (int i = 0; i < this.voxels.Length; i++)
{
Vector3 worldPoint = this.transform.TransformPoint(this.voxels[i]);

float waterLevelSum = 0;
waterCollides.ForEach(x => { waterLevelSum += x.GetWaterLevel(worldPoint); });
float waterLevel = waterLevelSum / waterCollides.Count;
//float waterLevel = this.water.GetWaterLevel(worldPoint);
float deepLevel = waterLevel - worldPoint.y + voxelHeightHalf; // How deep is the voxel
float submergedFactor = Mathf.Clamp(deepLevel * voxelOneHeightDel, 0f, 1f); // 0 - voxel is fully out of the water, 1 - voxel is fully submerged
submergedVolume += submergedFactor;

Vector3 surfaceNormal = Vector3.zero;
waterCollides.ForEach(x => { surfaceNormal += x.GetSurfaceNormal(worldPoint); });
surfaceNormal = surfaceNormal / waterCollides.Count;

Vector3 newRotation = Vector3.zero;
//waterCollides.ForEach(x => { newRotation += x.transform.up; });
//newRotation = newRotation / waterCollides.Count;
Quaternion surfaceRotation = Quaternion.FromToRotation(newRotation, surfaceNormal);
surfaceRotation = Quaternion.Slerp(surfaceRotation, Quaternion.identity, submergedFactor);

Vector3 finalVoxelForce = surfaceRotation * (forceAtSingleVoxel * submergedFactor);
this.rigidbody.AddForceAtPosition(finalVoxelForce, worldPoint);

Debug.DrawLine(worldPoint, worldPoint + finalVoxelForce.normalized, Color.blue);
}

submergedVolume = submergedVolume * voxelLength;// 0 - object is fully out of the water, 1 - object is fully submerged

this.rigidbody.drag = Mathf.Lerp(this.initialDrag, this.dragInWater, submergedVolume);
this.rigidbody.angularDrag = Mathf.Lerp(this.initialAngularDrag, this.angularDragInWater, submergedVolume);
}
}

Естественно мы избавились от лишних вычислений, которые нам не нужны, а именно от waterCollides, newRotation, waterLevel

Входные и выходные параметры для этих выражений имеют значение = 0. Но все же вычисления происходят и этот ноль нужно как-то получить. Поэтому логично было бы избавиться от этих вычислений.

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

private void CalculateMaxBuoyancyForce()
{
Vector3 maxBuoyancyForce = this.water.Density * objectVolume * -Physics.gravity;
forceAtSingleVoxel = maxBuoyancyForce * voxelLength;
}

Так мы сумеем повысить фпс на 10 пунктов.

Скрипт WaterVolume. Так же избавляемся от лишний вычислений. Тем самым повышаем фпс еще на 5 пунктов.

public float GetWaterLevel(Vector3 worldPoint)
{
Vector3[] meshPolygon = this.GetSurroundingTrianglePolygon(worldPoint);
if (meshPolygon != null)
{
Vector3 planeV1 = meshPolygon[1] - meshPolygon[0];
Vector3 planeV2 = meshPolygon[2] - meshPolygon[0];
Vector3 planeNormal = Vector3.Cross(planeV1, planeV2).normalized;
if (planeNormal.y < 0f)
{
planeNormal *= -1f;
}

// Plane equation
float yOnWaterSurface = (-(worldPoint.x * planeNormal.x) - (worldPoint.z * planeNormal.z) + Vector3.Dot(meshPolygon[0], planeNormal)) / planeNormal.y;
//Vector3 pointOnWaterSurface = new Vector3(point.x, yOnWaterSurface, point.z);
//DebugUtils.DrawPoint(pointOnWaterSurface, Color.magenta);

return yOnWaterSurface;
}

return this.transform.position.y;
}

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

protected virtual void Update()
{
for (var i = 0; i < this.vertices.Length; i++)
{
var vertex = this.baseVertices[i];
if (speed != 0 && height != 0)
{
vertex.y += Mathf.Sin(Time.time * this.speed + this.baseVertices[i].x + this.baseVertices[i].y + this.baseVertices[i].z) * chacheValue;
}
//print(height / this.transform.localScale.y);

//vertex.y += Mathf.PerlinNoise(baseVertices[i].x + this.noiseWalk, baseVertices[i].y) * this.noiseStrength;
this.vertices[i] = vertex;
}
this.mesh.vertices = this.vertices;
this.mesh.RecalculateNormals();
}

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

Возврат к списку статей

ПОДПИШИТЕСЬ НА ОБНОВЛЕНИЯ

Осмысленное изучение обучающих материалов позволит профессионально повысить квалификацию. Подпишитесь на бесплатные советы и статьи по ключевым этапам разработки.

Ваше имя: * E-mail: * Ваш комментарий или вопрос: * - обязательные поля для заполнения ПОДПИСАТЬСЯ




Наши клиенты
Tele 2

Tele 2

Оператор сотовой связи

Первая транспортная компания

Первая транспортная компания

Транспортная компания

Утконос

Утконос

Интернет-гипермаркет

Кофе хауз

Кофе хауз

Крупная кофейная сеть

Донстрой

Донстрой

Строительная компания

Цирк чудес

Цирк чудес

Московский цирк

Правительство Москвы

Правительство Москвы

Орган власти

Роскосмос

Роскосмос

Российская космическая корпорация

Министерство здравоохранения

Министерство здравоохранения

Орган власти

Foodband

Foodband

Служба доставки еды

Сбербанк

Сбербанк

Крупный Российский банк

Шоколадница

Шоколадница

Крупнейшая кофейная сеть

Взнания

Взнания

Образовательная платформа

Уральские пельмени

Уральские пельмени

Фабрика пельменей

photo of
Appfox
улица Профсоюзная, дом 27, корпус 1
Москва , Москва , 117418 Россия
8 (800) 551-30-75

This hCard created with the hCard creator.

Онлайн заявка
Оставьте ваши контактные данные и наш консультант свяжется с вами
Ценовой диапазон
5 000 р
5 000 000 р
Нажимая на кнопку «Отправить», Вы даете согласие на обработку своих персональных данных