Leave a comment

Smooth camera movement (for replay)

I see too many people produce youtube videos with “shakey cameras” for their game’s gameplay, rendering techniques, or whatever. Short jerkey movements that make it difficult to tell what’s going on.

Here’s a small XNA class that can record snapshots of the camera’s position and orientation and then smoothly play them back (with Catmull Rom interpolation). It is just a quick and dirty bit of code I use to ensure smoothly animating camera movement when I’m making a demo video.

 

    interface ICamera
    {
        Vector3 Position { get; set; }
        Vector3 LookAt { get; set; }
    }
    class Replay
    {
        struct CameraSnapshot
        {
            public Vector3 Position;
            public Vector3 LookAt;
            public float Time;
        }
        public Replay(ICamera camera)
        {
            this.camera = camera;
        }
        public void Reset()
        {
            lastSnapshot = null;
            snapshots.Clear();
        }
        private TimeSpan? lastSnapshot;
        public void TakeSnapshot(GameTime gameTime)
        {
            if (inReplay)
            {
                inReplay = false;
            }
            if (wasInReplay)
            {
                wasInReplay = false;
                Reset();
            }
            CameraSnapshot cs = new CameraSnapshot();
            cs.Position = camera.Position;
            cs.LookAt = camera.LookAt;
            if (lastSnapshot.HasValue)
            {
                TimeSpan delta = gameTime.TotalGameTime.Subtract(lastSnapshot.Value);
                cs.Time = (float)delta.TotalSeconds;
            }
            else
            {
                // First time
                cs.Time = 0f;
            }
            snapshots.Add(cs);
            lastSnapshot = gameTime.TotalGameTime;
        }
        private bool inReplay = false;
        private bool wasInReplay = false;
        private float timeEllapsed = 0f;
        private float nextTime;
        private int currentSnapshotIndex;   // and then there is a next too.
        public void StartReplay()
        {
            if (snapshots.Count > 1)
            {
                wasInReplay = true;
                inReplay = true;
                currentSnapshotIndex = 0;
                timeEllapsed = 0f;
                nextTime = snapshots[1].Time;
            }
        }
        public void Update(GameTime gameTime)
        {
            if (inReplay)
            {
                if ((timeEllapsed / nextTime) >= 1f)
                {
                    currentSnapshotIndex++;
                    timeEllapsed -= nextTime;
                }
                if (currentSnapshotIndex < (snapshots.Count - 1))
                {
                    CameraSnapshot p1 = (currentSnapshotIndex > 0) ? snapshots[currentSnapshotIndex - 1] : snapshots[currentSnapshotIndex];
                    CameraSnapshot p2 = snapshots[currentSnapshotIndex];
                    CameraSnapshot p3 = snapshots[currentSnapshotIndex + 1];
                    nextTime = p3.Time;
                    CameraSnapshot p4 = ((currentSnapshotIndex + 2) < snapshots.Count) ? snapshots[currentSnapshotIndex + 2] : p3;
                    float progression = timeEllapsed / nextTime;
                    Vector3 lookAt = Vector3.CatmullRom(p1.LookAt, p2.LookAt, p3.LookAt, p4.LookAt, progression);
                    Vector3 position = Vector3.CatmullRom(p1.Position, p2.Position, p3.Position, p4.Position, progression);
                    camera.LookAt = lookAt;
                    camera.Position = position;
                }
                else
                {
                    inReplay = false;
                }
            }
            timeEllapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;
        }
        public bool InReplay { get { return inReplay; } }
        private ICamera camera;
        private List<CameraSnapshot> snapshots = new List<CameraSnapshot>();
    }
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Space Quest Historian

Adventure game blogs, Let's Plays, live streams, and more

Harebrained Schemes

Developer's blog for IceFall Games

kosmonaut's blog

3d GFX and more

Halogenica

Turn up the rez!

bitsquid: development blog

Developer's blog for IceFall Games

Game Development by Sean

Developer's blog for IceFall Games

Lost Garden

Developer's blog for IceFall Games

Memories

Developer's blog for IceFall Games

Casey's Blog

Developer's blog for IceFall Games

Blog

Developer's blog for IceFall Games

Rendering Evolution

Developer's blog for IceFall Games

Simon schreibt.

Developer's blog for IceFall Games

Dev & Techno-phage

Do Computers Dream of Electric Developper?

- Woolfe -

Developer's blog for IceFall Games

Ferrara Fabio

Game & Application Developer, 3D Animator, Composer.

Clone of Duty: Stonehenge

First Person Shooter coming soon to the XBOX 360

Low Tide Productions

Games and other artsy stuff...

BadCorporateLogo

Just another WordPress.com site

Sipty's Writing

Take a look inside the mind of a game developer.

Jonas Kyratzes

Writer, game designer, filmmaker.

%d bloggers like this: