哈哈哈,看我写的aardio游戏:小孩骑马疾驰

import win.ui;
/*DSG{{*/
var winform = win.form(text="小孩骑马疾驰 2D 动画 - aardio GDI+ 自绘";right=794;bottom=437;bgcolor=0xFFFFFF;border="dialog frame";max=false)
winform.add(
canvas={cls="canvas";left=0;top=0;right=795;bottom=438;anchors={left=1;top=1;right=1;bottom=1};z=1}
)
/*}}*/
// ---------------- 动画状态变量 ----------------
var gallopPhase = 0; // 奔跑周期相位 (弧度)
var bgPos = 0; // 背景水平滚动距离 (逻辑像素)
var gallopFreq = 7.5; // 奔跑动作频率 (弧度/秒)
var runSpeed = 420; // 场景滚动速度 (像素/秒)
// ---------------- GDI+ 逐帧绘制回调 ----------------
winform.canvas.onDrawForeground = function(graphics, rc, foregroundRect, foregroundColor, color, font){
var dpiX, dpiY = winform.dpiScale(1, 1);
graphics.scale(dpiX, dpiY);
var width = rc.width / dpiX;
var height = rc.height / dpiY;
// --- 1. 天空与原野背景 ---
var skyBrush = gdip.solidBrush(0xFF80D8FF); // 晴空蓝
graphics.fillRect(skyBrush, 0, 0, width, 280);
skyBrush.delete();
var groundBrush = gdip.solidBrush(0xFF558B2F); // 深草绿草地
graphics.fillRect(groundBrush, 0, 280, width, height - 280);
groundBrush.delete();
// --- 2. 远景白云 (慢速视差) ---
var cloudBrush = gdip.solidBrush(0xFFFFFFFF);
var cloudOffset = (bgPos * 0.15) % (width + 250);
for(i = 0; 2; 1){
var cx = (i * 420 - cloudOffset) + 80;
if(cx < -120) cx += width + 250;
graphics.fillEllipse(cloudBrush, cx, 50, 90, 36);
graphics.fillEllipse(cloudBrush, cx + 30, 35, 75, 48);
graphics.fillEllipse(cloudBrush, cx + 65, 50, 80, 36);
}
cloudBrush.delete();
// --- 3. 远山连绵 (中速视差) ---
var mountainBrush = gdip.solidBrush(0xFF7CB342);
var mountStep = 320;
var mountOffset = (bgPos * 0.35) % mountStep;
for(x = -mountStep; width + mountStep; mountStep){
var mx = x - mountOffset;
graphics.fillPolygon(mountainBrush, [
[mx, 280],
[mx + 160, 160],
[mx + 320, 280]
]);
}
mountainBrush.delete();
// --- 4. 跑道栅栏 (快速视差,紧贴前进视角) ---
var fenceWoodBrush = gdip.solidBrush(0xFFD7CCC8);
var fenceStep = 110;
var fenceOffset = (bgPos * 0.9) % fenceStep;
// 栅栏横木
graphics.fillRect(fenceWoodBrush, 0, 275, width, 6);
graphics.fillRect(fenceWoodBrush, 0, 292, width, 6);
// 栅栏立柱
for(x = -fenceStep; width + fenceStep; fenceStep){
var fx = x - fenceOffset;
graphics.fillRect(fenceWoodBrush, fx, 265, 10, 42);
}
fenceWoodBrush.delete();
// ---------------- 运动学姿态计算 ----------------
// 马身腾跃与上下颠簸
var bodyBounce = -math.abs(math.sin(gallopPhase)) * 18;
var horseTilt = math.cos(gallopPhase) * 0.08; // 腾空时微仰,落地时微俯
var originX = 400; // 马体中心 X
var originY = 270 + bodyBounce; // 马体中心 Y
// 马体色值定义(栗色马匹,远近层明暗区分)
var colorBodyFar = 0xFF6D3C1F;
var colorBodyNear = 0xFF8B4513;
var colorHoof = 0xFF212121;
var colorMane = 0xFF3E2723;
// --- 马腿绘制通用骨骼函数 ---
var drawHorseLeg = function(jointX, jointY, isFrontLeg, isNearLayer, phaseShift){
var p = gallopPhase + phaseShift;
var upperAngle, lowerAngle, hoofAngle;
if(isFrontLeg){
// 前腿屈伸向前趴地
upperAngle = 0.55 * math.sin(p) + 0.45;
lowerAngle = -0.75 * math.sin(p - 0.4) - 0.6;
hoofAngle = 0.3 * math.sin(p);
} else {
// 后腿蹬地与收缩
upperAngle = 0.65 * math.sin(p + math.pi) - 0.2;
lowerAngle = 0.85 * math.sin(p + math.pi + 0.5) + 0.4;
hoofAngle = -0.4 * math.sin(p);
}
var len1 = 44, len2 = 42;
var kneeX = jointX + math.sin(upperAngle) * len1;
var kneeY = jointY + math.cos(upperAngle) * len1;
var ankleX = kneeX + math.sin(upperAngle + lowerAngle) * len2;
var ankleY = kneeY + math.cos(upperAngle + lowerAngle) * len2;
var hoofX = ankleX + math.sin(upperAngle + lowerAngle + hoofAngle) * 12;
var hoofY = ankleY + math.cos(upperAngle + lowerAngle + hoofAngle) * 12;
var legPen = gdip.pen(isNearLayer ? colorBodyNear : colorBodyFar, isNearLayer ? 13 : 11);
graphics.drawLine(legPen, jointX, jointY, kneeX, kneeY);
graphics.drawLine(legPen, kneeX, kneeY, ankleX, ankleY);
legPen.delete();
// 马蹄
var hoofBrush = gdip.solidBrush(colorHoof);
graphics.fillCircle(hoofBrush, hoofX, hoofY, 6);
hoofBrush.delete();
};
var hipJointX = originX - 60;
var hipJointY = originY - 5;
var shoulderJointX = originX + 55;
var shoulderJointY = originY - 10;
// --- 5. 远侧腿部 (后景层,先画) ---
drawHorseLeg(hipJointX, hipJointY, false, false, 0.4);
drawHorseLeg(shoulderJointX, shoulderJointY, true, false, 0.4);
// --- 6. 马体与飞扬尾巴 ---
// 飞扬摆动的马尾
var tailWave = math.sin(gallopPhase * 1.5) * 16;
var tailPoints = [
[originX - 75, originY - 20],
[originX - 120, originY - 35 + tailWave],
[originX - 165, originY - 10 + tailWave * 1.2],
[originX - 125, originY + 5],
[originX - 75, originY - 5]
];
var tailBrush = gdip.solidBrush(colorMane);
graphics.fillClosedCurve2(tailBrush, 0.4, tailPoints);
tailBrush.delete();
// 强壮马腹躯干
var horseBodyBrush = gdip.solidBrush(colorBodyNear);
graphics.fillEllipse(horseBodyBrush, originX - 75, originY - 35, 150, 68);
// 马颈部与头部 (仰角随颠簸微调)
var neckBaseX = originX + 45;
var neckBaseY = originY - 15;
var headBaseX = originX + 95;
var headBaseY = originY - 80 + (horseTilt * 25);
var neckPen = gdip.pen(colorBodyNear, 36);
graphics.drawLine(neckPen, neckBaseX, neckBaseY, headBaseX - 5, headBaseY + 15);
neckPen.delete();
// 飘动马鬃
var maneWave = math.cos(gallopPhase * 2) * 8;
var maneBrush = gdip.solidBrush(colorMane);
graphics.fillPolygon(maneBrush, [
[neckBaseX - 15, neckBaseY - 10],
[neckBaseX - 30 + maneWave, neckBaseY - 35],
[headBaseX - 35 + maneWave, headBaseY + 5],
[headBaseX - 12, headBaseY + 15]
]);
// 马头轮廓与口鼻
graphics.fillEllipse(horseBodyBrush, headBaseX - 18, headBaseY - 20, 42, 38);
var muzzleBrush = gdip.solidBrush(0xFF70360F);
graphics.fillEllipse(muzzleBrush, headBaseX + 8, headBaseY - 14, 32, 26);
muzzleBrush.delete();
// 马耳朵与眼睛
graphics.fillPolygon(horseBodyBrush, [
[headBaseX - 6, headBaseY - 18],
[headBaseX - 2, headBaseY - 34],
[headBaseX + 6, headBaseY - 18]
]);
var horseEye = gdip.solidBrush(0xFF000000);
graphics.fillCircle(horseEye, headBaseX + 5, headBaseY - 8, 3.5);
horseEye.delete();
// 马鞍与汗垫
var saddleClothBrush = gdip.solidBrush(0xFFE63946); // 红色鞍垫
graphics.fillRect(saddleClothBrush, originX - 30, originY - 36, 60, 16);
saddleClothBrush.delete();
var saddleBrush = gdip.solidBrush(0xFF3E2723); // 深皮鞍座
graphics.fillEllipse(saddleBrush, originX - 22, originY - 42, 44, 15);
saddleBrush.delete();
// --- 7. 小孩骑手 (身体各部自然骑乘随动) ---
var riderBounce = bodyBounce + math.sin(gallopPhase - 0.5) * 4;
var riderX = originX - 2;
var riderY = originY - 55;
// 小孩双腿跨在马身 (近侧腿)
var pantsPen = gdip.pen(0xFF1976D2, 10); // 牛仔蓝长裤
graphics.drawLine(pantsPen, riderX - 5, riderY + 18, riderX + 4, riderY + 45);
pantsPen.delete();
var shoeBrush = gdip.solidBrush(0xFF37474F);
graphics.fillCircle(shoeBrush, riderX + 5, riderY + 48, 5);
shoeBrush.delete();
// 躯干 (前倾防后倾)
var coatBrush = gdip.solidBrush(0xFFFFB703); // 明黄上衣
graphics.fillEllipse(coatBrush, riderX - 14, riderY - 22, 28, 42);
coatBrush.delete();
// 头部与红润脸蛋
var skinBrush = gdip.solidBrush(0xFFFFDFC4);
var kidHeadX = riderX + 3;
var kidHeadY = riderY - 36;
graphics.fillCircle(skinBrush, kidHeadX, kidHeadY, 15);
skinBrush.delete();
// 小孩五官笑脸
var kidEye = gdip.solidBrush(0xFF263238);
graphics.fillCircle(kidEye, kidHeadX + 5, kidHeadY - 2, 2);
kidEye.delete();
var smilePen = gdip.pen(0xFFD32F2F, 1.8);
graphics.drawArc(smilePen, kidHeadX + 2, kidHeadY - 1, 8, 8, 20, 140);
smilePen.delete();
// 红色棒球帽 (帽檐向前挡风)
var capBrush = gdip.solidBrush(0xFFE63946);
graphics.fillPie(capBrush, kidHeadX - 16, kidHeadY - 16, 32, 26, 170, 200);
graphics.fillRect(capBrush, kidHeadX + 4, kidHeadY - 10, 18, 4); // 帽檐突出
capBrush.delete();
// 手臂前伸牵引缰绳
var armPen = gdip.pen(0xFFFFB703, 7);
var handX = originX + 40;
var handY = originY - 45;
graphics.drawLine(armPen, riderX + 2, riderY - 6, handX, handY);
armPen.delete();
// 缰绳 (从手拉至马嘴水勒)
var reinPen = gdip.pen(0xFF4E342E, 2);
var bitX = headBaseX + 16;
var bitY = headBaseY - 2;
graphics.drawLine(reinPen, bitX, bitY, handX, handY);
reinPen.delete();
// --- 8. 近侧腿部 (前景层,遮挡大部分马体轮廓) ---
drawHorseLeg(hipJointX, hipJointY, false, true, 0);
drawHorseLeg(shoulderJointX, shoulderJointY, true, true, 0);
// 释放常驻笔刷
horseBodyBrush.delete();
maneBrush.delete();
// 还原画板变换矩阵
graphics.resetTransform();
};
// ---------------- 动画定时器更新逻辑 ----------------
winform.canvas.onAnimation = function(prevState, beginning, change, timestamp, duration, deltaMs){
var deltaSeconds = deltaMs / 1000;
gallopPhase = (gallopPhase + gallopFreq * deltaSeconds) % (math.pi * 2);
bgPos += runSpeed * deltaSeconds;
return true; // 循环刷新
};
// 启动平滑动画(约 16ms/帧,60 FPS)
winform.canvas.startAnimation(16);
winform.onEraseBkgnd = lambda() 0;
winform.show();
win.loopMessage();