-- 作者:wanghai00
-- 发布时间:4/13/2006 3:55:00 PM
-- [转帖]SVG实例展-俄罗斯方块
一个外国佬用SVG编的俄罗斯方块,超强! 下面为svg源文件: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!-- YAST Copyright (c) 2005, Jeff Schiller http://www.codedread.com/ --> <svg id="svgsvg" version="1.1" width="100%" height="100%" viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" cursor="wait" onload="setTimeout('init()', 100);" > <script xlink:href="yast.js"/> <defs> <!-- Learned this from Jan Kollhoff's SVG Aqua Button tutorial: http://jan.kollhof.net/projects/svg/examples/aqua.svg --> <!-- Background Paint --> <linearGradient id="bkgnd" x1="0.0" y1="0.0" x2="1.0" y2="1.0"> <stop offset="0.0" stop-color="#0000aa" stop-opacity="0.8" /> <stop offset="1.0" stop-color="#000000" stop-opacity="0.8" /> </linearGradient> <!-- Block Definitions --> <g id="matteblock"> <rect x="0" y="0" width="20" height="20" fill="inherit" stroke="black" /> </g> <g id="block"> <rect x="0" y="0" width="20" height="20" rx="3" ry="3" fill="inherit" stroke="black" /> <!-- glare --> <path d="M3,12 L3,3 L12,3 L5,5 Z" fill="white" opacity="0.4"/> <path d="M17,8 L17,17 L8,17 L15,15 Z" fill="white" opacity="0.4"/> </g> <!-- Begin Button Definitions --> <!-- Button background paints --> <linearGradient id="activebuttonbkgnd" x1="0.0" y1="0.0" x2="0.0" y2="1.0"> <stop offset="0.0" stop-color="#5a0000" stop-opacity="0.8" /> <stop offset="1.0" stop-color="#ff0000" stop-opacity="0.8" /> </linearGradient> <linearGradient id="pressedbuttonbkgnd" x1="0.0" y1="0.0" x2="0.0" y2="1.0"> <stop offset="0.0" stop-color="#7a2000" stop-opacity="1.0" /> <stop offset="1.0" stop-color="#ff7000" stop-opacity="1.0" /> </linearGradient> <linearGradient id="inactivebuttonbkgnd" x1="0.0" y1="0.0" x2="0.0" y2="1.0"> <stop offset="0.0" stop-color="#000" stop-opacity="0.5" /> <stop offset="1.0" stop-color="#557" stop-opacity="0.5" /> </linearGradient> <!-- Top Highlight --> <linearGradient id="tophigh" x1="0.0" y1="0.0" x2="0.0" y2="1.0"> <stop offset="0.0" stop-color="#ffffff" stop-opacity="0.7" /> <!-- 0.7 --> <stop offset="0.9" stop-color="#ffffff" stop-opacity="0.0" /> <!-- 0.0 --> </linearGradient> <!-- Bottom Gradient --> <linearGradient id="bottomhigh" x1="0.0" y1="0.0" x2="0.0" y2="1.0"> <stop offset="0.2" stop-color="#ffffff" stop-opacity="0.0"/> <!-- 0.0 --> <stop offset="1.0" stop-color="#ffffff" stop-opacity="0.6" /> <!-- 0.6 --> </linearGradient> <!-- Blurs the bottom highlight --> <filter id="gblur"> <feGaussianBlur stdDeviation="2" /> </filter> <!-- To give that text a slightly "baked-in" feel --> <filter id="gblurshadow"> <feGaussianBlur stdDeviation="0.8" /> </filter> <rect id="butt" x="0" y="0" width="87" height="40" rx="25" ry="25" fill="inherit" stroke="none" /> <g id="button"> <use xlink:href="#butt" fill="inherit" /> <use transform="scale(0.8,0.45) translate(12,4)" xlink:href="#butt" fill="url(#tophigh)" /> <use transform="scale(0.8,0.45) translate(12,45)" xlink:href="#butt" fill="url(#bottomhigh)" filter="url(#gblur)"/> </g> <g id="vanilla_button"> <use xlink:href="#butt" fill="inherit" /> </g> <polyline id="check" fill="none" stroke="green" stroke-width="5" points="0,12 6,20 20,0"/> <!-- NOTE: If I fill this with none, onclick only works on the stroke. Thus I have to set pointer-events --> <rect id="checkbox" pointer-events="fill" fill="none" stroke="yellow" stroke-width="3" x="0" y="0" width="15" height="15"/> <!-- End Button Definitions --> </defs> <rect id="canvas" x="0" y="0" width="800" height="600" fill="url(#bkgnd)" /> <g id="title"> <a xlink:href="http://www.codedread.com/" target="_none"> <text id="titletext" x="77" y="50" font-size="48" fill="yellow">YAST!</text> </a> <text id="leveltext" x="600" y="50" font-size="32" fill="yellow">Level: 1</text> <rect x="72" y="65" width="650" height="5" rx="50" ry="50" fill="yellow" stroke="black"/> </g> <text id="message" x="150" y="300" font-size="48" fill="yellow" >Loading...Please Wait...</text> <!-- Buttons Panel --> <g id="buttonspanel" display="none"> <g id="startbut" transform="translate(100,105)"> <use id="startbut_use" xlink:href="#button" x="0" y="0" width="100" height="50" /> <text id="startlabel" x="24" y="28" font-size="18" fill="yellow">Start</text> </g> <g id="pausebut" transform="translate(100,165)"> <use id="pausebut_use" xlink:href="#button" x="0" y="0" width="100" height="50" /> <text id="pauselabel" x="19" y="28" font-size="18" fill="yellow">Pause</text> </g> <g id="helpbut" transform="translate(100,225)"> <use id="helpbut_use" xlink:href="#button" x="0" y="0" width="100" height="50" /> <text id="helplabel" x="25" y="28" font-size="18" fill="yellow">Help</text> </g> <text id="effectslabel" x="38" y="330" font-size="32" fill="yellow">Effects:</text> <g id="effectspanel" transform="translate(38,340)"> <rect x="0" y="0" width="192" height="240" rx="10" ry="10" fill="none" stroke="yellow" stroke-width="1"/> <g id="effect_gradback"> <use id="effect_gradback_box" xlink:href="#checkbox" x="10" y="30"/> <use id="effect_gradback_check" xlink:href="#check" x="11" y="20" display="inline" /> <text x="34" y="43" font-size="16" fill="yellow">Gradient Background</text> </g> <g id="effect_aquabutt"> <use id="effect_aquabutt_box" xlink:href="#checkbox" x="10" y="55"/> <use id="effect_aquabutt_check" xlink:href="#check" x="11" y="45" display="inline" /> <text x="34" y="68" font-size="16" fill="yellow">Aqua Buttons</text> </g> </g> </g> <!-- End Buttons Panel --> <g id="gamescreen" display="none"> <switch> <rect requiredFeatures="http://www.w3.org/TR/SVG11/feature#Filter" x="10" y="10" width="322" height="502" opacity="0.6" fill="black" stroke="none" filter="url(#gblurshadow)" /> <rect x="10" y="10" width="322" height="502" opacity="0.6" fill="black" stroke="none" /> </switch> <g id="starfield"> <rect id="space" x="0" y="0" width="322" height="502" fill="#444" stroke="yellow" /> <!-- Should put some stars here as a nice effect one day --> </g> <g id="gameborder"> </g> <g id="gamegrid"> </g> </g> <g id="gameinfo" display="none"> <g id="thescore"> <text id="scorelabel" x="600" y="150" font-size="32" fill="yellow">Score:</text> <text id="score" x="600" y="190" font-size="32" fill="yellow">0</text> </g> <g id="next"> <text id="rowsleftlabel" x="600" y="250" font-size="32" fill="yellow">Rows Left:</text> <text id="rowsleft" x="600" y="290" font-size="32" fill="yellow">10</text> </g> <g id="next"> <text id="nextlabel" x="600" y="350" font-size="32" fill="yellow">Next:</text> <g id="nextblok" transform="translate(600,390)"> </g> </g> </g> <g id="helpscreen" display="none" transform="translate(250,150)"> <rect x="0" y="0" width="300" height="300" rx="20" ry="20" fill="white" stroke="black" /> <text x="67" y="30" font-size="32" fill="black">Instructions</text> <text x="20" y="70" font-size="20" fill="black">Left Arrow:</text> <text x="140" y="70" font-size="20" fill="black">Move block left</text> <text x="20" y="100" font-size="20" fill="black">Right Arrow:</text> <text x="140" y="100" font-size="20" fill="black">Move block right</text> <text x="20" y="130" font-size="20" fill="black">Up Arrow:</text> <text x="140" y="130" font-size="20" fill="black">Rotate block</text> <text x="20" y="160" font-size="20" fill="black">Down Arrow:</text> <text x="140" y="160" font-size="20" fill="black">Hurry descent</text> <text x="20" y="190" font-size="20" fill="black">Space:</text> <text x="140" y="190" font-size="20" fill="black">Drop block</text> <text x="20" y="220" font-size="20" fill="black">S:</text> <text x="140" y="220" font-size="20" fill="black">Start game</text> <text x="20" y="250" font-size="20" fill="black">P or Q:</text> <text x="140" y="250" font-size="20" fill="black">Pause game</text> <text x="30" y="280" font-size="20" fill="black">(Click this window to close)</text> </g> </svg> 下面为用到的js:yast.js // JavaScript for YAST // Copyright (c) 2006, Jeff Schiller // http://www.codedread.com/ // Updated 2005-11-20 to avoid memory leaks in Firefox // // =========================================== // CONSTANTS // =========================================== var buttons = [ "startbut", "pausebut", "helpbut" ]; var displayableElements = [ "buttonspanel", "gamescreen", "gameinfo" ]; // I have to give acknowledgments to Alex Fritze at // http://www.croczilla.com/svg/samples/svgtetris/svgtetris.svg // for this very sensible idea... // (I was going to put it all in SVG and then use rotations!) var gBlocks = [ [ [[0,0],[0,1],[1,0],[1,1]] ], [ [[0,0],[0,1],[0,2],[0,3]], [[0,0],[1,0],[2,0],[3,0]] ], [ [[0,0],[1,0],[0,1],[0,2]], [[0,0],[1,0],[2,0],[2,1]], [[1,0],[1,1],[1,2],[0,2]], [[0,0],[0,1],[1,1],[2,1]] ], [ [[1,1],[1,0],[0,0],[1,2]], [[1,1],[2,1],[2,0],[0,1]], [[0,1],[0,2],[1,2],[0,0]], [[1,0],[0,0],[0,1],[2,0]] ], [ [[1,1],[0,1],[1,0],[2,1]], [[0,1],[0,0],[1,1],[0,2]], [[1,0],[0,0],[1,1],[2,0]], [[1,1],[1,2],[0,1],[1,0]] ], [ [[0,0],[0,1],[1,1],[1,2]], [[1,0],[2,0],[1,1],[0,1]] ], [ [[1,1],[1,0],[0,1],[0,2]], [[1,1],[2,1],[1,0],[0,0]] ] ]; var gsBlockColors = [ "green", "red", "blueviolet", "olive", "blue", "mediumseagreen", "maroon", "black" ]; var gSVGNS = "http://www.w3.org/2000/svg"; var gXLINKNS = "http://www.w3.org/1999/xlink"; var WIDTH=320; var HEIGHT=500 var BLOCKSIZE=20; var NUMCOLS = (WIDTH/BLOCKSIZE)-2; var NUMROWS = (HEIGHT/BLOCKSIZE)-1; var DROPTIMER = 25; var ROWSTOCLEAR = 10; var VERSION = "0.1"; var KEY_LEFT = 37; var KEY_RIGHT = 39; var KEY_DOWN = 40; var KEY_UP = 38; var KEY_SPACE = 32; var KEY_P = 80; var KEY_Q = 81; var KEY_S = 83; // =========================================== // =========================================== // Global Variables // =========================================== var gHelpOn = false; var gPaused = true; // these should one day be made into an object var gCurrentBlockNum = -1; var gCurrentBlockOrient = 0; var gCurrentBlockTop = 0; var gCurrentBlockLeft = 0; var gNextBlockNum = -1; var gNextBlockOrient = 0; var gDropTimer = 0; var gsPressedButtonBkgnd = "url(#pressedbuttonbkgnd)"; var gsActiveButtonBkgnd = "url(#activebuttonbkgnd)"; var gsInactiveButtonBkgnd = "url(#inactivebuttonbkgnd)"; var gLevel = 1; var gRowsLeft = ROWSTOCLEAR; function Cell(parentElement) { this.currentColor = -1; // not displayed this.parent = parentElement; var tempBlock = document.createElementNS(gSVGNS, "use"); tempBlock.setAttributeNS(gXLINKNS, "href", "#block"); tempBlock.setAttribute("display", "none"); this.block = this.parent.appendChild(tempBlock); this.setColor = function(color) { this.block.setAttribute("display", "inline"); this.block.setAttribute("fill", gsBlockColors[color]); this.currentColor = color; } this.unsetColor = function() { this.block.setAttribute("display", "none"); this.currentColor = -1; } this.isSet = function() { return (this.currentColor != -1); } } // this tracks every cell in the grid var gGrid = new Array(NUMROWS); var gNextBlock = new Array(4); // total number of blocks created (set to -1 // so the first block doesn't count until it is // dropped) var gTotalBlocks = -1; // =========================================== function inspect(obj) { var str = new Array(); for(element in obj) { str[str.length] = element; } str.sort(); alert(obj + ":" + str.join(' ')); } // Aqua buttons with animation function highlightButton(evt) { if(evt && evt.currentTarget) evt.currentTarget.setAttribute("fill", gsPressedButtonBkgnd); } function unhighlightButton(evt) { if(evt && evt.currentTarget) evt.currentTarget.setAttribute("fill", gsActiveButtonBkgnd); } function setButtonActive(button, bActive) { if(!button) { return; } // class=active_button if(bActive) { button.setAttribute("enabled", "true"); button.setAttribute("fill", gsActiveButtonBkgnd); button.setAttribute("opacity", "1.0"); button.setAttribute("cursor", "pointer"); button.addEventListener("mousedown", highlightButton, false); button.addEventListener("mouseup", unhighlightButton, false); } // class=inactive_button else { button.setAttribute("enabled", "false"); button.setAttribute("fill", gsInactiveButtonBkgnd); button.setAttribute("opacity", "0.5"); button.setAttribute("cursor", "default"); button.removeEventListener("mousedown", highlightButton, false); button.removeEventListener("mouseup", unhighlightButton, false); } } function unsetSquare(x,y,grid) { var cell = grid[y][x]; if(cell) { cell.unsetColor(); } } function setSquare(x,y,color,grid) { var cell = grid[y][x]; if(cell) { cell.setColor(color); } } function doesBlockCollide(arr, left, top) { for(var pt = 0; pt < 4; ++pt) { if( arr[pt][1]+top >= NUMROWS || // if we've reached the bottom arr[pt][0]+left < 0 || arr[pt][0]+left >= NUMCOLS || // or gone over the sides gGrid[ arr[pt][1]+top ][ arr[pt][0]+left ].isSet()) // or collided with another brick { return true; } } return false; } function undrawBlock(left, top, blocknum, blockorient, grid) { if(blocknum==-1) { return; } for(var pt = 0; pt < 4; ++pt) { unsetSquare(left + gBlocks[blocknum][blockorient][pt][0], top + gBlocks[blocknum][blockorient][pt][1], grid); } } function drawBlock(left, top, blocknum, blockorient, grid) { if(blocknum==-1) { return; } for(var pt = 0; pt < 4; ++pt) { setSquare(left + gBlocks[blocknum][blockorient][pt][0], top + gBlocks[blocknum][blockorient][pt][1], blocknum, grid); } } function undrawCurrentBlock() { undrawBlock(gCurrentBlockLeft, gCurrentBlockTop, gCurrentBlockNum, gCurrentBlockOrient, gGrid); } function drawCurrentBlock() { drawBlock(gCurrentBlockLeft, gCurrentBlockTop, gCurrentBlockNum, gCurrentBlockOrient, gGrid); } function undrawNextBlock() { undrawBlock(0, 0, gNextBlockNum, gNextBlockOrient, gNextBlock); } function drawNextBlock() { drawBlock(0, 0, gNextBlockNum, gNextBlockOrient, gNextBlock); } function createBlock() { var blocknum = Math.floor(Math.random()*gBlocks.length); var maxorientation = gBlocks[blocknum].length; var orientation = Math.floor(Math.random()*maxorientation); undrawNextBlock(); gCurrentBlockNum = gNextBlockNum; gCurrentBlockOrient = gNextBlockOrient; gCurrentBlockTop = 0; gCurrentBlockLeft = NUMCOLS/2 - 2; gNextBlockNum = blocknum; gNextBlockOrient = orientation; ++gTotalBlocks; //if(gTotalBlocks % 10 == 0) { --DROPTIMER; if(DROPTIMER < 0) { DROPTIMER = 0; } } var bCollide = doesBlockCollide(gBlocks[gCurrentBlockNum][gCurrentBlockOrient], gCurrentBlockLeft, gCurrentBlockTop); drawNextBlock(); drawCurrentBlock(); return !bCollide; } function restartGame() { for(var row = 0; row < NUMROWS; ++row) { for(var col = 0; col < NUMCOLS; ++col) { unsetSquare(col,row,gGrid); } } for(var row = 0; row < 4; ++row) { for(var col = 0; col < 4; ++col) { unsetSquare(col,row,gNextBlock); } } var textele = document.getElementById("score"); if(textele) { textele.firstChild.nodeValue = 0; } gDropTimer = DROPTIMER; gLevel = 1; gRowsLeft = ROWSTOCLEAR; var rowsleft = document.getElementById("rowsleft"); if(rowsleft) { // update num rows left text ... rowsleft.firstChild.nodeValue = "" + gRowsLeft; } gNextBlockNum = Math.floor(Math.random()*gBlocks.length); gNextBlockOrient = Math.floor(Math.random()*gBlocks[gNextBlockNum].length); } function dropBlock() { undrawCurrentBlock(); if(doesBlockCollide(gBlocks[gCurrentBlockNum][gCurrentBlockOrient],gCurrentBlockLeft,gCurrentBlockTop+1)) { drawCurrentBlock(); return true; } else { ++gCurrentBlockTop; drawCurrentBlock(); } return false; } function startLevel(levnum) { var leveltext = document.getElementById("leveltext"); if(leveltext) { // update level text... leveltext.firstChild.nodeValue = "Level: " + levnum; } gRowsLeft = ROWSTOCLEAR; var rowsleft = document.getElementById("rowsleft"); if(rowsleft) { // update num rows left text ... rowsleft.firstChild.nodeValue = "" + gRowsLeft; } for(var row = 0; row < 4; ++row) { for(var col = 0; col < 4; ++col) { unsetSquare(col,row,gNextBlock); } } for(var row = 0; row < NUMROWS; ++row) { for(var col = 0; col < NUMCOLS; ++col) { unsetSquare(col,row,gGrid); } } // now randomly set a bunch of blocks var numblockstolay = (levnum-1)*4; while(numblockstolay) { var x = Math.floor(Math.random()*NUMCOLS); var y = NUMROWS - 1 - Math.floor(Math.random()*levnum); setSquare(x,y,gsBlockColors[gsBlockColors.length-1],gGrid); --numblockstolay; } } function doRowCheck() { var numRows = 0; // start from the bottom up, when we get to a row where no squares // had any children, then we are done for(var y = NUMROWS-1; y >=0; --y) { var bAnyOccupied = false; var bAnyMissing = false; for(var x = 0; x < NUMCOLS; ++x) { if(gGrid[y][x].isSet()) { bAnyOccupied = true; } else { bAnyMissing = true; } } // done one row if(!bAnyOccupied) { break; } if(!bAnyMissing) { ++numRows; // row to be deleted and all rows pushed down // start y-loop again, pushing all row contents down by one for(var newy = y; newy >= 0; --newy) { var bStopPushing = true; for(var x = 0; x < NUMCOLS; ++x) { // if square above is occupied then if(gGrid[newy-1][x].isSet()) { bStopPushing = false; gGrid[newy][x].setColor(gGrid[newy-1][x].currentColor); gGrid[newy-1][x].unsetColor(); } else { gGrid[newy][x].unsetColor(); } } // for x if(bStopPushing) { break; } } // for newy ++y; // increment y back so we check the row that was moved down } // if none were missing, we had to remove at least one row } // for y // update score and possibly advance level if(numRows > 0) { gRowsLeft -= numRows; var rowsleft = document.getElementById("rowsleft"); if(rowsleft) { // update num rows left text ... rowsleft.firstChild.nodeValue = "" + gRowsLeft; } var delta = 25; while(numRows > 1) { delta <<= 1; --numRows;} delta *= gLevel; var textele = document.getElementById("score"); if(textele) { // update score... var score = parseInt(textele.firstChild.nodeValue) + delta; textele.firstChild.nodeValue = score+""; } if(gRowsLeft <= 0) { ++gLevel; --DROPTIMER; startLevel(gLevel); } } } function gameTick() { if(gPaused) { return; } if(gCurrentBlockNum == -1) { gDropTimer = DROPTIMER; // check for any complete rows and remove them doRowCheck(); if(!createBlock()) { pauseClick(); alert("Game over!"); restartGame(); } } else if(gDropTimer == 0) { gDropTimer = DROPTIMER; // process drop of block if(dropBlock()) { gCurrentBlockNum = -1; } } else { --gDropTimer; } } function helpoff(evt) { gHelpOn = false; var helpscreen = document.getElementById("helpscreen"); if(helpscreen) { helpscreen.setAttribute("display", "none"); helpscreen.removeEventListener("click", helpoff, false); } } function helpClick(evt) { var butt = evt.currentTarget; if(butt && butt.getAttribute("enabled") == "true" && !gHelpOn) { // pause game pauseClick(evt); gHelpOn = true; var helpscreen = document.getElementById("helpscreen"); if(helpscreen) { helpscreen.setAttribute("display", "inline"); helpscreen.addEventListener("click", helpoff, false); } } } function pauseClick(evt) { if(gHelpOn) { return; } var butt = document.getElementById("pausebut"); if(butt) { setButtonActive(butt,false); } butt = document.getElementById("startbut"); if(butt) { setButtonActive(butt, true); } gPaused = true; } function startClick(evt) { if(gHelpOn) { return; } var butt = document.getElementById("startbut"); if(butt) { setButtonActive(butt, false); } butt = document.getElementById("pausebut"); if(butt) { setButtonActive(butt, true); } gPaused = false; } function toggleEffect(evt) { if(evt && evt.currentTarget) { var effectName = evt.currentTarget.getAttribute("id"); var check = document.getElementById(effectName + "_check"); if(check) { var bEnable = !(check.getAttribute("display") == "inline"); check.setAttribute("display", (bEnable ? "inline" : "none")); switch(effectName) { case "effect_gradback": var canvas = document.getElementById("canvas") if(canvas) { canvas.setAttribute("fill", (bEnable ? "url(#bkgnd)" : "#008")); } break; case "effect_aquabutt": if(bEnable) { gsPressedButtonBkgnd = "url(#pressedbuttonbkgnd)"; gsActiveButtonBkgnd = "url(#activebuttonbkgnd)"; gsInactiveButtonBkgnd = "url(#inactivebuttonbkgnd)"; } else { gsPressedButtonBkgnd = "#a70"; gsActiveButtonBkgnd = "#a00"; gsInactiveButtonBkgnd = "#aaa"; } for(var butt = 0; butt < buttons.length; ++butt) { var buttonuser = document.getElementById(buttons[butt] + "_use"); if(buttonuser) { buttonuser.setAttributeNS(gXLINKNS, "href", (bEnable ? "#button" : "#vanilla_button")); if(buttonuser.parentNode) { var button = buttonuser.parentNode; var bActive = button.getAttribute("enabled"); setButtonActive(button, (bActive=="true")); } } } break; default: alert("Unknown effect"); break; } } } } function initializeButtons() { var button = null; // Start button if( (button = document.getElementById("startbut")) ) { setButtonActive(button, true); button.addEventListener("click", startClick, false); } // Pause button if( (button = document.getElementById("pausebut")) ) { setButtonActive(button, false); button.addEventListener("click", pauseClick, false); } // Help button if( (button = document.getElementById("helpbut")) ) { setButtonActive(button, true); button.addEventListener("click", helpClick, false); } // Effects if( (button = document.getElementById("effect_gradback")) ) { button.addEventListener("click", toggleEffect, false); } if( (button = document.getElementById("effect_aquabutt")) ) { button.addEventListener("click", toggleEffect, false); } // hide "Please Wait" message var msg = document.getElementById("message"); if(msg) { msg.setAttribute("display", "none"); } } function initializeGameboard() { var gamescreen = document.getElementById("gamescreen"); if(!gamescreen) { return; } gamescreen.setAttribute("transform", "translate(240,80)"); // create border var border = document.getElementById("gameborder"); if(border) { var block = null; var sBorderColor = "#666"; for(var row=0; row < NUMROWS+1; ++row) { block = document.createElementNS(gSVGNS, "use"); if(block) { block.setAttributeNS(gXLINKNS, "href", "#matteblock"); block.setAttribute("fill", sBorderColor); block.setAttribute("transform", "translate(1," + (1+row*BLOCKSIZE) + ")"); border.appendChild(block); } block = document.createElementNS(gSVGNS, "use"); if(block) { block.setAttributeNS(gXLINKNS, "href", "#matteblock"); block.setAttribute("fill", sBorderColor); block.setAttribute("transform", "translate(" + (WIDTH-BLOCKSIZE) + "," + (1+row*BLOCKSIZE) + ")"); border.appendChild(block); } } for(var col = 0; col < NUMCOLS+2; ++col) { block = document.createElementNS(gSVGNS, "use"); if(block) { block.setAttributeNS(gXLINKNS, "href", "#matteblock"); block.setAttribute("fill", sBorderColor); block.setAttribute("transform", "translate(" + (col*BLOCKSIZE+1) + "," + (HEIGHT-BLOCKSIZE) + ")"); border.appendChild(block); } } } else { alert("Could not find border group"); } // create grid var gamegrid = document.getElementById("gamegrid"); if(gamegrid) { for(var row = 0; row < NUMROWS; ++row) { var rowg = document.createElementNS(gSVGNS, "g"); rowg.setAttribute("transform", "translate("+BLOCKSIZE+","+(row*BLOCKSIZE)+")"); gGrid[row] = new Array(NUMCOLS); for(var col = 0; col < NUMCOLS; ++col) { var squareg = document.createElementNS(gSVGNS, "g"); squareg.setAttribute("transform", "translate("+(col*BLOCKSIZE)+")"); squareg.setAttribute("width", ""+BLOCKSIZE); squareg.setAttribute("height", ""+BLOCKSIZE); // 2005-11-20: Fix for JS leaks in Firefox gGrid[row][col] = new Cell(squareg); rowg.appendChild(squareg); } // for column gamegrid.appendChild(rowg); } // for row } // create next block (4x4) var nextblok = document.getElementById("nextblok"); if(nextblok) { for(var row = 0; row < 4; ++row) { var rowg = document.createElementNS(gSVGNS, "g"); rowg.setAttribute("transform", "translate("+BLOCKSIZE+","+(row*BLOCKSIZE)+")"); gNextBlock[row] = new Array(4); for(var col = 0; col < 4; ++col) { var squareg = document.createElementNS(gSVGNS, "g"); squareg.setAttribute("transform", "translate("+(col*BLOCKSIZE)+")"); squareg.setAttribute("width", ""+BLOCKSIZE); squareg.setAttribute("height", ""+BLOCKSIZE); // 2005-11-20: Fix for JS leaks in Firefox gNextBlock[row][col] = new Cell(squareg); rowg.appendChild(squareg); } nextblok.appendChild(rowg); } } } function displayAll() { var ele = null; var num = 0; // display elements for(num = 0; num < displayableElements.length; ++num) { if( (ele = document.getElementById(displayableElements[num])) ) { ele.setAttribute("display", "inline"); } } } function getKey(evt) { if(gCurrentBlockNum == -1) { return; } evt.preventDefault(); // if we're paused, only accept the start key if(gPaused && (evt.keyCode == KEY_S)) { startClick(); } // if paused // else, any key else { switch(evt.keyCode) { case KEY_LEFT: undrawCurrentBlock(); if(!doesBlockCollide(gBlocks[gCurrentBlockNum][gCurrentBlockOrient],gCurrentBlockLeft-1,gCurrentBlockTop)) { --gCurrentBlockLeft; } drawCurrentBlock(); break; case KEY_RIGHT: undrawCurrentBlock(); if(!doesBlockCollide(gBlocks[gCurrentBlockNum][gCurrentBlockOrient],gCurrentBlockLeft+1,gCurrentBlockTop)) { ++gCurrentBlockLeft; } drawCurrentBlock(); break; case KEY_UP: undrawCurrentBlock(); rotateCurrentBlock(true); if(doesBlockCollide(gBlocks[gCurrentBlockNum][gCurrentBlockOrient],gCurrentBlockLeft,gCurrentBlockTop)) { rotateCurrentBlock(true); } drawCurrentBlock(); break; case KEY_DOWN: gDropTimer = 0; break; case KEY_SPACE: // this drops the current block down as fast as possible while(!dropBlock()) {} gCurrentBlockNum = -1; break; case KEY_S: startClick(); break; case KEY_P: case KEY_Q: pauseClick(); break; } // switch } // else } function rotateCurrentBlock(bClockwise) { if(gCurrentBlockNum == -1) { return; } if(bClockwise) { ++gCurrentBlockOrient; if(gCurrentBlockOrient >= gBlocks[gCurrentBlockNum].length) { gCurrentBlockOrient = 0; } } else { --gCurrentBlockOrient; if(gCurrentBlockOrient < 0) { gCurrentBlockOrient = gBlocks[gCurrentBlockNum].length-1; } } } function init() { initializeButtons(); initializeGameboard(); restartGame(); // now we're all ready, display everything // display all in one fell swoop displayAll(); var svg = document.getElementById("svgsvg"); if(svg) { svg.setAttribute("cursor", "default"); svg.addEventListener("keydown", getKey, false); } setInterval("gameTick()", 10); } 演示地址:http://www.codedread.com/yastgame.php
|