• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 18:47
CEST 00:47
KST 07:47
  • Home
  • Forum
  • Calendar
  • Streams
  • Liquipedia
  • Features
  • Store
  • EPT
  • TL+
  • StarCraft 2
  • Brood War
  • Smash
  • Heroes
  • Counter-Strike
  • Overwatch
  • Liquibet
  • Fantasy StarCraft
  • TLPD
  • StarCraft 2
  • Brood War
  • Blogs
Forum Sidebar
Events/Features
News
Featured News
BGE Stara Zagora 2025: Info & Preview19Code S RO12 Preview: GuMiho, Bunny, SHIN, ByuN3The Memories We Share - Facing the Final(?) GSL46Code S RO12 Preview: Cure, Zoun, Solar, Creator4[ASL19] Finals Preview: Daunting Task30
Community News
[BSL20] ProLeague: Bracket Stage & Dates6GSL Ro4 and Finals moved to Sunday June 15th12Weekly Cups (May 27-June 1): ByuN goes back-to-back0EWC 2025 Regional Qualifier Results26Code S RO12 Results + RO8 Groups (2025 Season 2)3
StarCraft 2
General
BGE Stara Zagora 2025: Info & Preview Jim claims he and Firefly were involved in match-fixing GSL Ro4 and Finals moved to Sunday June 15th Magnus Carlsen and Fabi review Clem's chess game. Serious Question: Mech
Tourneys
Bellum Gens Elite: Stara Zagora 2025 SOOPer7s Showmatches 2025 Cheeseadelphia 2025 - Open Bracket LAN! $25,000+ WardiTV 2025 Series Sparkling Tuna Cup - Weekly Open Tournament
Strategy
[G] Darkgrid Layout Simple Questions Simple Answers [G] PvT Cheese: 13 Gate Proxy Robo
Custom Maps
[UMS] Zillion Zerglings
External Content
Mutation # 476 Charnel House Mutation # 475 Hard Target Mutation # 474 Futile Resistance Mutation # 473 Cold is the Void
Brood War
General
[BSL20] ProLeague: Bracket Stage & Dates BW General Discussion Will foreigners ever be able to challenge Koreans? BGH auto balance -> http://bghmmr.eu/ I made an ASL quiz
Tourneys
[BSL 2v2] ProLeague Season 3 - Friday 21:00 CET [ASL19] Grand Finals [Megathread] Daily Proleagues Small VOD Thread 2.0
Strategy
I am doing this better than progamers do. [G] How to get started on ladder as a new Z player
Other Games
General Games
Nintendo Switch Thread Mechabellum Stormgate/Frost Giant Megathread Monster Hunter Wilds Path of Exile
Dota 2
Official 'what is Dota anymore' discussion
League of Legends
LiquidLegends to reintegrate into TL.net
Heroes of the Storm
Heroes of the Storm 2.0 Simple Questions, Simple Answers
Hearthstone
Heroes of StarCraft mini-set
TL Mafia
Vanilla Mini Mafia TL Mafia Community Thread
Community
General
US Politics Mega-thread Russo-Ukrainian War Thread Things Aren’t Peaceful in Palestine Vape Nation Thread European Politico-economics QA Mega-thread
Fan Clubs
Maru Fan Club Serral Fan Club
Media & Entertainment
Korean Music Discussion [Manga] One Piece
Sports
2024 - 2025 Football Thread Formula 1 Discussion NHL Playoffs 2024
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread Cleaning My Mechanical Keyboard
TL Community
The Automated Ban List
Blogs
Heero Yuy & the Tax…
KrillinFromwales
Research study on team perfo…
TrAiDoS
I was completely wrong ab…
jameswatts
Need Your Help/Advice
Glider
Trip to the Zoo
micronesia
Poker
Nebuchad
Info SLEgma_12
SLEgma_12
Customize Sidebar...

Website Feedback

Closed Threads



Active: 18960 users

Game Programming: The Camera

Blogs > Logo
Post a Reply
Logo
Profile Blog Joined April 2010
United States7542 Posts
February 02 2013 02:09 GMT
#1
Read part 1 here. Apologies for the delay in this second blog; I was on a short notice vacation for the past few weeks.

The Camera!

Now that I have a basic framework for a game setup (see part 1), it's time to work on moving things around. More specifically, the camera. I've hooked my player character up to some rudimentary controls for the time being, but without some work he'll just slide off the screen- there's no walk animation yet. That won't do at all.

Camera work in a 2d platformer is easy to make functional, but getting it right takes some work. Making the camera keep a player in the center of the screen is not hard at all. The problem is that's not what want to do. There's a big difference between a tight camera control and a camera that just follows the player along. At the very least I'm going to want to support horizontal only, vertical only, and free follow camera modes. In reality there's more to it than that. The camera is really another character in your game, or at least an extension of the main character. The way it controls has an impact on both the gameplay and the mood of the game.

The iPhone version of Canabalt is a great example of the camera imparting mood. In the iPhone version the camera is zoomed out further than the flash version. All of the buildings fall within maybe 25% of the screen's height (other than the start). If Canabalt never varied the camera's y coordinate it would still be completely playable. Yet the camera does move on the y-axis, and this adds a nice touch to the game. In a game all about making these long perfectly arced jumps, the jumps are given extra weight and feeling by allowing the camera to move up along with them. This is especially noticeable if you allow the character's speed to max out. Without this camera movement a lot of the jumping would feel flatter and stiffer. The camera control, not just the framing, has added to the game's mood and heightens the intensity of the character's run.

A Lesson Well Learned

Ok enough blabbering, time to get down to some gritty details. My plan is to setup a rudimentary camera to get things working, then expand on it with more sophisticated behavior. So I start by taking a look at what my engine gives me for camera controls. I find exactly what I was expecting: all entities are drawn relative to a camera view that can be set. There's no built in movement or controls, but at least I'm not managing how to translate from a game world position to where the thing should be drawn on the screen.

As my first stab, I create a camera class with an update function that takes the player entity as an input and centers the camera on the player. The camera is setup to stay focused on the level as well, when you go all the way to the left the camera will stop panning at the end of the level. Last thing we want is 1/2 of the screen to be black and the other 1/2 to be the leftmost edge of the level.

I add the camera to the player entity and have it call the update function every frame to move the camera. I don't like having this somewhat circular reference where the camera knows about the player and the player knows about the camera, but it's easy and efficient so I test it and move on.

That was easy... except it wasn't; something's wrong. As my character slides across the screen and the camera follows there's a noticeable problem. He's jiggling as if he is trying to stave off hypothermia. Rather than clearly seeing my horribly drawn sprite, I see my horribly draw sprite in some weird jiggly blur.

My first instinct is to check for math rounding errors, playing the character in the center of the screen means I need to do some math to go from the player's position to the camera. It's not uncommon for numbers to end up with odd remainders when programming. I thought perhaps the camera controls are reacting poorly to a misplaced .0000000000...1, but no such luck. My first instinct blew it this time.

With that out of the way I know the general issue, just not what's causing it. My sprites are being drawn without aliasing. This is great for performance and my art style (crap is an art style right?). The downside is that if my character is at {1.323, 100} he'll be drawn either at {1,100} or {2,200}. There's no in between for the character's sprite. For some reason he's occasionally moving, or not-moving, a pixel relative to the camera and it makes him look wobbly.

After digging some more into the issue; success! I take a close look at the following two lines on my player entity:

this.camera.update(this);
this.parent();

The first line is updating my camera. The second is running the engine's logic for controlling moving entities, it's responsible for taking the entity's velocity and translating that into a new position. Here's the lesson learned, the order you do stuff during a frame matters a lot.
[image loading]
Not alot, a lot.


This is something I already knew. It's something that's also somewhat obvious, but it's very important. The involuntary refresher lesson is taken to heart for the future.

My issue is the camera is it is moving before the player does. It's lagging a frame behind the player at all times. With the way I have it, the following happens:
  • The camera centers relative to the player's position a.
  • The player moves to position b.
  • The game draws with the camera relative to a and the player relative to b.
  • The game centers relative to player's position b.
  • The player moves to position c. When rounded to the nearest pixel it's the same pixel. In this case if the camera was stationary the player wouldn't have appeared to move at all.
  • The game draws with the camera relative to b and the player relative to the same point (b & c).
  • Since the camera moved from a -> b, but the player stayed in the 'same spot' when rounded to the nearest pixel the player moves backwards. This is the jitter.

Whew, now with that cleared up I make the change:
this.parent();
this.camera.update(this);

The previous steps change to:
  • The player moves to position b.
  • The camera centers relative to the player's position b.
  • The game draws with camera relative to b and player at b.
  • The player moves to position c (which rounds to b).
  • The camera moves relative to position c (which rounds to the same as b).
  • The game draws with the camera relative to b/c and the player at b/c. Instead of sliding back the player stays in the same spot on the screen and there's no jitter.

Now I have my basic camera setup working, time to get a bit fancy.

Boxing the player in

The first change to the camera I make is an important one. When a camera keeps the player centered at all times there's an issue with how much the camera moves: it moves too much. Anytime the player moves the character back the camera will follow immediately. This is distracting and disorienting. If a player is moving in a small area we'd like to keep the camera still to make things easier to process.

Instead of following the player, my camera is going to follow an invisible box around the player. An invisible box that the player will push. In my camera update rather than moving the camera directly I check to see if the player is outside of the box, if he is I move the box to correspond. Then I move the camera to reflect the box's position. I setup the box to be a little taller than the player's jump height and twice the character's width.

[image loading]
My player in his box. The box is being drawn for debugging and picture purposes.


The box serves several purposes. On the x-axis it means the camera will favor staying still until the player moves significantly from where they once were. If a player is making small adjustments back and forth on a platform the camera will remain stationary. Also, if a player decides to go the opposite direction the camera will have a lag to it that just feels nice. On the y-axis the advantage comes when the player jumps. Rather than making a small arc of the camera movements to match the player, the camera will stay level. Only when the player falls or starts ascending up platforms will the camera move. In Canabalt the y movement works to add weight to the movement, but here with a free moving player character it just adds wobble and noise. Generally the more stationary I can keep the camera while still following the player the better.

There's one last thing to stick between my player and the camera. Rather than updating the camera's position based on the box position, I update another coordinate that then gets used to determine the camera's position. This is going to allow me to support easing the camera in the future. It's also going to allow me an easy way to lock the camera to an axis, something I'll make use of right away.

The Camera Modes

I'd like to make complex level shapes; levels that look like Ls, Ts or other weird shapes. That means I'll need several modes for my camera that aren't based on the level's width/height. I'll also need the ability to switch between those modes. There are two types of unlocked modes I'd like to support: free follow and platform locked. In the latter case the idea is that the camera will only move on the y-axis when the player lands on a platform. This is nice for level sections that feature a series of ascending platforms. By using a platform locked camera the player can jump on the platforms while keeping the camera level. In a free form mode an ascending player will continuously be at the top of their camera box and each jump will move the camera. Plus this creates a nice delay effect in the camera motion, the camera moves a shorter distance when the player lands rather than tracking them through the air. Super Mario Brothers World used this type of camera technique (see video at end of blog).

So now I have my list of camera types:
  • x-axis locked
  • y-axis locked
  • platform locked
  • free follow


Each one is easily coded up and ready to go. There are some easing and panning issues to be dealt with later, but they're minor enough to push off for now. Each mode takes the box's current position and uses it to update the intermediate position I referred to earlier. When a transition happens the intermediate position may jump somewhat dramatically so it'll be up to clever transitioning and good camera easing to smooth it all out.

To handle transitioning between camera modes I make some new entities for my game world. I add invisible triggers can be placed as a game object in a level. When the player collides with them their velocity is used to determine which way the player is going. Each side of the trigger, the trigger can be horizontal or vertical, has an associated camera type that will be switched to based on the direction of the player. It's straightforward and simple; exactly what I need. I'll be transitioning the camera during levels, but I don't think I'll need anything too fancy in how I do it.

Conclusion

So that's it for now. My camera is functional enough to feel smooth and reasonable, and all the remaining work is lower priority. I now have a camera system that feels smooth and stable rather than the jittery and hyperactive camera I started with.

Next time I'll be getting into the of spawning enemies and may cover my creation of a real level layout that I'll use to fine tune my player's movement. I've also been trying to read up and practice my art skills as best I can with the eventual goal of making some art that doesn't look terrible.

For your further viewing pleasure here's someone analyzing the SMBW camera:
+ Show Spoiler +
This video is pretty awesome


Thanks again for reading!

*****
Logo
Fyodor
Profile Blog Joined September 2010
Canada971 Posts
February 02 2013 03:34 GMT
#2
I read this. It's a different approach than what I have chosen for my game.

I don't think it's a problem if half your screen is a solid wall or whatever else. If your character sprite is small in relation to the player's view there's always enough space to play with. It also cues the player that there's nothing in that direction for a while. It also solves the "can I jump down that hole?" problem.

I have the camera dead center on the player. (ground will be less than center, due to the player's legs) With a smoothing factor to make it... well... smooth. That way it doesn't look like you're actually moving the level instead of the character lol. So little movements don't make the camera move very fast while if you go away from rest position for a while the camera will accelerate to compensate. Looks very professional with little coding effort.

only bounds I have are the limits of the level themselves. I just place invisible objects in opposite corners of the map to have the locking coordinates. That way I just plug a generic camera every time and don't need to code anything. Since the bounds are the only edges of the map where the camera locks, it cues the player that absolutely nothing exists in that direction.
llllllllllllllllllllllllllllllllllllllllllll
Logo
Profile Blog Joined April 2010
United States7542 Posts
Last Edited: 2013-02-04 16:02:54
February 04 2013 15:59 GMT
#3
The main difference is in how you want to layout levels. If your levels are going to be straight horizontal, straight vertical, or complex generally box-ish shapes larger than 1 screen in each direction what you've done is perfectly fine.

When designing levels that take on something like an S or L shape it's an issue. With a long vertical section that's 1 screen wide you want the camera to stay centered on that section, think something like Metroid's vertical sections. Meanwhile on the horizontal parts you want the screen to stay centered on the 1 screen tall stage, rather than keeping the player centered. In both cases the edge of the level itself doesn't really come into play because we're carving out a S shape out of a big square of tiles. Likewise supporting different modes should let me do things like keep the player on the bottom 1/3rd, or more likely something like 3/8ths of the screen to heighten the mood of climbing and frame the on coming action better.

A lot of it also comes down to mood. Free-er cameras would probably give a better sense of exploration, but they provide worse framing and stability for a challenge based platformer. In my case if I want an area to invoke a sense of exploration I can switch the camera mode to the 'free mode' which behaves much like your camera- though it limits to the bounds of the region I set for it rather than the level itself.
Logo
Chezus
Profile Joined January 2011
Netherlands427 Posts
February 10 2013 22:00 GMT
#4
Fun read again thank you. I've never actually considered having different camera modes. Then again, I've only ever worked on one platformer camera system so far... and that wasn't even a proper platformer. I'm currently working one now though, am about to do the camera system :p
As for the panning issues, I'm thinking of turning the camera in to some sort of physics object, which can only collide with outer-level walls. I'm using Box2D for collision handling, I am not quite sure how efficient that solution will be, however...
I can't really think of any other elegant ways to solve that problem, though.

One thing I should probably touch on, is that my game will be a multiplayer game. So I might need to support zooming in and out aswell (similar to camera systems in Little Big Planet and Super Smash Bros).

By the way, the mario camera analysis video you linked sure does show a couple of flaws in their system. :p Often times they are looking at all the wrong things. But I'm sure you'll do a lot better job than them, haha .

Good luck on your project, I look forward to reading more about it . Perhaps I should blog about some of my work sometime... It might actually motivate me to keep working on my projects. Does it work like that for you, at all?
Logo
Profile Blog Joined April 2010
United States7542 Posts
Last Edited: 2013-02-11 19:27:02
February 11 2013 19:26 GMT
#5
The effects on my motivation are a bit mixed. Generally, I'm already pretty motivated to code in my spare time and the blog doesn't change that. If anything it detracts from that motivation a bit, both because it takes up some time and because I feel accomplished when I share things I've been working on. Either way by biggest limit on progress is free time and whether or not I blog, that really doesn't change much.

That's all fine though, because what the blog does help me do is stay focused on a single project. I enjoy writing these posts and sharing progress with people and if I work on something else I can't do either one. That helps me stay focused on the current project and encourages me to really improve on things I might otherwise put off.
Logo
Please log in or register to reply.
Live Events Refresh
Next event in 1h 13m
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
UpATreeSC 171
NeuroSwarm 136
JuggernautJason75
ForJumy 49
StarCraft: Brood War
Britney 16177
Artosis 552
Mini 194
Backho 19
NaDa 10
910 6
Dota 2
Pyrionflax189
PGG 159
League of Legends
JimRising 294
Counter-Strike
fl0m6203
Fnx 1635
Foxcn316
flusha260
Super Smash Bros
C9.Mang0840
Heroes of the Storm
Grubby4317
Liquid`Hasu380
Other Games
summit1g10437
FrodaN1349
shahzam855
hungrybox510
ViBE210
KnowMe38
RuFF_SC229
Organizations
Dota 2
PGL Dota 2 - Secondary Stream954
Other Games
BasetradeTV35
StarCraft 2
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
sctven
[ Show 18 non-featured ]
StarCraft 2
• Berry_CruncH133
• RyuSc2 36
• davetesta19
• Kozan
• Migwel
• sooper7s
• AfreecaTV YouTube
• intothetv
• IndyKCrew
• LaughNgamezSOOP
StarCraft: Brood War
• RayReign 18
• STPLYoutube
• ZZZeroYoutube
• BSLYoutube
Dota 2
• masondota22412
League of Legends
• Doublelift5881
Other Games
• imaqtpie1417
• Scarra1053
Upcoming Events
Replay Cast
1h 13m
OSC
1h 13m
Bellum Gens Elite
11h 13m
WardiTV Invitational
15h 13m
BSL 2v2 ProLeague
20h 13m
Replay Cast
1d 1h
CranKy Ducklings
1d 11h
SC Evo League
1d 13h
Bellum Gens Elite
1d 13h
Fire Grow Cup
1d 16h
[ Show More ]
CSO Contender
1d 18h
BSL: ProLeague
1d 19h
StRyKeR vs MadiNho
Cross vs UltrA
TT1 vs JDConan
Bonyth vs Sziky
Replay Cast
2 days
SOOP Global
2 days
Creator vs Rogue
Cure vs Classic
SOOP
2 days
Classic vs GuMiho
Sparkling Tuna Cup
2 days
AllThingsProtoss
2 days
Fire Grow Cup
2 days
BSL: ProLeague
2 days
HBO vs Doodle
spx vs Tech
DragOn vs Hawk
Dewalt vs TerrOr
Replay Cast
3 days
Replay Cast
4 days
Replay Cast
4 days
WardiTV Invitational
4 days
WardiTV Invitational
4 days
GSL Code S
5 days
Rogue vs GuMiho
Maru vs Solar
Replay Cast
6 days
GSL Code S
6 days
herO vs TBD
Classic vs TBD
The PondCast
6 days
Liquipedia Results

Completed

CSL Season 17: Qualifier 1
DreamHack Dallas 2025
Heroes 10 EU

Ongoing

JPL Season 2
BSL 2v2 Season 3
BSL Season 20
KCM Race Survival 2025 Season 2
NPSL S3
Rose Open S1
CSL Season 17: Qualifier 2
2025 GSL S2
BGE Stara Zagora 2025
BLAST.tv Austin Major 2025
ESL Impact League Season 7
IEM Dallas 2025
PGL Astana 2025
Asian Champions League '25
ECL Season 49: Europe
BLAST Rivals Spring 2025
MESA Nomadic Masters
CCT Season 2 Global Finals
IEM Melbourne 2025
YaLLa Compass Qatar 2025
PGL Bucharest 2025
BLAST Open Spring 2025

Upcoming

CSL 17: 2025 SUMMER
Copa Latinoamericana 4
CSLPRO Last Chance 2025
CSLPRO Chat StarLAN 3
K-Championship
SEL Season 2 Championship
Esports World Cup 2025
HSC XXVII
Championship of Russia 2025
Murky Cup #2
NC Random Cup
BLAST Bounty Fall 2025
BLAST Bounty Fall Qual
IEM Cologne 2025
FISSURE Playground #1
TLPD

1. ByuN
2. TY
3. Dark
4. Solar
5. Stats
6. Nerchio
7. sOs
8. soO
9. INnoVation
10. Elazer
1. Rain
2. Flash
3. EffOrt
4. Last
5. Bisu
6. Soulkey
7. Mini
8. Sharp
Sidebar Settings...

Advertising | Privacy Policy | Terms Of Use | Contact Us

Original banner artwork: Jim Warren
The contents of this webpage are copyright © 2025 TLnet. All Rights Reserved.