利用aardio制作简单的俄罗斯方块游戏

Mr_MAO 1天前 59

import win.ui;
/*DSG{{*/
var winform = win.form(text="俄罗斯方块 (By: Mr_MAO)";right=415;bottom=560;border="dialog frame";max=false)
winform.add(
btnRestart={cls="button";text="重新开始";left=280;top=8;right=400;bottom=45;z=2};
gameCanvas={cls="plus";left=10;top=50;right=260;bottom=550;bgcolor=0x222222;notify=1;z=1};
lblHint={cls="static";text='\u2191旋转 \u2193加速 \u2190\u2192移动 空格暂停';left=10;top=19;right=260;bottom=44;color=0x808080;transparent=1;z=4};
lblLevel={cls="static";text="等级: 1";left=280;top=272;right=400;bottom=302;font=LOGFONT(h=-16;weight=700);transparent=1;z=6};
lblLines={cls="static";text="消行: 0";left=280;top=312;right=400;bottom=342;font=LOGFONT(h=-16;weight=700);transparent=1;z=7};
lblNext={cls="static";text="下一个:";left=280;top=64;right=400;bottom=89;font=LOGFONT(h=-14);transparent=1;z=8};
lblScore={cls="static";text="分数: 0";left=280;top=232;right=400;bottom=262;font=LOGFONT(h=-16;weight=700);transparent=1;z=3};
nextCanvas={cls="plus";left=280;top=88;right=400;bottom=208;bgcolor=0x333333;notify=1;z=5}
)
/*}}*/

import win.timer;

winform.tmr = win.timer(winform);

// --- 游戏环境参数 ---
var conf = {
    cellSize = 25;
    cols = 10;
    rows = 20;
    baseSpeed = 500;
    colors = {
        0xFF00FFFF;  // I - 青色
        0xFFFFFF00;  // O - 黄色
        0xFFF000F0;  // T - 紫色
        0xFF00FF00;  // S - 绿色
        0xFFFF0000;  // Z - 红色
        0xFF0000FF;  // J - 蓝色
        0xFFFF8000;  // L - 橙色
        grid = 0xFF444444;
        text = 0xFFFFFFFF;
        ghost = 0x40FFFFFF;
    }
}

// 7种方块的形状定义 (每个方块4个旋转状态)
var shapes = {
    {// I
        {{0,1},{1,1},{2,1},{3,1}};
        {{2,0},{2,1},{2,2},{2,3}};
        {{0,2},{1,2},{2,2},{3,2}};
        {{1,0},{1,1},{1,2},{1,3}};
    };
    {// O
        {{1,0},{2,0},{1,1},{2,1}};
        {{1,0},{2,0},{1,1},{2,1}};
        {{1,0},{2,0},{1,1},{2,1}};
        {{1,0},{2,0},{1,1},{2,1}};
    };
    {// T
        {{1,0},{0,1},{1,1},{2,1}};
        {{1,0},{1,1},{2,1},{1,2}};
        {{0,1},{1,1},{2,1},{1,2}};
        {{1,0},{0,1},{1,1},{1,2}};
    };
    {// S
        {{1,0},{2,0},{0,1},{1,1}};
        {{1,0},{1,1},{2,1},{2,2}};
        {{1,1},{2,1},{0,2},{1,2}};
        {{0,0},{0,1},{1,1},{1,2}};
    };
    {// Z
        {{0,0},{1,0},{1,1},{2,1}};
        {{2,0},{1,1},{2,1},{1,2}};
        {{0,1},{1,1},{1,2},{2,2}};
        {{1,0},{0,1},{1,1},{0,2}};
    };
    {// J
        {{0,0},{0,1},{1,1},{2,1}};
        {{1,0},{2,0},{1,1},{1,2}};
        {{0,1},{1,1},{2,1},{2,2}};
        {{1,0},{1,1},{0,2},{1,2}};
    };
    {// L
        {{2,0},{0,1},{1,1},{2,1}};
        {{1,0},{1,1},{1,2},{2,2}};
        {{0,1},{1,1},{2,1},{0,2}};
        {{0,0},{1,0},{1,1},{1,2}};
    };
}

// --- 游戏状态 ---
var state = {
    board = {};
    current = null;
    next = null;
    score = 0;
    level = 1;
    lines = 0;
    gameOver = false;
    paused = false;
}

// 获取方块的格子位置
var getPieceCells = function(piece){
    var shape = shapes[[piece.typeSharp]][[piece.rotation]];
    var cells = {};
    for(i=1; #shape; 1){
        table.push(cells, {
            x = piece.x + shape[[i]][1];
            y = piece.y + shape[[i]][2];
        });
    }
    return cells;
}

// 碰撞检测
var checkCollision = function(piece){
    var cells = getPieceCells(piece);
    for(i=1; #cells; 1){
        var cx = cells[[i]].x;
        var cy = cells[[i]].y;
        if(cx < 0 || cx >= conf.cols || cy >= conf.rows){
            return true;
        }
        if(cy >= 0 && state.board[[cy+1]] && state.board[[cy+1]][[cx+1]]){
            return true;
        }
    }
    return false;
}

// 锁定方块到游戏板
var lockPiece = function(){
    var cells = getPieceCells(state.current);
    for(i=1; #cells; 1){
        var cx = cells[[i]].x;
        var cy = cells[[i]].y;
        if(cy >= 0){
            state.board[[cy+1]][[cx+1]] = state.current.typeSharp;
        }
    }
}

// 消行检测
var clearLines = function(){
    var linesCleared = 0;
    var y = conf.rows;
    while(y >= 1){
        var full = true;
        for(x=1; conf.cols; 1){
            if(!state.board[[y]][[x]]){
                full = false;
                break;
            }
        }
        if(full){
            table.remove(state.board, y);
            var newRow = {};
            for(x=1; conf.cols; 1) newRow[[x]] = null;
            table.insert(state.board, newRow, 1);
            linesCleared++;
        } else {
            y--;
        }
    }
    
    if(linesCleared > 0){
        var scoreTable = {100; 300; 500; 800};
        state.score += (scoreTable[[linesCleared]] : 100) * state.level;
        state.lines += linesCleared;
        state.level = math.floor(state.lines / 10) + 1;
        
        winform.lblScore.text = "分数: " + state.score;
        winform.lblLevel.text = "等级: " + state.level;
        winform.lblLines.text = "消行: " + state.lines;
        
        var newSpeed = conf.baseSpeed - (state.level - 1) * 40;
        if(newSpeed < 80) newSpeed = 80;
        winform.tmr.disable();
        winform.tmr.enable(newSpeed);
    }
}

// 生成随机方块
var randomPiece = function(){
    return {
        typeSharp = math.random(1, 7);
        rotation = 1;
        x = 3;
        y = -1;
    }
}

// 生成下一个方块
var spawnPiece = function(){
    state.current = state.next : randomPiece();
    state.next = randomPiece();
    
    if(checkCollision(state.current)){
        state.gameOver = true;
        winform.tmr.disable();
        winform.btnRestart.text = "重玩(R)";
        winform.gameCanvas.redraw();
        win.msgbox('游戏结束! \r\n🏆得分: ' ++ state.score ++ '\r\n消行: ' ++ state.lines, "提示");
    }
}

// 初始化游戏
var initGame = function(){
    state.board = {};
    for(y=1; conf.rows; 1){
        state.board[[y]] = {};
        for(x=1; conf.cols; 1) state.board[[y]][[x]] = null;
    }
    
    state.score = 0;
    state.level = 1;
    state.lines = 0;
    state.gameOver = false;
    state.paused = false;
    state.next = null;
    
    winform.lblScore.text = "分数: 0";
    winform.lblLevel.text = "等级: 1";
    winform.lblLines.text = "消行: 0";
    winform.btnRestart.text = "重新开始";
    
    spawnPiece();
    winform.tmr.enable(conf.baseSpeed);
}

// 移动方块
var movePiece = function(dx, dy){
    if(state.gameOver || state.paused) return false;
    
    var newPiece = {
        typeSharp = state.current.typeSharp;
        rotation = state.current.rotation;
        x = state.current.x + dx;
        y = state.current.y + dy;
    }
    
    if(!checkCollision(newPiece)){
        state.current = newPiece;
        return true;
    }
    return false;
}

// 旋转方块
var rotatePiece = function(){
    if(state.gameOver || state.paused) return;
    
    var newRotation = state.current.rotation + 1;
    if(newRotation > 4) newRotation = 1;
    
    var newPiece = {
        typeSharp = state.current.typeSharp;
        rotation = newRotation;
        x = state.current.x;
        y = state.current.y;
    }
    
    // 墙踢测试
    var kicks = {{0,0}; {-1,0}; {1,0}; {0,-1}; {-2,0}; {2,0}};
    for(i=1; #kicks; 1){
        newPiece.x = state.current.x + kicks[[i]][1];
        newPiece.y = state.current.y + kicks[[i]][2];
        if(!checkCollision(newPiece)){
            state.current = newPiece;
            return;
        }
    }
}

// 硬降落
var hardDrop = function(){
    if(state.gameOver || state.paused) return;
    var dropCount = 0;
    while(movePiece(0, 1)) dropCount++;
    state.score += dropCount * 2;
    winform.lblScore.text = "分数: " + state.score;
    
    lockPiece();
    clearLines();
    spawnPiece();
    winform.gameCanvas.redraw();
    winform.nextCanvas.redraw();
}

// 获取幽灵方块位置
var getGhostY = function(){
    var ghostPiece = {
        typeSharp = state.current.typeSharp;
        rotation = state.current.rotation;
        x = state.current.x;
        y = state.current.y;
    }
    while(!checkCollision(ghostPiece)){
        ghostPiece.y++;
    }
    return ghostPiece.y - 1;
}

// 游戏主循环
var update = function(){
    if(state.gameOver || state.paused) return;
    
    if(!movePiece(0, 1)){
        lockPiece();
        clearLines();
        spawnPiece();
    }
    
    winform.gameCanvas.redraw();
    winform.nextCanvas.redraw();
}

winform.tmr.onTimer = function(){
    update();
}

// 键盘事件
winform.isDialogMessage = function(hwnd, msg){
    if(msg.message == 0x0100/*_WM_KEYDOWN*/){
        var vk = msg.wParam;
        
        if(vk == 0x20/*_VK_SPACE*/){
            if(state.gameOver) initGame();
            else {
                state.paused = !state.paused;
                winform.gameCanvas.redraw();
            }
            return true;
        }
        
        if(vk == 0x52/*R*/){
            initGame();
            return true;
        }
        
        if(!state.paused && !state.gameOver){
            if(vk == 0x25/*_VK_LEFT*/){
                movePiece(-1, 0);
                winform.gameCanvas.redraw();
            }
            elseif(vk == 0x27/*_VK_RIGHT*/){
                movePiece(1, 0);
                winform.gameCanvas.redraw();
            }
            elseif(vk == 0x28/*_VK_DOWN*/){
                if(movePiece(0, 1)){
                    state.score += 1;
                    winform.lblScore.text = "分数: " + state.score;
                }
                winform.gameCanvas.redraw();
            }
            elseif(vk == 0x26/*_VK_UP*/){
                rotatePiece();
                winform.gameCanvas.redraw();
            }
            elseif(vk == 0x0D/*_VK_RETURN*/){
                hardDrop();
            }
        }
        return true;
    }
}

// 主游戏区绘图
winform.gameCanvas.onDrawForegroundEnd = function(graphics, rect){
    var cellSize = conf.cellSize;
    
    // 绘制网格线
    var penGrid = gdip.pen(conf.colors.grid, 1);
    for(x=0; conf.cols; 1){
        graphics.drawLine(penGrid, x * cellSize, 0, x * cellSize, conf.rows * cellSize);
    }
    for(y=0; conf.rows; 1){
        graphics.drawLine(penGrid, 0, y * cellSize, conf.cols * cellSize, y * cellSize);
    }
    penGrid.delete();
    
    // 绘制已锁定的方块
    for(y=1; conf.rows; 1){
        for(x=1; conf.cols; 1){
            var cell = state.board[[y]][[x]];
            if(cell){
                var brush = gdip.solidBrush(conf.colors[[cell]]);
                graphics.fillRectangle(brush, 
                    (x-1) * cellSize + 2, (y-1) * cellSize + 2, 
                    cellSize - 4, cellSize - 4);
                brush.delete();
            }
        }
    }
    
    // 绘制幽灵方块和当前方块
    if(state.current && !state.gameOver){
        var ghostY = getGhostY();
        var cells = getPieceCells(state.current);
        
        // 幽灵方块
        var brushGhost = gdip.solidBrush(conf.colors.ghost);
        for(i=1; #cells; 1){
            var gy = ghostY - state.current.y + cells[[i]].y;
            if(gy >= 0){
                graphics.fillRectangle(brushGhost, 
                    cells[[i]].x * cellSize + 2, gy * cellSize + 2, 
                    cellSize - 4, cellSize - 4);
            }
        }
        brushGhost.delete();
        
        // 当前方块
        var brush = gdip.solidBrush(conf.colors[[state.current.typeSharp]]);
        for(i=1; #cells; 1){
            if(cells[[i]].y >= 0){
                graphics.fillRectangle(brush, 
                    cells[[i]].x * cellSize + 2, cells[[i]].y * cellSize + 2, 
                    cellSize - 4, cellSize - 4);
            }
        }
        brush.delete();
    }
    
    // 绘制状态文字
    if(state.gameOver || state.paused){
        var txt = state.gameOver ? "GAME OVER" : "已暂停";
        var font = gdip.font("微软雅黑", 22);
        var brushTxt = gdip.solidBrush(conf.colors.text);
        var strFormat = gdip.stringformat();
        strFormat.align = 1;
        strFormat.lineAlign = 1;
        
        var rc = gdip.RECTF(0, 0, conf.cols * cellSize, conf.rows * cellSize);
        graphics.drawString(txt, font, rc, strFormat, brushTxt);
        
        font.delete(); brushTxt.delete(); strFormat.delete();
    }
}

// 下一个方块预览区绘图
winform.nextCanvas.onDrawForegroundEnd = function(graphics, rect){
    if(!state.next) return;
    
    var cellSize = 20;
    var shape = shapes[[state.next.typeSharp]][1];
    var brush = gdip.solidBrush(conf.colors[[state.next.typeSharp]]);
    
    var offsetX = 25;
    var offsetY = 35;
    
    for(i=1; #shape; 1){
        graphics.fillRectangle(brush, 
            offsetX + shape[[i]][1] * cellSize + 1, 
            offsetY + shape[[i]][2] * cellSize + 1, 
            cellSize - 2, cellSize - 2);
    }
    brush.delete();
}

winform.btnRestart.oncommand = function(id, event){
    initGame();
}

winform.enableDpiScaling(false);
winform.show();
initGame();
win.loopMessage();
最新回复 (0)
返回