diff options
author | gspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-27 23:15:42 +0000 |
---|---|---|
committer | gspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-27 23:15:42 +0000 |
commit | 05b47f7a8c5451f858dc220df0e3a97542edace6 (patch) | |
tree | a2273d619f0625c9d44d40842845ccce2eac1045 /o3d/samples/io | |
parent | 5cdc8bdb4c847cefe7f4542bd10c9880c2c557a0 (diff) | |
download | chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.zip chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.gz chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.bz2 |
This is the O3D source tree's initial commit to the Chromium tree. It
is not built or referenced at all by the chrome build yet, and doesn't
yet build in it's new home. We'll change that shortly.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17035 0039d316-1c4b-4281-b951-d872f2087c98
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 |