Working with Viewport
Working with Viewport
Since v1.3, ct.js has a Camera object that manipulates the viewport. It supports scaling and rotation, and can also follow a copy and create screen shake effects.
Moving the camera around
To move the camera around, you can:
- use
ct.camera.teleportTo
,ct.camera.moveTo
; - use the built-in variables to follow things on the screen;
- change the camera's parameters by yourself.
new in v1.3
Moving and teleportingct.camera.moveTo(x, y)
and ct.camera.teleportTo(x, y)
both move the camera to a new position. There are differences, though:
ct.camera.moveTo(x, y)
is useful for cutscenes and smooth transitions between objects, as it works withct.camera.drift
;ct.camera.teleportTo(x, y)
does not cause transitions and reset screen shake effects. It is useful for instant precise changes, e.g. when moving a camera to a distant location
Following a copy
A simple line ct.camera.follow = this
inside the On Create code of your main character will set up automagical camera movement ✨ You can also set a template to automatically follow in your room's settings.
ct.camera.borderX
and ct.camera.borderY
define the area at which the camera shifts when the followed copy enters these borders. These values are in UI coordinates.
// Place this code, e.g, to your hero's `OnCreate` code
ct.camera.follow = this;
// Follow the hero so it cannot be closer than 300 px to any side of the screen
ct.camera.borderX = 300;
ct.camera.borderY = 300;
# Place this code, e.g, to your hero's `OnCreate` code
ct.camera.follow = this
# Follow the hero so it cannot be closer than 300 px to any side of the screen
ct.camera.borderX = 300
ct.camera.borderY = 300
You can also disable following logic for one axis. Setting ct.camera.followX
to false
will disable horizontal movement, and setting ct.camera.followY
will disable vertical movement. This still allows you to move the camera with teleportTo
and moveTo
methods. new in v1.3
Manual positioning
If you ever find that above methods are not enough for you, use these parameters:
ct.camera.x
,ct.camera.y
,ct.camera.targetX
,ct.camera.targetY
.
x
and y
are the current position of the camera without screen shake and effects of shiftX
and shiftY
. targetX
and targetY
will be different if ct.camera.drift
is larger than 0, and you should firstly edit these values.
new in v1.3
Zooming and rotationTo scale the viewport, use ct.camera.scale.x
and ct.camera.scale.y
, similarly to scaling copies. This is not a zoom level, but a scaling factor of a capturing rectangle: when using values larger than 1, you will see a larger portion of a room.
To rotate the viewport, use ct.camera.rotation
(in degrees). Again, you rotate a capturing rectangle, so the stuff on the screen will rotate clockwise.
A little caveat
You should not change the camera's values in the "On Draw" event, as the camera updates after the "On Step" event and before "On Draw" event. If you do, you will notice some inconsistencies when converting UI coordinates to game ones. That's because ct.u.uiToGameCoord
and others will use new values though the room is not yet repositioned.
Modifiers and smooth transition
ct.camera.drift
is a value between [0; 1] that defines how fast the camera reacts to movement. The default is0
(no drift). Try settingct.camera.drift
to0.9
to create a smooth transition.ct.camera.shiftX
andct.camera.shiftY
allow placing the camera higher/lower/etc than the target. This is especially useful while following a copy: you may need to show more stuff on the left when a game character looks there, or below when it crouches, etc.
ct.camera.shiftX
and ct.camera.shiftY
are interpolated in a separate pass than other camera movements but still use ct.camera.drift
.
Tips
For smooth scaling and rotation, change values ct.camera.angle
, ct.camera.scale.x
, ct.camera.scale.y
continuously with ct.delta
, or use ct.tween
module.
For example, to zoom in, you could use this code:
ct.tween.add({
obj: ct.camera.scale,
duration: 500,
fields: {
x: 0.5,
y: 0.5
}
});
ct.tween.add
obj: ct.camera.scale
duration: 500
fields:
x: 0.5
y: 0.5
Tips
Or you could manipulate camera angle by user input (in "On Step" event):
ct.camera.angle += ct.actions.CameraRotate.value * ct.delta * 5;
ct.camera.angle += ct.actions.CameraRotate.value * ct.delta * 5
new in v1.3
Screen shake effectsYes, there is a built-in feature for that 😅 Its design is as follows:
- a screen shakes by two blended harmonious functions on each axis, with their phases unsynced;
- the power of a screen shake is set by
ct.camera.shake
and represents the largest possible amplitude of the effect. A value of10
is 10% of the viewport size; - the effect gradually decays through time — this can be tweaked by
ct.camera.shakeDecay
parameter, or disabled by setting it to0
.
DISCLAIMER
- Do remember that there are lots of people (e.g. me, the creator of ct.js) that quickly get dizzy because of screen wobble and shaking. There are also people with epilepsy.
- Do provide controls for screen shake/wobble and don't overuse the effect.
- Put warnings about screen shake/wobbling at the start of your game and inside your game's description.
There are many parameters described here to control its feel, but default values are good as well. Here are the examples:
// Add an impulse that will accumulate on repetitive calls
ct.camera.shake += 1;
# Add an impulse that will accumulate on repetitive calls
ct.camera.shake += 1
// Make a constant, slow camera wobble
ct.camera.shakeFrequency = 1;
ct.camera.shakeDecay = 0;
ct.camera.shake = 2;
# Make a constant, slow camera wobble
ct.camera.shakeFrequency = 1
ct.camera.shakeDecay = 0
ct.camera.shake = 2
Making an adaptive UI
Contemporary devices all have various resolutions, and thus your app should adapt to them and still give the best quality.
The first step you need to do is to enable the ct.fittoscreen
catmod. Then, select the "Settings" tab and select a scaling mode that suits your game project more:
- Fast scaling with letterboxing is suitable for purely pixelart games, or when performance is vital;
- Expansion works well when the more player sees on the screen, the better (e.g. RTS or games like Factorio);
- Scaling with letterboxing works for any type of projects, and can also give nice transforms to your pixelart games. This will remain your designed aspect ratio.
- Scaling without letterboxing ensures both the best quality and use of a full screen. It is often preferable over scaling with letterboxing.
If you are making a pixelart game, make sure you disable image smoothing at the "Project" tab -> "Render Options" on the left side.
In general, you should follow these rules:
- design UI in a separate room, and then import it with
ct.rooms.append('NameOfTheRoom', {isUi: true})
; - use
ct.camera.width
andct.camera.height
to position UI elements; - use
ct.camera.realign(this)
new in v1.3 in "On Draw" of the UI layer to quickly get decent results; - update the position of UI elements regularly, as any resolution change may crop your elements. This can be caused by resizing a windowed version, at random unplug of an external monitor, etc;
- when using "Scaling with/without letterboxing", start designing your rooms, graphic assets, and UI at a relatively big view size at rooms' settings, e.g. at 1920x1080px, so it will scale down on other resolutions nicely.
Don't forget to test your UI on different screen sizes and devices!
Resizing the viewport
Usually, it is best to use ct.fittoscreen
so that it manages the renderer and viewport for you. In other cases, use ct.camera.scale.x
and ct.camera.scale.y
.
If you still want to resize the viewport manually, use these parameters (this affects the renderer!):
ct.width
;ct.height
.
These can still be used with most of ct.fittoscreen
's modes, except for "expand" mode, as ct.fittoscreen
overrides ct.width
and ct.height
.