Warn if webgl not available
Happens automatically with the help of /src/extras/PolyfillRenderer.js
See /src/engine/Config.js comments for details
Config.instance.window.resize = true
Config.instance.renderer.alpha = false
new QRCode("qrcode", { text: "hello world", width: 128, height: 128 });
Each game has its own user/pass which currently is stored client side in an insecure way. It is "safe" to store it like this because the high scores for mini games are not that important when prototyping the game.
After you register and api_key and secret you can HighScoreManager.addScore
or HighScoreManager.getScores(20)
See /src/extras/HighScoreManager.js for more info.
See /tutorials/NETWORKING.md for a full tutorial.
let mn = new MeshNetwork()
mn.connect('https://mesh.opinie-publica.ro', 'room', { audio: false, video: false })
mn.onConnect = (peer) => {
console.log(`connected with peer ${peer.cmKey}`)
}
mn.onData = (peer, data) => {
console.log(`${data.from}: ${JSON.stringify(data)}`)
}
mn.onError = (peer, error) => {
console.error(error)
}
mn.onClose = function (peer) => {
console.log(`disconnected from peer ${peer.cmKey}`)
}
See /src/extras/MeshNetwork.js for more info.
Once sounds are loaded, you can use the SoundManager
class to play sounds.
SoundManager.play('orchestra.wav')
SoundManager.pause('orchestra.wav')
SoundManager.stop('orchestra.wav')
SoundManager.fadeIn('orchestra.wav', 1)
SoundManager.fadeOut('orchestra.wav', 0)
SoundManager.volume('orchestra.wav', 0.5)
SoundManager.volumeAll('orchestra.wav', 0.5)
SoundManager.looping('orchestra.wav', true)
For background music, we have a Playlist which can be used to loop music.
playlist = new Playlist(['shotgun.wav', 'hit.mp3'])
playlist.play()
SoundManager.pause(playlist.getPlayingKey())
this.sky = new Sky()
this.sky.addToScene(this)
Day/night cycle can be managed with the updateSun
function
Also see /src/objects/Sky.js for details Also see /src/objects/SkyBox.js for details
Send the path to the font without the extension. This will take care of adding the css import statements as well.
AssetManager.loadAssets([
{ type: 'font', path: 'assets/luckiest-guy' },
], function () {
})
var text = new BaseText({
text: 'Press <Enter> to start', fillStyle: 'blue',
canvasW: 1024, canvasH: 1024,
font: '64px luckiest-guy'})
text.position.set(0, 0, 4)
text.setText('hello')
this.add(text)
* {
font-family: 'luckiest-guy', sans-serif;
font-size: 2em;
}
scene.setWireframe(true)
model.setWireframe(true)
Utils.screenshot()
VideoRecorderManager.start()
VideoRecorderManager.isRunning()
VideoRecorderManager.stop()
dict = { hello: 'world' }
Utils.saveFile(dict, 'fileName.json')
Note: requires an event started by a user action not a script. It is a browser limitation.
Utils.toggleFullscreen()
Opacity ranges from 0 (transparent) to 1 (opaque) and can be applied recursively to all the object children as well as the object
let obj = new THREE.Object3D()
obj.setOpacity(0, true)
Add a panel in the top left corner showing FPS, MB used, geometries textures etc.
Config.instance.window.showStatsOnStart = true
If you want to use your red/cyan 3d glasses
Utils.toggleAnaglyphEffect()
NOTE: Doesn't work together with StereoEffect
If you want to use a VR headset
Utils.toggleStereoEffect()
NOTE: doesn't work together with AnaglyphEffect
You can adjust the renderer size with
engine.renderManager.setWidthHeight({ width: 320, height: 240 })
You can enforce a required screen orientation. Valid values are:
- all
- landscape
- portrait
Utils.orientation('landscape')
An screen informing the user to rotate the screen will appear over all the other content.
There are 2 helpers which can identify if you are on a pc/mobile device. They return true/false
Utils.isMobile()
Utils.isMobileOrTablet()
You can persist data on the client in Local Storage with the help of Persist. It supports defeault values, prefixing and different primitives.
See /src/extras/Persist.js for more info.
Sometimes you just want to be able to rotate around to inspect things. Move the mouse, zoom etc.
Utils.toggleOrbitControls()
The skin of a loaded model can be changed. Just make sure both the model and the new skin have been loaded with the AssetManager
let chicken = AssetManager.clone('chicken.glb')
chicken.setSkin('chicken_black.png')
scene.fog = Helper.fog('white', 0, 500)
grid = Utils.grid({ size: 10, step: 1, color: 0xffffff})
scene.add(grid)
See /src/objects/Water.js for details
this.water = new Water({
width: 100,
height: 100,
map: 'waternormals.jpg',
water: {
alpha: 0.8,
waterColor: 0x001e0f
}
})
this.add(this.water)
this.water.setSunDirection(this.sky.light)
See /src/objects/Tree.js for details
See Utils.forest() for more details
let forest = Utils.forest({
items: [
{
type: 'chicken.gltf',
count: 20,
}
]
})
forest.traverse(function (e) {
if (e instanceof THREE.Scene) {
e.animations.playRandom()
}
})
this.add(forest)
See /src/objects/LightningBolt.js for details
VolumetricSpotLight
// (x, y, z, r1, r2, height)
spotLight = new SpotLight(0, 10, 0, 0.1, 2.5, 5)
spotLight.addToScene(scene)
spotLight.lookAt(new (THREE.Vector3)(0, 0, 0))
spotLight.setColor('white')
let mirror = new Mirror({width: 5, height: 5})
this.add(mirror)
See [/src/objects/Mirror.js][/src/objects/Mirror.js] for more info.
To enable shadows, you need to toggle them.
Utils.toggleShadows()
You can configure shadow details with:
Utils.setShadowDetails(512, 512)
Utils.setShadowDetails(Config.instance.shadow.details.low)
Utils.setShadowDetails('medium')
Utils.setShadowDetails('high')
Utils.setShadowDetails('ultra')
Shadow behaviour can be controlled per object basis with the help of:
let bunny = AssetManager.clone('bunny.gltf')
bunny.shadowCastAndNotReceive()
let ground = AssetManager.clone('ground.gltf')
ground.shadowReceive()
To help debug lights, you can add wireframe objects around lights so they can be seen better.
Utils.toggleShadowCameraHelpers()
If some object dissapear off the screen at certain camera angles you can try setting its frustum culled to false to draw it all the time.
Utils.setFrustumCulled(object, false);
VirtualJoystick allows emulating a game controller on the display. It is customizable but tries to have sane defaults. The jist of it is instantiating the object and adding listeners:
let vc = new VirtualController()
let joystick1 = vc.joystick1
joystick1.addEventListener('touchStart', function () {
// do something
})
joystick1.addEventListener('touchEnd', function () {
// do something else. or not, I am just a comment
})
// check the state of the joystick with:
joystick1.deltaX()
joystick1.deltaY()
joystick1.up()
joystick1.down()
joystick1.left()
joystick1.right()
Checkout /workspace/games/controller/ for example usage.
See /src/extras/VirtualController.js for details
Helps you make bullets or endless monsters by reusing instantiated objects.
See /src/extras/PoolManager.js for details
The default camera is the perspective camera. If the defaults don't work for you
checkout Config.instance.camera
. The other camera type is ortographic. Think
2d games.
You can change the camera by changing the type
. Make sure you set the variable
before calling start.
Config.instance.camera.type = 'ortographic'
If you want an even finer control, you can use the helper Utils.camera
or override the initCamera
method called by the renderer.
RenderManager.initCamera = () => {
return Utils.camera({ type: 'ortographic' })
}
OrthographicCamera: PerspectiveCamera:
Adjust distance with fov
Config.instance.camera.fov = 50
this.rtsCam = new RTSCamera()
this.rtsCam.tick(tpf)
this.rtsCam.doMouseEvent(event)
this.rtsCam.isStatic() // returns true if camera is not doing anything
this.rtsCam.toggle()
// bound the panning to an area
this.rtsCam.oc.panBound = true
this.rtsCam.oc.panBoundRectangle = new THREE.Vector4(-10, 10, -10, 10)
// x - left most point
// y - right most point
// z - top most point
// w - bottom most point
this.terrain = Terrain.fromJson(AssetManager.get('terrain.json'))
this.terrain.shadowReceive()
this.add(this.terrain)
ShaderParticleEngine GroupOptions EmitterOptions
The structure for the saved json is:
{
"kind": "particle", // this is mandatory
"textures": [ // array of images used
{ "libPath": "/path/to/img.png" } // libPath - where the image is loaded from
]
"particle": [ // the actual particle
]
}
"particle" can be a string or an array of strings which will be joined. It
should form a valid array of obects. Each object represents a Group
and
each group can have an array of emitters under the emitters
key.
let jsonParticleData = AssetManager.get('particle.json').particle
this.explosion = new BaseParticle(jsonParticleData)
this.add(this.explosion)
this.explosion.tick(tpf)
let json = AssetManager.get('basic_shader.json')
let material = new ShaderMaterial(json)
let material = new ShaderMaterial(json, "function (tpf) { this.uniforms.time.value += tpf * 2 }")
let material = new ShaderMaterial(json, function (tpf) {
this.uniforms.time.value += tpf * 2
})
material.tick(tpf)
let json = AssetManager.get('dissolve_shader.json')
let material = new ShaderMaterial(json)
material.tick(tpf)
Art generator or graffiti
this.art = Utils.graffiti(AssetManager.get('majestic-frog-cover.json'))
this.add(this.art)
An on screen console is provided. It needs an update. It can be used to inspect logs on mobile devices.
Utils.console() // toggles the console
Tweens are used to smoothly transform object properties.
To read about them check this and the list of smoothing curves
A base implementation of tweens can be found here
- BaseModifier
- FadeModifier (chaining bugged)
- ScaleModifier
- WeightModifier (used to ease into animations)
var up = new BaseModifier(text.position, { x: '+1' }, 1000, TWEEN.Easing.Linear.None)
var down = new BaseModifier(text.position, { x: '-1' }, 1000)
up.chain(down)
down.chain(up)
up.start()
// chaining is bugged with the fade modifier, do this instead
let duration = 3000
this.setInterval(() => {
let fadeOut = new FadeModifier(text, 1, 0.1, duration)
let fadeIn = new FadeModifier(text, 0.1, 1, duration)
.delay(duration)
fadeOut.start()
fadeIn.start()
}, duration * 2)
Playing a video works by creating a fullscreen div and adding a scalable
video element to it. The video removes itself by calling removeVideo
automatically when the video finishes playing.
Utils.playVideo("assets/agent.mp4", () => {
// optional, called when video has finished playing
// at this point, removeVideo was automatically called with
// no callback and the video tag is gone.
})
Utils.isPlayingVideo()
// if you want to fade the scene before removing the video, you can set
// a delay on the removeVideo()
let delay = Config.instance.fade.duration // defaults to 1000 ms
Utils.removeVideo(() => {
// optional, called when the video tag is removed
}, delay)
Utils.removeVideo(undefined, 0)
A cinematic can be played with the help of the VideoScene
let skippable = true
let gameScene = new GameScene()
let videoScene = new VideoScene(gameScene, "assets/agent.mp4", skippable)
Engine.start(videoScene)
Or an example with a lot of points.
let starfield = new Starfield()
this.add(starfield)
Utils.addMeshOutlineTo(cube, outlineCube, 3, outlineMaterial)
There are a few helper methods to help you get started with giving a toon outline effect. It works is by overlaying the same shaped object with an outline material to a target. The outline object has its scaled increase by the specified percent.
let geometry = new THREE.BoxGeometry( 1, 1, 1 )
let material = new THREE.MeshBasicMaterial( { color: 0x4d4d4d } )
let cube = new THREE.Mesh( geometry, material )
let outlineCube = new THREE.Mesh( geometry, material )
Utils.addMeshOutlineTo(cube, outlineCube)
this.add(cube)
For Utils.addMeshOutlineTo
you can pass optional params scalePercent
to
change the size of the outline (default 3) and outlineMaterial if you want to
use a different material.
To create an outline material use Utils.outlineMaterial()
. It has 2 params,
color
and thickness
. Defaults are black and 0.002
let outlineMaterial = Utils.outlineMaterial('black', 0.002)
Adding an outline to meshes cloned with AssetManager is super simple, it even
takes care of animating the outline object. Use Utils.addOutline()
which
takes the mesh, scalePercent and outlineMaterial as params
let chicken = AssetManager.clone('chicken.gltf')
Utils.addOutline(chicken)
chicken.animations.play('walk')
this.add(chicken)