aardio版拼图游戏源码

By admin at 19 小时前 • 0人收藏 • 18人看过

Gemini改了很多次,才能正常运行, 大部分错误是对aardio一些gdip函数特性的误读导致.

后续有时间了慢慢继续改进.

先这样 

image.png

import win.ui;
import win.ui.menu;
import gdip;
import gdip.region;           // ★ 补全引用
import gdip.imageAttributes;  // ★ 补全引用
import math;
import inet.http;

/*DSG{{*/
var winform = win.form(text="Aardio 拼图 (最终修复版)";right=1000;bottom=650;bgcolor=16777215)
winform.add(
btnLoad={cls="button";text="更换图片";left=10;top=10;right=100;bottom=40;z=2};
canvas={cls="plus";left=0;top=0;right=1000;bottom=650;db=1;dl=1;dr=1;dt=1;notify=1;z=1};
chkPreview={cls="checkbox";text="查看原图";left=110;top=15;right=200;bottom=35;z=3}
)
/*}}*/

// ==========================================
// 1. 全局配置
// ==========================================
var config = {
    cols = 4;           
    rows = 3;           
    pieceSize = 120;    
    tabSize = 25;       
    sidebarWidth = 300; 
    snapDist = 20;      
}

var game = {
    imgRaw = null;      
    imgScaled = null;   
    pieces = {};        
    dragIndex = null;   
    offsetX = 0;        
    offsetY = 0;        
    boardRect = null;   
    showPreview = false;
}

// ==========================================
// 2. 几何算法
// ==========================================
var transformPoint = function(px, py, orientation, startX, startY, size){
    if(orientation == 0){ // 上
        return startX + px, startY + py;
    }
    elseif(orientation == 1){ // 右
        return startX + size - py, startY + px;
    }
    elseif(orientation == 2){ // 下
        return startX + size - px, startY + size - py;
    }
    elseif(orientation == 3){ // 左
        return startX + py, startY + size - px;
    }
}

var appendSidePath = function(path, x, y, sideType, orientation, size){
    var tabSize = config.tabSize;
    var curX, curY = transformPoint(0, 0, orientation, x, y, size);
    
    if(sideType == 0){ 
        var endX, endY = transformPoint(size, 0, orientation, x, y, size);
        path.addLine(curX, curY, endX, endY);
        return;
    }

    var sign = (sideType == 1) ? -1 : 1; 
    var h = tabSize * sign;
    var w = size;

    var p1x, p1y = transformPoint(w*0.35, 0, orientation, x, y, size);
    path.addLine(curX, curY, p1x, p1y);
    curX, curY = p1x, p1y;

    var c1x, c1y = transformPoint(w*0.35, h*1.2, orientation, x, y, size); 
    var c2x, c2y = transformPoint(w*0.45, h,     orientation, x, y, size); 
    var p2x, p2y = transformPoint(w*0.5,  h,     orientation, x, y, size); 
    path.addBezier(curX, curY, c1x, c1y, c2x, c2y, p2x, p2y);
    curX, curY = p2x, p2y;

    var c3x, c3y = transformPoint(w*0.55, h,     orientation, x, y, size); 
    var c4x, c4y = transformPoint(w*0.65, h*1.2, orientation, x, y, size); 
    var p3x, p3y = transformPoint(w*0.65, 0,     orientation, x, y, size); 
    path.addBezier(curX, curY, c3x, c3y, c4x, c4y, p3x, p3y);
    curX, curY = p3x, p3y;

    var endX, endY = transformPoint(w, 0, orientation, x, y, size);
    path.addLine(curX, curY, endX, endY);
}

var createPiecePath = function(x, y, size, top, right, bottom, left){
    var path = gdip.path();
    appendSidePath(path, x, y, top,    0, size);
    appendSidePath(path, x, y, right,  1, size);
    appendSidePath(path, x, y, bottom, 2, size);
    appendSidePath(path, x, y, left,   3, size);
    path.closeFigure();
    return path;
}

// ==========================================
// 3. 游戏初始化
// ==========================================
var initGame = function(imgData){
    // 清理资源
    if(game.imgRaw) game.imgRaw.dispose();
    if(game.imgScaled) game.imgScaled.dispose();
    for(k,v in game.pieces){ 
        if(v.bitmap) v.bitmap.dispose();
        if(v.path) v.path.dispose();
        if(v.region) v.region.delete(); // 注意region通常用delete/dispose
    }
    game.pieces = {}; 
    
    game.imgRaw = gdip.bitmap(imgData);
    if(!game.imgRaw) return;
    
    var viewW = winform.canvas.width - config.sidebarWidth - 40;
    var viewH = winform.canvas.height - 40;
    
    var w = game.imgRaw.width;
    var h = game.imgRaw.height;
    var scale = math.min(viewW/w, viewH/h);
    
    var finalW = w * scale;
    var finalH = h * scale;
    
    config.cols = math.round(finalW / 120); 
    if(config.cols < 2) config.cols = 2;
    config.rows = math.round(finalH / (finalW/config.cols));
    if(config.rows < 2) config.rows = 2;
    config.pieceSize = finalW / config.cols;
    
    game.imgScaled = gdip.bitmap(finalW, finalH);
    var g = game.imgScaled.getGraphics();
    g.smoothingMode = 4;
    g.drawImage(game.imgRaw, 0, 0, finalW, finalH);
    g.dispose();
    
    var boardX = config.sidebarWidth + (winform.canvas.width - config.sidebarWidth - finalW)/2;
    var boardY = (winform.canvas.height - finalH)/2;
    game.boardRect = { x=boardX; y=boardY; w=finalW; h=finalH };
    
    var vEdges = {}; 
    var hEdges = {}; 
    for(r=1; config.rows){
        vEdges[r] = {};
        for(c=1; config.cols-1) vEdges[r][c] = (math.random(0,1)==0) ? 1 : -1;
    }
    for(r=1; config.rows-1){
        hEdges[r] = {};
        for(c=1; config.cols) hEdges[r][c] = (math.random(0,1)==0) ? 1 : -1;
    }
    
    for(r=1; config.rows){
        for(c=1; config.cols){
            var p = {};
            p.row = r; p.col = c;
            
            p.top = (r > 1) ? -hEdges[r-1][c] : 0;
            p.bottom = (r < config.rows) ? hEdges[r][c] : 0;
            p.left = (c > 1) ? -vEdges[r][c-1] : 0;
            p.right = (c < config.cols) ? vEdges[r][c] : 0;
            
            p.targetX = (c-1) * config.pieceSize;
            p.targetY = (r-1) * config.pieceSize;
            
            p.x = math.random(20, config.sidebarWidth - config.pieceSize - 20);
            p.y = math.random(60, winform.canvas.height - config.pieceSize - 20);
            p.isLocked = false;
            
            p.path = createPiecePath(0, 0, config.pieceSize, p.top, p.right, p.bottom, p.left);
            
            // 依然创建region以备不时之需,但点击检测改用数学计算
            p.region = gdip.region(p.path);
            
            var pad = config.tabSize;
            var bmpW = config.pieceSize + pad*2; 
            var bmpH = config.pieceSize + pad*2;
            var pieceBmp = gdip.bitmap(bmpW, bmpH);
            var pg = pieceBmp.getGraphics();
            pg.smoothingMode = 4;
            
            // ★ 改正:使用 translate 代替 translateTransform
            pg.translate(pad, pad); 
            pg.setClipPath(p.path);
            
            pg.drawImage(game.imgScaled, -p.targetX, -p.targetY, game.boardRect.w, game.boardRect.h);
            
            var pen = gdip.pen(0x80000000, 1); 
            pg.resetClip(); 
            pg.drawPath(pen, p.path);
            
            pen.dispose();
            pg.dispose();
            
            p.bitmap = pieceBmp; 
            table.push(game.pieces, p);
        }
    }
    
    winform.canvas.redraw();
}

// ==========================================
// 4. 绘图渲染
// ==========================================
winform.canvas.onDrawForegroundEnd = function(graphics, rc){
    if(!game.imgScaled) return;
    graphics.smoothingMode = 4;
    
    var brushSide = gdip.solidBrush(0xFFE0E0E0);
    graphics.fillRectangle(brushSide, 0, 0, config.sidebarWidth, rc.bottom);
    brushSide.dispose();
    
    var brushBoard = gdip.solidBrush(0xFFF0F0F0);
    graphics.fillRectangle(brushBoard, config.sidebarWidth, 0, rc.right-config.sidebarWidth, rc.bottom);
    brushBoard.dispose();
    
    var penSplit = gdip.pen(0xFF999999, 2);
    graphics.drawLine(penSplit, config.sidebarWidth, 0, config.sidebarWidth, rc.bottom);
    penSplit.dispose();
    
    var attr = gdip.imageAttributes();
    var colorMatrix = { 1;0;0;0;0; 0;1;0;0;0; 0;0;1;0;0; 0;0;0;0.3;0; 0;0;0;0;1 };
    attr.setColorMatrix(colorMatrix);
    graphics.drawImage(game.imgScaled, game.boardRect.x, game.boardRect.y, game.boardRect.w, game.boardRect.h, attr);
    attr.dispose();
    
    var drawPiece = function(p, isDragging){
        if(!p.bitmap) return;

        var drawX = p.x;
        var drawY = p.y;
        
        if(p.isLocked){
            drawX = game.boardRect.x + p.targetX;
            drawY = game.boardRect.y + p.targetY;
        }
        
        var pad = config.tabSize;
        
        if(isDragging){
            var brushShadow = gdip.solidBrush(0x50000000);
            // ★ 改正:使用 translate
            graphics.translate(drawX - pad + 5, drawY - pad + 5);
            graphics.fillPath(brushShadow, p.path);
            graphics.resetTransform();
            brushShadow.dispose();
        }
        
        graphics.drawImage(p.bitmap, drawX - pad, drawY - pad);
    }
    
    for(i=1; #game.pieces){
        if(game.pieces[i].isLocked) drawPiece(game.pieces[i], false);
    }
    for(i=1; #game.pieces){
        var p = game.pieces[i];
        if(!p.isLocked && i != game.dragIndex) drawPiece(p, false);
    }
    if(game.dragIndex && game.pieces[game.dragIndex]){
        drawPiece(game.pieces[game.dragIndex], true);
    }
    
    if(game.showPreview){
        var preW = 200;
        var preH = preW * (game.imgRaw.height / game.imgRaw.width);
        var preX = (rc.right - preW) / 2 + config.sidebarWidth/2;
        var preY = (rc.bottom - preH) / 2;
        
        var brushBox = gdip.solidBrush(0xFFFFFFFF);
        graphics.fillRectangle(brushBox, preX-5, preY-5, preW+10, preH+10);
        graphics.drawRectangle(gdip.pen(0xFF000000,1), preX-5, preY-5, preW+10, preH+10);
        graphics.drawImage(game.imgRaw, preX, preY, preW, preH);
        brushBox.dispose();
    }
}

// ==========================================
// 5. 交互逻辑 (修改版)
// ==========================================
winform.canvas.onMouseDown = function(wParam,lParam){
    var x,y = win.getMessagePos(lParam);
    
    for(i=#game.pieces; 1; -1){
        var p = game.pieces[i];
        if(p.isLocked) continue;
        
        // ★★★ 核心修复:完全放弃依赖 isVisible 函数,改用数学矩形判定 ★★★
        // 这样绝对不会报错 "no function"。
        // 判定范围:拼图主体(config.pieceSize) + 四周的突起范围(config.tabSize)
        // 这种判定对于拼图游戏来说足够精确且性能极高。
        
        var pad = config.tabSize;
        
        // 鼠标点击区域检查
        if( x >= p.x - pad && x <= p.x + config.pieceSize + pad &&
            y >= p.y - pad && y <= p.y + config.pieceSize + pad ){
            
            game.dragIndex = i;
            game.offsetX = x - p.x;
            game.offsetY = y - p.y;
            
            table.remove(game.pieces, i);
            table.push(game.pieces, p);
            game.dragIndex = #game.pieces;
            
            winform.canvas.redraw();
            return;
        }
    }
}

winform.canvas.onMouseMove = function(wParam,lParam){
    if(game.dragIndex){
        var x,y = win.getMessagePos(lParam);
        var p = game.pieces[game.dragIndex];
        if(p){
            p.x = x - game.offsetX;
            p.y = y - game.offsetY;
            winform.canvas.redraw();
        }
    }
}

winform.canvas.onMouseUp = function(wParam,lParam){
    if(game.dragIndex){
        var p = game.pieces[game.dragIndex];
        
        if(p){
            var absTargetX = game.boardRect.x + p.targetX;
            var absTargetY = game.boardRect.y + p.targetY;
            
            if( math.abs(p.x - absTargetX) < config.snapDist && 
                math.abs(p.y - absTargetY) < config.snapDist ){
                
                p.x = absTargetX;
                p.y = absTargetY;
                p.isLocked = true;

            }
        }
        
        game.dragIndex = null;
        winform.canvas.redraw();
        
        var winState = true;
        for(i=1; #game.pieces){
            if(!game.pieces[i].isLocked){ winState = false; break; }
        }
        if(winState) winform.msgbox("恭喜!拼图完成!");
    }
}

winform.btnLoad.oncommand = function(id,event){
    var path = win.ui.ctrl.common.file.open("图片文件|*.jpg;*.png;*.bmp");
    if(path){
        var buf = string.load(path);
        if(buf) initGame(buf);
    }
}

winform.chkPreview.oncommand = function(id,event){
    game.showPreview = winform.chkPreview.checked;
    winform.canvas.redraw();
}

winform.setTimeout(function(){
    var url = "https://images.unsplash.com/photo-1587614382346-4ec70e388b28?w=600&q=80"; 
    var buf = inet.http().get(url);
    if(buf) initGame(buf);
}, 100);

winform.show();
win.loopMessage();


登录后方可回帖

登 录
信息栏
本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...