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: * Ваш комментарий или вопрос: * - обязательные поля для заполнения ПОДПИСАТЬСЯ

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

This hCard created with the hCard creator.

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