6
\$\begingroup\$

I've been playing around with porting a simple strategy game over to Javascript, the idea being to run it in a browser for testing. I've done some simple Javascript code in the past, but this is my first model/view setup. I'd love to get feedback on following Javascript best practices and avoiding pitfalls. I know that I am falling way short of the full features of the language because I don't use any prototypes. I am using THREE.js and jQuery.js, THREE.js being the main rendering engine.

The code here simply creates a Tower that contains a Javascript version of a dictionary of Floor objects with positions. They are then rendered in the THREE.scene based on their position. The idea will be to calculate clicking on them to issue commands to the floor based on the camera position and click position, but I haven't gotten that far yet. I want to find out if I am doing things properly before I get much further. This is partly just for fun but I still want to learn how to do things the right way.

Here is the codepen. Just move the mouse up and down to move, and click to see the coordinates of the view and camera.

Here is the HTML:

<!DOCTYPE html>
<html>
<head lang="en">
    <style>

        body {
        background-color: #C0C0C0;
        margin: 0px;
        overflow: hidden;
        font-family:Monospace;
        font-size:13px;
        text-align:center;
        font-weight: bold;
        text-align:center;
    }

    div{
        background: #C0C0C0;
    }
    </style>

    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <script src="js/jquery.min.js"></script>
    <script src="js/three.min.js"></script>
    <script src = "js/three2dtest.js"></script>
</body>

</html>

And here is the Javascript Game:

var container;
var camera;
var scene;
var renderer;

var mouseX = 0;
var mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

//this is the game model object
var worldSize = new WorldSize(windowHalfX, windowHalfY);
var tower = new Tower(worldSize);

init();
//not good to do animate here
//animate();

function init() {
    container = document.createElement('div');
    document.body.appendChild(container);

    //these settings have to be very specific for the scene to work
    camera = new THREE.OrthographicCamera(window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 500, 1000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 0;

    scene = new THREE.Scene();
    //fog seems to make no difference
    //scene.fog = new THREE.FogExp2(0x000000, 0.0025);
    console.log(scene);

    for (obj in tower.towerFloors) {
        //starting positions of the floors
        console.log(tower.towerFloors[obj].yposition);

        // Using wireframe materials to illustrate shape details.
        var darkMaterial = new THREE.MeshBasicMaterial({color: 0xffffcc});
        var wireframeMaterial = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true, transparent: true}); 
        var multiMaterial = [darkMaterial, wireframeMaterial];

        // create a cube for each of the floors on the tower
        var floorShape = THREE.SceneUtils.createMultiMaterialObject( 
        new THREE.CubeGeometry(500, tower.towerFloors[obj].floorSize * 10, 2, 1, 1, 1), 
        multiMaterial);
        floorShape.position.set(0, tower.towerFloors[obj].yposition * 10, 0);
        scene.add(floorShape);
    }

    renderer = new THREE.WebGLRenderer({clearColor: 0xff0000, clearAlpha: 1});
    renderer.setClearColorHex(0xC0C0C0, 1);  //this is light grey
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);

    document.addEventListener('mousemove', onDocumentMouseMove, false);
    window.addEventListener('resize', onWindowResize, false);

    //should be better to start animate inside here rather than outside
    animate();
}

//position registering function
$('div').click(function(e) {
    alert(e.pageX+ ' , ' + e.pageY);
    alert (camera.position.x + ' , ' + camera.position.y);
});

function onDocumentMouseMove(event) {
    mouseX = event.clientX - windowHalfX;
    mouseY = event.clientY - windowHalfY;
}
function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    //move only up and down
    //multiply by 0.15 to slow the overall scroll speed
    //camera.position.x += (mouseX - camera.position.x) * 0.15;  
    camera.position.y += (-mouseY - camera.position.y / 10) * 0.15;  

    //the camera wont move above the top floor so no bounds check needed
    if (camera.position.y < 0) {
        camera.position.y = 0;
    }

    renderer.render(scene, camera);
}

///////////////////////////////////////////////
/*           Tower Objects                   */
///////////////////////////////////////////////
function Tower (worldSize) {
    //create the dictionary of floors
    this.towerFloors = {};
    var floorNumber = 0;
    for (floorNumber = 0; floorNumber < 50; floorNumber++) { 
        var floor = new Floor(floorNumber, worldSize);
        this.towerFloors[floorNumber] = floor;
    }

    this.testLog = "tower created and logged";
    console.log(this.testLog);

    //test methods
    for (obj in this.towerFloors) {
        console.log(this.towerFloors[obj].floorNumber);
    }
    for (obj in this.towerFloors) {
        console.log(this.towerFloors[obj].yposition);
    }
}
function Floor (floorNumber, worldSize) {
    this.floorNumber = floorNumber;
    this.floorSize = worldSize.ysize / 50;
    this.yposition = this.floorSize * floorNumber;
}
function WorldSize (xsize, ysize) {
    this.xsize = xsize;
    this.ysize = ysize;
}
\$\endgroup\$
  • \$\begingroup\$ Is this really MVC? \$\endgroup\$ – Schism Jul 29 '14 at 15:14
  • \$\begingroup\$ By MVC I just mean that I tried to have a separation between the model that contains the game data, and its representation and rendering on the screen. So the model is the Tower "object", the view is the THREE.WebGLRenderer, and the controller is the Javascript that links them together. \$\endgroup\$ – bazola Jul 29 '14 at 15:20
3
\$\begingroup\$

From a once over:

  • HTML looks clean, though your title should not be blank per the HTML spec
  • Your objects look fine, old skool JS OO, which is nice to read
  • When you write for (obj in this.towerFloors) { you are polluting the global namespace, either declare obj on top in your function (my favourite approach) or use for (var obj in this.towerFloors) { , but only the first time you use obj otherwise JsHint throw warnings for duplicate declarations
  • There is not much functionality to review really, I hope that you got further with this and post a new question with more meat.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.