You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.6 KiB
C#
154 lines
4.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using Duality;
|
|
using Duality.Editor;
|
|
using Duality.Components;
|
|
using Duality.Resources;
|
|
|
|
namespace DualStickSpaceShooter
|
|
{
|
|
[RequiredComponent(typeof(Camera))]
|
|
public class CameraController : Component, ICmpUpdatable, ICmpInitializable
|
|
{
|
|
private const float ReferenceFocusDist = 500.0f;
|
|
private const float ReferenceScreenDiameter = 1500.0f;
|
|
|
|
private Transform microphone = null;
|
|
private List<Transform> followObjects = null;
|
|
private float zoomFactor = 1.0f;
|
|
private float softness = 1.0f;
|
|
private float zoomOutScale = 1.0f;
|
|
private float maxZoomOutDist = 350.0f;
|
|
private float screenShakeStrength = 0.0f;
|
|
private Vector2 screenShakeOffset = Vector2.Zero;
|
|
|
|
public List<Transform> FollowObjects
|
|
{
|
|
get { return this.followObjects; }
|
|
set { this.followObjects = value; }
|
|
}
|
|
[EditorHintRange(0.0f, 2.0f)]
|
|
public float Softness
|
|
{
|
|
get { return this.softness; }
|
|
set { this.softness = value; }
|
|
}
|
|
public float MaxZoomOutDist
|
|
{
|
|
get { return this.maxZoomOutDist; }
|
|
set { this.maxZoomOutDist = value; }
|
|
}
|
|
[EditorHintRange(0.1f, 2.0f)]
|
|
public float ZoomFactor
|
|
{
|
|
get { return this.zoomFactor; }
|
|
set { this.zoomFactor = value; }
|
|
}
|
|
public float ZoomOutScale
|
|
{
|
|
get { return this.zoomOutScale; }
|
|
set { this.zoomOutScale = value; }
|
|
}
|
|
public Transform Microphone
|
|
{
|
|
get { return this.microphone; }
|
|
set { this.microphone = value; }
|
|
}
|
|
|
|
public void ShakeScreen(float strength)
|
|
{
|
|
this.screenShakeStrength += strength;
|
|
}
|
|
|
|
private void AdjustToScreenSize()
|
|
{
|
|
Vector2 screenSize = DualityApp.TargetResolution;
|
|
Camera camera = this.GameObj.GetComponent<Camera>();
|
|
camera.FocusDist = ReferenceFocusDist * screenSize.Length * this.zoomFactor / ReferenceScreenDiameter;
|
|
}
|
|
private Vector3 GetTargetOffset(float maxDistFromCenter)
|
|
{
|
|
float zoomThreshold = 200.0f;
|
|
float zoomOutDistance = this.zoomOutScale * MathF.Max(0, maxDistFromCenter - zoomThreshold);
|
|
zoomOutDistance = MathF.Min(this.maxZoomOutDist, zoomOutDistance);
|
|
return -new Vector3(0.0f, 0.0f, ReferenceFocusDist + zoomOutDistance);
|
|
}
|
|
|
|
void ICmpUpdatable.OnUpdate()
|
|
{
|
|
if (this.followObjects == null) return;
|
|
if (this.followObjects.Count == 0) return;
|
|
|
|
Camera camera = this.GameObj.GetComponent<Camera>();
|
|
Transform transform = this.GameObj.Transform;
|
|
|
|
// Update screen shake behavior
|
|
Vector2 lastScreenShakeOffset = this.screenShakeOffset;
|
|
this.screenShakeStrength *= MathF.Pow(0.9f, Time.TimeMult);
|
|
if (this.screenShakeStrength <= 0.1f) this.screenShakeStrength = 0.0f;
|
|
if (this.screenShakeOffset != Vector2.Zero)
|
|
{
|
|
float oldAngle = this.screenShakeOffset.Angle;
|
|
this.screenShakeOffset = Vector2.FromAngleLength(
|
|
oldAngle + MathF.Rnd.NextFloat(MathF.DegToRad(120.0f), MathF.DegToRad(240.0f)),
|
|
this.screenShakeStrength);
|
|
}
|
|
else
|
|
{
|
|
this.screenShakeOffset = MathF.Rnd.NextVector2(this.screenShakeStrength);
|
|
}
|
|
|
|
// Remove old screen shake offset
|
|
transform.Pos -= new Vector3(lastScreenShakeOffset);
|
|
|
|
// Let the camera follow its objects.
|
|
Transform[] activeFollowObjects = this.followObjects.Where(obj => obj.Active).ToArray();
|
|
if (activeFollowObjects.Length > 0)
|
|
{
|
|
// Determine the position to focus on. It's the average of all follow object positions.
|
|
Vector3 focusPos = Vector3.Zero;
|
|
foreach (Transform obj in activeFollowObjects)
|
|
{
|
|
focusPos += obj.Pos;
|
|
}
|
|
focusPos /= activeFollowObjects.Length;
|
|
|
|
// Determine how far these objects are away from each other
|
|
float maxDistFromCenter = 0.0f;
|
|
foreach (Transform obj in activeFollowObjects)
|
|
{
|
|
maxDistFromCenter = MathF.Max((obj.Pos - focusPos).Length, maxDistFromCenter);
|
|
}
|
|
|
|
// Move the camera so it can most likely see all of the required objects
|
|
Vector3 targetPos = focusPos + this.GetTargetOffset(maxDistFromCenter);
|
|
transform.MoveByAbs((targetPos - transform.Pos) * MathF.Pow(10.0f, -this.softness) * Time.TimeMult);
|
|
}
|
|
|
|
// Apply new screen shake offset
|
|
transform.Pos += new Vector3(this.screenShakeOffset);
|
|
|
|
// Make sure the microphone is always at the Z-0 plane
|
|
if (this.microphone != null)
|
|
{
|
|
this.microphone.Pos = new Vector3(this.microphone.Pos.Xy, 0.0f);
|
|
}
|
|
}
|
|
void ICmpInitializable.OnInit(Component.InitContext context)
|
|
{
|
|
if (context == InitContext.Activate)
|
|
{
|
|
this.AdjustToScreenSize();
|
|
|
|
// Move near initial spawn point
|
|
Transform transform = this.GameObj.Transform;
|
|
transform.MoveToAbs(SpawnPoint.SpawnPos + this.GetTargetOffset(0.0f));
|
|
}
|
|
}
|
|
void ICmpInitializable.OnShutdown(Component.ShutdownContext context) {}
|
|
}
|
|
}
|