Skip to content

Instantly share code, notes, and snippets.

@w0wca7a
Last active April 2, 2025 05:37
Show Gist options
  • Save w0wca7a/6cf54ad9a68671aad4b3f295de6b7496 to your computer and use it in GitHub Desktop.
Save w0wca7a/6cf54ad9a68671aad4b3f295de6b7496 to your computer and use it in GitHub Desktop.
Script provides Camera Shaking in Stride Game Engine
// Copyright (c) Stride contributors (https://stride3d.net).
// Distributed under the MIT license.
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Input;
using System;
using System.Threading;
using System.Threading.Tasks;
public class CameraShake : AsyncScript
{
// Default Shake Settings / Настройки тряски по умолчанию
// Shaking intensity / Интенсивность тряски
public float ShakeIntensity { get; set; } = 0.1f;
// Shaking duration (seconds) / Длительность тряски (секунды)
public float ShakeDuration { get; set; } = 0.5f;
// Shaking attenuation / Затухание тряски (0-1)
public float ShakeDamping { get; set; } = 0.9f;
// Shaking frequency / Частота тряски
public float ShakeFrequency { get; set; } = 25f;
private Vector3 originalPosition;
private Random random = new Random();
private bool isShaking = false;
private CancellationTokenSource shakeCancellation;
public override async Task Execute()
{
while (Game.IsRunning)
{
// For the test, we start shaking when we press the space bar / Для теста - запускаем тряску при нажатии пробела
if (Input.IsKeyPressed(Keys.Space))
{
await ShakeAsync();
}
await Script.NextFrame();
}
}
// Basic shaking method / Основной метод тряски
// For start shaking from another place we can use:
// var cameraShake = cameraEntity.Get<CameraShake>();
// await cameraShake.ShakeAsync();
public async Task ShakeAsync()
{
await ShakeAsync(ShakeIntensity, ShakeDuration, ShakeDamping);
}
// Shaking method with parameters / Метод тряски с параметрами
// We can use shaking from another place with parameters:
// await cameraShake.ShakeAsync(0.2f, 1f, 0.8f);
public async Task ShakeAsync(float intensity, float duration, float damping = 0.9f)
{
// Save camera position / Сохраняем текущую позицию перед началом тряски
originalPosition = Entity.Transform.Position;
// Stop previous shaking if it`s active/ Отменяем предыдущую тряску, если она активна
if (isShaking)
{
shakeCancellation?.Cancel();
shakeCancellation?.Dispose();
}
isShaking = true;
shakeCancellation = new CancellationTokenSource();
var token = shakeCancellation.Token;
try
{
float remainingDuration = duration;
float currentIntensity = intensity;
while (remainingDuration > 0 && !token.IsCancellationRequested)
{
// Вычисляем силу тряски с учетом затухания
float shakeAmount = currentIntensity * (remainingDuration / duration);
// Генерируем случайные смещения
Vector3 randomOffset = new Vector3(
(float)(random.NextDouble() * 2 - 1),
(float)(random.NextDouble() * 2 - 1),
(float)(random.NextDouble() * 2 - 1)) * shakeAmount;
// Применяем тряску с учетом частоты
float timeFactor = (float)Math.Sin(Game.UpdateTime.Total.TotalSeconds * ShakeFrequency);
Entity.Transform.Position = originalPosition + randomOffset * timeFactor;
// Тут можно запустить воспроизведение
// Подробнее: https://doc.stride3d.net/latest/en/manual/audio/non-spatialized-audio.html
// Обновляем параметры тряски
remainingDuration -= (float)Game.UpdateTime.Elapsed.TotalSeconds;
currentIntensity *= damping;
await Script.NextFrame();
}
// Restore camera to original position / Возвращаем камеру в исходное положение
Entity.Transform.Position = originalPosition;
}
catch (TaskCanceledException)
{
Entity.Transform.Position = originalPosition;
}
finally
{
isShaking = false;
shakeCancellation?.Dispose();
shakeCancellation = null;
}
}
// immediately shaking stop / Метод для немедленной остановки тряски
public void StopShake()
{
if (isShaking)
{
shakeCancellation?.Cancel();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment