// Example of porting physics World unchanged to AB using plain physics API
// World from "3D Game Programming for Kids", Second Edition
// "Purple Fruit Monster" from Chapter 14
// https://pragprog.com/titles/csjava2/source_code
// basically unchanged
AB.headerLHS();
// === scoreboard.js ================================================================================================
// https://www.code3dgames.com/scoreboard.js
// unchanged
// "Purple Fruit Monster" includes it with <script>
// We can include it like this:
// start of include scoreboard.js
$.getScript ( "https://www.code3dgames.com/scoreboard.js", function() {
// === purple_fruit_monster/code.html ================================================================================================
// from:
// https://pragprog.com/titles/csjava2/source_code
// unchanged (only because we matched paths of our images with image paths in this code)
/*
<!--
! Excerpted from "3D Game Programming for Kids, Second Edition",
! published by The Pragmatic Bookshelf.
! Copyrights apply to this code. It may not be used to create training material,
! courses, books, articles, and the like. Contact us if you are in doubt.
! We make no guarantees that this code is fit for any purpose.
! Visit http://www.pragmaticprogrammer.com/titles/csjava2 for more book information.
-->
*/
// The "scene" is where stuff in our game will happen:
var scene = new Physijs.Scene();
scene.setGravity(new THREE.Vector3( 0, -250, 0 ));
var flat = {flatShading: true};
var light = new THREE.AmbientLight('white', 0.8);
scene.add(light);
// The "camera" is what sees the stuff:
var w = window.innerWidth / 2;
var h = window.innerHeight / 2;
var camera = new THREE.OrthographicCamera(-w, w, h, -h, 1, 10000);
camera.position.z = 500;
scene.add(camera);
// The "renderer" draws what the camera sees onto the screen:
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('skyblue');
document.body.appendChild(renderer.domElement);
// ******** START CODING ON THE NEXT LINE ********
var gameOver = false;
var ground = addGround();
var avatar = addAvatar();
var scoreboard = addScoreboard();
reset();
function addGround() {
var shape = new THREE.BoxGeometry(2*w, h, 10);
var cover = new THREE.MeshBasicMaterial({color: 'lawngreen'});
var ground = new Physijs.BoxMesh(shape, cover, 0);
ground.position.y = -h/2;
scene.add(ground);
return ground;
}
function addAvatar() {
var shape = new THREE.CubeGeometry(100, 100, 1);
var cover = new THREE.MeshBasicMaterial({visible: false});
var avatar = new Physijs.BoxMesh(shape, cover, 1);
scene.add(avatar);
var image = new THREE.TextureLoader().load("/images/monster.png");
var material = new THREE.SpriteMaterial({map: image});
var sprite = new THREE.Sprite(material);
sprite.scale.set(100, 100, 1);
avatar.add(sprite);
avatar.setLinearFactor(new THREE.Vector3(1, 1, 0));
avatar.setAngularFactor(new THREE.Vector3(0, 0, 0));
return avatar;
}
function addScoreboard() {
var scoreboard = new Scoreboard();
scoreboard.score();
scoreboard.help(
"Use arrow keys to move and the space bar to jump. " +
"Don't let the fruit get past you!!!"
);
return scoreboard;
}
function reset() {
avatar.__dirtyPosition = true;
avatar.position.set(-0.6*w, 200, 0);
avatar.setLinearVelocity(new THREE.Vector3(0, 250, 0));
scoreboard.score(0);
scoreboard.message('');
var last = scene.children.length - 1;
for (var i=last; i>=0; i--) {
var obj = scene.children[i];
if (obj.isFruit) scene.remove(obj);
}
if (gameOver) {
gameOver = false;
animate();
}
}
function launchFruit() {
if (gameOver) return;
var speed = 500 + (10 * Math.random() * scoreboard.getScore());
var fruit = makeFruit();
fruit.setLinearVelocity(new THREE.Vector3(-speed, 0, 0));
fruit.setAngularVelocity(new THREE.Vector3(0, 0, 10));
}
launchFruit();
setInterval(launchFruit, 3*1000);
function makeFruit() {
var shape = new THREE.SphereGeometry(40, 16, 24);
var cover = new THREE.MeshBasicMaterial({visible: false});
var fruit = new Physijs.SphereMesh(shape, cover);
fruit.position.set(w, 40, 0);
scene.add(fruit);
var image = new THREE.TextureLoader().load("/images/fruit.png");
cover = new THREE.MeshBasicMaterial({map: image, transparent: true});
shape = new THREE.PlaneGeometry(80, 80);
var picturePlane = new THREE.Mesh(shape, cover);
fruit.add(picturePlane);
fruit.setAngularFactor(new THREE.Vector3(0, 0, 1));
fruit.setLinearFactor(new THREE.Vector3(1, 1, 0));
fruit.isFruit = true;
return fruit;
}
function checkMissedFruit() {
var count=0;
for (var i=0; i<scene.children.length; i++) {
var obj = scene.children[i];
if (obj.isFruit && obj.position.x < -w) count++;
}
if (count > 10) {
gameOver = true;
scoreboard.message(
'Purple Fruit Monster missed too much fruit! ' +
'Press R to try again.'
);
}
}
function gameStep() {
scene.simulate();
setTimeout(gameStep, 1000/30);
}
gameStep();
var clock = new THREE.Clock();
function animate() {
if (gameOver) return;
requestAnimationFrame(animate);
var t = clock.getElapsedTime();
// Animation code goes here...
renderer.render(scene, camera);
}
animate();
document.addEventListener("keydown", sendKeyDown);
function sendKeyDown(event) {
var code = event.code;
if (code == 'ArrowLeft') left();
if (code == 'ArrowRight') right();
if (code == 'ArrowUp') up();
if (code == 'ArrowDown') down();
if (code == 'Space') up();
if (code == 'KeyR') reset();
}
function left() { move(-100, 0); }
function right() { move(100, 0); }
function up() { move(0, 250); }
function down() { move(0, -50); }
function move(x, y) {
if (x > 0) avatar.scale.x = 1;
if (x < 0) avatar.scale.x = -1;
var dir = new THREE.Vector3(x, y, 0);
avatar.applyCentralImpulse(dir);
}
avatar.addEventListener('collision', sendCollision);
function sendCollision(object) {
if (gameOver) return;
if (object.isFruit) {
scoreboard.addPoints(10);
avatar.setLinearVelocity(new THREE.Vector3(0, 250, 0));
scene.remove(object);
}
if (object == ground) {
gameOver = true;
scoreboard.message(
"Purple Fruit Monster crashed! " +
"Press R to try again."
);
}
}
// end of include scoreboard.js
});