diff options
Diffstat (limited to 'o3d/samples/io')
52 files changed, 3204 insertions, 0 deletions
diff --git a/o3d/samples/io/README.txt b/o3d/samples/io/README.txt new file mode 100644 index 0000000..e6ede03 --- /dev/null +++ b/o3d/samples/io/README.txt @@ -0,0 +1,29 @@ +Steps to Create a level: + +1. Install the SketchUp Level Creation tools +2. Start SU 6 +3. Draw your "world path" using the line tool + +- Using the line tool, draw a line from the drawing origin along the solid green axis line (that's your x axis) It can be as long or as short as you want. +- From there, you can draw lines continuously from the end of your first line segment. Each line is a distinct plane in the world path. +- Only draw horizontal lines along the Sketchup drawing's ground plane. No slopes or vertical changes in altitude. +- Your avatar will NOT walk on these lines. They are only used to define the path that the world will run along. + +4. Draw your platforms +- Each horizontal line must be exactly parallel and exactly "above" or "below" one of your "world path" line segments. +- Good way to do this is to CTRL+MOVE your base lines up or down, and then chop them up from there. +- Each horizontal line is a platform that your avatar can walk on. +- Each vertical line is an "obstacle" that your avatar can't walk through. + +5. Drag in your actors +- The installer created a directory under components > Prince IO (or it will, once we're done with it. -SEL) +- Drag these suckers in. Note that you're going to want to put them on line segments, typically. + +6. Draw random geometry only in components and groups. + +7. Test everything in SU. +- Press the "play" button in the Prince IO level designer. You can play the game. +- Note: Set your field of view to 45 degrees to have approximately the same camera view as in O3D. + +8. Press the "export" button and save your myLevelName.js and myLevelName.kmz into your prince IO /levels directory. +(this will also automatically generate the autoincludes.js file.) diff --git a/o3d/samples/io/actors/actor.js b/o3d/samples/io/actors/actor.js new file mode 100644 index 0000000..a0e1e50 --- /dev/null +++ b/o3d/samples/io/actors/actor.js @@ -0,0 +1,144 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the Actor class. + */ + +/** + * Pulls in all names attributes of a source object and applies them to a + * target object. Handy for pulling in a bunch of name:value pairs that were + * passed all at once. + */ +function Actor() { + // Create some defaults for our "required" attributes. + this.x = 0; + this.y = 0; + this.z = 0; + this.width = 20; + this.height = 20; + this.mapX = 0; + this.platformID = 0; + this.rotZ = 0; + this.frameName = ''; +} + +Actor.prototype.absorbNamedValues = function(initObj) { + for (var key in initObj) { + this[key] = initObj[key]; + } +}; + +/** + * Note that for collision detection, all actors are envisioned as 2d rectangles + * inside a single plane. These rectangles have a width and a height, and their + * "origin" is on the bottom center of the rectangle. So if you create a new + * actor, be sure to give it a reasonable width and height. + */ +Actor.prototype.collidesWith = function(otherActor) { + thisLeft = this.mapX - this.width/2; + thisRight = this.mapX + this.width/2; + thisTop = this.z + this.height; + thisBottom = this.z; + + otherLeft = otherActor.mapX - otherActor.width/2; + otherRight = otherActor.mapX + otherActor.width/2; + otherTop = otherActor.z + otherActor.height; + otherBottom = otherActor.z; + + // First see if we're not overlapping in any dimension. + if (thisRight < otherLeft || + thisLeft > otherRight || + thisBottom > otherTop || + thisTop < otherBottom) { + return false; + } + + // Next check for overlap along X. + if (thisRight >= otherLeft && + thisLeft <= otherRight) { + // then we're still in the running... + } else { + return false; + } + + // Next check for overlap along Y. + if (thisBottom <= otherTop && + thisTop >= otherBottom) { + return true; + } + + // We're not overlapping in Y, so bomb. + return false; +}; + +Actor.prototype.isHitBySword = function() { + var isHit = false; + if (avatar.animation == "Hero_Sword" && avatar.frame > 3) { + avatar.width += 80; + avatar.height += avatar.frame * 5; + if (this.collidesWith(avatar)) { + var isHit = true; + } + avatar.width -= 80; + avatar.height -= avatar.frame * 5; + } + return isHit; +} + +Actor.prototype.isHitByArrow = function() { + var isHit = false; + // TODO: Make this allow multiple arrows, perform better, etc. + if (top.arrowActor != undefined) { + // If we don't have the same "parentPlatform, meaning we're in different + // world path space, then we don't collide. + if (world.platforms[top.arrowActor.platformID].parentID != + world.platforms[this.platformID].parentID) { + return false; + } + if (this.collidesWith(top.arrowActor)) { + var isHit = true; + } + } + return isHit; +} + +Actor.prototype.moveMapX = function(change) { + var platformAngle = world.platforms[this.platformID].rotZ; + this.mapX += change; + this.x += change * Math.cos(platformAngle); + this.y += change * Math.sin(platformAngle); +}; + + + + diff --git a/o3d/samples/io/actors/arrow.js b/o3d/samples/io/actors/arrow.js new file mode 100644 index 0000000..0103b5c --- /dev/null +++ b/o3d/samples/io/actors/arrow.js @@ -0,0 +1,94 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the Arrow class. + */ + +/** + * An arrow that Io can shoot. + */ +function Arrow(initObj) { + this.absorbNamedValues(initObj); + + // Hide myself by moving way off the screen. + this.z = -10000; + this.mapX = -10000; + this.width = 40; + this.height = 1; + this.velX = 0; + + // Figure out which arrow number I am. + this.arrowNumber = parseInt(initObj.name.substr(initObj.name.length-1,1)); + +} +Arrow.prototype = new Actor; + +Arrow.prototype.onTick = function(timeElapsed) { + if (this.mapX < avatar.mapX-500 || this.mapX > avatar.mapX+500 && + this.z > -10000) { + // then hide ourselves way off screen. + this.mapX = -10000; + this.z = -10000; + updateActor(this); + } else { + // Here's how I move. moveMapX is a handy function that updates both + // my "virtual 2d world" mapX, as well as my literal x + y values + this.moveMapX(this.velX * timeElapsed) + updateActor(this); + } +} + +Arrow.prototype.shoot = function() { + this.x = avatar.x; + this.y = avatar.y; + this.z = avatar.z + 33; // Approximate height of IO's crossbow. + this.platformID = avatar.platformID; + this.parentPlatformID = avatar.parentPlatformID; + this.rotZ = world.platforms[this.platformID].rotZ; + this.mapX = avatar.mapX; + + if (Math.abs(avatar.rotZ - this.rotZ) < Math.PI/2) { + this.velX = 50 * 20; + } else { + this.velX = -50 * 20; + this.rotZ -= Math.PI; + } + soundPlayer.play('sound/arrow.mp3', 100); + updateActor(this); +} + +// TODO: This should be a generic concept, not an arrow-specifc +// thing. +Arrow.prototype.hide = function() { + this.mapX = -10000; +} diff --git a/o3d/samples/io/actors/avatar.js b/o3d/samples/io/actors/avatar.js new file mode 100644 index 0000000..aac4f45e --- /dev/null +++ b/o3d/samples/io/actors/avatar.js @@ -0,0 +1,67 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Our avatar object. Hooray! + */ +function Avatar(initObj) { + this.absorbNamedValues(initObj); + + this.animation = "Hero_Stand" + this.velX = 0; + this.velY = 0; + this.velZ = 0; + this.targetRotZ = 0; // Where we'd like to be facing. + this.targetVelX = 0; // Speed we'd like to be going. + this.swordRate = .5; + + this.width = 30; + this.height = 50; + + this.frame = 1; + this.framesSinceShot = 0; // If > 0, tack a "#1" onto our instance name. + this.isJumping = false; + + // We always start on platform 0 to fix a placement bug. + this.platformID = 0; + this.x = 0; + this.y = 0; + this.mapX = 0; + this.z = 200; + this.parentPlatformID = 0; + +} + +Avatar.prototype = new Actor; + +Avatar.prototype.onTick = function(timeElapsed) { + updateActor(this); +} diff --git a/o3d/samples/io/actors/coin.js b/o3d/samples/io/actors/coin.js new file mode 100644 index 0000000..1124d5e --- /dev/null +++ b/o3d/samples/io/actors/coin.js @@ -0,0 +1,68 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the Coin class. + */ + +/** + * A Coin to be picked up + */ +function Coin(initObj) { + this.absorbNamedValues(initObj); + this.hasBeenPickedUp = false; + this.width = 14; + this.height = 14; + this.isHidden = false; +} +Coin.prototype = new Actor; + +Coin.prototype.onTick = function(timeElapsed) { + if (this.isHidden == true) { + return; + } else if (this.hasBeenPickedUp == true) { + this.z = (this.z*6 + eyeZ+40)/7; + this.x = (this.x*3 + eyeX)/4; + this.y = (this.y*3 + eyeY)/4; + if (Math.abs(this.z - eyeZ+40) < 1) { + this.isHidden = true; + this.z = -10000; + } + } else { + if (this.collidesWith(avatar)) { + soundPlayer.play('sound/coin_3.mp3', 100, 0, true); + this.hasBeenPickedUp = true; + } + } + this.rotZ += .4 * 20 * timeElapsed; + updateActor(this); +} diff --git a/o3d/samples/io/actors/horizontalpad.js b/o3d/samples/io/actors/horizontalpad.js new file mode 100644 index 0000000..b2e3f85 --- /dev/null +++ b/o3d/samples/io/actors/horizontalpad.js @@ -0,0 +1,85 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the HorizontalPad class. + */ + +/** + * A Horizontal Floater. + */ +function HorizontalPad(initObj) { + this.absorbNamedValues(initObj); + this.maxSpeed = 4 * 20; + this.moveAmount = 4 * 20; + this.width = 42; + this.height = 1; +} +HorizontalPad.prototype = new Actor; + +HorizontalPad.prototype.onTick = function(timeElapsed) { + // When you attach me to a platform, I make it so nobody + // can stand on it... only me. + world.platforms[this.platformID].isNotSolid = true; + + // I move based off of the platform that I'm on. So get that now. + var myPlatform = world.platforms[this.platformID]; + + // I bounce back and forth between the left and right points on my platform. + if (this.mapX < myPlatform.left.mapX) { + this.moveAmount += 1; + } else if (this.mapX > myPlatform.right.mapX) { + this.moveAmount -= 1; + } else if (this.moveAmount >= 0) { + this.moveAmount = this.maxSpeed; + } else { + this.moveAmount = -this.maxSpeed; + } + + // I match my rotation to that of my platform. + this.rotZ = myPlatform.rotZ; + + // Here's how I move. moveMapX is a handy function that updates both + // my "virtual 2d world" mapX, as well as my literal x + y values + this.moveMapX(this.moveAmount * timeElapsed) + + // If I collide with the avatar, then move the avatar along with me, + // and set his "override" groundZ to be my own Z. + if (this.collidesWith(avatar)) { + if (avatar.velZ <= 0 && avatar.z >= this.z - 25) { + avatar.moveMapX(this.moveAmount * timeElapsed); + avatar.groundZ = this.z; + } + } + + updateActor(this); +} diff --git a/o3d/samples/io/actors/mover.js b/o3d/samples/io/actors/mover.js new file mode 100644 index 0000000..8a36eed --- /dev/null +++ b/o3d/samples/io/actors/mover.js @@ -0,0 +1,48 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the Mover class. + */ + +/** + * A Horizontal Floater. + */ +function Mover(initObj) { + this.absorbNamedValues(initObj); +} +Mover.prototype = new Actor; + +Mover.prototype.onTick = function(timeElapsed) { + this.z += 1 * 20 * timeElapsed; + updateActor(this); +} diff --git a/o3d/samples/io/actors/spikem.js b/o3d/samples/io/actors/spikem.js new file mode 100644 index 0000000..e056c98 --- /dev/null +++ b/o3d/samples/io/actors/spikem.js @@ -0,0 +1,126 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the Spikem class. + */ + +/** + * A Horizontal Floater. + */ +function Spikem(initObj) { + this.absorbNamedValues(initObj); + this.width = 24; + this.height = 55; + this.velX = -200; + this.velZ = 0; + this.isDead = false; + this.isHit = false; + this.pauseFrames = 0; + this.frameName = "spinning" +} +Spikem.prototype = new Actor; + +Spikem.prototype.onTick = function(timeElapsed) { + if (this.isDead == true) { + return; + } + + if (this.isHit == true) { + if (this.z < -1000) { + isDead = true; + } else { + this.velX = this.velX*.9; + // Here's how I move. moveMapX is a handy function that updates both + // my "virtual 2d world" mapX, as well as my literal x + y values + this.z -= 20; + this.moveMapX(this.velX * timeElapsed) + } + } else { + // I move based off of the platform that I'm on. So get that now. + var myPlatform = world.platforms[this.platformID]; + + // I stay on my platform + if (this.mapX - this.width/2 < myPlatform.left.mapX + && this.velX < 0) { + this.velX *= -1; + } else if (this.mapX + this.width/2 > myPlatform.right.mapX + && this.velX > 0) { + this.velX *= -1; + } + + this.rotZ += this.velX / 60 * timeElapsed; + + if (Math.abs(this.velX) < .1) { + if (Math.random() > .5) { + this.velX = -400; + } else { + this.velX = 400; + } + this.pauseFrames = Math.random() * 0.5 + 1; + } + + if (this.pauseFrames > 0) { + this.frameName = "spinning" + this.pauseFrames -= timeElapsed; + } else { + this.frameName = "charging" + this.velX = this.velX*.9; + // Here's how I move. moveMapX is a handy function that updates both + // my "virtual 2d world" mapX, as well as my literal x + y values + this.moveMapX(this.velX * timeElapsed) + } + + if (this.isHitBySword()) { + this.isHit = true; + soundPlayer.play('sound/_SMASH.mp3', 100); + this.velX = 0; + } else if (this.isHitByArrow()) { + top.arrowActor.hide(); + this.isHit = true; + soundPlayer.play('sound/_SMASH.mp3', 100); + this.velX = top.arrowActor.velX; + } else if (this.collidesWith(avatar)) { + // Play an event sound @100% volume, 0 repeats + soundPlayer.play('sound/ah.mp3', 100); + + this.velZ = 0; + if (avatar.velX < 1) { + avatar.velX = this.velX * 7; + } else { + avatar.velX = avatar.velX * -7; + } + } + } + + updateActor(this); +} diff --git a/o3d/samples/io/actors/verticalpad.js b/o3d/samples/io/actors/verticalpad.js new file mode 100644 index 0000000..fd90425 --- /dev/null +++ b/o3d/samples/io/actors/verticalpad.js @@ -0,0 +1,84 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines the VerticalPad class. + */ + +/** + * A Vertical Pad you can run on. These things oscillate between their starting + * position and a z of 350" + */ +function VerticalPad(initObj) { + this.absorbNamedValues(initObj); + this.maxSpeed = 4 * 20; + this.moveAmount = 4 * 20; + this.bottomZ = this.z; + this.topZ = 350; + this.width = 42; + this.height = 10; +} +VerticalPad.prototype = new Actor; + +VerticalPad.prototype.onTick = function(timeElapsed) { + // I bounce back and forth between the left and right points on my platform. + if (this.z < this.bottomZ) { + this.moveAmount += 1; + } else if (this.z > this.topZ) { + this.moveAmount -= 1; + } else if (this.moveAmount >= 0) { + this.moveAmount = this.maxSpeed; + } else { + this.moveAmount = -this.maxSpeed; + } + + // I match my rotation to that of my platform. + var myPlatform = world.platforms[this.platformID]; + this.rotZ = myPlatform.rotZ; + + + this.z += this.moveAmount * timeElapsed; + + // If I collide with the avatar, then move the avatar along with me, + // and set his "override" groundZ to be my own Z. + if (this.collidesWith(avatar)) { + if (avatar.velZ <= 0 && avatar.z >= this.z - 45) { + avatar.z = this.z + if (this.moveAmount < 0) { + avatar.z += this.moveAmount * timeElapsed; + } + avatar.groundZ = avatar.z; + } + } + + updateActor(this); +} diff --git a/o3d/samples/io/autoincludes.js b/o3d/samples/io/autoincludes.js new file mode 100644 index 0000000..be2163f --- /dev/null +++ b/o3d/samples/io/autoincludes.js @@ -0,0 +1,49 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This file was auto-generated by a SketchUp ruby script. Include this in your + * game and everything else will load right in. + * + * WARNING: This file will be overwritten when you publish a new level from + * SketchUp, so if you wan to manually modify it, you've been warned. :) + */ +document.write('<script type="text/javascript" src="actors/actor.js"></script>'); +document.write('<script type="text/javascript" src="actors/arrow.js"></script>'); +document.write('<script type="text/javascript" src="actors/avatar.js"></script>'); +document.write('<script type="text/javascript" src="actors/coin.js"></script>'); +document.write('<script type="text/javascript" src="actors/horizontalpad.js"></script>'); +document.write('<script type="text/javascript" src="actors/mover.js"></script>'); +document.write('<script type="text/javascript" src="actors/spikem.js"></script>'); +document.write('<script type="text/javascript" src="actors/verticalpad.js"></script>'); + +document.write('<script type="text/javascript" src="levels/all_actors.js"></script>'); +document.write('<script type="text/javascript" src="levels/map1.js"></script>'); diff --git a/o3d/samples/io/cutscenes.js b/o3d/samples/io/cutscenes.js new file mode 100644 index 0000000..376a7845 --- /dev/null +++ b/o3d/samples/io/cutscenes.js @@ -0,0 +1,148 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file isn't important to the actual game. It just runs + * pretty animations outside the o3d window. + */ + +/** + * "Opens" the cover. This thing calls itself again and again until it's done. + * @param {number} lastPercent Number from 0 to 100 representing how "done" + */ +function animateCover(lastPercent) { + // Move 10% more toward a 100% animation + lastPercent = ifEmpty(lastPercent,0); + lastPercent = lastPercent + 10; + + // Play a nice sound. + if (lastPercent == 10) { + soundPlayer.play('sound/page.mp3', 100); + $('innercover-div').style.width = $('book-left').offsetWidth; + $('book-left').style.width = $('book-left').offsetWidth; + } + + // Transform the cover graphic from "closed" to "open." If we're more than + // 50% along the way, then this cover gets hidden. + var cover = $('cover') + var innerCover = $('innercover') + + var factor = Math.abs(Math.cos(lastPercent/50*Math.PI/2)); + if (lastPercent < 50){ + cover.style.width = factor * 1000; + cover.style.height = 600; + } else { + cover.visibility = 'hidden'; + cover.style.width = 1; + innerCover.style.width = factor * 1000; + innerCover.style.height = 600; + } + + var shadow = $('cover-shadow'); + if (lastPercent <= 70) { + factor = Math.abs(Math.cos(lastPercent/70*Math.PI/2)); + shadow.style.width = factor * 1000; + shadow.style.height = 600; + shadow.style.opacity = (70 - lastPercent)/70; + } + + if (lastPercent < 100) { + setTimeout('animateCover(' + lastPercent + ')',100); + } else { + shadow.style.visibility = 'hidden'; + } +} + + +/** + * "Opens" a page. This thing calls itself again and again until it's done. + * @param {string} id HTML element ID of the page image that we're animating. + * @param {number} lastPercent Number from 0 to 100 representing how "done" + */ +function animatePage(id, lastPercent) { + // Transform the page graphic from "closed" to "open." If we're more than + // 50% along the way, then this cover gets hidden. + var page = $(id) + page.style.zIndex = 200; + lastPercent = ifEmpty(lastPercent,0); + + // if we've already animated this page... don't do it again. + if (parseInt(page.style.width) < 900 && lastPercent == 0) { + return; + } + + // Move 10% more toward a 100% animation + lastPercent = lastPercent + 10; + + // Play a nice sound. + if (lastPercent == 10) { + soundPlayer.play('sound/page.mp3', 100); + } + + var factor = Math.abs(Math.cos(lastPercent/50*Math.PI/2)); + if (lastPercent < 50) { + page.style.width = factor * 951; + page.style.height = 549; + } else { + page.visibility = 'hidden'; + page.style.width = 1; + } + + var shadow = $('cover-shadow') + var coverDiv = $('cover-div') + + if (lastPercent <= 70){ + coverDiv.style.zIndex = 99; + factor = Math.abs(Math.cos(lastPercent/70*Math.PI/2)); + shadow.style.width = factor * 1000; + shadow.style.height = 600; + shadow.style.opacity = (70 - lastPercent)/70; + shadow.style.visibility = 'visible'; + } + + // Fade in a bit for the start of the animated shadow. + if (lastPercent <= 20) { + shadow.style.opacity = (lastPercent/30); + } + + if (lastPercent < 100) { + setTimeout('animatePage("' + id + '",' + lastPercent + ')',100); + } else { + shadow.style.visibility = 'hidden'; + if (id == "page2") { + // We'll fire the animation of page 3 after 2 seconds. + setTimeout('animatePage("page3")',2000); + } else if (id == "page3") { + loadLevel(0); + } + } +} diff --git a/o3d/samples/io/dynamic_lights.js b/o3d/samples/io/dynamic_lights.js new file mode 100644 index 0000000..9a5b1f9 --- /dev/null +++ b/o3d/samples/io/dynamic_lights.js @@ -0,0 +1,123 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview Manage all the dynamic lights in a level. + */ + + +var s_light_array = new Array(); +var s_number_of_lights_in_scene = 0; + +var s_number_of_lights_in_program = 0; +var s_light_parameter_array = new Array(); + +// Call this before any UpdateLightsInProgram. +function InitializeLightParameters(context, number_of_lights) { + s_number_of_lights_in_program = number_of_lights; + for (var l = 0; l < number_of_lights; ++l) { + s_light_parameter_array[l] = {}; + s_light_parameter_array[l].location = context.createParam( + 'light' + l + '_location', 'ParamFloat3'); + s_light_parameter_array[l].location.value = [0, 0, 0]; + + // For the light, the final color parameter is the attentuation. + s_light_parameter_array[l].color = context.createParam( + 'light' + l + '_color', 'ParamFloat4'); + s_light_parameter_array[l].color.value = [0, 0, 0, 1]; + } +} + +// Returns the index of the new light for future manipulation. +// World location and color should be arrays. +// These will be assigned to Param objects. +function AddLight(world_location, color) { + var light_index = s_number_of_lights_in_scene++; + s_light_array[light_index] = {}; + s_light_array[light_index].location = world_location; + s_light_array[light_index].color = color; + return light_index; +} + +// Sets the shader parameters to render using the closest lights +// to the 'focus' (whatever's passed in). +// |focus_location| must provide .x, .y, and .z for determining the +// distance to each light. +function UpdateLightsInProgram(focus_location) { + // TODO: Modulate the lights' color / add behaviors for the lights. + var lights_to_render = new Array(); + for (var i = 0; i < s_number_of_lights_in_program; ++i) { + lights_to_render[i] = {}; + lights_to_render[i].distance = 10000000000000.0; // Arbitrary large number. + lights_to_render[i].index = -1; + } + var number_of_lights = s_number_of_lights_in_scene; + for (var l = 0; l < number_of_lights; ++l) { + var x_diff = s_light_array[l].location.x - focus_location.x; + var y_diff = s_light_array[l].location.y - focus_location.y; + // TODO: This should be focus_location.z, but the avatar's location that is + // passed in is offset from the world coordinates. For our relatively flat + // levels, this works more predictably. + var z_diff = s_light_array[l].location.z - 0; + var distance_to_focus = x_diff * x_diff + y_diff * y_diff + z_diff * z_diff; + // This may change if we assign to an entry early in the list. + var index_to_assign = l; + for (var i = 0; i < s_number_of_lights_in_program; ++i) { + if (distance_to_focus < lights_to_render[i].distance) { + // Swap the index into this entry. We will percolate the + // light up. + var replaced_index = lights_to_render[i].index; + lights_to_render[i].index = index_to_assign; + index_to_assign = replaced_index; + + var replaced_distance = lights_to_render[i].distance; + lights_to_render[i].distance = distance_to_focus; + distance_to_focus = replaced_distance; + } + if (index_to_assign < 0) { + break; + } + } + } + + // Finally, assign to the actual shader parameters. + for (var i = 0; i < s_number_of_lights_in_program; ++i) { + var light_index = lights_to_render[i].index; + if (light_index >= 0) { + s_light_parameter_array[i].location.value = + s_light_array[light_index].location; + s_light_parameter_array[i].color.value = + s_light_array[light_index].color; + } + } +} + diff --git a/o3d/samples/io/editor.html b/o3d/samples/io/editor.html new file mode 100644 index 0000000..a212e58 --- /dev/null +++ b/o3d/samples/io/editor.html @@ -0,0 +1,126 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<html> +<head> + <title>Level Editor - Don't open this is a browser. + It's only good inside a SketchUp WebDialog</title> + <script type="text/javascript" src="init.js"></script> + <script type="text/javascript" src="autoincludes.js"></script> + <script type="text/javascript" src="gamelogic.js"></script> + <script type="text/javascript" src="sound/soundplayer.js"></script> + +<script> +function parseWorld() { + url = 'skp:parse_world'; + window.location.href = url; +} + +function play() { + $('play-button').disabled = false; + $('pause-button').disabled = true; + + url = 'skp:do_play@'; + window.location.href = url; + +} + +function pause() { + + $('play-button').disabled = false; + $('pause-button').disabled = true; + clearTimeout(timerID) +} + +function save() { + url = 'skp:do_save@'; + window.location.href = url; +} + +function startNew() { + name = prompt("What do you want to call your new level?\n" + + "(Choose wisely... you can't rename yet.)","My First Level"); + url = 'skp:do_new@'; + url += 'name=' + name; + window.location.href = url; + $('export-button').disabled = false; + $('play-button').disabled = false; +} + +function setWorldFromName(name) { + output.innerHTML += '<script type="text/javascript" src="autoincludes.js"><' + '/script>'; + for (i=0;i<levels.length; i++) { + //alert('looking at ' + levels[i].colladaFile); + if (levels[i].colladaFile == name + '.o3dtgz') { + world = levels[i]; + avatar = levels[i].actors[0]; + nextFrame(); + $('pause-button').disabled = false; + $('play-button').disabled = true; + break; + } + } + +} + +</script> +</head> +<style> +A { font-family: sans-serif; text-decoration: none; } +A:link { color: yellow; } +A:visited { color: yellow; } +A:active { color: yellow; } +A:hover { color: yellow; } +BODY { font-family: sans-serif; } +INPUT { width: 100%; text-align: left; padding-left: 6px; margin-top: 3px;} +.head { background-color: black; color: gold; font-weight: bold; padding: 6px; } +.levellink { + color: blue; + text-decoration: underline; + cursor: pointer; + +} +</style> +<body style="background-color:threedface;" onload="init()"> + <div class="head">Select an action...</div> + <input type="button" onclick="startNew()" value="Start a new level from a template"> + <input id="export-button" type="button" onclick="save()" disabled="true" value="Save this file and export to O3D"> + <input id="play-button" type="button" disabled="true" onclick="play();" value="Play the level inside SketchUp"> + <input id="pause-button" type="button" disabled="true" onclick="pause();" value="Pause playback"> + + <br><div class="head">Or select an existing level to load...</div> + + <span id="content">List...</span> + + <span id="output"></span> +</body> +</html> + diff --git a/o3d/samples/io/gamelogic.js b/o3d/samples/io/gamelogic.js new file mode 100644 index 0000000..65f5ff6 --- /dev/null +++ b/o3d/samples/io/gamelogic.js @@ -0,0 +1,578 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file sets up the game state JS structures, sets up + * keyboard handlers, and contains the main game loop. + */ + + /** + * Global constants that drive the game engine. + */ +var FRAMES_PER_SECOND = 20; // Change for a faster or slower game. +var FRAME_DELAY = 1000 / FRAMES_PER_SECOND; // Milliseconds between frames. +var GRAVITY = -2000; // Inches per second per second. +var JUMP_VELOCITY = 650; +var RUN_VELOCITY = 200; +var WORLD_ANGLE = 0; +var CAMERA_SOFTNESS = 15; + + +/** + * These are some global pointers that we'll use for to point at our world + * object (aka "current map" or "current level"), and our happy avatar (aka + * the protagonist, Prince Io.) + */ +var world; +var avatar; + +/** + * Keyboard constants. + */ +var BACKSPACE = 8; +var TAB = 9; +var ENTER = 13; +var SHIFT = 16; +var CTRL = 17; +var ALT = 18; +var ESCAPE = 27; +var PAGEUP = 33; +var PAGEDOWN = 34; +var END = 35; +var HOME = 36; +var LEFT = 37; +var UP = 38; +var RIGHT = 39; +var DOWN = 40; +var DELETE = 46; +var SPACE = 32; + +/** + * These variables are special SketchUp constants that aren't really constant. + * They are updated by SketchUp every frame to indicate what's around the + * avatar. + * TODO: ADDENDUM! These vars used to be "special constants," + * but now they're leftovers of a time when SU was the main engine, and the + * game logic below should be cleaned up so we're not using all caps on these. + */ +var GROUNDZ; // Absolute Z of the obstacle beneath the avatar. +var OBSTACLE_LEFT; // Distance to nearest obstacle to the left. +var OBSTACLE_RIGHT; // Distance to nearest obstacle on the right. + +/** + * Camera position stuff. + * TODO: These are redundant vs. the camera.eye.x stuff in + * init.js. Clean that outa thar! + */ +var eyeX = 0; +var eyeY = -1000; +var eyeZ = 1000; +var targetX = 0; +var targetY = 0; +var targetZ = 0; + +/** + * If the user presses the swing button while we're showing a swing, then we'll + * mark the fact that we need to immediately swing again once the current + * animation is done. + */ +var swingAgain = false; + +/** + * Way of determining that the user just pressed then unpressed certain keys. + */ +var upWasJustDown = false; +var ctrlWasJustUp = false; + +/** + * Identifier for our global game timer. This is only used when SketchUp is the + * main CG engine. + */ +var timerID; + +/** + * Code to keep track of the current key state. Since these events can fire at + * any time but we only want to apply changes to our game state at the start of + * each game loop, we do this trick so that the nextFrame() function can poll + * the keyIsDown data structure to determine what's happened since the last + * frame. + */ +var keyIsDown = {}; + +function keyMessage(e, state) { + keyIsDown[o3djs.event.getEventKeyChar(e ? e : window.event)] = state; +} + +document.onkeydown = function(e) { keyMessage(e, true); }; + +document.onkeyup = function(e) { keyMessage(e, false); }; + + +/** + * Main Game Loop.... Here's where we actually run the game. + * @param {number} elapsedTime Number of seconds since we were last called. + */ +function nextFrame(elapsedTime) { + // First, let's look at our avatar. If he's jumping, then figure out which + // platform (if any) he's currently over. + if (avatar.isJumping) { + var lowestZFound = -5000; + for (var i = 0; i < world.platforms.length; i++) { + platform = world.platforms[i]; + if (platform.parentID == avatar.parentPlatformID || + i == avatar.parentPlatformID) { + if (avatar.z > platform.z && + avatar.mapX > platform.left.mapX && + avatar.mapX < platform.right.mapX && + platform.z > lowestZFound && platform.isNotSolid != true) { + lowestZFound = world.platforms[i].z + avatar.platformID = i; + } + } + } + } + + // Create a myPlatform variable for convenience. + var myPlatform = world.platforms[avatar.platformID] + + // Platforms without a parentID aren't really platforms. The actually define + // the "world path" that meanders through our level. Therefore, if the only + // platform that Io is over is one of these, then our current GROUNDZ (aka + // the nearest walkable altitude), + if (exists(myPlatform.parentID)) { + GROUNDZ = myPlatform.z + avatar.parentPlatformID = myPlatform.parentID; + } else { + GROUNDZ = -5000; + avatar.parentPlatformID = avatar.platformID; + } + + // The avatar's mapX is really important. It defines his position in the + // imaginary 2d platformer that we weave through a 3D world. When he's at + // mapX of 0, he's at the far left of the level (think super mario.) As + // he proceeds through the level, his mapX will get bigger. Meanwhile, his + // actual x, y, and z (aka altitude) values will be kept track of as well. + // Anyway, every platform that Io can stand on has a "left" and a "right" + // to them. Let's check to see if we've walked off of it... + if (avatar.mapX < myPlatform.left.mapX) { + // Whoa! We've walked off the left of our platform! If there's an adjacent + // platform to step onto, then do that. Otherwise, it's fallin' time. + if (exists(myPlatform.left.adjacentID)) { + // Do some math to ensure that our actual x and y values are corrected + // so Io stays perfectly in our "world path" plane. + oldPlatform = myPlatform; + overshot = avatar.mapX - myPlatform.left.mapX; + avatar.platformID = myPlatform.left.adjacentID; + myPlatform = world.platforms[avatar.platformID]; + avatar.x -= Math.cos(oldPlatform.rotZ) * overshot; + avatar.y -= Math.sin(oldPlatform.rotZ) * overshot; + avatar.x += Math.cos(myPlatform.rotZ) * overshot; + avatar.y += Math.sin(myPlatform.rotZ) * overshot; + } else { + GROUNDZ = -5000; + } + } else if (avatar.mapX > myPlatform.right.mapX) { + // Whoa! We've walked off the right of our platform! + if (exists(myPlatform.right.adjacentID)) { + oldPlatform = myPlatform; + overshot = avatar.mapX - myPlatform.right.mapX; + avatar.platformID = myPlatform.right.adjacentID; + myPlatform = world.platforms[avatar.platformID]; + avatar.x -= Math.cos(oldPlatform.rotZ) * overshot; + avatar.y -= Math.sin(oldPlatform.rotZ) * overshot; + avatar.x += Math.cos(myPlatform.rotZ) * overshot; + avatar.y += Math.sin(myPlatform.rotZ) * overshot; + } else { + GROUNDZ = -5000; + } + } + + // Now it's time to figure out if there's a "obstacle" nearby. Each platform + // can potentially have a left.obstacleHeight and/or a right.obstableHeight. + // We'll store how close any of them are in these OBSTABLE_LEFT type + // "constants." + OBSTACLE_RIGHT = 9000 + OBSTACLE_RIGHT_HEIGHT = 0 + OBSTACLE_LEFT = 9000 + OBSTACLE_LEFT_HEIGHT = 0 + + if (myPlatform.right.obstacleHeight > 0) { + OBSTACLE_RIGHT = myPlatform.right.mapX - avatar.mapX; + OBSTACLE_RIGHT_HEIGHT = myPlatform.right.obstacleHeight - avatar.velZ + 20; + } + if (myPlatform.left.obstacleHeight > 0) { + OBSTACLE_LEFT = avatar.mapX - myPlatform.left.mapX; + OBSTACLE_LEFT_HEIGHT = myPlatform.left.obstacleHeight - avatar.velZ + 20; + } + + // So... now that we've figured all of that stuff out, let's store how + // far *above* the current platform Io is. + avatar.relativeZ = avatar.z - myPlatform.z; + + // This special variable, avatar.groundZ, can be set by moving + // platforms and other actors to override our actual groundZ. This allows + // the avatar to "float" in space (or really, to stand on stuff that's + // not a static platform but a moving one.) So if we find that variable, + // it trumps the calculated GROUNDZ. However, we *always* clear that + // variable out after using it. It's up to the Actor who is moving Io to + // keep this updated inside their onTick event. (See horizontalpad.js for + // an example of this.) + if (exists(avatar.groundZ)) { + GROUNDZ = avatar.groundZ; + avatar.groundZ = undefined; + } + + // Gah. Another one of our "special constants" that used to be updated + // by SketchUp but now is done via JS data structures. + // TODO: Clean 'tup. + WORLD_ANGLE = myPlatform.rotZ; + + // Check for keyboard stuff. + handleInput(); + + // Handle falling and gravity. + avatar.z += avatar.velZ * elapsedTime; + if (avatar.z - GROUNDZ > 1) { + avatar.isJumping = true; + } else { + if (avatar.isJumping == true) { + soundPlayer.play('sound/step2.mp3', 100); + } + avatar.isJumping = false; + } + if (avatar.isJumping == true) { + avatar.velZ += GRAVITY * elapsedTime; + } + if (avatar.z < GROUNDZ) { + avatar.velZ = 0; + avatar.z = GROUNDZ + .1; + avatar.isJumping = false; + avatar.animation = 'Hero_Run'; + + } + if (avatar.z < -1000) { + avatar.x = 0; + avatar.y = 0; + avatar.z = 200; + avatar.mapX = 0; + avatar.platformID = 0; + avatar.parentPlatformID = 0; + } + + // Handle collision with things to the left and right of our avatar. + // From here is where we start to decide which animation cycle we're on. + // Now you can see how we're using avatar.relativeZ along with our + // OBSTACLE_FOO "special constants" to determine not only if we've hit an + // obstacle, but whether we've jumped high enough to get over it. + if (OBSTACLE_LEFT < 25 && keyIsDown[LEFT] && + OBSTACLE_LEFT_HEIGHT > avatar.relativeZ) { + avatar.targetVelX = 0; + avatar.animation = 'Hero_Stand'; + avatar.frame = 1; + } + if (OBSTACLE_RIGHT < 25 && keyIsDown[RIGHT] && + OBSTACLE_RIGHT_HEIGHT > avatar.relativeZ) { + avatar.targetVelX = 0; + avatar.animation = 'Hero_Stand'; + avatar.frame = 1; + } + + // If we're jumping, then use the jumping animation cycle. + if (avatar.isJumping == true) { + avatar.animation = 'Hero_Jump'; + if (avatar.velZ > 0) { + avatar.frame += elapsedTime * 20; + if (avatar.frame > 3) { + avatar.frame = 3; + } + } else { + if (avatar.z > GROUNDZ + 20) { + avatar.frame = 4; + } else { + avatar.frame = 5; + } + } + } + + // Figure out which frame to display inside our current cycle. + didSwordStrike = '0'; + if (avatar.animation == 'Hero_Run') { + avatar.frame += elapsedTime * 20; + if (avatar.frame > 10) { + avatar.frame = 1; + } + if (Math.floor(avatar.frame % 5) == 0) { + var soundToPlay = 'sound/step' + soundToPlay += (Math.floor(Math.random() * 3) + 1); + soundToPlay += '.mp3' + soundPlayer.play(soundToPlay, 100); + } + } else if (avatar.animation == 'Hero_Sword') { + avatar.targetVelX = 0; + avatar.framesSinceShot = 0; + avatar.frame += avatar.swordRate * 20 * elapsedTime; + if (avatar.frame < 1) { + avatar.animation = 'Hero_Stand' + avatar.frame = 1; + } else if (avatar.frame > 7) { + avatar.swordRate = -.5; + avatar.frame = 6.2; + didSwordStrike = '1'; + } else if (avatar.frame == 3 && avatar.swordRate < 0) { + if (swingAgain == true) { + avatar.swordRate = 1; + swingAgain = false; + } else { + avatar.swordRate = -.5; + } + } + + if (avatar.frame == 3 && avatar.swordRate > 0) { + soundPlayer.play('sound/_MISS.mp3', 100); + } + } + + // Update our position. + avatar.velX = (avatar.velX + avatar.targetVelX + avatar.targetVelX) / 3; + if (Math.abs(avatar.velX) < .2) { + avatar.velX = 0; + } + avatar.mapX += avatar.velX * elapsedTime; + avatar.x += avatar.velX * Math.cos(WORLD_ANGLE) * elapsedTime; + avatar.y += avatar.velX * Math.sin(WORLD_ANGLE) * elapsedTime; + avatar.rotZ = (avatar.rotZ + avatar.targetRotZ + avatar.targetRotZ) / 3; + + // Calculate our final frameName string to pass to SketchUp (or o3d). + frameName = avatar.animation; + if (avatar.frame < 10) { + frameName += '0'; + } + frameName += Math.floor(avatar.frame); + if (avatar.framesSinceShot > 0) { + frameName += 'Shoot'; + avatar.framesSinceShot--; + } + if (avatar.framesSinceShot == 3) { + // TODO: Make this work with multiple arrows, perform + // better, and be smart enough to handle level reloads. + if (top.arrowActor == undefined) { + for (var actorID = 0; actorID < world.actors.length; actorID++) { + arrow = world.actors[actorID]; + if (arrow.name.indexOf('Arrow') == 0) { + top.arrowActor = arrow; + top.arrowActor.shoot(); + } + } + } else { + top.arrowActor.shoot(); + } + } + avatar.frameName = frameName; + + // Here's where we send our state down to SketchUp or O3D. + // Always do our avatar last, since he's the one likely to have + // been modified by other things in the environment. (Our avatar + // is guaranteed by the level exporter to be in world.actors[0]) + for (i = world.actors.length - 1; i >= 0; i--) { + world.actors[i].onTick(elapsedTime); + } + + // Now move the camera in a pleasing motion to float over Io's + // right shoulder. (Well, it's his right shoulder when he's + // facing "right" toward the end of the level.) + newEyeX = avatar.x + 350 * Math.sin(WORLD_ANGLE); + newEyeY = avatar.y - 350 * Math.cos(WORLD_ANGLE); + newEyeZ = avatar.z + 150; + eyeX = (newEyeX + eyeX * CAMERA_SOFTNESS) / (CAMERA_SOFTNESS + 1); + eyeY = (newEyeY + eyeY * CAMERA_SOFTNESS) / (CAMERA_SOFTNESS + 1); + eyeZ = (newEyeZ + eyeZ * CAMERA_SOFTNESS) / (CAMERA_SOFTNESS + 1); + targetX = (avatar.x + targetX) / 2; + targetY = (avatar.y + targetY) / 2; + targetZ = (avatar.z + 200 + targetZ * 3) / 5; + + // Here's where we send our camera down to SketchUp or O3D. + updateCamera(targetX, targetY, targetZ, eyeX, eyeY, eyeZ) + + // If we're running inside SketchUp, clear out our old timer and set a new + // one. + if (isSU) { + clearTimeout(timerID); + timerID = self.setTimeout('nextFrame()', FRAME_DELAY); + } +} + + +/** + * Sends our state to our render engine. (See knightgame.rb for the Sketchup + * ruby handler.) + * @param {Object} actor An instance of an Actor object. + */ +function updateActor(actor) { + var frameName = actor.frameName; + var x = actor.x; + var y = actor.y; + var z = actor.z; + var rotZ = actor.rotZ; + + // Sending stuff to SU vs. to O3D. + if (isSU == true) { + url = 'skp:push_frame_js@'; + url += 'name=' + actor.name; + url += '&frame=' + frameName; + url += '&x=' + x; + url += '&y=' + y; + url += '&z=' + z; + url += '&rotz=' + rotZ; + window.location.href = url; + } else { + // For performance reasons, we want to cache node pointers directly onto + // our Actor object, so we don't have to look it all up every time. + if (actor.nodesHaveBeenCached != true) { + actor.hasBeenCached = true; + nodes = client.getObjects(actor.colladaID, 'o3d.Transform'); + actor.node = nodes[0]; + + var instance = actor.node.children[0]; + actor.children = instance.children; + actor.nodesHaveBeenCached = true; + } + + var m = math.matrix4.rotationZYX([0, rotZ, 0]); + math.matrix4.setTranslation(m, [x, z, -y]); + actor.node.localMatrix = m; + + if (!isEmpty(frameName)) { + for (var c = 0; c < actor.children.length; c++) { + var child = actor.children[c]; + child_name = child.name; + child.visible = (child_name == frameName || + child_name == frameName + '1' || + child_name == frameName + '_1'); + } + } + } +} + +/** + * Sends our state down to SketchUp or o3d. (See knightgame.rb for the handler.) + * @param {number} targetX Where we want the camera to point at. + * @param {number} targetY Where we want the camera to point at. + * @param {number} targetZ Where we want the camera to point at. + * @param {number} eyeX Where we want the camera to point from. + * @param {number} eyeY Where we want the camera to point from. + * @param {number} eyeZ Where we want the camera to point from. + */ +function updateCamera(targetX, targetY, targetZ, eyeX, eyeY, eyeZ) { + if (isSU == true) { + url = 'skp:push_camera@'; + url += 'targetX=' + targetX; + url += '&targetY=' + targetY; + url += '&targetZ=' + targetZ; + url += '&eyeX=' + eyeX; + url += '&eyeY=' + eyeY; + url += '&eyeZ=' + eyeZ; + window.location.href = url; + } else { + var target = [targetX, targetZ, -targetY]; + var eye = [eyeX, eyeZ, -eyeY]; + var up = [0, 1, 0]; + var view_matrix = math.matrix4.lookAt(eye, target, up); + + drawContext.view = view_matrix; + + // !lacz modified! + camera_eye_param.value = eye; + camera_target_param.value = target; + } +} + +/** + * Checks for keyboard stuff. + */ +function handleInput() { + if (keyIsDown[SPACE]) { + avatar.framesSinceShot = 5; + } + + if (keyIsDown[DOWN]) { + if (avatar.animation == 'Hero_Sword') { + if (ctrlWasJustUp == true) { + swingAgain = true; + } + } else { + avatar.animation = 'Hero_Sword'; + avatar.frame = 1; + avatar.swordRate = 1; + ctrlWasJustUp = false; + } + } else { + ctrlWasJustUp = true; + } + + if (keyIsDown[UP] && avatar.isJumping != true && upWasJustDown == false) { + avatar.velZ = JUMP_VELOCITY; + avatar.isJumping = true; + upWasJustDown = true; + } + if (keyIsDown[UP]) { + upWasJustDown = true; + } else { + upWasJustDown = false; + } + + if (keyIsDown[RIGHT] || keyIsDown[LEFT]) { + if (avatar.animation == 'Hero_Stand' && avatar.frame == 1) { + avatar.frame = 2; + } else if (avatar.animation == 'Hero_Stand' && avatar.frame == 2) { + avatar.animation = 'Hero_Run'; + avatar.frame = 1; + } + + } else { + if (avatar.animation == 'Hero_Run') { + avatar.animation = 'Hero_Stand'; + avatar.frame = 2; + } else if (avatar.animation == 'Hero_Stand' && avatar.frame == 2) { + avatar.frame = 1; + } + } + + if (keyIsDown[RIGHT]) { + avatar.targetVelX = RUN_VELOCITY; + avatar.targetRotZ = WORLD_ANGLE; + } else if (keyIsDown[LEFT]) { + avatar.targetVelX = -RUN_VELOCITY; + avatar.targetRotZ = -(Math.PI) + WORLD_ANGLE; + } else { + avatar.targetVelX = 0; + } +} diff --git a/o3d/samples/io/init.js b/o3d/samples/io/init.js new file mode 100644 index 0000000..e6c145f --- /dev/null +++ b/o3d/samples/io/init.js @@ -0,0 +1,395 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file creates all of the global o3d stuff that + * establishes the plugin window, sets its size, creates necessary light + * and camera parameters, and stuff like that. + */ +o3djs.require('o3djs.util'); +o3djs.require('O3D.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.pack'); +o3djs.require('o3djs.scene'); + +// Create some globals that store our main pointers to o3d objects. +var o3d; +var math; +var math; +var client; +var pack; +var globalParams; +var g_viewInfo; +var drawContext; +var blackSampler; +var g_loadInfo; + +// This variable keeps track of whether a collada file is correctly loaded. +var isLoaded = false; + +// This variable, surprisingly, contains the time since the last frame +// (in seconds) +var timeSinceLastFrame = 0; +var frameCount = 0; + +// This is only a handy data structure for storing camera information. It's not +// actually a core O3D object. +var camera = { + eye: [0, 0, 500], + target: [0, 0, 0] +}; + +/** + * This is a top-level switch that tells us whether we're running inside a + * SketchUp web dialog. (If not, then we're in O3D.) + * TODO : Re-enable the SketchUp web-dialog functionality, but through + * a check different than simply testing if we are running in IE. + */ +//var isSU = (navigator.appVersion.indexOf('MSIE') != -1) ? true : false; +var isSU = false; + +// Some parameters to pass to the shaders as the camera moves around. +var camera_eye_param; +var camera_target_param; + +// Keep track of the lights in the level. +var light_array; +var max_number_of_lights = 4; // Determined from the GPU effect. + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Gets called at the page's onLoad event. This function sets up our plugin and + * level selection UI. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Walk across all levels loaded by includes.js and show a list for the user + // to choose from. + $('content').innerHTML = 'Choose a level...<br>'; + for (var i = 0; i < levels.length; i++) { + var level = levels[i]; + var str = '<span class="levellink" onclick="loadLevel(' + i + ')">' + + level.name + '</span><br>' + $('content').innerHTML += str; + } + + soundPlayer.play('sound/music.mp3', 100, 999); + + // If we're NOT running inside SketchUp, then we need to set up our o3d + // window. + if (!isSU) { + var o3dElement = clientElements[0]; + o3dElement.id = 'o3dObj'; + o3d = o3dElement.o3d; + math = o3djs.math; + client = o3dElement.client; + pack = client.createPack(); + var blackTexture = pack.createTexture2D(1, 1, o3d.Texture.XRGB8, 1, false); + blackTexture.set(0, [0, 0, 0]); + blackSampler = pack.createObject('Sampler'); + blackSampler.texture = blackTexture; + + // Create the render graph for a view. + g_viewInfo = o3djs.rendergraph.createBasicView( + pack, + client.root, + client.renderGraphRoot); + + drawContext = g_viewInfo.drawContext; + + var target = [0, 0, 0]; + var eye = [0, 0, 5]; + var up = [0, 1, 0]; + var view_matrix = math.matrix4.lookAt(eye, target, up); + + drawContext.view = view_matrix; + + globalParams = pack.createObject('ParamObject'); + + // Initialize all the effect's required parameters. + var ambient_light_color_param = globalParams.createParam( + 'ambientLightColor', + 'ParamFloat4'); + ambient_light_color_param.value = [0.27, 0.2, 0.2, 1]; + var sunlight_direction_param = globalParams.createParam('sunlightDirection', + 'ParamFloat3'); + + // 20 degrees off. + sunlight_direction_param.value = [-0.34202, 0.93969262, 0.0]; + var sunlight_color_param = globalParams.createParam('sunlightColor', + 'ParamFloat4'); + + sunlight_color_param.value = [0.55, 0.6, 0.7, 1.0]; + // global parameter, this will change as the character moves. + camera_eye_param = globalParams.createParam('cameraEye', 'ParamFloat3'); + camera_eye_param.value = eye; + camera_target_param = globalParams.createParam('cameraTarget', + 'ParamFloat3'); + camera_target_param.value = target; + + InitializeLightParameters(globalParams, max_number_of_lights); + + var fog_color_param = globalParams.createParam('fog_color', 'ParamFloat4'); + fog_color_param.value = [0.5, 0.5, 0.5, 1.0]; + + // Create a perspective projection matrix. + var o3d_width = 845; + var o3d_height = 549; + + var proj_matrix = math.matrix4.perspective( + 45 * Math.PI / 180, o3d_width / o3d_height, 0.1, 5000); + + drawContext.projection = proj_matrix; + + o3dElement.onkeydown = document.onkeydown; + o3dElement.onkeyup = document.onkeyup; + + o3djs.event.startKeyboardEventSynthesis(o3dElement); + } +} + +/** + * Remove callbacks on the o3d client. + */ +function uninit() { + if (client) { + client.cleanup(); + } +} + +/** + * Helper function to shorten document.getElementById() + * @param {string} value The elementID to find. + * @return {string} The document element with our ID. + */ +function $(id) { + return document.getElementById(id); +} + +/** + * Helper function to tell us if a value is set to something useful. + * @param {Object} value The thing to check out. + * @return {boolean} Whether the thing is empty. + * TODO: 'Tis silly to have both an isEmpty and exists function + * when they're probably doing the same thing. + */ +function isEmpty(value) { + return (value == undefined) || (value == ''); +} + +/** + * Returns the 2nd value if the first is rmpty. + * @param {Object} val1 The thing to check for emptyness. + * @param {Object} val2 The thing to maybe pass back. + * @return {Object} One of the above. + */ +function ifEmpty(val1, val2) { + if (val1 == undefined || val1 == '') { + return val2; + } + return val1; +} + +/** + * Helper function to tell us if a value exists. + * @param {Object} item The thing to check out. + * @return {boolean} Whether the thing exists. + */ +function exists(item) { + if (item == undefined || item == null) { + return false; + } else { + return true; + } +} + +/** + * Takes an index number into our global levels[] array, and it loads up that + * level. + * @param {number} levelID The number of the level to load in. + */ +function loadLevel(levelID) { + if (isLoaded) { + return; + } + world = levels[levelID]; + + // If we're running in 'SketchUp mode' inside the level editor, tell SU to + // do the loading, then bail out of here. + if (isSU) { + clearTimeout(timerID) + url = 'skp:do_open@'; + url += 'level_name=' + world.colladaFile; + url += '&friendly_name=' + world.name; + window.location.href = url; + $('export-button').disabled = false; + $('play-button').disabled = false; + $('pause-button').disabled = true; + isLoaded = true; + return; + } + + var path = window.location.href; + var index = path.lastIndexOf('/'); + path = path.substring(0, index + 1) + 'levels/' + world.colladaFile; + $('o3d').style.width = '845px'; + $('o3d').style.height = '549px'; + + // Create a callback function to prepare the transform graph once its loaded. + function callback(exception) { + if (exception) { + alert('Could not load: ' + path + '\n' + exception); + } else { + var current_light = 0; + var my_effect = pack.createObject('Effect'); + my_effect.name = 'global_effect'; + var effect_string = $('global_effect').value; + my_effect.loadFromFXString(effect_string); + + var xform_nodes = client.root.getTransformsInTree(); + for (var i = 0; i < xform_nodes.length; ++i) { + var shape_name = xform_nodes[i].name; + if (shape_name.indexOf('Light') == 0) { + var world_transform = xform_nodes[i].getUpdatedWorldMatrix(); + var world_loc = world_transform[3]; + var world_location = world_loc; + var color = [1.0, 0.7, 0.10, 150.0]; + + var light_index = AddLight(world_location, color); + xform_nodes[i].parent = null; + ++current_light; + } + } + + { + var materials = pack.getObjectsByClassName('o3d.Material'); + for (var m = 0; m < materials.length; ++m) { + var material = materials[m]; + if (!material.getParam('diffuseSampler')) { + diffuseParam = material.createParam('diffuseSampler', + 'ParamSampler'); + diffuseParam.value = blackSampler; + } + material.effect = my_effect; + my_effect.createUniformParameters(material); + // go through each param on the material + var params = material.params; + for (var p = 0; p < params.length; ++p) { + var dst_param = params[p]; + // see if there is one of the same name on the paramObject we're + // using for global parameters. + var src_param = globalParams.getParam(dst_param.name); + if (src_param) { + // see if they are compatible + if (src_param.isAClassName(dst_param.className)) { + // bind them + dst_param.bind(src_param); + } + } + } + } + } + + // Remove all line primitives as we don't really want them to render. + { + var primitives = pack.getObjectsByClassName('o3d.Primitive'); + for (var p = 0; p < primitives.length; ++p) { + var primitive = primitives[p]; + if (primitive.primitiveType == o3d.Primitive.LINELIST) { + primitive.owner = null; + pack.removeObject(primitive); + } + } + } + + o3djs.pack.preparePack(pack, g_viewInfo); + avatar = world.actors[0]; + isLoaded = true; + client.setRenderCallback(onRender); + $('container').style.visibility = 'visible'; + } + } + + // Create a new transform node to attach our world to. + var world_parent = pack.createObject('Transform'); + world_parent.parent = client.root; + + function loadSceneCallback(pack, parent, exception) { + g_loadInfo = null; + callback(exception); + } + g_loadInfo = o3djs.scene.loadScene(client, pack, world_parent, path, + loadSceneCallback); +} + +/** + * This is our little callback handler that o3d calls after each frame. + * @param {Object} renderEvent An event object. + */ +function onRender(renderEvent) { + if (g_loadInfo) { + $('fps').innerHTML = 'Loading: ' + + g_loadInfo.getKnownProgressInfoSoFar().percent + '%'; + } + if (isLoaded == false) { + return; + } + + var elapsedTime = Math.min(renderEvent.elapsedTime, 1 / 20); + + nextFrame(elapsedTime); + UpdateLightsInProgram(avatar); + + // Every 20 frames, update our frame rate display + frameCount++; + if (frameCount % 20 == 0) { + $('fps').innerHTML = Math.floor(1.0 / elapsedTime + 0.5); + } +} + +/** + * This cancels scrolling and keeps focus on a hidden element so spacebar + * doesn't page down. + */ +function cancelScroll() { + $('focusHolder').focus(); + var pageWidth = document.body.clientWidth; + var pageHeight = document.body.clientHeight; + document.body.scrollTop = 0; + document.body.scrollLeft = 0; +} diff --git a/o3d/samples/io/io.html b/o3d/samples/io/io.html new file mode 100644 index 0000000..55c0db3 --- /dev/null +++ b/o3d/samples/io/io.html @@ -0,0 +1,173 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<html> + <title>The Journies of Prince IO: An O3D Adventure</title> + <link href="ui/io.css" rel="stylesheet" type="text/css"/> + <script type="text/javascript" src="../o3djs/base.js"></script> + <script type="text/javascript" src="dynamic_lights.js"></script> + <script type="text/javascript" src="init.js"></script> + <script type="text/javascript" src="autoincludes.js"></script> + <script type="text/javascript" src="gamelogic.js"></script> + <script type="text/javascript" src="cutscenes.js"></script> + <script type="text/javascript" src="sound/soundplayer.js"></script> +</head> + +<body onload="init();" onscroll="cancelScroll()" onunload="uninit();"> + +<table id="table-main"><tr><td valign=center> + +<table id="table-middle" cellspacing="0" cellpadding="0" border="0"> + <tr> + <td id="book-left" width="50%"><div id="innercover-div"><img id="innercover" src="ui/book_innercover.jpg"></div></td> + <td id="book-center" width="1000"><div id="cover-div"><img id="cover-shadow" src="ui/covershadow.png"><img onclick="animateCover()" id="cover" src="ui/book_cover.jpg"></div><img src="ui/book_captop.jpg" width="988" height="39"><br><div id="cover-seam"></div><div id="content"> + + Choose a level... + + </div><div id="container" name="container" > + <div id="o3d" style="width: 1px; height: 1px;"></div> + </div><img id="page1" src="ui/book_page1.jpg" onclick="animatePage('page1')"><img id="page2" src="ui/book_page2.jpg" onclick="animatePage('page2')"><img id="page3" src="ui/book_page3.jpg" onclick="animatePage('page3')"><img src="ui/book_pageblank.jpg" width="951" height="549"><img src="ui/book_capright.jpg" width="37" height="549"><br><img src="ui/book_capbottom.jpg" width="988" height="90"></td> + <td id="book-right" width="50%"> </td> + </tr> +</table> + +</td></tr></table> + +<form> +<input id="focusHolder" style="position:absolute;top:-100px;"> +</form> + +<div id="footer"><div id="output"></div><div id="fps"></div><img src="ui/logo.gif" alt="Google"></div> +<div id="fx" style="visibility:hidden"> +<textarea id="global_effect"> +struct a2v { + float4 position : POSITION; + float3 normal : NORMAL; + float2 texCoord : TEXCOORD0; +}; + +struct v2f { + float4 position : POSITION; + float3 worldPosition : TEXCOORD0; + float2 texCoord : TEXCOORD1; + float3 n : TEXCOORD2; + float3 l : TEXCOORD3; +}; + +float4x4 worldViewProj : WorldViewProjection; +float4x4 world : World; +float4x4 worldIT : WorldInverseTranspose; + +uniform float4 ambientLightColor; +uniform float3 sunlightDirection; +uniform float4 sunlightColor; +uniform float3 cameraEye; +uniform float3 cameraTarget; + +uniform float3 light0_location; +uniform float3 light1_location; +uniform float3 light2_location; +uniform float3 light3_location; +uniform float3 light4_location; + +uniform float4 light0_color; +uniform float4 light1_color; +uniform float4 light2_color; +uniform float4 light3_color; +uniform float4 light4_color; +uniform float4 fog_color; + +// The texture from a sketchup6 file +// A diffuseTexture and a diffuse color (when there isn't a texture) +uniform float4 diffuse; // The color, unless texture +sampler2D diffuseSampler; + +v2f vsMain(a2v IN) { + v2f OUT; + OUT.position = mul(IN.position, worldViewProj); + OUT.worldPosition = mul(IN.position, world).xyz; + OUT.texCoord = IN.texCoord; + + OUT.n = mul(float4(IN.normal,0), worldIT).xyz; + OUT.l = IN.normal; + return OUT; +} + +float4 fsMain(v2f IN): COLOR { + float4 textureColor = tex2D(diffuseSampler, IN.texCoord); + float3 normalDirection = normalize(IN.n); + float3 viewDirection = normalize(cameraEye - IN.worldPosition.xyz); + // Only diffuse light until we can get better than face normals. + float4 litWorld = lit(dot(normalDirection.xyz, sunlightDirection), 0, 0); + float4 total_color = ambientLightColor + litWorld.yyyy * sunlightColor; + + float3 light_direction = light0_location - IN.worldPosition.xyz; + float attenuation = light0_color.a / length(light_direction); + light_direction = normalize(light_direction); + float4 litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0); + litLight.y *= clamp(attenuation * attenuation, 0, 1); + total_color.rgb += litLight.yyy * light0_color.rgb; + + light_direction = light1_location - IN.worldPosition.xyz; + attenuation = light1_color.a / length(light_direction); + light_direction = normalize(light_direction); + litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0); + litLight.y *= clamp(attenuation * attenuation, 0, 1); + total_color.rgb += litLight.yyy * light1_color.rgb; + + light_direction = light2_location - IN.worldPosition.xyz; + attenuation = light2_color.a / length(light_direction); + light_direction = normalize(light_direction); + litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0); + litLight.y *= clamp(attenuation * attenuation, 0, 1); + total_color.rgb += litLight.yyy * light2_color.rgb; + + light_direction = light3_location - IN.worldPosition.xyz; + attenuation = light3_color.a / length(light_direction); + light_direction = normalize(light_direction); + litLight = lit(dot(normalDirection.xyz, light_direction), 0, 0); + litLight.y *= clamp(attenuation * attenuation, 0, 1); + total_color.rgb += litLight.yyy * light3_color.rgb; + + textureColor.rgb += diffuse.rgb; + total_color *= textureColor; + + // Fog + float fog = saturate(pow(2.718, -.005 * (length(cameraEye - IN.worldPosition.xyz) - 300))); + return lerp(fog_color, total_color, fog); +} + +// #o3d VertexShaderEntryPoint vsMain +// #o3d PixelShaderEntryPoint fsMain +// #o3d MatrixLoadOrder RowMajor +</textarea> +</div> +</body> diff --git a/o3d/samples/io/levels/all_actors.js b/o3d/samples/io/levels/all_actors.js new file mode 100644 index 0000000..e630949 --- /dev/null +++ b/o3d/samples/io/levels/all_actors.js @@ -0,0 +1,383 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview This file defines one level that our little game can run + * inside of. This file was auto-generated by io.rb from a SketchUp model. + */ +if (levels == undefined) { + var levels = []; +} + +levels.push({ + name: 'All Actors', + colladaFile: 'all_actors.o3dtgz', + + platforms: [ + {'left': {'mapX': 0}, + 'z': 0, 'rotZ': 0.0, + 'right': {'adjacentID': 1, 'mapX': 1151}}, + {'left': {'adjacentID': 0, 'mapX': 1151}, + 'z': 0, 'rotZ': 0.432710088213842, + 'right': {'adjacentID': 2, 'mapX': 2588}}, + {'left': {'adjacentID': 1, 'mapX': 2588}, + 'z': 0, 'rotZ': 0.0, + 'right': {'adjacentID': 3, 'mapX': 3159}}, + {'left': {'adjacentID': 2, 'mapX': 3159}, + 'z': 0, 'rotZ': 5.85194141379659, + 'right': {'adjacentID': 4, 'mapX': 3474}}, + {'left': {'adjacentID': 3, 'mapX': 3474}, + 'z': 0, 'rotZ': 5.27977245408739, + 'right': {'adjacentID': 5, 'mapX': 4178}}, + {'left': {'adjacentID': 4, 'mapX': 4178}, + 'z': 0, 'rotZ': 4.97548502987221, + 'right': {'adjacentID': 6, 'mapX': 4798}}, + {'left': {'adjacentID': 5, 'mapX': 4798}, + 'z': 0, 'rotZ': 4.71238898038469, + 'right': {'mapX': 6726}}, + {'left': {'mapX': 3960}, + 'z': 397, 'parentID': 4, 'rotZ': 5.27977245408739, + 'right': {'mapX': 4051}}, + {'left': {'mapX': 1308}, + 'z': 45, 'parentID': 1, 'rotZ': 0.432710088213843, + 'right': {'obstacleHeight': 15, 'mapX': 1563}}, + {'left': {'mapX': 312}, + 'z': 172, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 524}}, + {'left': {'mapX': 2915}, + 'z': 123, 'parentID': 2, 'rotZ': 0.0, + 'right': {'obstacleHeight': 64, 'mapX': 3066}}, + {'left': {'obstacleHeight': 72, 'mapX': 525}, + 'z': 99, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 545}}, + {'left': {'mapX': 2117}, + 'z': 74, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'obstacleHeight': 76, 'mapX': 2441}}, + {'left': {'mapX': 514}, + 'z': 365, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 576}}, + {'left': {'mapX': 1377}, + 'z': 115, 'parentID': 1, 'rotZ': 0.432710088213839, + 'right': {'mapX': 1433}}, + {'left': {'mapX': 1828}, + 'z': 309, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'mapX': 1897}}, + {'left': {'obstacleHeight': 37, 'mapX': 6233}, + 'z': 166, 'parentID': 6, 'rotZ': 4.71238898038469, + 'right': {'mapX': 6327}}, + {'left': {'mapX': 714}, + 'z': 138, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 869}}, + {'left': {'mapX': 1505}, + 'z': 233, 'parentID': 1, 'rotZ': 0.432710088213845, + 'right': {'mapX': 1563}}, + {'left': {'obstacleHeight': 43, 'mapX': 4338}, + 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221, + 'right': {'mapX': 4502}}, + {'left': {'mapX': 593}, + 'z': 287, 'parentID': 0, 'rotZ': 0.0, + 'right': {'obstacleHeight': 24, 'mapX': 717}}, + {'left': {'mapX': 3377}, + 'z': 326, 'parentID': 3, 'rotZ': 5.85194141379659, + 'right': {'obstacleHeight': 144, 'mapX': 4466}}, + {'left': {'mapX': 3704}, + 'z': 194, 'parentID': 4, 'rotZ': 5.27977245408739, + 'right': {'mapX': 3862}}, + {'left': {'mapX': 4087}, + 'z': 397, 'parentID': 4, 'rotZ': 5.27977245408739, + 'right': {'mapX': 4161}}, + {'left': {'mapX': 2699}, + 'z': 351, 'parentID': 2, 'rotZ': 0.0, + 'right': {'mapX': 2705}}, + {'left': {'obstacleHeight': 22, 'mapX': 545}, + 'z': 76, 'parentID': 0, 'rotZ': 0.0, + 'right': {'obstacleHeight': 22, 'mapX': 636}}, + {'left': {'mapX': 1678}, + 'z': 309, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'mapX': 1767}}, + {'left': {'mapX': 4208}, + 'z': 373, 'parentID': 5, 'rotZ': 4.97548502987219, + 'right': {'mapX': 4232}}, + {'left': {'mapX': 2441}, + 'z': 150, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'adjacentID': 29, 'mapX': 2587}}, + {'left': {'adjacentID': 28, 'mapX': 2587}, + 'z': 150, 'parentID': 2, 'rotZ': 0.0, + 'right': {'obstacleHeight': 200, 'mapX': 2705}}, + {'left': {'mapX': 4208}, + 'z': 252, 'parentID': 5, 'rotZ': 4.97548502987219, + 'right': {'obstacleHeight': 30, 'mapX': 4238}}, + {'left': {'obstacleHeight': 107, 'mapX': -24}, + 'z': 76, 'parentID': 0, 'rotZ': 0.0, + 'right': {'obstacleHeight': 42, 'mapX': 265}}, + {'left': {'mapX': 4239}, + 'z': 282, 'parentID': 5, 'rotZ': 4.9754850298722, + 'right': {'mapX': 4301}}, + {'left': {'obstacleHeight': 38, 'mapX': 1433}, + 'z': 76, 'parentID': 1, 'rotZ': 0.432710088213846, + 'right': {'obstacleHeight': 34, 'mapX': 1477}}, + {'left': {'obstacleHeight': 17, 'mapX': 4302}, + 'z': 265, 'parentID': 5, 'rotZ': 4.97548502987222, + 'right': {'mapX': 4338}}, + {'left': {'mapX': 1505}, + 'z': 148, 'parentID': 1, 'rotZ': 0.432710088213845, + 'right': {'mapX': 1563}}, + {'left': {'obstacleHeight': 30, 'mapX': 2441}, + 'z': 43, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'mapX': 2587}}, + {'left': {'mapX': 1478}, + 'z': 111, 'parentID': 1, 'rotZ': 0.432710088213837, + 'right': {'obstacleHeight': 37, 'mapX': 1504}}, + {'left': {'mapX': 1927}, + 'z': 290, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'mapX': 2193}}, + {'left': {'mapX': 2706}, + 'z': 351, 'parentID': 2, 'rotZ': 0.0, + 'right': {'mapX': 2738}}, + {'left': {'obstacleHeight': 37, 'mapX': 6136}, + 'z': 203, 'parentID': 6, 'rotZ': 4.71238898038469, + 'right': {'mapX': 6232}}, + {'left': {'mapX': 4843}, + 'z': 240, 'parentID': 6, 'rotZ': 4.71238898038469, + 'right': {'mapX': 6135}}, + {'left': {'mapX': 3921}, + 'z': 222, 'parentID': 4, 'rotZ': 5.27977245408739, + 'right': {'adjacentID': 43, 'mapX': 4177}}, + {'left': {'adjacentID': 42, 'mapX': 4177}, + 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987222, + 'right': {'obstacleHeight': 30, 'mapX': 4207}}, + {'left': {'mapX': 1478}, + 'z': 196, 'parentID': 1, 'rotZ': 0.432710088213837, + 'right': {'mapX': 1504}}, + {'left': {'obstacleHeight': 61, 'mapX': 870}, + 'z': 76, 'parentID': 0, 'rotZ': 0.0, + 'right': {'adjacentID': 46, 'mapX': 1151}}, + {'left': {'adjacentID': 45, 'mapX': 1151}, + 'z': 76, 'parentID': 1, 'rotZ': 0.432710088213843, + 'right': {'obstacleHeight': 38, 'mapX': 1377}}, + {'left': {'mapX': 4665}, + 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221, + 'right': {'mapX': 4739}}, + {'left': {'obstacleHeight': 72, 'mapX': 1563}, + 'z': 76, 'parentID': 1, 'rotZ': 0.432710088213843, + 'right': {'mapX': 2018}}, + {'left': {'mapX': 4769}, + 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221, + 'right': {'adjacentID': 50, 'mapX': 4798}}, + {'left': {'adjacentID': 49, 'mapX': 4798}, + 'z': 222, 'parentID': 6, 'rotZ': 4.71238898038469, + 'right': {'obstacleHeight': 18, 'mapX': 4843}}, + {'left': {'mapX': 312}, + 'z': 234, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 362}}, + {'left': {'mapX': 265}, + 'z': 119, 'parentID': 0, 'rotZ': 0.0, + 'right': {'obstacleHeight': 53, 'mapX': 312}}, + {'left': {'mapX': 2642}, + 'z': 326, 'parentID': 2, 'rotZ': 0.0, + 'right': {'obstacleHeight': 25, 'mapX': 2699}}, + {'left': {'obstacleHeight': 37, 'mapX': 6327}, + 'z': 129, 'parentID': 6, 'rotZ': 4.71238898038469, + 'right': {'mapX': 6596}}, + {'left': {'obstacleHeight': 96, 'mapX': 6596}, + 'z': 32, 'parentID': 6, 'rotZ': 4.71238898038469, + 'right': {'mapX': 6726}}, + {'left': {'mapX': 1352}, + 'z': 155, 'parentID': 1, 'rotZ': 0.432710088213843, + 'right': {'mapX': 1388}}, + {'left': {'mapX': 4551}, + 'z': 222, 'parentID': 5, 'rotZ': 4.97548502987221, + 'right': {'mapX': 4595}}, + {'left': {'mapX': 636}, + 'z': 98, 'parentID': 0, 'rotZ': 0.0, + 'right': {'obstacleHeight': 39, 'mapX': 714}}, + {'left': {'obstacleHeight': 227, 'mapX': 2738}, + 'z': 123, 'parentID': 2, 'rotZ': 0.0, + 'right': {'mapX': 2762}}, + {'left': {'mapX': 2642}, + 'z': 247, 'parentID': 2, 'rotZ': 0.0, + 'right': {'obstacleHeight': 78, 'mapX': 2701}}, + {'left': {'mapX': 4401}, + 'z': 394, 'parentID': 3, 'rotZ': 5.85194141379659, + 'right': {'obstacleHeight': 161, 'mapX': 4463}}, + {'left': {'mapX': 1561}, + 'z': 309, 'parentID': 1, 'rotZ': 0.432710088213842, + 'right': {'mapX': 1623}}, + {'left': {'mapX': 3248}, + 'z': 222, 'parentID': 3, 'rotZ': 5.85194141379659, + 'right': {'adjacentID': 64, 'mapX': 3473}}, + {'left': {'adjacentID': 63, 'mapX': 3473}, + 'z': 222, 'parentID': 4, 'rotZ': 5.2797724540874, + 'right': {'mapX': 3607}}, + {'left': {'mapX': 400}, + 'z': 270, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 524}}, + {'left': {'mapX': 3066}, + 'z': 188, 'parentID': 2, 'rotZ': 0.0, + 'right': {'adjacentID': 67, 'mapX': 3159}}, + {'left': {'adjacentID': 66, 'mapX': 3159}, + 'z': 188, 'parentID': 3, 'rotZ': 5.85194141379659, + 'right': {'obstacleHeight': 33, 'mapX': 3248}}], + actors: [ + new Avatar({ name: 'Avatar1', colladaID: 'Avatar1', + x: 23, y: 0, z: 77, mapX: 24, rotZ: 0.0628318530722379, + + platformID: 31}), + new Spikem({ name: 'Spikem1', colladaID: 'Spikem1', + x: 186, y: -1, z: 76, mapX: 186, rotZ: 0.0, + platformID: 31}), + new Spikem({ name: 'Spikem2', colladaID: 'Spikem2', + x: 763, y: -2, z: 144, mapX: 762, rotZ: 0.0, + platformID: 17}), + new Spikem({ name: 'Spikem3', colladaID: 'Spikem3', + x: 437, y: -1, z: 178, mapX: 436, rotZ: 0.0, + platformID: 9}), + new Spikem({ name: 'Spikem4', colladaID: 'Spikem4', + x: 1819, y: 311, z: 80, mapX: 1886, rotZ: 0.0, + platformID: 48}), + new Spikem({ name: 'Spikem5', colladaID: 'Spikem5', + x: 2861, y: 602, z: 130, mapX: 2992, rotZ: 0.0, + platformID: 10}), + new Spikem({ name: 'Spikem6', colladaID: 'Spikem6', + x: 3830, y: -631, z: 228, mapX: 4704, rotZ: 0.0, + platformID: 47}), + new Spikem({ name: 'Spikem7', colladaID: 'Spikem7', + x: 3854, y: -1682, z: 246, mapX: 5757, rotZ: 0.0, + platformID: 41}), + new Spikem({ name: 'Spikem8', colladaID: 'Spikem8', + x: 3796, y: -507, z: 228, mapX: 4575, rotZ: 0.0, + platformID: 57}), + new Spikem({ name: 'Spikem9', colladaID: 'Spikem9', + x: 3765, y: -390, z: 228, mapX: 4454, rotZ: 0.0, + platformID: 19}), + new Spikem({ name: 'Spikem10', colladaID: 'Spikem10', + x: 3848, y: -2623, z: 22, mapX: 6699, rotZ: 0.0, + platformID: 55}), + new Arrow({ name: 'Arrow1', colladaID: 'Arrow1', + x: 40, y: 3, z: 99, mapX: 40, rotZ: 0.0, + platformID: 31}), + new Arrow({ name: 'Arrow2', colladaID: 'Arrow2', + x: 37, y: 0, z: 76, mapX: 37, rotZ: 0.0, + platformID: 31}), + new Arrow({ name: 'Arrow3', colladaID: 'Arrow3', + x: 40, y: 3, z: 86, mapX: 40, rotZ: 0.0, + platformID: 31}), + new HorizontalPad({ name: 'HorizontalPad1', colladaID: 'HorizontalPad1', + x: 1692, y: 247, z: 312, mapX: 1745, rotZ: -0.411897703470668, + platformID: 26}), + new HorizontalPad({ name: 'HorizontalPad2', colladaID: 'HorizontalPad2', + x: 1926, y: 355, z: 292, mapX: 2003, rotZ: -0.411897703470668, + platformID: 38}), + new Coin({ name: 'Coin1', colladaID: 'Coin1', + x: 342, y: -2, z: 247, mapX: 341, rotZ: 0.0, + platformID: 51}), + new Coin({ name: 'Coin2', colladaID: 'Coin2', + x: 424, y: -2, z: 299, mapX: 423, rotZ: 0.0, + platformID: 65}), + new Coin({ name: 'Coin3', colladaID: 'Coin3', + x: 461, y: -2, z: 303, mapX: 461, rotZ: 0.0, + platformID: 65}), + new Coin({ name: 'Coin4', colladaID: 'Coin4', + x: 496, y: -2, z: 303, mapX: 495, rotZ: 0.0, + platformID: 65}), + new Coin({ name: 'Coin5', colladaID: 'Coin5', + x: 1426, y: 121, z: 83, mapX: 1450, rotZ: 0.0, + platformID: 33}), + new Coin({ name: 'Coin6', colladaID: 'Coin6', + x: 1659, y: 232, z: 344, mapX: 1709, rotZ: 0.0, + platformID: 26}), + new Coin({ name: 'Coin7', colladaID: 'Coin7', + x: 1697, y: 254, z: 344, mapX: 1753, rotZ: 0.0, + platformID: 26}), + new Coin({ name: 'Coin8', colladaID: 'Coin8', + x: 1971, y: 382, z: 304, mapX: 2055, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin9', colladaID: 'Coin9', + x: 2053, y: 419, z: 304, mapX: 2145, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin10', colladaID: 'Coin10', + x: 2015, y: 402, z: 305, mapX: 2103, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin11', colladaID: 'Coin11', + x: 2184, y: 475, z: 229, mapX: 2287, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin12', colladaID: 'Coin12', + x: 2184, y: 475, z: 256, mapX: 2287, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin13', colladaID: 'Coin13', + x: 2184, y: 475, z: 307, mapX: 2287, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin14', colladaID: 'Coin14', + x: 2184, y: 475, z: 282, mapX: 2287, rotZ: 0.0, + platformID: 38}), + new Coin({ name: 'Coin15', colladaID: 'Coin15', + x: 546, y: -2, z: 422, mapX: 545, rotZ: 0.0, + platformID: 13}), + new Coin({ name: 'Coin16', colladaID: 'Coin16', + x: 2590, y: 607, z: 371, mapX: 2721, rotZ: 0.0, + platformID: 39}), + new Coin({ name: 'Coin17', colladaID: 'Coin17', + x: 2737, y: 606, z: 246, mapX: 2961, rotZ: 0.0, + platformID: 10}), + new Coin({ name: 'Coin18', colladaID: 'Coin18', + x: 2737, y: 606, z: 273, mapX: 2868, rotZ: 0.0, + platformID: 39}), + new Coin({ name: 'Coin19', colladaID: 'Coin19', + x: 3599, y: 21, z: 433, mapX: 4005, rotZ: 0.0, + platformID: 7}), + new Coin({ name: 'Coin20', colladaID: 'Coin20', + x: 3665, y: -78, z: 429, mapX: 4125, rotZ: 0.0, + platformID: 23}), + new Coin({ name: 'Coin21', colladaID: 'Coin21', + x: 4156, y: 77, z: 423, mapX: 4402, rotZ: 0.0, + platformID: 61}), + new Coin({ name: 'Coin22', colladaID: 'Coin22', + x: 4182, y: 71, z: 418, mapX: 4428, rotZ: 0.0, + platformID: 61}), + new Coin({ name: 'Coin23', colladaID: 'Coin23', + x: 4182, y: 71, z: 447, mapX: 4428, rotZ: 0.0, + platformID: 61}), + new Coin({ name: 'Coin24', colladaID: 'Coin24', + x: 4156, y: 77, z: 452, mapX: 4402, rotZ: 0.0, + platformID: 61}), + new Coin({ name: 'Coin25', colladaID: 'Coin25', + x: 4156, y: 77, z: 482, mapX: 4402, rotZ: 0.0, + platformID: 61}), + new Coin({ name: 'Coin26', colladaID: 'Coin26', + x: 4182, y: 71, z: 477, mapX: 4428, rotZ: 0.0, + platformID: 61}), + new VerticalPad({ name: 'VerticalPad1', colladaID: 'VerticalPad1', + x: 2663, y: 603, z: 221, mapX: 2794, rotZ: 0.0, + platformID: 60}), + new VerticalPad({ name: 'VerticalPad2', colladaID: 'VerticalPad2', + x: 2799, y: 603, z: 152, mapX: 2930, rotZ: 0.0, + platformID: 10})] +}); diff --git a/o3d/samples/io/levels/all_actors.skp b/o3d/samples/io/levels/all_actors.skp Binary files differnew file mode 100644 index 0000000..99e97ee --- /dev/null +++ b/o3d/samples/io/levels/all_actors.skp diff --git a/o3d/samples/io/levels/map1.js b/o3d/samples/io/levels/map1.js new file mode 100644 index 0000000..2bd7eee --- /dev/null +++ b/o3d/samples/io/levels/map1.js @@ -0,0 +1,156 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview This file defines one level that our little game can run + * inside of. This file was auto-generated by io.rb from a SketchUp model. + */ +if (levels == undefined) { + var levels = []; +} + +levels.push({ + name: 'Chapter One', + colladaFile: 'map1.o3dtgz', + + platforms: [ + {'left': {'mapX': 0}, + 'z': 0.0, 'rotZ': 0.0, + 'right': {'adjacentID': 1, 'mapX': 99.9999999999998}}, + {'left': {'adjacentID': 0, 'mapX': 99.9999999999998}, + 'z': 0.0, 'rotZ': 0.785398163397443, + 'right': {'adjacentID': 2, 'mapX': 399.999999999999}}, + {'left': {'adjacentID': 1, 'mapX': 399.999999999999}, + 'z': 0.0, 'rotZ': 1.5707963267949, + 'right': {'adjacentID': 3, 'mapX': 561.617965644037}}, + {'left': {'adjacentID': 2, 'mapX': 561.617965644037}, + 'z': 0.0, 'rotZ': 0.0, + 'right': {'adjacentID': 4, 'mapX': 812.03592686014}}, + {'left': {'adjacentID': 3, 'mapX': 812.03592686014}, + 'z': 0.0, 'rotZ': 5.49970875351729, + 'right': {'adjacentID': 5, 'mapX': 922.215597985646}}, + {'left': {'adjacentID': 4, 'mapX': 922.215597985646}, + 'z': 0.0, 'rotZ': 4.716232199855, + 'right': {'adjacentID': 6, 'mapX': 1105.95801639536}}, + {'left': {'adjacentID': 5, 'mapX': 1105.95801639536}, + 'z': 0.0, 'rotZ': 4.04298946008257, + 'right': {'adjacentID': 7, 'mapX': 1208.29233370876}}, + {'left': {'adjacentID': 6, 'mapX': 1208.29233370876}, + 'z': 0.0, 'rotZ': 4.71238898038469, + 'right': {'adjacentID': 8, 'mapX': 1367.79233370876}}, + {'left': {'adjacentID': 7, 'mapX': 1367.79233370876}, + 'z': 0.0, 'rotZ': 0.0, + 'right': {'mapX': 1748.54233370876}}, + {'left': {'mapX': 672.461706167729}, + 'z': 133.25, 'parentID': 3, 'rotZ': 0.0, + 'right': {'mapX': 725.904505439235}}, + {'left': {'mapX': 70.3557338817432}, + 'z': 58.5, 'parentID': 0, 'rotZ': 0.0, + 'right': {'adjacentID': 11, 'mapX': 99.9999999999998}}, + {'left': {'adjacentID': 10, 'mapX': 99.9999999999998}, + 'z': 58.5, 'parentID': 1, 'rotZ': 0.785398163397443, + 'right': {'mapX': 177.235601196938}}, + {'left': {'obstacleHeight': 32.0, 'mapX': 832.589734479398}, + 'z': 65.5, 'parentID': 4, 'rotZ': 5.49970875351729, + 'right': {'adjacentID': 13, 'mapX': 922.215597985645}}, + {'left': {'adjacentID': 12, 'mapX': 922.215597985645}, + 'z': 65.5, 'parentID': 5, 'rotZ': 4.716232199855, + 'right': {'mapX': 1025.68972725654}}, + {'left': {'mapX': 1176.12562519989}, + 'z': 133.25, 'parentID': 6, 'rotZ': 4.04298946008257, + 'right': {'adjacentID': 15, 'mapX': 1208.29233370876}}, + {'left': {'adjacentID': 14, 'mapX': 1208.29233370876}, + 'z': 133.25, 'parentID': 7, 'rotZ': 4.71238898038469, + 'right': {'adjacentID': 16, 'mapX': 1367.79233370876}}, + {'left': {'adjacentID': 15, 'mapX': 1367.79233370876}, + 'z': 133.25, 'parentID': 8, 'rotZ': 0.0, + 'right': {'mapX': 1748.54233370876}}, + {'left': {'obstacleHeight': 13.75, 'mapX': -13.0628855147159}, + 'z': 69.5, 'parentID': 0, 'rotZ': 0.0, + 'right': {'mapX': 31.2499999999998}}, + {'left': {'mapX': 812.03592686014}, + 'z': 47.0, 'parentID': 4, 'rotZ': 5.49970875351729, + 'right': {'mapX': 922.215597985646}}, + {'left': {'mapX': 177.235601196938}, + 'z': 75.5, 'parentID': 1, 'rotZ': 0.785398163397443, + 'right': {'obstacleHeight': 28.25, 'mapX': 254.471202393877}}, + {'left': {'mapX': 757.192725889269}, + 'z': 97.5, 'parentID': 3, 'rotZ': 0.0, + 'right': {'adjacentID': 21, 'mapX': 812.03592686014}}, + {'left': {'adjacentID': 20, 'mapX': 812.03592686014}, + 'z': 97.5, 'parentID': 4, 'rotZ': 5.49970875351729, + 'right': {'mapX': 832.589734479398}}, + {'left': {'mapX': 254.471202393877}, + 'z': 103.75, 'parentID': 1, 'rotZ': 0.785398163397442, + 'right': {'mapX': 331.706803590815}}, + {'left': {'mapX': 1091.9536790532}, + 'z': 60.5, 'parentID': 5, 'rotZ': 4.71623219985501, + 'right': {'adjacentID': 24, 'mapX': 1105.95801639536}}, + {'left': {'adjacentID': 23, 'mapX': 1105.95801639536}, + 'z': 60.5, 'parentID': 6, 'rotZ': 4.04298946008257, + 'right': {'obstacleHeight': 31.5, 'mapX': 1143.95891669101}}, + {'left': {'mapX': 399.999999999999}, + 'z': 133.25, 'parentID': 2, 'rotZ': 1.5707963267949, + 'right': {'adjacentID': 26, 'mapX': 561.617965644037}}, + {'left': {'adjacentID': 25, 'mapX': 561.617965644037}, + 'z': 133.25, 'parentID': 3, 'rotZ': 0.0, + 'right': {'mapX': 621.461706167729}}, + {'left': {'obstacleHeight': 74.25, 'mapX': 621.461706167729}, + 'z': 59.0, 'parentID': 3, 'rotZ': 0.0, + 'right': {'obstacleHeight': 74.25, 'mapX': 672.461706167729}}, + {'left': {'mapX': 1143.95891669101}, + 'z': 92.0, 'parentID': 6, 'rotZ': 4.04298946008257, + 'right': {'mapX': 1176.12562519989}}, + {'left': {'obstacleHeight': 21.25, 'mapX': 331.706803590815}, + 'z': 82.5, 'parentID': 1, 'rotZ': 0.785398163397442, + 'right': {'mapX': 384.382894323691}}], + actors: [ + new Avatar({ + name: 'Avatar1', colladaID: 'Avatar1', + x: 8.25548871083476, y: -10.107499431384, z: 70.0761619683742, + mapX: 8.25548871083476, rotZ: 0.0628318530722379, platformID: 17}), + new HorizontalPad({ + name: 'HorizontalPad1', colladaID: 'HorizontalPad1', + x: 69.9999999999999, y: 0.0, z: 0.0, + mapX: 69.9999999999999, rotZ: 0.0, platformID: 0}), + new Arrow({ + name: 'Arrow1', colladaID: 'Arrow1', + x: 24.8151490181853, y: -1.89670669278537, z: 68.75, + mapX: 24.8151490181853, rotZ: 0.0, platformID: 17}), + new Arrow({ + name: 'Arrow2', colladaID: 'Arrow2', + x: 24.8151490181853, y: -1.89670669278537, z: 79.25, + mapX: 24.8151490181853, rotZ: 0.0, platformID: 17}), + new Arrow({ + name: 'Arrow3', colladaID: 'Arrow3', + x: 24.8151490181853, y: -1.89670669278537, z: 92, + mapX: 24.8151490181853, rotZ: 0.0, platformID: 17})] +}); diff --git a/o3d/samples/io/levels/map1.skp b/o3d/samples/io/levels/map1.skp Binary files differnew file mode 100644 index 0000000..8014334 --- /dev/null +++ b/o3d/samples/io/levels/map1.skp diff --git a/o3d/samples/io/levels/starter_level.skp b/o3d/samples/io/levels/starter_level.skp Binary files differnew file mode 100644 index 0000000..31869f0 --- /dev/null +++ b/o3d/samples/io/levels/starter_level.skp diff --git a/o3d/samples/io/sound/_MISS.mp3 b/o3d/samples/io/sound/_MISS.mp3 Binary files differnew file mode 100644 index 0000000..7acfc80 --- /dev/null +++ b/o3d/samples/io/sound/_MISS.mp3 diff --git a/o3d/samples/io/sound/_PUNCH.mp3 b/o3d/samples/io/sound/_PUNCH.mp3 Binary files differnew file mode 100644 index 0000000..abb7277 --- /dev/null +++ b/o3d/samples/io/sound/_PUNCH.mp3 diff --git a/o3d/samples/io/sound/_SMASH.mp3 b/o3d/samples/io/sound/_SMASH.mp3 Binary files differnew file mode 100644 index 0000000..c655a11 --- /dev/null +++ b/o3d/samples/io/sound/_SMASH.mp3 diff --git a/o3d/samples/io/sound/_woosh.mp3 b/o3d/samples/io/sound/_woosh.mp3 Binary files differnew file mode 100644 index 0000000..5687be2 --- /dev/null +++ b/o3d/samples/io/sound/_woosh.mp3 diff --git a/o3d/samples/io/sound/ah.mp3 b/o3d/samples/io/sound/ah.mp3 Binary files differnew file mode 100644 index 0000000..ff40207 --- /dev/null +++ b/o3d/samples/io/sound/ah.mp3 diff --git a/o3d/samples/io/sound/arrow.mp3 b/o3d/samples/io/sound/arrow.mp3 Binary files differnew file mode 100644 index 0000000..e106d668 --- /dev/null +++ b/o3d/samples/io/sound/arrow.mp3 diff --git a/o3d/samples/io/sound/coin_3.mp3 b/o3d/samples/io/sound/coin_3.mp3 Binary files differnew file mode 100644 index 0000000..d8f3ff5 --- /dev/null +++ b/o3d/samples/io/sound/coin_3.mp3 diff --git a/o3d/samples/io/sound/music.mp3 b/o3d/samples/io/sound/music.mp3 Binary files differnew file mode 100644 index 0000000..653d191 --- /dev/null +++ b/o3d/samples/io/sound/music.mp3 diff --git a/o3d/samples/io/sound/page.mp3 b/o3d/samples/io/sound/page.mp3 Binary files differnew file mode 100644 index 0000000..f2c9a08 --- /dev/null +++ b/o3d/samples/io/sound/page.mp3 diff --git a/o3d/samples/io/sound/soundplayer.js b/o3d/samples/io/sound/soundplayer.js new file mode 100644 index 0000000..95c0470 --- /dev/null +++ b/o3d/samples/io/sound/soundplayer.js @@ -0,0 +1,147 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file defines a SoundPlayer object that can be used to + * play .mp3 files via a tiny soundplayer.swf file. + * + * Here's some example javascript for how you'd use this thing: + * var soundPlayer = new SoundPlayer(); + * soundPlayer.play('songToPlayOnce.mp3') + * soundPlayer.play('soundToLoopForeverAt50PercentVolume.mp3',50,999) + * soundPlayer.play('sfxToPlayAsEvent.mp3',100,0,true) + * soundPlayer.setVolume('soundToTurnOff.mp3',0); + * soundPlayer.setGlobalVolume(20); + * + */ + +// Write a DIV to the screen that we can later use to embed our flash movie. + var html = '<div style="position:absolute; top:-1000px; left:-1000px; z-index: 0;width: 200px; height: 200px; ">' + html = '<OBJECT style="position:absolute; top:-1000px; left:-1000px;" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' + html += 'codebase="http://download.macromedia.com/pub/shockwave/cabs/flash' + html += '/swflash.cab#version=6,0,0,0" WIDTH="200" HEIGHT="200" ' + html += 'id="soundPlayer" ALIGN=""> ' + html += '<PARAM NAME=movie VALUE="sound/soundplayer.swf"> ' + html += '<PARAM NAME=quality VALUE=high> ' + html += '<PARAM NAME=allowScriptAccess VALUE=always> ' + html += '<EMBED src="sound/soundplayer.swf" quality=high WIDTH="200" HEIGHT="200" ' + html += 'NAME="soundPlayer" swLiveConnect=true ALIGN="" ' + html += 'TYPE="application/x-shockwave-flash" allowScriptAccess="always" ' + html += 'PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">' + html += '</EMBED></OBJECT></div>'; + document.write(html); + +/** + * Constructor for our SoundPlayer object. + */ +function SoundPlayer() { + // TODO: Make this more generic so it loads at the author's + // request rather than at include time. +} + +/** + * This is a helper function to simplify code throughout. Returns a default + * value if the first is empty. + * @param {Object} val1 Value to check for emptiness + * @param {Object} val2 Value to return if va1 is empty + * @return {Object} One of the above. + */ +SoundPlayer.prototype.defaultIfEmpty = function(val1,val2) { + if (val1 == undefined) { + return val2; + } else { + return val1; + } +} + +/** + * This is the way to send action calls to the flash plugin. In this case, + * a string containing our action script that we want to execute. (Note that + * flash doesn't have a true "eval" function, so this isn't a security hole.) + * @param {string} callStr The command to have flash execute. + */ +SoundPlayer.prototype.makeActionScriptCall = function(callStr) { + try { + window.document['soundPlayer'].SetVariable('actionScriptCall', callStr); + } catch (ex) { + // Catch the exception so that any problems with the sound player don't + // derail the whle game. + } +} + +// TODO: Need to clean up these function comments to follow +// jsdoc standard. Also need to clean up for readability. + +/** + * SoundPlayer.play() : Call this guy to play a sound or music file. + * + * fileURL : a url to any mp3 you want to play (required) + * volumeLevel : a number from 0 (silent) to 100 (optional, defaults to 100) + * loopCount : How many times to loop the sound (optional, defaults to 0) + * isNewTrack : Boolean. If true, then a new "track" will be created, + * allowing you to layer as many sounds as you like + */ +SoundPlayer.prototype.play = function(fileURL,volumeLevel,loopCount,isNewTrack) { + volumeLevel = this.defaultIfEmpty(volumeLevel,100); + loopCount = this.defaultIfEmpty(loopCount,0); + isNewTrack = this.defaultIfEmpty(isNewTrack,false); + var actionScriptCall = 'play('+fileURL+',' + volumeLevel + ',' + + loopCount + ',' + isNewTrack + ')'; + this.makeActionScriptCall(actionScriptCall); +} + +/** + * SoundPlayer.setVolume() : Call this guy to change the volume on a sound. + * + * fileURL : a url to any mp3 or wav file you want to change the volume on + * volumeLevel : a number from 0 (silent) to 100 (loud) + */ +SoundPlayer.prototype.setVolume = function(fileURL,volumeLevel,fadeTime) { + var actionScriptCall = 'setVolume('+fileURL+',' + volumeLevel + ')'; + this.makeActionScriptCall(actionScriptCall); +} + +/** + * SoundPlayer.setGlobalVolume() : Call this guy to change the global + * volume on a sound. The global volume "multiplies" each sound's volume, + * so if your sound is playing at 100% and your global is at 50%, then + * your sounds will be half as loud. + * + * volumeLevel : a number from 0 (silent) to 100 (loud) + */ +SoundPlayer.prototype.setGlobalVolume = function(volumeLevel) { + var actionScriptCall = 'setGlobalVolume(' + volumeLevel + ')'; + this.makeActionScriptCall(actionScriptCall); +} + +// Create a global variable for this application to use. +var soundPlayer = new SoundPlayer(); diff --git a/o3d/samples/io/sound/soundplayer.swf b/o3d/samples/io/sound/soundplayer.swf Binary files differnew file mode 100644 index 0000000..4a1f0e0 --- /dev/null +++ b/o3d/samples/io/sound/soundplayer.swf diff --git a/o3d/samples/io/sound/step1.mp3 b/o3d/samples/io/sound/step1.mp3 Binary files differnew file mode 100644 index 0000000..8419591 --- /dev/null +++ b/o3d/samples/io/sound/step1.mp3 diff --git a/o3d/samples/io/sound/step2.mp3 b/o3d/samples/io/sound/step2.mp3 Binary files differnew file mode 100644 index 0000000..02895f0 --- /dev/null +++ b/o3d/samples/io/sound/step2.mp3 diff --git a/o3d/samples/io/sound/step3.mp3 b/o3d/samples/io/sound/step3.mp3 Binary files differnew file mode 100644 index 0000000..8d7cf61 --- /dev/null +++ b/o3d/samples/io/sound/step3.mp3 diff --git a/o3d/samples/io/sound/ug.mp3 b/o3d/samples/io/sound/ug.mp3 Binary files differnew file mode 100644 index 0000000..7297175 --- /dev/null +++ b/o3d/samples/io/sound/ug.mp3 diff --git a/o3d/samples/io/ui/Thumbs.db b/o3d/samples/io/ui/Thumbs.db Binary files differnew file mode 100644 index 0000000..1bb8f7a --- /dev/null +++ b/o3d/samples/io/ui/Thumbs.db diff --git a/o3d/samples/io/ui/bgtile.jpg b/o3d/samples/io/ui/bgtile.jpg Binary files differnew file mode 100644 index 0000000..d6278f1 --- /dev/null +++ b/o3d/samples/io/ui/bgtile.jpg diff --git a/o3d/samples/io/ui/book_capbottom.jpg b/o3d/samples/io/ui/book_capbottom.jpg Binary files differnew file mode 100644 index 0000000..ef07486 --- /dev/null +++ b/o3d/samples/io/ui/book_capbottom.jpg diff --git a/o3d/samples/io/ui/book_capleft.jpg b/o3d/samples/io/ui/book_capleft.jpg Binary files differnew file mode 100644 index 0000000..eae6cd9 --- /dev/null +++ b/o3d/samples/io/ui/book_capleft.jpg diff --git a/o3d/samples/io/ui/book_capright.jpg b/o3d/samples/io/ui/book_capright.jpg Binary files differnew file mode 100644 index 0000000..0d7bfad --- /dev/null +++ b/o3d/samples/io/ui/book_capright.jpg diff --git a/o3d/samples/io/ui/book_captop.jpg b/o3d/samples/io/ui/book_captop.jpg Binary files differnew file mode 100644 index 0000000..a1e2705 --- /dev/null +++ b/o3d/samples/io/ui/book_captop.jpg diff --git a/o3d/samples/io/ui/book_cover.jpg b/o3d/samples/io/ui/book_cover.jpg Binary files differnew file mode 100644 index 0000000..eaf42a0 --- /dev/null +++ b/o3d/samples/io/ui/book_cover.jpg diff --git a/o3d/samples/io/ui/book_innercover.jpg b/o3d/samples/io/ui/book_innercover.jpg Binary files differnew file mode 100644 index 0000000..7eca9e8 --- /dev/null +++ b/o3d/samples/io/ui/book_innercover.jpg diff --git a/o3d/samples/io/ui/book_page1.jpg b/o3d/samples/io/ui/book_page1.jpg Binary files differnew file mode 100644 index 0000000..3b62f53e --- /dev/null +++ b/o3d/samples/io/ui/book_page1.jpg diff --git a/o3d/samples/io/ui/book_page2.jpg b/o3d/samples/io/ui/book_page2.jpg Binary files differnew file mode 100644 index 0000000..a0bfa1f --- /dev/null +++ b/o3d/samples/io/ui/book_page2.jpg diff --git a/o3d/samples/io/ui/book_page3.jpg b/o3d/samples/io/ui/book_page3.jpg Binary files differnew file mode 100644 index 0000000..740e8b9 --- /dev/null +++ b/o3d/samples/io/ui/book_page3.jpg diff --git a/o3d/samples/io/ui/book_pageblank.jpg b/o3d/samples/io/ui/book_pageblank.jpg Binary files differnew file mode 100644 index 0000000..d266853 --- /dev/null +++ b/o3d/samples/io/ui/book_pageblank.jpg diff --git a/o3d/samples/io/ui/covershadow.png b/o3d/samples/io/ui/covershadow.png Binary files differnew file mode 100644 index 0000000..2409a78 --- /dev/null +++ b/o3d/samples/io/ui/covershadow.png diff --git a/o3d/samples/io/ui/io.css b/o3d/samples/io/ui/io.css new file mode 100644 index 0000000..03918ad --- /dev/null +++ b/o3d/samples/io/ui/io.css @@ -0,0 +1,181 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +BODY { + overflow: hidden; + background-image: url(../ui/bgtile.jpg); + padding: 0px; + margin: 0px; + color: white; +} +#content { + visibility: hidden; /* for now */ + position: absolute; + color: black; + text-align: center; + padding-top: 50px; + font-size: 25px; + width: 951px; + height: 500px; +} +#container { + position: absolute; + text-align: center; + width: 882px; + height: 549px; + margin-left: 37px; +} +#footer { + position: absolute; + bottom: 0px; + height: 70px; + width: 100%; + text-align: center; +} +#whole-page { + position: absolute; + width: 100%; + height: 100%; + line-height: 100%; + border: 1px solid red; +} +#table-main { + position: absolute; + width: 100%; + height: 100%; +} +#table-middle { + padding: 0px; + margin: 0px; + border: 0px; +} +#book-left { + background-image: url(../ui/scrollwork.gif); + background-repeat: repeat-x; + background-position: right 40px; + text-align: right; + vertical-align: top; +} +#book-center { + width: 988px; + height: 662px; +} +#book-right { + background-image: url(../ui/scrollwork.gif); + background-repeat: repeat-x; + background-position: left 40px; +} +#book-capleft { + position: absolute; +} +#book-captop { + position: relative; +} +#cover-div { + position: absolute; + z-index: 100; + padding-top: 15px; + margin: 0px; +} +#cover-seam { + position: absolute; + z-index: 1000; + border-left: 1px solid #222222; + height: 575px; +} +#cover { + width: 975px; + height: 600px; + position: absolute; + z-index: 100; + cursor: pointer; + border: 0px; +} +#page1 { + position: absolute; + z-index: 90; + cursor: pointer; + border: 0px; +} +#page2 { + position: absolute; + z-index: 80; + cursor: pointer; +} +#page3 { + position: absolute; + z-index: 70; + cursor: pointer; +} +#cover-shadow { + position: absolute; + z-index: 99; +} +#innercover-div { + padding-top: 15px; + width: 20px; + height: 600px; + overflow: hidden; + text-align: right; + float: right; +} + +#innercover { + width: 0px; + height: 600px; + float: right; +} + +.levellink { + cursor: pointer; + text-decoration: underline; +} + + +#fps { + font-family: sans-serif; + text-align: left; + padding-top: 15px; + width: 250px; + float: left; + padding-left: 25px; + color: #B87333; +} +#output { + font-family: sans-serif; + text-align: right; + padding-top: 15px; + width: 250px; + float: right; + padding-right: 25px; + color: #222222; +} diff --git a/o3d/samples/io/ui/logo.gif b/o3d/samples/io/ui/logo.gif Binary files differnew file mode 100644 index 0000000..7c9bae3 --- /dev/null +++ b/o3d/samples/io/ui/logo.gif diff --git a/o3d/samples/io/ui/scrollwork.gif b/o3d/samples/io/ui/scrollwork.gif Binary files differnew file mode 100644 index 0000000..55e2476 --- /dev/null +++ b/o3d/samples/io/ui/scrollwork.gif |