按照光神的意见改了后,确实不错!
将 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();