So far
we have been using pixel coordinates to move or set the location of the sprite.
That works, but pixels don’t translate very well to “real units”. The Orb is
now 100 pixels big… But what is that? 100 nanometers? 100 Kangaroo jumps? And
what if you buy a new phone with a
resolution twice as big… does that mean the orb appears twice as small?
And how
about that movement speed of 0.2 “things per cycle”? It’s like your teacher
asking how fast a car can drive, and you answer with “3 knots per fart”. It doesn’t
mean much for one thing, and yet another problem is that you can’t always
predict how many cycles the phone does per second. If the game runs “ASAP” - As
Fast As Possible. It could be anything from 10 to 10000 cycles per second. The
speed might be reasonable on your current phone, but a new phone may blast away
that orb at hyper-speed, as it is capable of doing much more cycles per second
(having a stronger CPU/GPU). If you ever wondered why some of those old (DOS)
games seem fast-forwarded when trying to replay them. Well, that’s why. The
programmers were lazy and thought computers couldn’t become much faster than 16
MegaHertz. Or maybe, these games just weren't meant to be played in the future, who knows.
Fuck
pixels, can’t rely on them. Before writing piles of code, first get the units
to your likes. What is a “pixel” anyway? Sure, a dot on the screen, but it
doesn’t mean much in a (game)world context. I want to work with real sizes,
real velocities. William Wallace was 10 feet tall and could shit lighting bolts
from his arse, at a velocity of 100 miles per hour, using 320 Kilojoules. You
know what, fuck the imperial system too. Metric units. Meters, meters per
second. From now on, we talk in meters.
So,
let’s say that Orb-sprite should have an initial diameter of 4 meters (remember
it will grow as foes enter the sphere). Ok… And how big is that on your screen then?
That, of course, depends on the Camera Zoom.
The Camera
In every
game, you “spectate” the battlefield through a virtualcamera. That camera could
be a first person view, thus inside your hero’s (invisible) head. It could also
be a side-view, or a “God” view from above. Or a POV, when looking at a - never
mind. A camera can zoom in and out (or in this case, fly up and down). But it
can also move. In the code above we draw the orb at the center of the screen.
But, where is that? The center of the universe? It’s all relative. The orb
should be in the center of my view, if the camera is exactly above it.
So,
let’s start doing some actual ENGINE programming: our Camera class. But before
going too fast, let’s see what LibGDX itself has to offer. And well, yes it has
a “Camera” class already! Nonetheless, I will make my own camera class as a
wrapper in between though. Just so we can add our little magic and twerks to
it, if ever needed. So let’s make a new file. In these tutorials, you will see
a lot of Wrapper classes that extend the functionality of basic LibGDX
elements, such as the Sprite, Camera, (level)Map, and so on.
Added a “engine”
folder, and some (empty) sub-folders within. I’ll get into detail on this in
the next chapter. For now, just do it. Anyway, the Camera class. What can it
do? Let’s keep it simple for now: it can move (in X/Y direction, over the map,
topview), an zoom in/out. We move in meters, and {0,0} is considered to be the
centre of the map. Ok? Deal.
In
addition, I made a “moveToPos( posX, posY, maxSpeedMtrPerSec )” function. When
calling this, it will overrule manual controls, and flies to a certain point of
the map. For example, if the Orb explodes, you may want to move the camera
quickly to that point, just before the “Game Over” rolls by. Again, note that
the Engine doesn’t decide how & when the camera is controlled. The Game code
does that part. We just offer code that makes things happen.
Finally,
it has an “update( deltaSecs )” function, which is called every cycle so it can
update its movements. More about that later. The constructor, update and move functions of this Camera look like this, so far:
public GxCamera()
{
this.screenWidth = Gdx.graphics.getWidth();
this.screenHeight = Gdx.graphics.getHeight();
this.camera = new OrthographicCamera( 1.f, (float)this.screenHeight / (float)this.screenWidth );
this.camera.zoom = 30; // Zoom out a bit
} // create
public void update( float deltaSecs )
{
this.camera.update();
} // update
public void move( float deltaMetersX, float deltaMetersY )
{
this.camera.translate( deltaMetersX, deltaMetersY );
} // move
(make
sure you convert to floats when doing the division in the Constructor. Wasted 30 minutes figuring
out why I couldn’t see shit. Camera ended up with a rounded 0 height for a view, which
isn’t much).
Internally,
it uses a LibGDX Orthographic camera. Orthographic basically means “without
perspective” – stuff doesn’t get smaller or disappears as the distance grows.
Since we’re not making 3D graphics, a simple view does it. Pay attention to the
width / height arguments we are giving. Since we want to get rid of pixels, we
say the camera sees “one” (meter) unit wide, and a bit more height, as the
phone display is typically not exactly square. In other words, if the camera is
not zoomed out (thus at zoom level 0), it can only see 1 meter wide.
There is a Camera class now, but engines don't start themselves. You will have to utilize it somehow in your game-code, so that it will actually CREATE a camera and APPLY it every render cycle:
@Override
public void create () {
camera = new GxCamera(); // Your new class!
batch = new SpriteBatch();
img = new Texture("Images/Orb/Orb01.png");
spr = new Sprite( img );
spr.setOrigin( 0,0 );
spr.setSize( 4,4 );
} // create
@Override
public void render () {
Gdx.gl.glClearColor(0.05f, 0.21f, 0.2f, 1.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update(); // Update the camera sub-routines
batch.setProjectionMatrix( camera.combined ); // Apply view
spr.setPosition( -2, -2 );
batch.begin();
spr.draw( batch );
batch.end();
} // render
Now run
the program… You may wonder where the hell the Orb went, or why the entire screen is pink/purple in all of a sudden... Ah right,I forgot to adjust the sprite position & size. It was still sized to 100 pixels - which is now 100 meters (entire screen pink). And also the position was far, far away.
Probably you will need a moment screwing around with the position, size and zoom numbers. I always have a hard time setting up the camera
initially, in a near empty world, since you don't have any reference point. Imagine waking up in a complete ugly-green world, like our camera and orb did above.
In the next tiny chapter, I'll explain a few things about the Camera MOVE function, and how to work with proper velocity units, like "meters per second".
No comments:
Post a Comment