[求助] 美化一下挖金矿小游戏

Mr_MAO 2天前 232

// 黄金矿工小游戏 (没有美工版)
import win.ui;
import gdip;
/*DSG{{*/
var winform = win.form(text="黄金矿工小游戏 (By:Mr_MAO)";right=800;bottom=600;bgcolor=0xFFFFFF;border="dialog frame";max=false)
winform.add(
canvas={cls="plus";left=0;top=0;right=800;bottom=600;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
)
/*}}*/

// 游戏状态常量
var STATE_SWING = 1;   // 摇摆中
var STATE_SHOOT = 2;   // 发射中
var STATE_REWIND = 3;  // 拉回中

// 游戏参数配置
var config = {
    originX = 400;      // 钩子起始X
    originY = 50;       // 钩子起始Y
    baseSpeed = 10;     // 钩子基础速度
    ropeLen = 50;       // 绳子初始长度
    maxLen = 800;       // 绳子最大长度
    swingSpeed = 2;     // 摇摆角速度
}

// 游戏全局变量
var game = {
    score = 0;
    state = STATE_SWING;
    angle = 90;         // 当前角度(度)
    swingDir = 1;       // 摇摆方向 1 或 -1
    curLen = config.ropeLen; // 当前绳长
    items = {};         // 矿石数组
    grabbedItem = null; // 当前抓住的物品
}

// 初始化矿石数据
function initLevel(){
    game.items = {};
    math.randomize();
    
    // 生成大金块
    for(i=1;3;1){
        table.push(game.items, {
            x = math.random(50, 750);
            y = math.random(200, 550);
            r = 30; 
            weight = 3; 
            score = 500;
            color = 0xFFFFD700; 
            alive = true;
        }) 
    }
    
    // 生成小金块
    for(i=1;5;1){
        table.push(game.items, {
            x = math.random(50, 750);
            y = math.random(200, 550);
            r = 15;
            weight = 1;
            score = 200;
            color = 0xFFFFD700;
            alive = true;
        }) 
    }
    
    // 生成石头
    for(i=1;4;1){
        table.push(game.items, {
            x = math.random(50, 750);
            y = math.random(200, 550);
            r = 25;
            weight = 4;
            score = 20;
            color = 0xFF808080; 
            alive = true;
        }) 
    }
}

// 计算两点距离
function getDist(x1,y1,x2,y2){
    return math.sqrt( (x1-x2)**2 + (y1-y2)**2 );
}

// --- 绘图逻辑 ---
winform.canvas.onDrawForegroundEnd = function(graphics,rc){

    //随窗体DPI缩放
    var scaleX, scaleY = winform.getScale();
    graphics.scale(scaleX, scaleY);

    graphics.clear(0xFF333333) // 深色背景

    // 1. 绘制矿石
    for(k,item in game.items){
        if(item.alive){
            var brush = gdip.solidBrush(item.color);
            graphics.fillEllipse(brush, item.x - item.r, item.y - item.r, item.r*2, item.r*2);
            brush.delete();
        }
    }

    // 计算钩子末端坐标
    var rad = game.angle * math.pi / 180;
    var endX = config.originX + game.curLen * math.cos(rad);
    var endY = config.originY + game.curLen * math.sin(rad);

    // 2. 绘制绳子
    var penRope = gdip.pen(0xFFFFFFFF, 2);
    graphics.drawLine(penRope, config.originX, config.originY, endX, endY);
    penRope.delete();

    // 3. 绘制钩子头
    var brushHook = gdip.solidBrush(0xFFFF0000);
    graphics.fillEllipse(brushHook, endX - 5, endY - 5, 10, 10);
    brushHook.delete();
    
    // 如果抓住了物体
    if(game.state == STATE_REWIND && game.grabbedItem){
        var item = game.grabbedItem;
        var brush = gdip.solidBrush(item.color);
        graphics.fillEllipse(brush, endX - item.r, endY - item.r, item.r*2, item.r*2);
        brush.delete();
    }

    // 4. 绘制分数    
    var fontFamily = gdip.family("Arial");
    var font = fontFamily.createFont(16, 1);
    var strformat = gdip.stringformat();
    var brushText = gdip.solidBrush(0xFFFFFFFF);
    graphics.drawString("得分: " + game.score, font, ::RECTF(10, 10, 200, 50), strformat, brushText);
    graphics.drawString("按 [空格键] 发射钩子", font, ::RECTF(10, 40, 300, 50), strformat, brushText);
    
    font.delete();
    brushText.delete();
    strformat.delete();
    fontFamily.delete();
}

// 游戏主循环
winform.setInterval(
    function(){
        // 状态机逻辑
        if(game.state == STATE_SWING){
            game.angle = game.angle + (config.swingSpeed * game.swingDir);
            if(game.angle >= 170 || game.angle <= 10){
                game.swingDir = -game.swingDir;
            }
        }
        elseif(game.state == STATE_SHOOT){
            game.curLen = game.curLen + config.baseSpeed;
            
            var rad = game.angle * math.pi / 180;
            var curX = config.originX + game.curLen * math.cos(rad);
            var curY = config.originY + game.curLen * math.sin(rad);

            if(curX < 0 || curX > 800 || curY > 600 || game.curLen >= config.maxLen){
                game.state = STATE_REWIND;
                game.grabbedItem = null;
            } else {
                for(k,item in game.items){
                    if(item.alive){
                        if(getDist(curX, curY, item.x, item.y) <= item.r){
                            game.state = STATE_REWIND;
                            game.grabbedItem = item;
                            item.alive = false;
                            break;
                        }
                    }
                }
            }
        }
        elseif(game.state == STATE_REWIND){
            var speed = config.baseSpeed;
            
            if(game.grabbedItem){
                speed = config.baseSpeed / game.grabbedItem.weight;
            } else {
                speed = config.baseSpeed * 2;
            }
            
            game.curLen = game.curLen - speed;
            
            if(game.curLen <= config.ropeLen){
                game.curLen = config.ropeLen;
                game.state = STATE_SWING;
                
                if(game.grabbedItem){
                    game.score = game.score + game.grabbedItem.score;
                    game.grabbedItem = null;
                    
                    var allClear = true;
                    for(k,v in game.items){
                        if(v.alive) allClear = false;
                    }
                    if(allClear) {
                        winform.msgbox("恭喜!你挖空了所有矿藏!","提示");
                        initLevel();
                        game.score = 0;
                    }
                }
            }
        }
        
        winform.canvas.redraw();
    }, 20 
)

// --- 窗口级键盘事件处理 ---
winform.isDialogMessage = function(hwnd,msg){
    if(msg.message == 0x0100/*_WM_KEYDOWN*/){
        var vk = msg.wParam;
        if(vk == 0x20/*_VK_SPACE*/){
            if(game.state == STATE_SWING){
                game.state = STATE_SHOOT;
            }
        }
    }
}

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


最新回复 (15)
  • 光庆 2天前
    0 2
    好东西,没想到你私藏了这么多好东西!!!
  • 光庆 2天前
    0 3
    想漂亮,就放图片,找几张漂亮的背景图、矿石、钩子、绳子,再放个小老头啥的,立马就漂亮了。
  • 光庆 2天前
    0 4

     // 黄金矿工小游戏 (没有美工版)
    import win.ui;
    import gdip;
    /*DSG{{*/
    var winform = win.form(text="黄金矿工小游戏 (By:Mr_MAO)";right=800;bottom=600;bgcolor=0xFFFFFF;border="dialog frame";max=false)
    winform.add(
    canvas={cls="plus";left=0;top=0;right=800;bottom=600;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
    )
    /*}}*/
    
    // 游戏状态常量
    var STATE_SWING = 1;   // 摇摆中
    var STATE_SHOOT = 2;   // 发射中
    var STATE_REWIND = 3;  // 拉回中
    
    // 游戏参数配置
    var config = {
        originX = 400;      // 钩子起始X
        originY = 50;       // 钩子起始Y
        baseSpeed = 10;     // 钩子基础速度
        ropeLen = 50;       // 绳子初始长度
        maxLen = 800;       // 绳子最大长度
        swingSpeed = 2;     // 摇摆角速度
    }
    
    // 游戏全局变量
    var game = {
        score = 0;
        state = STATE_SWING;
        angle = 90;         // 当前角度(度)
        swingDir = 1;       // 摇摆方向 1 或 -1
        curLen = config.ropeLen; // 当前绳长
        items = {};         // 矿石数组
        grabbedItem = null; // 当前抓住的物品
    }
    
    // 初始化矿石数据
    function initLevel(){
        game.items = {};
        math.randomize();
        
        // 生成大金块
        for(i=1;3;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 30; 
                weight = 3; 
                score = 500;
                color = 0xFFFFD700; 
                alive = true;
                pic = "jinkuang.png";
            }) 
        }
        
        // 生成小金块
        for(i=1;5;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 15;
                weight = 1;
                score = 200;
                color = 0xFFFFD700;
                alive = true;
                pic = "jinkuang.png";
            }) 
        }
        
        // 生成石头
        for(i=1;4;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 25;
                weight = 4;
                score = 20;
                color = 0xFF808080; 
                alive = true;
                pic = "shitou.png";
            }) 
        }
    }
    
    // 计算两点距离
    function getDist(x1,y1,x2,y2){
        return math.sqrt( (x1-x2)**2 + (y1-y2)**2 );
    }
    
    // --- 绘图逻辑 ---
    var beijing = ..gdip.bitmap("/beijing.png")
    var xiaolaotou = ..gdip.bitmap("/xiaolaotou.png")
    winform.canvas.onDrawForegroundEnd = function(graphics,rc){
    
        //随窗体DPI缩放
        var scaleX, scaleY = winform.getScale();
        graphics.scale(scaleX, scaleY);
        graphics.clear(0xFF333333) // 深色背景
        graphics.drawImageStretch(beijing,rc); 
    	graphics.drawImageStretch(xiaolaotou,::RECT( 370,0,450,70));  
        // 1. 绘制矿石
        for(k,item in game.items){
            if(item.alive){
    			graphics.drawImageStretch(..gdip.bitmap("/"++item.pic),::RECT(item.x - item.r,
    																		 item.y - item.r,item.x + item.r,
    																		 item.y + item.r)
    			);
            }
        }
    
        // 计算钩子末端坐标
        var rad = game.angle * math.pi / 180;
        var endX = config.originX + game.curLen * math.cos(rad);
        var endY = config.originY + game.curLen * math.sin(rad);
    
        // 2. 绘制绳子
        var penRope = gdip.pen(0xFFFFFFFF, 2);
        graphics.drawLine(penRope, config.originX, config.originY, endX, endY);
        penRope.delete();
    
        // 3. 绘制钩子头
        var rect = ::RECT(endX - 15, endY - 15, endX + 15, endY + 15);
        graphics.rotateRect(rect,game.angle);
        graphics.drawImageStretch(..gdip.bitmap("/gouzi.png"),rect);
        graphics.resetTransform();
        
        // 如果抓住了物体
        if(game.state == STATE_REWIND && game.grabbedItem){
            var item = game.grabbedItem;
    		graphics.drawImageStretch(..gdip.bitmap("/"++item.pic),::RECT( endX - item.r, endY - item.r, endX + item.r, endY + item.r));   
          }
    
        // 4. 绘制分数    
        var fontFamily = gdip.family("Arial");
        var font = fontFamily.createFont(16, 1);
        var strformat = gdip.stringformat();
        var brushText = gdip.solidBrush(0xFFFFFFFF);
        graphics.drawString("得分: " + game.score, font, ::RECTF(10, 10, 200, 50), strformat, brushText);
        graphics.drawString("按 [空格键] 发射钩子", font, ::RECTF(10, 40, 300, 50), strformat, brushText);
        font.delete();
        brushText.delete();
        strformat.delete();
        fontFamily.delete();
    }
    
    // 游戏主循环
    winform.setInterval(
        function(){
            // 状态机逻辑
            if(game.state == STATE_SWING){
                game.angle = game.angle + (config.swingSpeed * game.swingDir);
                if(game.angle >= 170 || game.angle <= 10){
                    game.swingDir = -game.swingDir;
                }
            }
            elseif(game.state == STATE_SHOOT){
                game.curLen = game.curLen + config.baseSpeed;
                
                var rad = game.angle * math.pi / 180;
                var curX = config.originX + game.curLen * math.cos(rad);
                var curY = config.originY + game.curLen * math.sin(rad);
    
                if(curX < 0 || curX > 800 || curY > 600 || game.curLen >= config.maxLen){
                    game.state = STATE_REWIND;
                    game.grabbedItem = null;
                } else {
                    for(k,item in game.items){
                        if(item.alive){
                            if(getDist(curX, curY, item.x, item.y) <= item.r){
                                game.state = STATE_REWIND;
                                game.grabbedItem = item;
                                item.alive = false;
                                break;
                            }
                        }
                    }
                }
            }
            elseif(game.state == STATE_REWIND){
                var speed = config.baseSpeed;
                
                if(game.grabbedItem){
                    speed = config.baseSpeed / game.grabbedItem.weight;
                } else {
                    speed = config.baseSpeed * 2;
                }
                
                game.curLen = game.curLen - speed;
                
                if(game.curLen <= config.ropeLen){
                    game.curLen = config.ropeLen;
                    game.state = STATE_SWING;
                    
                    if(game.grabbedItem){
                        game.score = game.score + game.grabbedItem.score;
                        game.grabbedItem = null;
                        
                        var allClear = true;
                        for(k,v in game.items){
                            if(v.alive) allClear = false;
                        }
                        if(allClear) {
                            winform.msgbox("恭喜!你挖空了所有矿藏!","提示");
                            initLevel();
                            game.score = 0;
                        }
                    }
                }
            }
            
            winform.canvas.redraw();
        }, 20 
    )
    
    // --- 窗口级键盘事件处理 ---
    winform.isDialogMessage = function(hwnd,msg){
        if(msg.message == 0x0100/*_WM_KEYDOWN*/){
            var vk = msg.wParam;
            if(vk == 0x20/*_VK_SPACE*/){
                if(game.state == STATE_SWING){
                    game.state = STATE_SHOOT;
                }
            }
        }
    }
    
    winform.show();
    initLevel();
    return win.loopMessage();


    上传的附件:
  • 近我者赤 2天前
    0 5
    此楼层已删除
  • Mr_MAO 2天前
    0 6
    @光庆,@近我者赤,卧虎藏龙,你们牛B,👍x3!
  • 近我者赤 2天前
    0 7

    大佬珠玉在前,我就删了,不过可以在画绳子后面加个指向线,比较直观:

    // 绘制指向线
        var penRope2 = gdip.pen(0xF0c0c0c0, 1);
        penRope2.dashStyle = 2;
        var tt=15;
        var endXx = (1 - tt)*config.originX + tt*endX;
        var endYy = (1 - tt)*config.originY + tt*endY;
        graphics.drawLine(penRope2, endX, endY, endXx, endYy);
        penRope2.delete();


  • 光庆 2天前
    0 8
    删了干嘛,各有特色呗,反正都是探讨,都发出来更好
  • 光庆 2天前
    0 9
    用aardio的plus处理图片做游戏,底层用的gdip,效率还是很低,一旦图片较多,速度非常慢,不太合适。
  • 近我者赤 2天前
    0 10
    光庆 删了干嘛,各有特色呗,反正都是探讨,都发出来更好
    我就是学的你在贪吃蛇中的画图方法,不过实现的稍嫌麻烦,不如你这个简洁,就不误导大家了,所以删了。
  • Mr_MAO 2天前
    0 11

    感谢大神们的热心指点。人靠衣杉马靠鞍,这个游戏贴了图片后,看上去有点感觉了哦😀!!

    好了,我又吸收大家的意见完善了一下代码,主要是增加了【限时计分完成任务】的小功能,让这个游戏玩起来有一丢丢紧迫感~

    // 黄金矿工小游戏(增加了限时计分的功能)
    import win.ui;
    import gdip;
    /*DSG{{*/
    var winform = win.form(text="黄金矿工小游戏 (By:Mr_MAO)";right=799;bottom=599;bgcolor=0xFFFFFF;border="dialog frame";max=false)
    winform.add(
    canvas={cls="plus";left=0;top=0;right=800;bottom=600;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
    )
    /*}}*/
    
    //加载游戏图片
    import inet.http;
    var bmp_bk     = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/62_664V26GVCC29MJ2.png");
    var bmp_oldman = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_JHWVGUTV3MTBXRH.png");
    var bmp_hook   = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_ED2XTECQ8TVBSTV.png");
    var bmp_gold   = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_WZ3QAUH2QJW2GWF.png");
    var bmp_stone  = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_EVACW5HUX2WXPXA.png");
    
    // 游戏状态常量
    var STATE_SWING = 1;    // 摇摆中
    var STATE_SHOOT = 2;    // 发射中
    var STATE_REWIND = 3;   // 拉回中
    
    // 游戏参数配置
    var config = {
        originX = 400;      // 钩子起始X
        originY = 60;       // 钩子起始Y
        baseSpeed = 15;     // 钩子基础速度
        ropeLen = 50;       // 绳子初始长度
        maxLen = 800;       // 绳子最大长度
        swingSpeed = 2;     // 摇摆角速度
        timeLimit = 60;     // 时间限制(秒)
        targetScore = 2000; // 目标分数
    }
    
    // 游戏全局变量
    var game = {
        score = 0;
        state = STATE_SWING;
        angle = 90;         // 当前角度(度)
        swingDir = 1;       // 摇摆方向 1 或 -1
        curLen = config.ropeLen; // 当前绳长
        items = {};         // 矿石数组
        grabbedItem = null; // 当前抓住的物品
        isEnd = false;      // 游戏结束标识
        startTime = 0;      // 游戏开始时间戳(毫秒)
        timeLeft = 60;      // 剩余时间(秒)
        passedCheck = false;// 是否已达标(分数>=2000)
    }
    
    // 初始化矿石数据
    function initLevel(){
        game.items = {};
        game.score = 0;
        game.state = STATE_SWING;
        game.curLen = config.ropeLen;
        game.grabbedItem = null;
        game.isEnd = false;
        
        // 使用系统时间戳
        game.startTime = time.tick();
        game.timeLeft = config.timeLimit;
        game.passedCheck = false;
        
        math.randomize();
        
        // 生成大金块
        for(i=1;3;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 30; 
                weight = 3; 
                score = 500;
                alive = true;
                isGold = true; 
            }) 
        }
        
        // 生成小金块
        for(i=1;5;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 15;
                weight = 1;
                score = 200;
                alive = true;
                isGold = true; 
            }) 
        }
        
        // 生成石头
        for(i=1;4;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 25;
                weight = 4;
                score = 20;
                alive = true;
                isGold = false; 
            }) 
        }
    }
    
    // 计算两点距离
    function getDist(x1,y1,x2,y2){
        return math.sqrt( (x1-x2)**2 + (y1-y2)**2 );
    }
    
    // --- 绘图逻辑 ---
    winform.canvas.onDrawForegroundEnd = function(graphics,rc){  
    	// 绘制背景图
        graphics.drawImageStretch(bmp_bk, rc)
        
        // 随窗体DPI缩放
        var scaleX, scaleY = winform.getScale();
        graphics.scale(scaleX, scaleY);
        
    
        // 绘制小老头
        graphics.drawImageStretch(bmp_oldman,::RECT(370,20,450,100)); 
        
        // 绘制时间和分数信息
        var fontFamily = gdip.family("Microsoft YaHei UI");
        var font = fontFamily.createFont(14, 1);
        var strformat = gdip.stringformat();
        var brushText = gdip.solidBrush(0xFFFFFFFF);
        
        var timeStr = game.passedCheck ? "已达标" : (game.timeLeft + " s");
        graphics.drawString("剩余时间: " + timeStr, font, ::RECTF(10, 10, 200, 30), strformat, brushText);
        graphics.drawString("目前得分: " + game.score, font, ::RECTF(10, 35, 300, 55), strformat, brushText);
        graphics.drawString("目标分数: " + config.targetScore, font, ::RECTF(10, 60, 300, 80), strformat, brushText);
        graphics.drawString("按 [空格键] 发射钩子", font, ::RECTF(650, 10, 790, 50), strformat, brushText);  
        font.delete();
        brushText.delete();
        strformat.delete();
        fontFamily.delete();
        
        // 绘制矿石
        for(k,item in game.items){
            if(item.alive){
                var bmp = item.isGold?bmp_gold:bmp_stone;
                graphics.drawImageStretch(bmp, ::RECT(item.x - item.r, item.y - item.r,item.x + item.r,item.y + item.r) );
            }
        }
        
        var rad = game.angle * math.pi / 180;
        var endX = config.originX + game.curLen * math.cos(rad);
        var endY = config.originY + game.curLen * math.sin(rad);
        
        // 绘制绳子
        var penRope = gdip.pen(0xFF000000, 2);
        graphics.drawLine(penRope, config.originX, config.originY, endX, endY);
        penRope.delete();
           
        // 检查是否钩中矿石
        if(game.state == STATE_REWIND && game.grabbedItem){
            // 如果抓住了矿石,绘制矿产形状
            var item = game.grabbedItem;
            var rc1 = ::RECT( endX - item.r, endY - item.r, endX + item.r,  endY + item.r)
            var bmp = item.isGold?bmp_gold:bmp_stone;
            graphics.drawImageStretch(bmp, rc1);    
        }else{
            // 如果没有抓住了物体
            if(game.state != STATE_REWIND){
                // 绘制指向线
                var penRope2 = gdip.pen(0xF0c0c0c0, 1);
                penRope2.dashStyle = 2/*_DashStyleDot*/;
                var tt = 15;
                var endXx = (1 - tt)*config.originX + tt*endX;
                var endYy = (1 - tt)*config.originY + tt*endY;
                graphics.drawLine(penRope2, endX, endY, endXx, endYy);
                penRope2.delete();
            }
            // 绘制钩子头
            var rc2 = ::RECT(endX - 15, endY - 15, endX + 15, endY + 15);
            graphics.rotateRect(rc2, game.angle);
            graphics.drawImageStretch(bmp_hook, rc2);
            graphics.resetTransform();
        }
    }
    
    // 游戏主循环
    winform.setInterval(
        function(){
            if(game.isEnd) return;
            
            // 计算剩余时间
            if(!game.passedCheck){
                var elapsed = (time.tick() - game.startTime) / 1000;  // 已过去的秒数
                game.timeLeft = math.floor(config.timeLimit - elapsed);
                if(game.timeLeft < 0) game.timeLeft = 0; // 确保不显示负数
    
                if(elapsed >= config.timeLimit){ // 时间到,检查分数
                    if(game.score < config.targetScore){
                        game.isEnd = true;
                        winform.msgbox('时间到!挑战失败!\n(得分: ' ++ game.score ++ " 分, 未达到目标 " ++ config.targetScore ++ " 分)", "游戏失败");
                        initLevel();
                        return;
                    }
                }
                
                // 随时检查是否达标
                if(game.score >= config.targetScore){
                    game.passedCheck = true;
                }
            }
            
            // 状态机逻辑
            if(game.state == STATE_SWING){
                game.angle = game.angle + (config.swingSpeed * game.swingDir);
                if(game.angle >= 170 || game.angle <= 10){
                    game.swingDir = -game.swingDir;
                }
            }
            elseif(game.state == STATE_SHOOT){
                game.curLen = game.curLen + config.baseSpeed;
                
                var rad = game.angle * math.pi / 180;
                var curX = config.originX + game.curLen * math.cos(rad);
                var curY = config.originY + game.curLen * math.sin(rad);
                if(curX < 0 || curX > 800 || curY > 600 || game.curLen >= config.maxLen){
                    game.state = STATE_REWIND;
                    game.grabbedItem = null;
                } else {
                    for(k,item in game.items){
                        if(item.alive){
                            if(getDist(curX, curY, item.x, item.y) <= item.r){
                                game.state = STATE_REWIND;
                                game.grabbedItem = item;
                                item.alive = false;
                                break;
                            }
                        }
                    }
                }
            }
            elseif(game.state == STATE_REWIND){
                var speed = config.baseSpeed;
                
                if(game.grabbedItem){
                    speed = config.baseSpeed / game.grabbedItem.weight;
                } else {
                    speed = config.baseSpeed * 2;
                }
                
                game.curLen = game.curLen - speed;
                
                if(game.curLen <= config.ropeLen){
                    game.curLen = config.ropeLen;
                    game.state = STATE_SWING;
                    
                    if(game.grabbedItem){
                        game.score = game.score + game.grabbedItem.score;
                        game.grabbedItem = null;
                        
                        // 检查是否清空所有矿藏
                        var allClear = true;
                        for(k,v in game.items){
                            if(v.alive) allClear = false;
                        }
                        
                        if(allClear) {
                            if(game.score >= config.targetScore){
                                winform.msgbox('🎉恭喜!你挖空了所有矿藏!\n(最终得分: ' ++ game.score ++ " 分)", "游戏胜利");
                            } else {
                                winform.msgbox('矿藏已挖完,但未达到目标分数!\n(得分: ' ++ game.score ++ " 分)", "游戏结束");
                            }
                            initLevel();
                        }
                    }
                }
            }
            winform.canvas.redraw();
        }, 20 
    )
    
    // --- 窗口级键盘事件处理 ---
    winform.isDialogMessage = function(hwnd,msg){
        if(msg.message == 0x0100/*_WM_KEYDOWN*/){
            var vk = msg.wParam;
            if(vk == 0x20/*_VK_SPACE*/){
                if(game.state == STATE_SWING && !game.isEnd){
                    game.state = STATE_SHOOT;
                }
            }
        }
    }
    
    winform.canvas.wndproc = function(hwnd, message, wParam, lParam){
        if( message == 0x20/*_WM_SETCURSOR*/ ){
            ::User32.SetCursor(null); //隐藏鼠标
            return true; 
        }
    }
    
    winform.show();
    initLevel(); //启动程序,直接开始游戏
    win.loopMessage();
    上传的附件:
  • Mr_MAO 2天前
    0 12

    用plus控件做小游戏基本上就这些套路了(绘图、响应键鼠、定时器写逻辑)。 

    其实写小游戏更有趣的是写 游戏逻辑,这个比较烧脑,但是现在应该也有捷径了吧,呵呵! 

    另外,plus控件的优势是底层开了双缓冲,绘图时画面不闪烁,但是效率确实如光神所言速度较慢,练练手装装逼可以,不太适合做高频刷新的游戏。

  • 光庆 2天前
    0 13
    Mr_MAO 感谢大神们的热心指点。人靠衣杉马靠鞍,这个游戏贴了图片后,看上去有点感觉了哦😀!!好了,我又吸收大家的意见完善了一下代码,主要是增加了【限时计分完成任务】的小功能,让这个游戏玩起来有一丢丢紧迫感~// ...

    isGold = true;

    这个地方用的有点绕路了。


    直接改成这样:

    isGold = true; 改成 pic = bmp_gold;

    isGold = false; 改成:pic = bmp_stone;


                var bmp = item.isGold?bmp_gold:bmp_stone;

                graphics.drawImageStretch(bmp, ::RECT(item.x - item.r, item.y - item.r,item.x + item.r,item.y + item.r) );

    改成:

                graphics.drawImageStretch(item.pic, ::RECT(item.x - item.r, item.y - item.r,item.x + item.r,item.y + item.r) );


    我觉得这样更直接。

  • Mr_MAO 2天前
    0 14
    光神提醒的非常正确,“item.pic”这种写法带有面向对象的深刻含义,只有写库大神才深谙奇妙!佩服佩服🙏🙏
  • 近我者赤 1天前
    0 15
    Mr_MAO 光神提醒的非常正确,“item.pic”这种写法带有面向对象的深刻含义,只有写库大神才深谙奇妙!佩服佩服🙏🙏
    我之所以删除了我的代码也是因为用了和你一样的想法,我用了个tp变量表示要画的物体类型,感觉不如大佬的想法更妙,要多向大佬学习.
  • Mr_MAO 1天前
    0 16

    按照光神的意见改了后,确实不错!

    将 isGold = true; 改成 pic = bmp_gold;  

    这样实际上提高了可扩充性。比如我想给小金块指定bitmap大小,设置它的属性这样设置: pic = bmp_gold.resize(60,60),就OK了,多方便~


    顺手又小优化了一下,发现graphics.drawImageStretch()绘图有点慢,用graphics.drawImagePoint()替换了它,好像绘图快了一点。

    // 黄金矿工小游戏(增加了限时计分的功能)
    import win.ui;
    import gdip;
    /*DSG{{*/
    var winform = win.form(text="黄金矿工小游戏 (By:Mr_MAO)";right=799;bottom=599;bgcolor=0xFFFFFF;border="dialog frame";max=false)
    winform.add(
    canvas={cls="plus";left=0;top=0;right=800;bottom=600;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
    )
    /*}}*/
    
    //加载游戏图片
    import inet.http;
    var bmp_bk     = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/62_664V26GVCC29MJ2.png").resize(800,600);
    var bmp_oldman = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_JHWVGUTV3MTBXRH.png").resize(80,80);
    var bmp_hook   = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_ED2XTECQ8TVBSTV.png").resize(30,30);
    var bmp_gold   = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_WZ3QAUH2QJW2GWF.png").resize(60,60);
    var bmp_stone  = gdip.bitmap("https://aar.chengxu.online/upload/attach/202512/2_EVACW5HUX2WXPXA.png").resize(60,60);
    
    // 游戏状态常量
    var STATE_SWING = 1;    // 摇摆中
    var STATE_SHOOT = 2;    // 发射中
    var STATE_REWIND = 3;   // 拉回中
    
    // 游戏参数配置
    var config = {
        originX = 400;      // 钩子起始X
        originY = 60;       // 钩子起始Y
        baseSpeed = 15;     // 钩子基础速度
        ropeLen = 50;       // 绳子初始长度
        maxLen = 800;       // 绳子最大长度
        swingSpeed = 2;     // 摇摆角速度
        timeLimit = 60;     // 时间限制(秒)
        targetScore = 2000; // 目标分数
    }
    
    // 游戏全局变量
    var game = {
        score = 0;
        state = STATE_SWING;
        angle = 90;         // 当前角度(度)
        swingDir = 1;       // 摇摆方向 1 或 -1
        curLen = config.ropeLen; // 当前绳长
        items = {};         // 矿石数组
        grabbedItem = null; // 当前抓住的物品
        isEnd = false;      // 游戏结束标识
        startTime = 0;      // 游戏开始时间戳(毫秒)
        timeLeft = 60;      // 剩余时间(秒)
        passedCheck = false;// 是否已达标(分数>=2000)
    }
    
    // 初始化矿石数据
    function initLevel(){
        game.items = {};
        game.score = 0;
        game.state = STATE_SWING;
        game.curLen = config.ropeLen;
        game.grabbedItem = null;
        game.isEnd = false;
        
        // 使用系统时间戳
        game.startTime = time.tick();
        game.timeLeft = config.timeLimit;
        game.passedCheck = false;
        
        math.randomize();
        
        // 生成大金块
        for(i=1;3;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 30; 
                weight = 3; 
                score = 500;
                alive = true;
                pic = bmp_gold
            }) 
        }
        
        // 生成小金块
        for(i=1;5;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 15;
                weight = 1;
                score = 200;
                alive = true;
                pic = bmp_gold.resize(30,30);
            }) 
        }
        
        // 生成石头
        for(i=1;4;1){
            table.push(game.items, {
                x = math.random(50, 750);
                y = math.random(200, 550);
                r = 25;
                weight = 4;
                score = 20;
                alive = true;
                pic = bmp_stone;
            }) 
        }
    }
    
    // 计算两点距离
    function getDist(x1,y1,x2,y2){
        return math.sqrt( (x1-x2)**2 + (y1-y2)**2 );
    }
    
    // --- 绘图逻辑 ---
    winform.canvas.onDrawForegroundEnd = function(graphics,rc){  
        // 随窗体DPI缩放
        var scaleX, scaleY = winform.getScale();
        graphics.scale(scaleX, scaleY);
        
        // 绘制背景图
        graphics.drawImagePoint(bmp_bk, rc)
        
        // 绘制小老头
        graphics.drawImagePoint(bmp_oldman,::RECT(370,20,380,100)); 
        
        // 绘制时间和分数信息
        var fontFamily = gdip.family("Microsoft YaHei UI");
        var font = fontFamily.createFont(14, 1);
        var strformat = gdip.stringformat();
        var brushText = gdip.solidBrush(0xFFFFFFFF);
        
        var timeStr = game.passedCheck ? "已达标" : (game.timeLeft + " s");
        graphics.drawString("剩余时间: " + timeStr, font, ::RECTF(10, 10, 200, 30), strformat, brushText);
        graphics.drawString("目前得分: " + game.score, font, ::RECTF(10, 35, 300, 55), strformat, brushText);
        graphics.drawString("目标分数: " + config.targetScore, font, ::RECTF(10, 60, 300, 80), strformat, brushText);
        graphics.drawString("按 [空格键] 发射钩子", font, ::RECTF(650, 10, 790, 50), strformat, brushText);  
        font.delete();
        brushText.delete();
        strformat.delete();
        fontFamily.delete();
        
        // 绘制矿石
        for(k,item in game.items){
            if(item.alive){
                graphics.drawImagePoint(item.pic, ::RECT(item.x - item.r, item.y - item.r,item.x + item.r,item.y + item.r) );
            }
        }
        
        var rad = game.angle * math.pi / 180;
        var endX = config.originX + game.curLen * math.cos(rad);
        var endY = config.originY + game.curLen * math.sin(rad);
        
        // 绘制绳子
        var penRope = gdip.pen(0xFF000000, 2);
        graphics.drawLine(penRope, config.originX, config.originY, endX, endY);
        penRope.delete();
           
           // 检查是否钩中矿石
        if(game.state == STATE_REWIND && game.grabbedItem){
            // 如果抓住了矿石,绘制矿产形状
            var item = game.grabbedItem;
            var rc1 = ::RECT( endX - item.r, endY - item.r, endX + item.r,  endY + item.r)
            graphics.drawImagePoint(item.pic, rc1);    
        }else{
            // 如果没有抓住了物体
            if(game.state != STATE_REWIND){
                // 绘制指向线
                var penRope2 = gdip.pen(0xF0c0c0c0, 1);
                penRope2.dashStyle = 2/*_DashStyleDot*/;
                var tt = 15;
                var endXx = (1 - tt)*config.originX + tt*endX;
                var endYy = (1 - tt)*config.originY + tt*endY;
                graphics.drawLine(penRope2, endX, endY, endXx, endYy);
                penRope2.delete();
            }
            // 绘制钩子头
            var rc2 = ::RECT(endX - 15, endY - 15, endX + 15, endY + 15);
            graphics.rotateRect(rc2, game.angle);
            graphics.drawImagePoint(bmp_hook, rc2);
            graphics.resetTransform();
        }
    }
    
    // 游戏主循环
    winform.setInterval(
        function(){
            if(game.isEnd) return;
            
            // 计算剩余时间
            if(!game.passedCheck){
                var elapsed = (time.tick() - game.startTime) / 1000;  // 已过去的秒数
                game.timeLeft = math.floor(config.timeLimit - elapsed);
                if(game.timeLeft < 0) game.timeLeft = 0; // 确保不显示负数
    
                if(elapsed >= config.timeLimit){ // 时间到,检查分数
                    if(game.score < config.targetScore){
                        game.isEnd = true;
                        winform.msgbox('时间到!挑战失败!\n(得分: ' ++ game.score ++ " 分, 未达到目标 " ++ config.targetScore ++ " 分)", "游戏失败");
                        initLevel();
                        return;
                    }
                }
                
                // 随时检查是否达标
                if(game.score >= config.targetScore){
                    game.passedCheck = true;
                }
            }
            
            // 状态机逻辑
            if(game.state == STATE_SWING){
                game.angle = game.angle + (config.swingSpeed * game.swingDir);
                if(game.angle >= 170 || game.angle <= 10){
                    game.swingDir = -game.swingDir;
                }
            }
            elseif(game.state == STATE_SHOOT){
                game.curLen = game.curLen + config.baseSpeed;
                
                var rad = game.angle * math.pi / 180;
                var curX = config.originX + game.curLen * math.cos(rad);
                var curY = config.originY + game.curLen * math.sin(rad);
                if(curX < 0 || curX > 800 || curY > 600 || game.curLen >= config.maxLen){
                    game.state = STATE_REWIND;
                    game.grabbedItem = null;
                } else {
                    for(k,item in game.items){
                        if(item.alive){
                            if(getDist(curX, curY, item.x, item.y) <= item.r){
                                game.state = STATE_REWIND;
                                game.grabbedItem = item;
                                item.alive = false;
                                break;
                            }
                        }
                    }
                }
            }
            elseif(game.state == STATE_REWIND){
                var speed = config.baseSpeed;
                
                if(game.grabbedItem){
                    speed = config.baseSpeed / game.grabbedItem.weight;
                } else {
                    speed = config.baseSpeed * 2;
                }
                
                game.curLen = game.curLen - speed;
                
                if(game.curLen <= config.ropeLen){
                    game.curLen = config.ropeLen;
                    game.state = STATE_SWING;
                    
                    if(game.grabbedItem){
                        game.score = game.score + game.grabbedItem.score;
                        game.grabbedItem = null;
                        
                        // 检查是否清空所有矿藏
                        var allClear = true;
                        for(k,v in game.items){
                            if(v.alive) allClear = false;
                        }
                        
                        if(allClear) {
                            if(game.score >= config.targetScore){
                                winform.msgbox('🎉恭喜!你挖空了所有矿藏!\n(最终得分: ' ++ game.score ++ " 分)", "游戏胜利");
                            } else {
                                winform.msgbox('矿藏已挖完,但未达到目标分数!\n(得分: ' ++ game.score ++ " 分)", "游戏结束");
                            }
                            initLevel();
                        }
                    }
                }
            }
            winform.canvas.redraw();
        }, 20 
    )
    
    // --- 窗口级键盘事件处理 ---
    winform.isDialogMessage = function(hwnd,msg){
        if(msg.message == 0x0100/*_WM_KEYDOWN*/){
            var vk = msg.wParam;
            if(vk == 0x20/*_VK_SPACE*/){
                if(game.state == STATE_SWING && !game.isEnd){
                    game.state = STATE_SHOOT;
                }
            }
        }
    }
    
    winform.canvas.wndproc = function(hwnd, message, wParam, lParam){
        if( message == 0x20/*_WM_SETCURSOR*/ ){
            ::User32.SetCursor(null); //隐藏鼠标
            return true; 
        }
    }
    
    winform.show();
    initLevel(); //启动程序,直接开始游戏
    win.loopMessage();


返回