diff --git a/index.html b/index.html
index 348db09..14db98f 100644
--- a/index.html
+++ b/index.html
@@ -86,6 +86,17 @@
img {
cursor: pointer;
}
+ .message {
+ min-width: 300px;
+ border: 1px solid black;
+ background-color: white;
+ padding: 20px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ position: absolute;
+ transform: translate(-50%, -50%);
+ }
diff --git a/toast.js b/toast.js
index b808c23..36873af 100644
--- a/toast.js
+++ b/toast.js
@@ -9,9 +9,10 @@ function initGame(){
const clock = new THREE.Clock()
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
- camera.fov = 15
- camera.position.set( 0, 60, 40 );
+ camera.fov = 20
+ camera.position.set( 0, 320, 200 );
camera.lookAt(new THREE.Vector3(0,0,0))
+ camera.updateProjectionMatrix()
window.camera = camera
const renderer = new THREE.WebGLRenderer({canvas:document.getElementById("canvas"),antialias:true});
@@ -25,6 +26,7 @@ function initGame(){
light.target.position.set(0,0,-30)
light.castShadow = true
light.shadow.mapSize.width = 2048
+ camera.updateProjectionMatrix()
light.shadow.mapSize.height = 2048
light.shadow.camera.near = 0.5
light.shadow.camera.far = 500
@@ -46,48 +48,82 @@ function initGame(){
let mixer;
let velocity = new THREE.Vector3(0,0,10)
+
+ let slopeAngle = THREE.MathUtils.degToRad(30)
+
+ const GRAVITY = new THREE.Vector3(0,0,9.8)
+ const FRICTION = new THREE.Vector3(0,0,-1)
+ const FOREST_WIDTH = 1000
+ const zOffset = 300
+
+ const spawnTree = (i) => {
+ trees[i].pos.set(
+ (Math.random() - 0.5)*FOREST_WIDTH,
+ 0,
+ (Math.random() * 10) + zOffset,
+ )
+ trees[i].scale = 1 + (Math.random()*0.4)
+ trees[i].slope = -slopeAngle
+ }
- const GRAVITY = new THREE.Vector3(0,0,1)
- const FOREST_WIDTH = 500
- const initTrees = (zOffset) => {
+ const initTrees = () => {
trees.forEach(tree => {
tree.pos.set(
(Math.random() - 0.5)*FOREST_WIDTH,
0,
- (Math.random() - 0.5)*FOREST_WIDTH + zOffset,
+ (Math.random() - 0.5)*(FOREST_WIDTH/2) + zOffset,
)
tree.scale = 1 + (Math.random()*0.4),
- tree.slope = THREE.MathUtils.degToRad(-15)
+ tree.slope = -slopeAngle
})
}
+ let gameOver = false
+
+ const handleCrash = (tree) => {
+ gameOver = true
+ const msg = document.createElement('div')
+ msg.className = "message"
+ msg.innerHTML = 'Woops, you crashed! Game Over!'
+ document.body.appendChild(msg)
+ }
+
+ const TREE_HIT_RADIUS = 2
const slopeAxis = new THREE.Vector3(1,0,0)
const SKIER_POS = -50
const tick = (delta) => {
+ if(gameOver){
+ return
+ }
if(skier.position.z < SKIER_POS){
skier.position.add(velocity.clone().multiplyScalar(delta))
}else{
- if(keys.get('ArrowLeft')){
+ if(keys.get('ArrowLeft') || keys.get('MouseLeft')){
if(skier.rotation.y > -Math.PI/2)
- skier.rotation.y -= delta * 2
- }else if(keys.get('ArrowRight')){
+ skier.rotation.y -= delta * 3
+ }else if(keys.get('ArrowRight') || keys.get('MouseRight')){
if(skier.rotation.y < Math.PI/2)
- skier.rotation.y += delta * 2
+ skier.rotation.y += delta * 3
}
// update velocity in the direction of skier
velocity.set(0,0,velocity.length()).applyAxisAngle(UP,skier.rotation.y)
- // TODO add gravity / friction
- // todo scale gravity based on slope
- velocity.add(GRAVITY.clone().multiplyScalar(delta))
+ velocity.add(GRAVITY.clone().multiplyScalar(delta * Math.sin(slopeAngle)))
+ velocity.add(FRICTION.clone().multiplyScalar(delta * Math.sin(skier.rotation.y)))
+ velocity.add(velocity.clone().normalize().multiplyScalar(-1).multiplyScalar(0.01))
for(let i=0; i< trees.length;i++){
trees[i].pos.z -= velocity.z * delta
trees[i].pos.x -= velocity.x * delta
}
}
- // TODO cull and respawn trees that are past the top of the screen
for(let i = 0; i < trees.length; i++){
const tree = trees[i]
+ if(tree.pos.z < -125){
+ spawnTree(i)
+ }
+ if(new THREE.Vector3().subVectors(skier.position,tree.pos).length() < TREE_HIT_RADIUS){
+ handleCrash(tree)
+ }
const matrix = new THREE.Matrix4().makeScale(tree.scale,tree.scale,tree.scale)
matrix.premultiply(new THREE.Matrix4().makeRotationAxis(slopeAxis,tree.slope))
matrix.premultiply(new THREE.Matrix4().makeTranslation(tree.pos.x,tree.pos.y,tree.pos.z))
@@ -100,7 +136,7 @@ function initGame(){
const delta = clock.getDelta()
tick(delta)
mixer.update(delta)
- renderer.render( scene, camera );
+ renderer.render(scene,camera)
}
const loader = new GLTFLoader()
@@ -117,10 +153,9 @@ function initGame(){
treeMesh = gltf.scene.children.find(obj => obj.name === "tree")
gltf.scene.remove(treeMesh)
- console.log(treeMesh)
treeInstances = new THREE.InstancedMesh(treeMesh.geometry,new THREE.MeshToonMaterial({color:'DarkGreen'}),TREE_COUNT)
treeInstances.castShadow = true
- initTrees(300)
+ initTrees()
scene.add(treeInstances)
skier.add(gltf.scene)
@@ -131,10 +166,38 @@ function initGame(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
+ composer.setSize(window.innerWidth, window.innerHeight);
});
window.addEventListener('keydown',(e) => keys.set(e.key,true))
window.addEventListener('keyup',(e) => keys.set(e.key,false))
+ window.addEventListener('pointerdown', (e) => {
+ if(e.button !== 0) return
+ if(e.clientX < window.innerWidth/2){
+ keys.set('MouseLeft',true)
+ keys.set('MouseRight',false)
+ }else{
+ keys.set('MouseLeft',false)
+ keys.set('MouseRight',true)
+ }
+ })
+ window.addEventListener('pointermove', (e) => {
+ if(e.buttons & 1){
+ if(e.clientX < window.innerWidth/2){
+ keys.set('MouseLeft',true)
+ keys.set('MouseRight',false)
+ }else{
+ keys.set('MouseLeft',false)
+ keys.set('MouseRight',true)
+ }
+ }
+ })
+ window.addEventListener('pointerup', (e) => {
+ keys.set('MouseLeft',false)
+ keys.set('MouseRight',false)
+ })
+
+
}
function main(){
diff --git a/toasterbot_skifree.glb b/toasterbot_skifree.glb
index dd3961c..4ab3c13 100755
Binary files a/toasterbot_skifree.glb and b/toasterbot_skifree.glb differ