以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 SVG/GML/VRML/X3D/XAML 』  (http://bbs.xml.org.cn/list.asp?boardid=21)
----  [转帖]SVG实例展-俄罗斯方块  (http://bbs.xml.org.cn/dispbbs.asp?boardid=21&rootid=&id=30508)


--  作者: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


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
734.375ms