Forum'da ara:
Ara


« Önceki başlık :: Sonraki başlık »  
Yazar Mesaj
Mesaj24.09.2008, 18:08 (UTC)    
Mesaj konusu: Tetris Oyunu

Tetris Oyunu


Kod:
<script type="text/javascript">
/* This script and many more are available free online at
The JavaScript Source!! http://javascript.internet.com
Created by: Cezary Tomczak | http://gosu.pl/Licensed under: BSD
 */

/*
 * PROJECT:  JsTetris
 * VERSION:  1.1.0
 * LICENSE:  BSD (revised)
 * AUTHOR:   (c) 2004 Cezary Tomczak
 * LINK:     http://gosu.pl/dhtml/JsTetris.html
 *
 * This script can be used freely as long as all
 * copyright messages are intact.
 */

/**
 * Tetris Game
 * Initializes the buttons automatically, no additional actions required
 *
 * Score:
 * 1) puzzle speed = 80+700/level
 * 2) if puzzles created in current level >= 10+level*2 then increase level
 * 3) after puzzle falling score is increased by 1000*level*linesRemoved
 * 4) each down action increases score by 5+level
 *
 * API:
 *
 * public - method can be called outside of the object
 * event - method is used as event, "this" refers to html object, "self" refers to javascript object
 *
 * class Tetris
 * ------------
 * public event void start()
 * public event void reset()
 * public event void gameOver()
 * public event void up()
 * public event void down()
 * public event void left()
 * public event void right()
 * public event void space()
 *
 * class Window
 * ------------
 * event void activate()
 * event void close()
 * public bool isActive()
 *
 * class Keyboard
 * --------------
 * public void set(int key, function func)
 * event void event(object e)
 *
 * class Stats
 * -----------
 * public void start()
 * public void stop()
 * public void reset()
 * public event void incTime()
 * public void setScore(int i)
 * public void setLevel(int i)
 * public void setLines(int i)
 * public void setPuzzles(int i)
 * public void setActions(int i)
 * public int getScore()
 * public int getLevel()
 * public int getLines()
 * public int getPuzzles()
 * public int getActions()
 *
 * class Area
 * ----------
 * public Constructor(int unit, int x, int y, string id)
 * public void destroy()
 * public int removeFullLines()
 * public bool isLineFull(int y)
 * public void removeLine(int y)
 * public mixed getBlock(int y, int x)
 * public void addElement(htmlObject el)
 *
 * class Puzzle
 * ------------
 * public Constructor(object area)
 * public void reset()
 * public bool isRunning()
 * public bool isStopped()
 * public int getX()
 * public int getY()
 * public bool mayPlace()
 * public void place()
 * public void destroy()
 * private array createEmptyPuzzle(int y, int x)
 * event void fallDown()
 * public event void forceMoveDown()
 * public void stop()
 * public bool mayRotate()
 * public void rotate()
 * public bool mayMoveDown()
 * public void moveDown()
 * public bool mayMoveLeft()
 * public void moveLeft()
 * public bool mayMoveRight()
 * public void moveRight()
 *
 * class Highscores
 * ----------------
 * public Constructor(maxscores)
 * public void load()
 * public void save()
 * public bool mayAdd(int score)
 * public void add(string name, int score)
 * public array getScores()
 * public string toHtml()
 * private void sort()
 *
 * class Cookie
 * ------------
 * public string get(string name)
 * public void set(string name, string value, int seconds, string path, string domain, bool secure)
 * public void del(string name)
 *
 * TODO:
 * document.getElementById("tetris-nextpuzzle") cache ?
 *
 */
function Tetris() {

    var self = this;

    this.stats = new Stats();
    this.puzzle = null;
    this.area = null;

    this.unit  = 20; // unit = x pixels
    this.areaX = 20; // area width = x units
    this.areaY = 20; // area height = y units

    this.highscores = new Highscores(10);

    /**
     * @return void
     * @access public event
     */
    this.start = function() {
        self.reset();
        self.stats.start();
        document.getElementById("tetris-nextpuzzle").style.display = "block";
        self.area = new Area(self.unit, self.areaX, self.areaY, "tetris-area");
        self.puzzle = new Puzzle(self, self.area);
        if (self.puzzle.mayPlace()) {
            self.puzzle.place();
        } else {
            self.gameOver();
        }
    }

    /**
     * @return void
     * @access public event
     */
    this.reset = function() {
        if (self.puzzle) {
            self.puzzle.destroy();
            self.puzzle = null;
        }
        if (self.area) {
            self.area.destroy();
            self.area = null;
        }
        document.getElementById("tetris-gameover").style.display = "none";
        document.getElementById("tetris-nextpuzzle").style.display = "none";
        self.stats.reset();
    }

    /**
     * End game.
     * Stop stats, ...
     * @return void
     * @access public event
     */
    this.gameOver = function() {
        self.stats.stop();
        self.puzzle.stop();
        document.getElementById("tetris-nextpuzzle").style.display = "none";
        document.getElementById("tetris-gameover").style.display = "block";
        if (this.highscores.mayAdd(this.stats.getScore())) {
            var name = prompt("Game Over !\nEnter your name:", "");
            if (name && name.trim().length) {
                this.highscores.add(name, this.stats.getScore());
            }
        }
    }

    /**
     * @return void
     * @access public event
     */
    this.up = function() {
        if (self.puzzle && self.puzzle.isRunning() && !self.puzzle.isStopped()) {
            if (self.puzzle.mayRotate()) {
                self.puzzle.rotate();
                self.stats.setActions(self.stats.getActions() + 1);
            }
        }
    }

    /**
     * @return void
     * @access public event
     */
    this.down = function() {
        if (self.puzzle && self.puzzle.isRunning() && !self.puzzle.isStopped()) {
            if (self.puzzle.mayMoveDown()) {
                self.stats.setScore(self.stats.getScore() + 5 + self.stats.getLevel());
                self.puzzle.moveDown();
                self.stats.setActions(self.stats.getActions() + 1);
            }
        }
    }

    /**
     * @return void
     * @access public event
     */
    this.left = function() {
        if (self.puzzle && self.puzzle.isRunning() && !self.puzzle.isStopped()) {
            if (self.puzzle.mayMoveLeft()) {
                self.puzzle.moveLeft();
                self.stats.setActions(self.stats.getActions() + 1);
            }
        }
    }

    /**
     * @return void
     * @access public event
     */
    this.right = function() {
        if (self.puzzle && self.puzzle.isRunning() && !self.puzzle.isStopped()) {
            if (self.puzzle.mayMoveRight()) {
                self.puzzle.moveRight();
                self.stats.setActions(self.stats.getActions() + 1);
            }
        }
    }

    /**
     * @return void
     * @access public event
     */
    this.space = function() {
        if (self.puzzle && self.puzzle.isRunning() && !self.puzzle.isStopped()) {
            self.puzzle.stop();
            self.puzzle.forceMoveDown();
        }
    }

    // windows
    var helpwindow = new Window("tetris-help");
    var highscores = new Window("tetris-highscores");

    // game menu
    document.getElementById("tetris-menu-start").onclick = function() { helpwindow.close(); highscores.close(); self.start(); this.blur(); }
    document.getElementById("tetris-menu-reset").onclick = function() { helpwindow.close(); highscores.close(); self.reset(); this.blur(); }

    // help
    document.getElementById("tetris-menu-help").onclick = function() { highscores.close(); helpwindow.activate(); this.blur(); }
    document.getElementById("tetris-help-close").onclick = helpwindow.close;

    // highscores
    document.getElementById("tetris-menu-highscores").onclick = function() {
        helpwindow.close();
        document.getElementById("tetris-highscores-content").innerHTML = self.highscores.toHtml();
        highscores.activate();
        this.blur();
    }
    document.getElementById("tetris-highscores-close").onclick = highscores.close;

    // keyboard - buttons
    document.getElementById("tetris-keyboard-up").onclick = function() { self.up(); this.blur(); }
    document.getElementById("tetris-keyboard-down").onclick = function() { self.down(); this.blur(); }
    document.getElementById("tetris-keyboard-left").onclick = function () { self.left(); this.blur(); }
    document.getElementById("tetris-keyboard-right").onclick = function() { self.right(); this.blur(); }

    // keyboard
    var keyboard = new Keyboard();
    keyboard.set(keyboard.n, this.start);
    keyboard.set(keyboard.r, this.reset);
    keyboard.set(keyboard.up, this.up);
    keyboard.set(keyboard.down, this.down);
    keyboard.set(keyboard.left, this.left);
    keyboard.set(keyboard.right, this.right);
    keyboard.set(keyboard.space, this.space);
    document.onkeydown = keyboard.event;

    /**
     * Window replaces game area, for example help window
     * @param string id
     */
    function Window(id) {

        this.id = id;
        this.el = document.getElementById(this.id);
        var self = this;

        /**
         * Activate or deactivate a window - update html
         * @return void
         * @access event
         */
        this.activate = function() {
            self.el.style.display = (self.el.style.display == "block" ? "none" : "block");
        }

        /**
         * Close window - update html
         * @return void
         * @access event
         */
        this.close = function() {
            self.el.style.display = "none";
        }

        /**
         * @return bool
         * @access public
         */
        this.isActive = function() {
            return (self.el.style.display == "block");
        }
    }

    /**
     * Assigning functions to keyboard events
     * When key is pressed, searching in a table if any function has been assigned to this key, execute the function.
     */
    function Keyboard() {

        this.up = 38;
        this.down = 40;
        this.left = 37;
        this.right = 39;
        this.n = 78;
        this.r = 82;
        this.space = 32;
        this.f12 = 123;
        this.escape = 27;

        this.keys = [];
        this.funcs = [];

        var self = this;

        /**
         * @param int key
         * @param function func
         * @return void
         * @access public
         */
        this.set = function(key, func) {
            this.keys.push(key);
            this.funcs.push(func);
        }

        /**
         * @param object e
         * @return void
         * @access event
         */
        this.event = function(e) {
            if (!e) { e = window.event; }
            for (var i = 0; i < self.keys.length; i++) {
                if (e.keyCode == self.keys[i]) {
                    self.funcs[i]();
                }
            }
        }
    }

    /**
     * Live game statistics
     * Updating html
     */
    function Stats() {

        this.level;
        this.time;
        this.apm;
        this.lines;
        this.score;
        this.puzzles; // number of puzzles created on current level

        this.actions;

        this.el = {
            "level": document.getElementById("tetris-stats-level"),
            "time":  document.getElementById("tetris-stats-time"),
            "apm":   document.getElementById("tetris-stats-apm"),
            "lines": document.getElementById("tetris-stats-lines"),
            "score": document.getElementById("tetris-stats-score")
        }

        this.timerId = null;
        var self = this;

        /**
         * Start counting statistics, reset stats, turn on the timer
         * @return void
         * @access public
         */
        this.start = function() {
            this.reset();
            this.timerId = setInterval(this.incTime, 1000);
        }

        /**
         * Stop counting statistics, turn off the timer
         * @return void
         * @access public
         */
        this.stop = function() {
            if (this.timerId) {
                clearInterval(this.timerId);
            }
        }

        /**
         * Reset statistics - update html
         * @return void
         * @access public
         */
        this.reset = function() {
            this.stop();
            this.level = 1;
            this.time  = 0;
            this.apm   = 0;
            this.lines = 0;
            this.score = 0;
            this.puzzles = 0;
            this.actions = 0;
            this.el.level.innerHTML = this.level;
            this.el.time.innerHTML  = this.time;
            this.el.apm.innerHTML   = this.apm;
            this.el.lines.innerHTML = this.lines;
            this.el.score.innerHTML = this.score;
        }

        /**
         * Increase time, update apm - update html
         * This func is called by setInterval()
         * @return void
         * @access public event
         */
        this.incTime = function() {
            self.time++;
            self.el.time.innerHTML = self.time;
            self.apm = parseInt((self.actions / self.time) * 60);
            self.el.apm.innerHTML = self.apm;
        }

        /**
         * Set score - update html
         * @param int i
         * @return void
         * @access public
         */
        this.setScore = function(i) {
            this.score = i;
            this.el.score.innerHTML = this.score;
        }

        /**
         * Set level - update html
         * @param int i
         * @return void
         * @access public
         */
        this.setLevel = function(i) {
            this.level = i;
            this.el.level.innerHTML = this.level;
        }

        /**
         * Set lines - update html
         * @param int i
         * @return void
         * @access public
         */
        this.setLines = function(i) {
            this.lines = i;
            this.el.lines.innerHTML = this.lines;
        }

        /**
         * Number of puzzles created on current level
         * @param int i
         * @return void
         * @access public
         */
        this.setPuzzles = function(i) {
            this.puzzles = i;
        }

        /**
         * @param int i
         * @return void
         * @access public
         */
        this.setActions = function(i) {
            this.actions = i;
        }

        /**
         * @return int
         * @access public
         */
        this.getScore = function() {
            return this.score;
        }

        /**
         * @return int
         * @access public
         */
        this.getLevel = function() {
            return this.level;
        }

        /**
         * @return int
         * @access public
         */
        this.getLines = function() {
            return this.lines;
        }

        /**
         * Number of puzzles created on current level
         * @return int
         * @access public
         */
        this.getPuzzles = function() {
            return this.puzzles;
        }

        /**
         * @return int
         * @access public
         */
        this.getActions = function() {
            return this.actions;
        }
    }

    /**
     * Area consists of blocks (2 dimensional board).
     * Block contains "0" (if empty) or Html Object.
     * @param int x
     * @param int y
     * @param string id
     */
    function Area(unit, x, y, id) {

        this.unit = unit;
        this.x = x;
        this.y = y;
        this.el = document.getElementById(id);

        this.board = [];

        // create 2-dimensional board
        for (var y = 0; y < this.y; y++) {
            this.board.push(new Array());
            for (var x = 0; x < this.x; x++) {
                this.board[y].push(0);
            }
        }

        /**
         * Removing html elements from area.
         * @return void
         * @access public
         */
        this.destroy = function() {
            for (var y = 0; y < this.board.length; y++) {
                for (var x = 0; x < this.board[y].length; x++) {
                    if (this.board[y][x]) {
                        this.el.removeChild(this.board[y][x]);
                        this.board[y][x] = 0;
                    }
                }
            }
        }

        /**
         * Searching for full lines.
         * Must go from the bottom of area to the top.
         * Returns the number of lines removed - needed for Stats.score.
         * @see isLineFull() removeLine()
         * @return void
         * @access public
         */
        this.removeFullLines = function() {
            var lines = 0;
            for (var y = this.y - 1; y > 0; y--) {
                if (this.isLineFull(y)) {
                    this.removeLine(y);
                    lines++;
                    y++;
                }
            }
            return lines;
        }

        /**
         * @param int y
         * @return bool
         * @access public
         */
        this.isLineFull = function(y) {
            for (var x = 0; x < this.x; x++) {
                if (!this.board[y][x]) { return false; }
            }
            return true;
        }

        /**
         * Remove given line
         * Remove html objects
         * All lines that are above given line move down by 1 unit
         * @param int y
         * @return void
         * @access public
         */
        this.removeLine = function(y) {
            for (var x = 0; x < this.x; x++) {
                this.el.removeChild(this.board[y][x]);
                this.board[y][x] = 0;
            }
            y--;
            for (; y > 0; y--) {
                for (var x = 0; x < this.x; x++) {
                    if (this.board[y][x]) {
                        var el = this.board[y][x];
                        el.style.top = el.offsetTop + this.unit + "px";
                        this.board[y+1][x] = el;
                        this.board[y][x] = 0;
                    }
                }
            }
        }

        /**
         * @param int y
         * @param int x
         * @return mixed 0 or Html Object
         * @access public
         */
        this.getBlock = function(y, x) {
            if (y < 0) { return 0; }
            if (y < this.y && x < this.x) {
                return this.board[y][x];
            } else {
                throw "Area.getBlock("+y+", "+x+") failed";
            }
        }

        /**
         * Add Html Element to the area.
         * Find (x,y) position using offsetTop and offsetLeft
         * @param object el
         * @return void
         * @access public
         */
        this.addElement = function(el) {
            var x = parseInt(el.offsetLeft / this.unit);
            var y = parseInt(el.offsetTop / this.unit);
            if (y >= 0 && y < this.y && x >= 0 && x < this.x) {
                this.board[y][x] = el;
            } else {
                // not always an error ..
            }
        }
    }

    /**
     * Puzzle consists of blocks.
     * Each puzzle after rotating 4 times, returns to its primitive position.
     */
    function Puzzle(tetris, area) {

        var self = this;
        this.tetris = tetris;
        this.area = area;

        // timeout ids
        this.fallDownID = null;
        this.forceMoveDownID = null;

        this.type = null; // 0..6
        this.nextType = null; // next puzzle
        this.position = null; // 0..3
        this.speed = null;
        this.running = null;
        this.stopped = null;

        this.board = []; // filled with html elements after placing on area
        this.elements = [];
        this.nextElements = []; // next board elements

        // (x,y) position of the puzzle (top-left)
        this.x = null;
        this.y = null;

        // width & height must be the same
        this.puzzles = [
            [
                [0,0,1],
                [1,1,1],
                [0,0,0]
            ],
            [
                [1,0,0],
                [1,1,1],
                [0,0,0]
            ],
            [
                [0,1,1],
                [1,1,0],
                [0,0,0]
            ],
            [
                [1,1,0],
                [0,1,1],
                [0,0,0]
            ],
            [
                [0,1,0],
                [1,1,1],
                [0,0,0]
            ],
            [
                [1,1],
                [1,1]
            ],
            [
                [0,0,0,0],
                [1,1,1,1],
                [0,0,0,0],
                [0,0,0,0]
            ]
        ];

        /**
         * Reset puzzle. It does not destroy html elements in this.board.
         * @return void
         * @access public
         */
        this.reset = function() {
            if (this.fallDownID) {
                clearTimeout(this.fallDownID);
            }
            if (this.forceMoveDownID) {
                clearTimeout(this.forceMoveDownID);
            }
            this.type = this.nextType;
            this.nextType = random(this.puzzles.length);
            this.position = 0;
            this.speed = 80 + (700 / this.tetris.stats.getLevel());
            this.running = false;
            this.stopped = false;
            this.board = [];
            this.elements = [];
            for (var i = 0; i < this.nextElements.length; i++) {
                document.getElementById("tetris-nextpuzzle").removeChild(this.nextElements[i]);
            }
            this.nextElements = [];
            this.x = null;
            this.y = null;
        }

        this.nextType = random(this.puzzles.length);
        this.reset();

        /**
         * Check whether puzzle is running.
         * @return bool
         * @access public
         */
        this.isRunning = function() {
            return this.running;
        }

        /**
         * Check whether puzzle has been stopped by user. It happens when user clicks
         * "down" when puzzle is already at the bottom of area. The puzzle may still
         * be running with event fallDown(). When puzzle is stopped, no actions will be
         * performed when user press a key.
         * @return bool
         * @access public
         */
        this.isStopped = function() {
            return this.stopped;
        }

        /**
         * Get X position of puzzle (top-left)
         * @return int
         * @access public
         */
        this.getX = function() {
            return this.x;
        }

        /**
         * Get Y position of puzzle (top-left)
         * @return int
         * @access public
         */
        this.getY = function() {
            return this.y;
        }

        /**
         * Check whether new puzzle may be placed on the area.
         * Find (x,y) in area where beginning of the puzzle will be placed.
         * Check if first puzzle line (checking from the bottom) can be placed on the area.
         * @return bool
         * @access public
         */
        this.mayPlace = function() {
            var puzzle = this.puzzles[this.type];
            var areaStartX = parseInt((this.area.x - puzzle[0].length) / 2);
            var areaStartY = 1;
            var lineFound = false;
            var lines = 0;
            for (var y = puzzle.length - 1; y >= 0; y--) {
                for (var x = 0; x < puzzle[y].length; x++) {
                    if (puzzle[y][x]) {
                        lineFound = true;
                        if (this.area.getBlock(areaStartY, areaStartX + x)) { return false; }
                    }
                }
                if (lineFound) {
                    lines++;
                }
                if (areaStartY - lines < 0) {
                    break;
                }
            }
            return true;
        }

        /**
         * Create empty board, create blocks in area - html objects, update puzzle board.
         * Check puzzles on current level, increase level if needed.
         * @return void
         * @access public
         */
        this.place = function() {
            // stats
            this.tetris.stats.setPuzzles(this.tetris.stats.getPuzzles() + 1);
            if (this.tetris.stats.getPuzzles() >= (10 + this.tetris.stats.getLevel() * 2)) {
             this.tetris.stats.setLevel(this.tetris.stats.getLevel() + 1);
             this.tetris.stats.setPuzzles(0);
          }
            // init
            var puzzle = this.puzzles[this.type];
            var areaStartX = parseInt((this.area.x - puzzle[0].length) / 2);
            var areaStartY = 1;
            var lineFound = false;
            var lines = 0;
            this.x = areaStartX;
            this.y = 1;
            this.board = this.createEmptyPuzzle(puzzle.length, puzzle[0].length);
            // create puzzle
            for (var y = puzzle.length - 1; y >= 0; y--) {
                for (var x = 0; x < puzzle[y].length; x++) {
                    if (puzzle[y][x]) {
                        lineFound = true;
                        var el = document.createElement("div");
                        el.className = "block" + this.type;
                        el.style.left = (areaStartX + x) * this.area.unit + "px";
                        el.style.top = (areaStartY - lines) * this.area.unit + "px";
                        this.area.el.appendChild(el);
                        this.board[y][x] = el;
                        this.elements.push(el);
                    }
                }
                if (lines) {
                    this.y--;
                }
                if (lineFound) {
                    lines++;
                }
            }
            this.running = true;
            this.fallDownID = setTimeout(this.fallDown, this.speed);
            // next puzzle
            var nextPuzzle = this.puzzles[this.nextType];
            for (var y = 0; y < nextPuzzle.length; y++) {
                for (var x = 0; x < nextPuzzle[y].length; x++) {
                    if (nextPuzzle[y][x]) {
                        var el = document.createElement("div");
                        el.className = "block" + this.nextType;
                        el.style.left = (x * this.area.unit) + "px";
                        el.style.top = (y * this.area.unit) + "px";
                        document.getElementById("tetris-nextpuzzle").appendChild(el);
                        this.nextElements.push(el);
                    }
                }
            }
        }

        /**
         * Remove puzzle from the area.
         * Clean some other stuff, see reset()
         * @return void
         * @access public
         */
        this.destroy = function() {
            for (var i = 0; i < this.elements.length; i++) {
                this.area.el.removeChild(this.elements[i]);
            }
            this.elements = [];
            this.board = [];
            this.reset();
        }

        /**
         * @param int y
         * @param int x
         * @return array
         * @access private
         */
        this.createEmptyPuzzle = function(y, x) {
            var puzzle = [];
            for (var y2 = 0; y2 < y; y2++) {
                puzzle.push(new Array());
                for (var x2 = 0; x2 < x; x2++) {
                    puzzle[y2].push(0);
                }
            }
            return puzzle;
        }

        /**
         * Puzzle fall from the top to the bottom.
         * After placing a puzzle, this event will be called as long as the puzzle is running.
         * @see place() stop()
         * @return void
         * @access event
         */
        this.fallDown = function() {
            if (self.isRunning()) {
                if (self.mayMoveDown()) {
                    self.moveDown();
                    self.fallDownID = setTimeout(self.fallDown, self.speed);
                } else {
                    // move blocks into area board
                    for (var i = 0; i < self.elements.length; i++) {
                        self.area.addElement(self.elements[i]);
                    }
                    // stats
                    var lines = self.area.removeFullLines();
                    if (lines) {
                        self.tetris.stats.setLines(self.tetris.stats.getLines() + lines);
                        self.tetris.stats.setScore(self.tetris.stats.getScore() + (1000 * self.tetris.stats.getLevel() * lines));
                    }
                    // reset puzzle
                    self.reset();
                    if (self.mayPlace()) {
                        self.place();
                    } else {
                        self.tetris.gameOver();
                    }
                }
            }
        }

        /**
         * After clicking "space" the puzzle is forced to move down, no user action is performed after
         * this event is called. this.running must be set to false. This func is similiar to fallDown()
         * Also update score & actions - like Tetris.down()
         * @see fallDown()
         * @return void
         * @access public event
         */
        this.forceMoveDown = function() {
            if (!self.isRunning() && !self.isStopped()) {
                if (self.mayMoveDown()) {
                    // stats: score, actions
                    self.tetris.stats.setScore(self.tetris.stats.getScore() + 5 + self.tetris.stats.getLevel());
                    self.tetris.stats.setActions(self.tetris.stats.getActions() + 1);
                    self.moveDown();
                    self.forceMoveDownID = setTimeout(self.forceMoveDown, 30);
                } else {
                    // move blocks into area board
                    for (var i = 0; i < self.elements.length; i++) {
                        self.area.addElement(self.elements[i]);
                    }
                    // stats: lines
                    var lines = self.area.removeFullLines();
                    if (lines) {
                        self.tetris.stats.setLines(self.tetris.stats.getLines() + lines);
                        self.tetris.stats.setScore(self.tetris.stats.getScore() + (1000 * self.tetris.stats.getLevel() * lines));
                    }
                    // reset puzzle
                    self.reset();
                    if (self.mayPlace()) {
                        self.place();
                    } else {
                        self.tetris.gameOver();
                    }
                }
            }
        }

        /**
         * Stop the puzzle falling
         * @return void
         * @access public
         */
        this.stop = function() {
            this.running = false;
        }

        /**
         * Check whether puzzle may be rotated.
         * Check down, left, right, rotate
         * @return bool
         * @access public
         */
        this.mayRotate = function() {
            for (var y = 0; y < this.board.length; y++) {
                for (var x = 0; x < this.board[y].length; x++) {
                    if (this.board[y][x]) {
                        var newY = this.getY() + this.board.length - 1 - x;
                        var newX = this.getX() + y;
                        if (newY >= this.area.y) { return false; }
                        if (newX < 0) { return false; }
                        if (newX >= this.area.x) { return false; }
                        if (this.area.getBlock(newY, newX)) { return false; }
                    }
                }
            }
            return true;
        }

        /**
         * Rotate the puzzle to the left.
         * @return void
         * @access public
         */
        this.rotate = function() {
            var puzzle = this.createEmptyPuzzle(this.board.length, this.board[0].length);
            for (var y = 0; y < this.board.length; y++) {
                for (var x = 0; x < this.board[y].length; x++) {
                    if (this.board[y][x]) {
                        var newY = puzzle.length - 1 - x;
                        var newX = y;
                        var el = this.board[y][x];
                        var moveY = newY - y;
                        var moveX = newX - x;
                        el.style.left = el.offsetLeft + (moveX * this.area.unit) + "px";
                        el.style.top = el.offsetTop + (moveY * this.area.unit) + "px";
                        puzzle[newY][newX] = el;
                    }
                }
            }
            this.board = puzzle;
        }

        /**
         * Check whether puzzle may be moved down.
         * - is any other puzzle on the way ?
         * - is it end of the area ?
         * If false, then true is assigned to variable this.stopped - no user actions will be performed to this puzzle,
         * so this func should be used carefully, only in Tetris.down() and Tetris.puzzle.fallDown()
         * @return bool
         * @access public
         */
        this.mayMoveDown = function() {
            for (var y = 0; y < this.board.length; y++) {
                for (var x = 0; x < this.board[y].length; x++) {
                    if (this.board[y][x]) {
                        if (this.getY() + y + 1 >= this.area.y) { this.stopped = true; return false; }
                        if (this.area.getBlock(this.getY() + y + 1, this.getX() + x)) { this.stopped = true; return false; }
                    }
                }
            }
            return true;
        }

        /**
         * Move the puzzle down by 1 unit.
         * @return void
         * @access public
         */
        this.moveDown = function() {
            for (var i = 0; i < this.elements.length; i++) {
                this.elements[i].style.top = this.elements[i].offsetTop + this.area.unit + "px";
            }
            this.y++;
        }

        /**
         * Check whether puzzle may be moved left.
         * - is any other puzzle on the way ?
         * - is the end of the area
         * @return bool
         * @access public
         */
        this.mayMoveLeft = function() {
            for (var y = 0; y < this.board.length; y++) {
                for (var x = 0; x < this.board[y].length; x++) {
                    if (this.board[y][x]) {
                        if (this.getX() + x - 1 < 0) { return false; }
                        if (this.area.getBlock(this.getY() + y, this.getX() + x - 1)) { return false; }
                    }
                }
            }
            return true;
        }

        /**
         * Move the puzzle left by 1 unit
         * @return void
         * @access public
         */
        this.moveLeft = function() {
            for (var i = 0; i < this.elements.length; i++) {
                this.elements[i].style.left = this.elements[i].offsetLeft - this.area.unit + "px";
            }
            this.x--;
        }

        /**
         * Check whether puzle may be moved right.
         * - is any other puzzle on the way ?
         * - is the end of the area
         * @return bool
         * @access public
         */
        this.mayMoveRight = function() {
            for (var y = 0; y < this.board.length; y++) {
                for (var x = 0; x < this.board[y].length; x++) {
                    if (this.board[y][x]) {
                        if (this.getX() + x + 1 >= this.area.x) { return false; }
                        if (this.area.getBlock(this.getY() + y, this.getX() + x + 1)) { return false; }
                    }
                }
            }
            return true;
        }

        /**
         * Move the puzzle right by 1 unit.
         * @return void
         * @access public
         */
        this.moveRight = function() {
            for (var i = 0; i < this.elements.length; i++) {
                this.elements[i].style.left = this.elements[i].offsetLeft + this.area.unit + "px";
            }
            this.x++;
        }
    }

    /**
     * Generates random number that is >= 0 and < i
     * @return int
     * @access private
     */
    function random(i) {
        return Math.floor(Math.random() * i);
    }

    /**
     * Store highscores in cookie.
     */
    function Highscores(maxscores) {
        this.maxscores = maxscores;
        this.scores = [];

        /**
         * Load scores from cookie.
         * Note: it is automatically called when creating new instance of object Highscores.
         * @return void
         * @access public
         */
        this.load = function() {
            var cookie = new Cookie();
            var s = cookie.get("tetris-highscores");
            this.scores = [];
            if (s.length) {
                var scores = s.split("|");
                for (var i = 0; i < scores.length; ++i) {
                    var a = scores[i].split(":");
                    this.scores.push(new Score(a[0], Number(a[1])));
                }
            }


        }

        /**
         * Save scores to cookie.
         * Note: it is automatically called after adding new score.
         * @return void
         * @access public
         */
        this.save = function() {
            var cookie = new Cookie();
            var a = [];
            for (var i = 0; i < this.scores.length; ++i) {
                a.push(this.scores[i].name+":"+this.scores[i].score);
            }
            var s = a.join("|");
            cookie.set("tetris-highscores", s, 3600*24*1000);
        }

        /**
         * Is the score high enough to be able to add ?
         * @return bool
         * @access public
         */
        this.mayAdd = function(score) {
            if (this.scores.length < this.maxscores) { return true; }
            for (var i = this.scores.length - 1; i >= 0; --i) {
                if (this.scores[i].score < score) { return true; }
            }
            return false;
        }

        /**
         * @param string name
         * @param int score
         * @return void
         * @access public
         */
        this.add = function(name, score) {
            name = name.replace(/[;=:|]/g, "?");
            name = name.replace(/</g, "<").replace(/>/g, ">");
            if (this.scores.length < this.maxscores) {
                this.scores.push(new Score(name, score));
            } else {
                for (var i = this.scores.length - 1; i >= 0; --i) {
                    if (this.scores[i].score < score) {
                        this.scores.removeByIndex(i);
                        this.scores.push(new Score(name, score));
                        break;
                    }
                }
            }
            this.sort();
            this.save();
        }

        /**
         * Get array of scores.
         * @return array [Score, Score, ..]
         * @access public
         */
        this.getScores = function() {
            return this.scores;
        }

        /**
         * All highscores returned in html friendly format.
         * @return string
         * @access public
         */
        this.toHtml = function() {
            var s = '<table cellspacing="0" cellpadding="2"><tr><th></th><th>Name</th><th>Score</th></tr>';
            for (var i = 0; i < this.scores.length; ++i) {
                s += '<tr><td>?.</td><td>?</td><td>?</td></tr>'.format(i+1, this.scores[i].name, this.scores[i].score);
            }
            s += '</table>';
            return s;
        }

        /**
         * Sort table with scores.
         * @return void
         * @access private
         */
        this.sort = function() {
            var scores = this.scores;
            var len = scores.length;
            this.scores = [];
            for (var i = 0; i < len; ++i) {
                var el = null, index = null;
                for (var j = 0; j < scores.length; ++j) {
                    if (!el || (scores[j].score > el.score)) {
                        el = scores[j];
                        index = j;
                    }
                }
                scores.removeByIndex(index);
                this.scores.push(el);
            }
        }

        /* Simple score object. */
        function Score(name, score) {
            this.name = name;
            this.score = score;
        }

        this.load();
    }

    /**
     * Managing cookies.
     */
    function Cookie() {

        /**
         * @param string name
         * @return string
         * @access public
         */
        this.get = function(name) {
            var cookies = document.cookie.split(";");
            for (var i = 0; i < cookies.length; ++i) {
                var a = cookies[i].split("=");
                if (a.length == 2) {
                    a[0] = a[0].trim();
                    a[1] = a[1].trim();
                    if (a[0] == name) {
                        return unescape(a[1]);
                    }
                }
            }
            return "";
        };

        /**
         * @param string name
         * @param string value (do not use special chars like ";" "=")
         * @param int seconds
         * @param string path
         * @param string domain
         * @param bool secure
         * @return void
         * @access public
         */
        this.set = function(name, value, seconds, path, domain, secure) {
            var cookie = (name + "=" + escape(value));
            if (seconds) {
                var date = new Date(new Date().getTime()+seconds*1000);
                cookie += ("; expires="+date.toGMTString());
            }
            cookie += (path    ? "; path="+path : "");
            cookie += (domain  ? "; domain="+domain : "");
            cookie += (secure  ? "; secure" : "");
            document.cookie = cookie;
        };

        /**
         * @param name
         * @return void
         * @access public
         */
        this.del = function(name) {
            document.cookie = name + "=; expires=Thu, 01-Jan-70 00:00:01 GMT";
        };
    }
}

if (!String.prototype.trim) {
    String.prototype.trim = function() {
        return this.replace(/^\s*|\s*$/g, "");
    };
}

if (!Array.prototype.removeByIndex) {
    Array.prototype.removeByIndex = function(index) {
        this.splice(index, 1);
    };
}

if (!String.prototype.format) {
    String.prototype.format = function() {
        if (!arguments.length) { throw "String.format() failed, no arguments passed, this = "+this; }
        var tokens = this.split("?");
        if (arguments.length != (tokens.length - 1)) { throw "String.format() failed, tokens != arguments, this = "+this; }
        var s = tokens[0];
        for (var i = 0; i < arguments.length; ++i) {
            s += (arguments[i] + tokens[i + 1]);
        }
        return s;
    };
}
</script>

<style>
html, body { height: 100%; margin: 0; padding: 0; }
body {
    background: #E1D4C0;
}
body, table {
    font: 11px tahoma;
    color: #826C55;
}

/*** tetris 168,308 ***/

#tetris {
    position: relative;
    width: 300px;
    height: 310px;
    border: 1px solid #BAA68E;
    background: #ffffff;
    margin: 0 auto;
}

/*** left ***/

#tetris .left {
    background: #F5EDE3;
    position: absolute;
    width: 130px;
    height: 100%;
    left: 0px;
    top: 0px;
}
#tetris .left h1 {
    font-size: 11px;
    text-align: center;
    margin-top: 10px;
    margin-bottom: 10px;
}
#tetris .left h1 a {
    color: #3366CC;
    text-decoration: none;
}
#tetris .left h1 a:hover {
    color: #FF6600;
    text-decoration: none;
}

/* menu */

#tetris .left .menu {
    text-align: center;
}
#tetris .left input {
    font: 10px tahoma;
    color: #333333;
    text-transform: uppercase;
    background: #EAE0D1;
}
#tetris .left .menu input {
    width: 90px;
}

/* keyboard */

#tetris .left .keyboard {
    position: absolute;
    top: 163px;
    left: 32px;
    width: 85px;
    height: 55px;
    overflow: visible;
    display: none;
}
#tetris .left .keyboard input {
    font: 11px tahoma;
    width: 25px;
    height: 25px;
    padding-bottom: 2px;
    text-transform: none;
}
* html #tetris .left .keyboard input {
    padding-left: 1px;
}
#tetris .left .keyboard .up {
    position: absolute;
    left: 30px;
    top: 0px;
    width: 30px;
    height: 30px;
}
#tetris .left .keyboard .up input {
    font: 15px tahoma;
    padding-top: 3px;
}
#tetris .left .keyboard .down {
    position: absolute;
    left: 30px;
    top: 30px;
    width: 30px;
    height: 30px;
}
#tetris .left .keyboard .down input {
    font: 14px tahoma;
}
#tetris .left .keyboard .left {
    position: absolute;
    left: 0px;
    top: 30px;
    width: 30px;
    height: 30px;
}
#tetris .left .keyboard .right {
    position: absolute;
    left: 60px;
    top: 30px;
    width: 30px;
    height: 30px;
}

/* game over */

#tetris-gameover {
    position: absolute;
    width: 100%;
    top: 50%;
    text-align: center;
    font-weight: bold;
    display: none;
}

/* next puzzle */
#tetris-nextpuzzle {
    position: absolute;
    top: 49%;
    left: 35%;
    background: #ffffff;
    overflow: visible;
    display: none;
}

/* stats */

#tetris .left .stats {
    position: absolute;
    left: 35px;
    bottom: 10px;
}
#tetris .stats td { padding-bottom: 1px; }

#tetris .stats .level { text-align: right; padding-right: 10px; }
#tetris-stats-level { font-weight: bold; }

#tetris .stats .time { text-align: right; padding-right: 10px; }
#tetris-stats-time { font-weight: bold; }

#tetris .stats .apm { text-align: right; padding-right: 10px; }
#tetris-stats-apm { font-weight: bold; }

#tetris .stats .lines { text-align: right; padding-right: 10px; }
#tetris-stats-lines { font-weight: bold; }

#tetris .stats .score { text-align: right; padding-right: 10px; }
#tetris-stats-score { font-weight: bold; }

/*** area ***/

#tetris-area {
    background: #FFFFFF;
    position: absolute;
    width: 168px;
    height: 308px;
    left: 131px;
    top: 1px;
    overflow: hidden;
}
#tetris .block0,
#tetris .block1,
#tetris .block2,
#tetris .block3,
#tetris .block4,
#tetris .block5,
#tetris .block6 {
    position: absolute;
    width: 13px;
    height: 13px;
    border: 0.5px solid #ffffff;
    /* with margin 0.5px there were problems with offsetLeft and offsetTop */
}
#tetris .block0,
#tetris .block1 {
    background: #6699FF;
}
#tetris .block2,
#tetris .block3 {
    background: #FF6600;
}
#tetris .block4 {
    background: #FFAC1C;
}
#tetris .block5 {
    background: #BAA68E;
}
#tetris .block6 {
    background: #FF0000;
}

/*** window ***/

#tetris .window {
    background: #EFE8DE;
    position: absolute;
    width: 168px;
    height: 308px;
    left: 131px;
    top: 1px;
    z-index: 5;
    display: none;
}
#tetris .window .top {
    position: relative;
    background: #EAE0D1;
    color: #666666;
    font: 10px tahoma;
    letter-spacing: +1px;
    height: 20px;
    line-height: 20px;
    vertical-align: middle;
    border-bottom: 1px solid #ffffff;
    text-indent: 10px;
}
#tetris .window .top .close {
    position: absolute;
    background: #EAE0D1;
    font: 11px verdana;
    font-weight: bold;
    right: 0px;
    top: 0px;
    height: 20px;
    line-height: 19px;
    text-indent: 7px;
    width: 21px;
    border-left: 1px solid #ffffff;
    cursor: pointer;
}
#tetris .window .top .close:hover {
    background: #EFE8DE;
}
#tetris .window .content {
    font: 10px tahoma;
    margin: 10px;
}
#tetris .window .content table {
    font: 10px tahoma;
}
</style>


<table cellspacing="0" cellpadding="0" width="100%" height="100%"><tr><td valign="middle">
<div id="tetris">
  <div class="left">
    <h1>JsTetris 1.1.0</h1>
    <div class="menu">
      <div><input type="button" value="New Game" id="tetris-menu-start" /></div>
      <div><input type="button" value="Reset" id="tetris-menu-reset" /></div>
      <div><input type="button" value="Help" id="tetris-menu-help" /></div>
      <div><input type="button" value="Highscores" id="tetris-menu-highscores" /></div>
    </div>
    <div class="keyboard">
      <div class="up"><input type="button" value="^" id="tetris-keyboard-up" /></div>
      <div class="down"><input type="button" value="v" id="tetris-keyboard-down" /></div>
      <div class="left"><input type="button" value="<" id="tetris-keyboard-left" /></div>
      <div class="right"><input type="button" value=">" id="tetris-keyboard-right" /></div>
    </div>
    <div id="tetris-nextpuzzle"></div>
    <div id="tetris-gameover">Game Over</div>
    <div class="stats">
      <table cellspacing="0" cellpadding="0">
      <tr>
        <td class="level">Level:</td>
        <td><span id="tetris-stats-level">1</span></td>
      </tr>
      <tr>
        <td class="score">Score:</td>
        <td><span id="tetris-stats-score">0</span></td>
      </tr>
      <tr>
        <td class="lines">Lines:</td>
        <td><span id="tetris-stats-lines">0</span></td>
      </tr>
      <tr>
        <td class="apm">APM:</td>
        <td><span id="tetris-stats-apm">0</span></td>
      </tr>
      <tr>
        <td class="time">Time:</td>
        <td><span id="tetris-stats-time">0</span></td>
      </tr>
      </table>
    </div>
  </div>
  <div id="tetris-area"></div>
  <div id="tetris-help" class="window">
    <div class="top">
      Help <span id="tetris-help-close" class="close">x</span>
    </div>
    <div class="content">
      <b>Controllers:</b> <br />
      up - rotate <br />
      down - move down <br />
      left - move left <br />
      right - move right <br />
      space - fall to the bottom <br />
      n - new game <br />
      r - reset <br />
      <br />
      <b>Rules:</b> <br />
      1) Puzzle speed = 80+700/level miliseconds, the smaller value the faster puzzle falls <br />
      2) If puzzles created in current level >= 10+level*2 then increase level <br />
      3) After puzzle falling score is increased by 1000*level*linesRemoved <br />
      4) Each "down" action increases score by 5+level (pressing space counts as multiple down actions)
    </div>
  </div>
  <div id="tetris-highscores" class="window">
      <div class="top">
        Highscores <span id="tetris-highscores-close" class="close">x</span>
      </div>
      <div class="content">
        <div id="tetris-highscores-content"></div>
        <br />
        Note: these scores are kept in cookies, they are only visible to your computer, other players that visit this page see their own scores.
      </div>
  </div>
</div>

</td></tr></table>

<script type="text/javascript">
  var tetris = new Tetris();
  tetris.unit = 14;
  tetris.areaX = 12;
  tetris.areaY = 22;
</script>
[/code]
Mesaj27.09.2008, 10:55 (UTC)    
Mesaj konusu:

baya uzun bır kod ama çalışıyor teşekkurler...
Mesaj22.12.2008, 13:32 (UTC)    
Mesaj konusu:

Çok uzun bir kod.Ama çok teşekkürler bu kıymetli bilgi için.
Önceki mesajları göster:   


Powered by phpBB © 2001, 2005 phpBB Group
Türkçe Çeviri: phpBB Türkiye & Erdem Çorapçıoğlu