UNPKG

shaku

Version:

A simple and effective JavaScript game development framework that knows its place!

254 lines (210 loc) 11.3 kB
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Shaku</title> <meta name="description" content="Shaku - a simple and easy-to-use javascript library for videogame programming."> <meta name="author" content="Ronen Ness"> <link href="css/style.css" rel="stylesheet" type="text/css" media="all"> </head> <body> <div class="noselect"> <button class="view-code-btn" onclick="showSampleCode();">View Code</button> <h1 class="demo-title">Shaku Gfx Demo: 3D</h1> <p>Shaku is designed for 2D, but it can also do some basic 3D rendering. This demo shows how.<br /><br /> Use <b>Arrows</b> or <b>WASD</b> to move the sprite.</p> <span class="credits">Knight image is from: https://opengameart.org/content/knight-sprite <br/> Tree image is from: https://opengameart.org/content/gnarled-tree<br/> Grass image is from: https://opengameart.org/content/10-seamless-grass-textures-that-are-2048-x-2048-grass-1png</span> <!-- include shaku --> <script src="js/demos.js"></script> <script src="js/shaku.js"></script> <!-- demo code --> <script> async function runDemo() { // init shaku Shaku.gfx.setContextAttributes({depth:true}); await Shaku.init(); // screen size let screenX = 1000; let screenY = 700; // add canvas to document document.body.appendChild(Shaku.gfx.canvas); Shaku.gfx.setResolution(screenX, screenY, true); // load textures and font let spriteTexture = await Shaku.assets.loadTexture('assets/sprite.png'); let grassTexture = await Shaku.assets.loadTexture('assets/grass.png'); let treeTexture = await Shaku.assets.loadTexture('assets/baum.png'); let fontTexture = await Shaku.assets.loadFontTexture('assets/DejaVuSansMono.ttf', {fontName: 'DejaVuSansMono'}); // create 3d sprites batch let spritesBatch3d = new Shaku.gfx.SpriteBatch3D(); spritesBatch3d.setPerspectiveCamera(); // sprite size and position const spriteSize = new Shaku.utils.Vector2(spriteTexture.width * 1.5, spriteTexture.height * 1.5); const position = new Shaku.utils.Vector3(0, 0, 0); // create random trees const trees = []; for (let i = 0; i < 25; ++i) { const maxPosOffset = 2600; const treeSize = new Shaku.utils.Vector2(treeTexture.width * 3, treeTexture.height * 3); const treePosition = new Shaku.utils.Vector2(Math.random() * maxPosOffset - maxPosOffset / 2, Math.random() * maxPosOffset - maxPosOffset / 2); const treeOffsetY = -20; const tv1 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-treeSize.x / 2 + treePosition.x, treeOffsetY, treePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(0, 1)); const tv2 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(treeSize.x / 2 + treePosition.x, treeOffsetY, treePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(1, 1)); const tv3 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-treeSize.x / 2 + treePosition.x, treeSize.y + treeOffsetY, treePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(0, 0)); const tv4 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(treeSize.x / 2 + treePosition.x, treeSize.y + treeOffsetY, treePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(1, 0)); trees.push([tv1, tv2, tv3, tv4]); } // create sprite vertices const v1 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-spriteSize.x / 2, 0, 0)) .setTextureCoords(new Shaku.utils.Vector2(0, 1)); const v2 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(spriteSize.x / 2, 0, 0)) .setTextureCoords(new Shaku.utils.Vector2(1, 1)); const v3 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-spriteSize.x / 2, spriteSize.y, 0)) .setTextureCoords(new Shaku.utils.Vector2(0, 0)); const v4 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(spriteSize.x / 2, spriteSize.y, 0)) .setTextureCoords(new Shaku.utils.Vector2(1, 0)); // create floor vertices const floorPosY = 0; const floorWidth = grassTexture.width * 2.5; const floorDepth = grassTexture.height * 2.5; const vf1 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-floorWidth, floorPosY, -floorDepth)) .setTextureCoords(new Shaku.utils.Vector2(0, 1)); const vf2 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(floorWidth, floorPosY, -floorDepth)) .setTextureCoords(new Shaku.utils.Vector2(1, 1)); const vf3 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-floorWidth, floorPosY, floorDepth)) .setTextureCoords(new Shaku.utils.Vector2(0, 0)); const vf4 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(floorWidth, floorPosY, floorDepth)) .setTextureCoords(new Shaku.utils.Vector2(1, 0)); // do a main loop step. function step() { Shaku.startFrame(); Shaku.gfx.clear(Shaku.utils.Color.cornflowerblue); Shaku.gfx.clearDepth(); // begin drawing spritesBatch3d.begin(); // set view matrix spritesBatch3d.camera.setViewLookat( new Shaku.utils.Vector3(position.x, 500, 600 + position.z), new Shaku.utils.Vector3(position.x, 0, position.z) ); // create transformation matrix const matrix = Shaku.gfx.Matrix.createTranslation(position.x, position.y, position.z); // draw floor spritesBatch3d.drawVertices(grassTexture, [vf1, vf2, vf3, vf4]); // draw sprite from vertices const vertices = [Shaku.gfx.Matrix.transformVertex(matrix, v1), Shaku.gfx.Matrix.transformVertex(matrix, v2), Shaku.gfx.Matrix.transformVertex(matrix, v3), Shaku.gfx.Matrix.transformVertex(matrix, v4)]; spritesBatch3d.drawVertices(spriteTexture, vertices); // draw trees for (let tree of trees) { spritesBatch3d.drawVertices(treeTexture, tree); } // update sprite position if (Shaku.input.down('left') || Shaku.input.down('a')) { position.x -= Shaku.gameTime.delta * 175; } if (Shaku.input.down('right') || Shaku.input.down('d')) { position.x += Shaku.gameTime.delta * 175; } if (Shaku.input.down('up') || Shaku.input.down('w')) { position.z -= Shaku.gameTime.delta * 175; } if (Shaku.input.down('down') || Shaku.input.down('s')) { position.z += Shaku.gameTime.delta * 175; } // draw everything spritesBatch3d.end(); // end frame Shaku.endFrame(); Shaku.requestAnimationFrame(step); } step(); } // start demo runDemo(); </script> </div> <!-- code example part --> <div id="sample-code-modal" class="modal"> <div class="modal__overlay jsOverlay"></div> <div class="modal__container"> <p class="noselect">The following is a code example on how to draw 3D quads with vertices.</i> </p> <pre><code class="language-js">// init shaku with depth enabled // this is important for z-order Shaku.gfx.setContextAttributes({depth:true}); await Shaku.init(); // load a test texture let texture = await Shaku.assets.loadTexture('assets/sprite.png'); // create 3d sprites batch and set default perspective camera (check out setPerspectiveCamera params for more options) let spritesBatch3d = new Shaku.gfx.SpriteBatch3D(); spritesBatch3d.setPerspectiveCamera(); // do a main loop step. function step() { // start frame and clear buffers + depth // you need to clear depth in addition to color when using z buffers Shaku.startFrame(); Shaku.gfx.clear(Shaku.utils.Color.cornflowerblue); Shaku.gfx.clearDepth(); // set camera view matrix // eyePosition should be Vector3 with the position of your camera // lookatPosition should be Vector3 with the position the camera looks at spritesBatch3d.camera.setViewLookat( eyePosition, lookatPosition ); // create vertices for our 3d quad const spriteSize = new Shaku.utils.Vector2(texture.width, texture.height); const spritePosition = new Shaku.utils.Vector2(Math.random() * maxPosOffset - maxPosOffset / 2, Math.random() * maxPosOffset - maxPosOffset / 2); const spriteOffsetY = 0; const v1 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-spriteSize.x / 2 + spritePosition.x, spriteOffsetY, spritePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(0, 1)); const v2 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(spriteSize.x / 2 + spritePosition.x, spriteOffsetY, spritePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(1, 1)); const v3 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(-spriteSize.x / 2 + spritePosition.x, spriteSize.y + spriteOffsetY, spritePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(0, 0)); const v4 = (new Shaku.gfx.Vertex()) .setPosition(new Shaku.utils.Vector3(spriteSize.x / 2 + spritePosition.x, spriteSize.y + spriteOffsetY, spritePosition.y)) .setTextureCoords(new Shaku.utils.Vector2(1, 0)); // draw a 3D quad (note: quad origin point is bottom-center, making it appear as if its standing) // vertices should be an array with 4 Vertex objects that have 3d Vectors for positions spritesBatch3d.begin(); spritesBatch3d.drawVertices(texture, [v1,v2,v3,v4]); spritesBatch3d.end(); // end frame and request next one Shaku.endFrame(); Shaku.requestAnimationFrame(step); } step(); </code></pre> <button class="modal__close" onclick="closeModal('sample-code-modal')">&#10005;</button> </div> </div> <link href="prism/prism.css" rel="stylesheet" /> <script src="prism/prism.js"></script> </body> </html>