aardio 文档
aardio 范例: 五子棋 - 自绘小游戏
import win.ui;
/*DSG{{*/
var winform = win.form(text="五子棋 - 自绘小游戏";right=580;bottom=640;bgcolor=0xFFFFFF;border="dialog frame";max=false)
winform.add(
btnRestart={cls="plus";text="重新开始";left=40;top=585;right=140;bottom=620;bgcolor=0x50AF4C;border={radius=6};color=0xFFFFFF;font=LOGFONT(h=-14;weight=600);z=2};
btnUndo={cls="plus";text="悔棋";left=161;top=585;right=261;bottom=620;bgcolor=0x0098FF;border={radius=6};color=0xFFFFFF;font=LOGFONT(h=-14;weight=600);z=3};
lblStatus={cls="plus";text="黑方执子";left=300;top=585;right=540;bottom=620;color=0x333333;font=LOGFONT(h=-16;weight=600);z=4};
plus={cls="plus";left=15;top=15;right=565;bottom=565;border={color=0x60A4D4;radius=8;width=3};clipBk=false;notify=1;z=1}
)
/*}}*/
// 游戏配置
var boardSize = 15;
// 动态布局参数
var layout = {
cellSize = 36;
padding = 18;
pieceRadius = 15;
};
// 计算布局(根据控件大小自适应)
var calculateLayout = function(width, height) {
var size = math.min(width, height);
var margin = 20;
var availableSize = size - margin * 2;
layout.cellSize = math.floor(availableSize / (boardSize - 1));
layout.padding = math.floor((size - layout.cellSize * (boardSize - 1)) / 2);
layout.pieceRadius = math.floor(layout.cellSize * 0.42);
}
// 游戏状态
var board = {};
var currentPlayer = 1; // 1=黑, 2=白
var gameOver = false;
var winner = 0;
var moveHistory = {};
var hoverX, hoverY = 0, 0;
var winLine = {};
// 初始化棋盘
var initBoard = function() {
board = {};
for(y=1; boardSize) {
board[y] = {};
for(x=1; boardSize) {
board[y][x] = 0;
}
}
currentPlayer = 1;
gameOver = false;
winner = 0;
moveHistory = {};
winLine = {};
winform.lblStatus.text = "☯ 黑方执子";
}
// 屏幕坐标转棋盘坐标
var screenToBoard = function(sx, sy) {
var x = math.floor((sx - layout.padding + layout.cellSize/2) / layout.cellSize) + 1;
var y = math.floor((sy - layout.padding + layout.cellSize/2) / layout.cellSize) + 1;
if(x >= 1 && x <= boardSize && y >= 1 && y <= boardSize) {
return x, y;
}
return 0, 0;
}
// 棋盘坐标转屏幕坐标
var boardToScreen = function(bx, by) {
return layout.padding + (bx - 1) * layout.cellSize,
layout.padding + (by - 1) * layout.cellSize;
}
// 检查某方向是否五子连珠
var checkDirection = function(x, y, dx, dy, player) {
var count = 1;
var line = {{x=x, y=y}};
var nx, ny = x + dx, y + dy;
while(nx >= 1 && nx <= boardSize && ny >= 1 && ny <= boardSize && board[ny][nx] == player) {
count = count + 1;
table.push(line, {x=nx, y=ny});
nx = nx + dx;
ny = ny + dy;
}
nx, ny = x - dx, y - dy;
while(nx >= 1 && nx <= boardSize && ny >= 1 && ny <= boardSize && board[ny][nx] == player) {
count = count + 1;
table.push(line, {x=nx, y=ny});
nx = nx - dx;
ny = ny - dy;
}
return count, line;
}
// 检查是否获胜
var checkWin = function(x, y, player) {
var directions = {{1,0}, {0,1}, {1,1}, {1,-1}};
for(i, dir in directions) {
var count, line = checkDirection(x, y, dir[1], dir[2], player);
if(count >= 5) {
return true, line;
}
}
return false, {};
}
// 检查是否平局
var checkDraw = function() {
for(y=1; boardSize) {
for(x=1; boardSize) {
if(board[y][x] == 0) return false;
}
}
return true;
}
// 落子
var placePiece = function(x, y) {
if(gameOver) return false;
if(x < 1 || x > boardSize || y < 1 || y > boardSize) return false;
if(board[y][x] != 0) return false;
board[y][x] = currentPlayer;
table.push(moveHistory, {x=x, y=y, player=currentPlayer});
var won, line = checkWin(x, y, currentPlayer);
if(won) {
gameOver = true;
winner = currentPlayer;
winLine = line;
winform.lblStatus.text = (winner == 1) ? "黑方获胜!" : "白方获胜!";
}
elseif(checkDraw()) {
gameOver = true;
winner = 0;
winform.lblStatus.text = "平局!";
}
else {
currentPlayer = (currentPlayer == 1) ? 2 : 1;
winform.lblStatus.text = (currentPlayer == 1) ? "☯ 黑方执子" : "○ 白方执子";
}
return true;
}
// 悔棋
var undoMove = function() {
if(#moveHistory == 0) return;
if(gameOver) {
gameOver = false;
winner = 0;
winLine = {};
}
var lastMove = table.pop(moveHistory);
board[lastMove.y][lastMove.x] = 0;
currentPlayer = lastMove.player;
winform.lblStatus.text = (currentPlayer == 1) ? "☯ 黑方执子" : "○ 白方执子";
}
initBoard();
// 按钮样式
winform.btnRestart.skin({
background = {default=0xFF4CAF50; hover=0xFF45A049; active=0xFF388E3C};
color = {default=0xFFFFFFFF};
});
winform.btnUndo.skin({
background = {default=0xFFFF9800; hover=0xFFF57C00; active=0xFFE65100};
color = {default=0xFFFFFFFF};
});
// 绘制棋子(柔和高光)
var drawPiece = function(graphics, sx, sy, isBlack) {
var r = layout.pieceRadius;
// 阴影
var shadowPath = gdip.path();
shadowPath.addEllipse(sx - r + 2, sy - r + 2, r * 2, r * 2);
var shadowBrush = gdip.pathGradientBrush(shadowPath);
shadowBrush.setCenterColor(0x50000000);
shadowBrush.setSurroundColors(0x00000000);
graphics.fillPath(shadowBrush, shadowPath);
shadowBrush.delete();
shadowPath.delete();
// 棋子主体
var path = gdip.path();
path.addEllipse(sx - r, sy - r, r * 2, r * 2);
var pathBrush = gdip.pathGradientBrush(path);
if(isBlack) {
pathBrush.setCenterColor(0xFF454545);
pathBrush.setSurroundColors(0xFF0A0A0A);
}
else {
pathBrush.setCenterColor(0xFFFFFFFF);
pathBrush.setSurroundColors(0xFFAAAAAA);
}
pathBrush.setCenterPoint(sx - r * 0.3, sy - r * 0.3);
graphics.fillPath(pathBrush, path);
pathBrush.delete();
path.delete();
// 柔和高光(路径渐变,边缘透明)
var hlPath = gdip.path();
hlPath.addEllipse(sx - r * 0.55, sy - r * 0.65, r * 0.85, r * 0.55);
var hlBrush = gdip.pathGradientBrush(hlPath);
if(isBlack) {
hlBrush.setCenterColor(0x38FFFFFF);
hlBrush.setSurroundColors(0x00FFFFFF);
}
else {
hlBrush.setCenterColor(0x70FFFFFF);
hlBrush.setSurroundColors(0x00FFFFFF);
}
hlBrush.setCenterPoint(sx - r * 0.25, sy - r * 0.4);
graphics.fillPath(hlBrush, hlPath);
hlBrush.delete();
hlPath.delete();
// 小亮点(更自然的反光)
var dotPath = gdip.path();
dotPath.addEllipse(sx - r * 0.35, sy - r * 0.45, r * 0.25, r * 0.18);
var dotBrush = gdip.pathGradientBrush(dotPath);
dotBrush.setCenterColor(isBlack ? 0x50FFFFFF : 0x90FFFFFF);
dotBrush.setSurroundColors(0x00FFFFFF);
graphics.fillPath(dotBrush, dotPath);
dotBrush.delete();
dotPath.delete();
}
// 绘制背景
winform.plus.onDrawBackground = function(graphics,rc,backgroundColor,color){
var width = rc.right - rc.left;
var height = rc.bottom - rc.top;
calculateLayout(width, height);
// 棋盘底色渐变
var p1 = ::POINTF(0, 0);
var p2 = ::POINTF(rc.right, rc.bottom);
var brush = gdip.lineBrush(p1, p2, 0xFFDEB887, 0xFFD2A064, 1);
graphics.fillRectangle(brush, rc);
brush.delete();
// 木纹纹理
var texturePen = gdip.pen(0x12000000, 1);
for(i=0; 60) {
var y = i * 10 + math.sin(i * 0.5) * 4;
graphics.drawLine(texturePen, 0, y, rc.right, y + 2);
}
texturePen.delete();
}
// 绘制内容
winform.plus.onDrawForeground = function(graphics,rc,foregroundRect,foregroundColor,color,font){
graphics.smoothingMode = 4;
var width = rc.right - rc.left;
var height = rc.bottom - rc.top;
// 绘制网格线
var linePen = gdip.pen(0xFF5D4037, 1);
for(i=1; boardSize) {
var x1, y1 = boardToScreen(i, 1);
var x2, y2 = boardToScreen(i, boardSize);
graphics.drawLine(linePen, x1, y1, x2, y2);
x1, y1 = boardToScreen(1, i);
x2, y2 = boardToScreen(boardSize, i);
graphics.drawLine(linePen, x1, y1, x2, y2);
}
linePen.delete();
// 星位(天元和四角星)
var starPoints = {{8,8}, {4,4}, {4,12}, {12,4}, {12,12}};
var starSize = math.max(3, layout.cellSize / 10);
var starBrush = gdip.solidBrush(0xFF5D4037);
for(i, pt in starPoints) {
var sx, sy = boardToScreen(pt[1], pt[2]);
graphics.fillEllipse(starBrush, sx - starSize, sy - starSize, starSize * 2, starSize * 2);
}
starBrush.delete();
// 悬停提示
if(!gameOver && hoverX > 0 && hoverY > 0 && board[hoverY][hoverX] == 0) {
var hx, hy = boardToScreen(hoverX, hoverY);
var r = layout.pieceRadius;
var borderColor = (currentPlayer == 1) ? 0x70000000 : 0x70A0A0A0;
var hoverColor = (currentPlayer == 1) ? 0x45000000 : 0x45FFFFFF;
if(winform.plus.state.active){
borderColor = borderColor | 0x30000000;
hoverColor = hoverColor | 0x30000000;
}
var hoverBrush = gdip.solidBrush(hoverColor);
graphics.fillEllipse(hoverBrush, hx - r, hy - r, r * 2, r * 2);
hoverBrush.delete();
var borderPen = gdip.pen(borderColor, 2);
graphics.drawEllipse(borderPen, hx - r, hy - r, r * 2, r * 2);
borderPen.delete();
}
// 绘制所有棋子
for(y=1; boardSize) {
for(x=1; boardSize) {
if(board[y][x] != 0) {
var sx, sy = boardToScreen(x, y);
drawPiece(graphics, sx, sy, board[y][x] == 1);
}
}
}
// 标记最后一步
if(#moveHistory > 0) {
var lastMove = moveHistory[#moveHistory];
var lx, ly = boardToScreen(lastMove.x, lastMove.y);
var markSize = math.max(4, layout.cellSize / 7);
var markPen = gdip.pen(0xFFFF0000, 2);
graphics.drawLine(markPen, lx - markSize, ly, lx + markSize, ly);
graphics.drawLine(markPen, lx, ly - markSize, lx, ly + markSize);
markPen.delete();
}
// 获胜连线
if(gameOver && winner != 0 && #winLine >= 5) {
var minIdx, maxIdx = 1, 1;
for(i, pt in winLine) {
var minPt = winLine[minIdx];
var maxPt = winLine[maxIdx];
// 按 x 排序,x 相同则按 y 排序
if(pt.x < minPt.x || (pt.x == minPt.x && pt.y < minPt.y)) {
minIdx = i;
}
if(pt.x > maxPt.x || (pt.x == maxPt.x && pt.y > maxPt.y)) {
maxIdx = i;
}
}
var sx1, sy1 = boardToScreen(winLine[minIdx].x, winLine[minIdx].y);
var sx2, sy2 = boardToScreen(winLine[maxIdx].x, winLine[maxIdx].y);
// 光晕
var glowPen = gdip.pen(0x50FF4444, layout.cellSize / 2.5);
graphics.drawLine(glowPen, sx1, sy1, sx2, sy2);
glowPen.delete();
// 主线
var winPen = gdip.pen(0xE0FF0000, 3);
graphics.drawLine(winPen, sx1, sy1, sx2, sy2);
winPen.delete();
}
// 游戏结束遮罩
if(gameOver) {
var maskBrush = gdip.solidBrush(0x35000000);
graphics.fillRectangle(maskBrush, rc);
maskBrush.delete();
var resultText = (winner == 1) ? "黑方获胜!" : ((winner == 2) ? "白方获胜!" : "平局!");
var fontSize = math.max(20, layout.cellSize * 0.8);
var font = gdip.font("Tahoma", fontSize);
var format = gdip.stringFormat();
format.align = 1;
format.lineAlign = 1;
// 文字阴影
var shadowBrush = gdip.solidBrush(0x90000000);
graphics.drawString(resultText, font, ::RECTF(3, 3, width, height), format, shadowBrush);
shadowBrush.delete();
// 文字主体
var textColor = (winner == 1) ? 0xFFFFD700 : ((winner == 2) ? 0xFFFFFFFF : 0xFF90EE90);
var textBrush = gdip.solidBrush(textColor);
graphics.drawString(resultText, font, ::RECTF(0, 0, width, height), format, textBrush);
textBrush.delete();
format.delete();
font.delete();
}
}
// 鼠标移动
winform.plus.onMouseMove = function(wParam, lParam) {
var x, y = win.getMessagePos(lParam);
var bx, by = screenToBoard(x, y);
if(bx != hoverX || by != hoverY) {
hoverX, hoverY = bx, by;
owner.redraw();
}
}
// 鼠标离开
winform.plus.onMouseLeave = function() {
hoverX, hoverY = 0, 0;
owner.redraw();
}
import sys.midiOut;
var midiOut = sys.midiOut();
winform.plus.onMouseDown = function(wParam, lParam) {
owner.redraw();
}
// 鼠标点击落子
winform.plus.onMouseUp = function(wParam, lParam) {
if(gameOver) return;
var x, y = win.getMessagePos(lParam);
var bx, by = screenToBoard(x, y);
if(bx > 0 && by > 0) {
if(placePiece(bx, by)) {
owner.redraw();
if(midiOut) {
midiOut.play("changeInstrument(115), 5_", "C5", 80);
}
}
}
}
// 按钮事件
winform.btnRestart.oncommand = function() {
initBoard();
winform.plus.redraw();
}
winform.btnUndo.oncommand = function() {
undoMove();
winform.plus.redraw();
}
winform.show();
win.loopMessage();
Markdown 格式