diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000..f05bc7d --- /dev/null +++ b/BUILD.md @@ -0,0 +1,143 @@ +# Tetris Game 构建系统 + +这是一个统一的构建系统,支持 Windows、macOS 和 Linux 平台的应用打包,所有分发文件统一存放在 `dist/` 目录中。 + +## 🚀 快速开始 + +### 构建所有平台 +```bash +make all +``` + +### 构建特定平台 +```bash +make windows # 构建 Windows 版本 +make macos # 构建 macOS 版本 +make linux # 构建 Linux 版本 +``` + +### 查看帮助 +```bash +make help +``` + +## 📁 目录结构 + +构建完成后,`dist/` 目录结构如下: + +``` +dist/ +├── TetrisGame-Windows-v1.0.zip # Windows 分发包 +├── TetrisGame-macOS-v1.0.dmg # macOS 分发包 +├── TetrisGame-Linux-v1.0.tar.gz # Linux 分发包 +├── windows/ # Windows 构建临时目录 +├── macos/ # macOS 构建临时目录 +└── linux/ # Linux 构建临时目录 +``` + +## 🛠️ 可用命令 + +### 基础命令 +- `make help` - 显示帮助信息 +- `make info` - 显示构建信息 +- `make check-env` - 检查构建环境 +- `make clean` - 清理所有构建文件 + +### 构建命令 +- `make windows` - 构建 Windows 版本 +- `make macos` - 构建 macOS 版本 +- `make linux` - 构建 Linux 版本 +- `make all` - 构建所有平台版本 + +### 验证命令 +- `make verify` - 验证构建结果 +- `make run` - 运行游戏(开发模式) +- `make test` - 运行测试 + +### 依赖管理 +- `make deps` - 下载依赖 + +### 迁移命令 +- `make migrate` - 迁移旧版本文件到 dist 目录 + +## 📦 分发包内容 + +### Windows 版本 (TetrisGame-Windows-v1.0.zip) +``` +TetrisGame-Windows-v1.0/ +├── TetrisGame.exe # 主程序 +├── 启动游戏.bat # 中文启动脚本 +├── README.txt # 英文说明 +├── 安装说明.txt # 中文说明 +└── assets/ # 资源文件 + └── fonts/ # 字体文件 + ├── HYSongYunLangHeiW-1.ttf + └── README.md +``` + +### macOS 版本 (TetrisGame-macOS-v1.0.dmg) +- 包含完整的 TetrisGame.app 应用包 +- 支持拖拽到 Applications 文件夹安装 +- 包含应用图标和中文显示名称 + +### Linux 版本 (TetrisGame-Linux-v1.0.tar.gz) +``` +TetrisGame-Linux-v1.0/ +├── tetris # 主程序 +├── start_game.sh # 启动脚本 +├── README.txt # 说明文档 +└── assets/ # 资源文件 + └── fonts/ # 字体文件 +``` + +## 🔧 系统要求 + +### 构建环境 +- Go 1.19 或更高版本 +- macOS (用于构建 macOS 版本的 DMG) +- zip 命令 (用于创建 Windows 压缩包) +- tar 命令 (用于创建 Linux 压缩包) + +### 运行环境 +- **Windows**: Windows 10/11 (64-bit) +- **macOS**: macOS 10.15 或更高版本 +- **Linux**: 64-bit Linux 发行版,支持 X11 或 Wayland + +## 🎮 游戏控制 + +- **←→** 方向键:左右移动方块 +- **↑** 方向键:旋转方块 +- **↓** 方向键:快速下降 +- **空格键**:瞬间下降到底部 +- **L 键**:切换中英文界面 +- **R 键**:游戏结束后重新开始 + +## 🌍 多语言支持 + +游戏支持中英文双语界面,按 L 键可以实时切换语言。 + +## 📝 版本信息 + +- **版本**: v1.0 +- **构建时间**: 自动生成 +- **Git 提交**: 自动检测 + +## 🔍 故障排除 + +### 构建失败 +1. 检查 Go 环境:`go version` +2. 检查依赖:`make deps` +3. 清理重建:`make clean && make all` + +### 字体问题 +- 确保 `assets/fonts/` 目录存在 +- 确保字体文件 `HYSongYunLangHeiW-1.ttf` 存在 + +### macOS DMG 创建失败 +- 确保在 macOS 系统上运行 +- 确保有足够的磁盘空间 +- 检查 hdiutil 命令是否可用 + +## 📄 许可证 + +© 2025 Tetris Game. All rights reserved. \ No newline at end of file diff --git a/Makefile b/Makefile index 938c8d0..dd8b6d5 100644 --- a/Makefile +++ b/Makefile @@ -1,223 +1,331 @@ -# Tetris Game Makefile -# Supports cross-compilation for Windows, macOS, and Linux - -# Variables -BINARY_NAME=tetris -MAIN_PATH=. -BUILD_DIR=build -VERSION?=dev -LDFLAGS=-ldflags "-s -w" - -# Platform specific settings -WINDOWS_BINARY=$(BINARY_NAME).exe -MACOS_BINARY=$(BINARY_NAME)_macos -LINUX_BINARY=$(BINARY_NAME)_linux - -# Default target +# Tetris Game - 统一构建系统 +# 支持 Windows 和 macOS 应用打包,统一使用 dist 目录 + +# 基础配置 +BINARY_NAME := tetris +APP_NAME := TetrisGame +VERSION := 1.0 +BUILD_TIME := $(shell date '+%Y-%m-%d %H:%M:%S') +GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") + +# 目录配置 +DIST_DIR := dist +ASSETS_DIR := assets +BUILD_TEMP := .build_temp + +# Go 构建标志 +GO_LDFLAGS := -ldflags "-s -w" +GO_LDFLAGS_GUI := -ldflags "-s -w -H windowsgui" + +# 平台特定配置 +WINDOWS_DIR := $(DIST_DIR)/windows +MACOS_DIR := $(DIST_DIR)/macos +LINUX_DIR := $(DIST_DIR)/linux + +# 版本文件名 +WINDOWS_ZIP := $(APP_NAME)-Windows-v$(VERSION).zip +MACOS_DMG := $(APP_NAME)-macOS-v$(VERSION).dmg +LINUX_TAR := $(APP_NAME)-Linux-v$(VERSION).tar.gz + +# 颜色输出 +BLUE := \033[34m +GREEN := \033[32m +YELLOW := \033[33m +RED := \033[31m +RESET := \033[0m + +.DEFAULT_GOAL := help + +# 帮助信息 .PHONY: help -help: ## Show this help message - @echo "Available targets:" - @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST) - -# Build targets -.PHONY: build -build: ## Build for current platform - @echo "Building $(BINARY_NAME) for current platform..." - go build $(LDFLAGS) -o $(BINARY_NAME) $(MAIN_PATH) - @echo "Build complete: $(BINARY_NAME)" - -.PHONY: build-windows -build-windows: ## Build for Windows (64-bit) - requires Windows or cross-compilation setup - @echo "Building $(BINARY_NAME) for Windows..." - @echo "Note: Cross-compilation for Ebitengine requires proper CGO setup" - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(WINDOWS_BINARY) $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(WINDOWS_BINARY)" - -.PHONY: build-windows-native -build-windows-native: ## Build for Windows using native Go (may have limitations) - @echo "Building $(BINARY_NAME) for Windows (native Go)..." - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -tags ebitengine -o $(BUILD_DIR)/$(WINDOWS_BINARY) $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(WINDOWS_BINARY)" - -.PHONY: build-macos -build-macos: ## Build for macOS (Intel) - requires macOS or cross-compilation setup - @echo "Building $(BINARY_NAME) for macOS (Intel)..." - @echo "Note: Cross-compilation for Ebitengine requires proper CGO setup" - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(MACOS_BINARY)_amd64 $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(MACOS_BINARY)_amd64" - -.PHONY: build-macos-arm -build-macos-arm: ## Build for macOS (Apple Silicon) - requires macOS or cross-compilation setup - @echo "Building $(BINARY_NAME) for macOS (Apple Silicon)..." - @echo "Note: Cross-compilation for Ebitengine requires proper CGO setup" - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(MACOS_BINARY)_arm64 $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(MACOS_BINARY)_arm64" - -.PHONY: build-macos-current -build-macos-current: ## Build for current macOS architecture - @echo "Building $(BINARY_NAME) for current macOS architecture..." - @mkdir -p $(BUILD_DIR) - go build $(LDFLAGS) -o $(BUILD_DIR)/$(MACOS_BINARY)_$$(go env GOARCH) $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(MACOS_BINARY)_$$(go env GOARCH)" - -.PHONY: build-linux -build-linux: ## Build for Linux (64-bit) - requires Linux or cross-compilation setup - @echo "Building $(BINARY_NAME) for Linux..." - @echo "Note: Cross-compilation for Ebitengine requires proper CGO setup" - @mkdir -p $(BUILD_DIR) - CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/$(LINUX_BINARY) $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(LINUX_BINARY)" - -.PHONY: build-current-platform -build-current-platform: ## Build for current platform (recommended) - @echo "Building $(BINARY_NAME) for current platform: $$(go env GOOS)/$$(go env GOARCH)" - @mkdir -p $(BUILD_DIR) - go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)_$$(go env GOOS)_$$(go env GOARCH) $(MAIN_PATH) - @echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)_$$(go env GOOS)_$$(go env GOARCH)" - -.PHONY: build-all -build-all: ## Build for all platforms (requires proper cross-compilation setup) - @echo "Attempting to build for all platforms..." - @echo "Note: This may fail without proper cross-compilation environment" - $(MAKE) build-current-platform - -$(MAKE) build-windows-native - @echo "Build summary:" - @ls -la $(BUILD_DIR)/ 2>/dev/null || echo "No builds completed successfully" - -# Development targets -.PHONY: run -run: ## Run the game - @echo "Starting Tetris game..." - go run $(MAIN_PATH) +help: ## 显示帮助信息 + @echo "$(BLUE)🎮 Tetris Game 构建系统$(RESET)" + @echo "" + @echo "$(GREEN)基础命令:$(RESET)" + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(YELLOW)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST) + @echo "" + @echo "$(GREEN)示例:$(RESET)" + @echo " make all # 构建所有平台" + @echo " make windows # 仅构建 Windows 版本" + @echo " make macos # 仅构建 macOS 版本" + @echo " make clean # 清理所有构建文件" -.PHONY: dev -dev: clean build run ## Clean, build and run for development +# 信息显示 +.PHONY: info +info: ## 显示构建信息 + @echo "$(BLUE)📋 构建信息$(RESET)" + @echo " 应用名称: $(APP_NAME)" + @echo " 版本: v$(VERSION)" + @echo " 构建时间: $(BUILD_TIME)" + @echo " Git 提交: $(GIT_COMMIT)" + @echo " Go 版本: $(shell go version)" + @echo " 当前平台: $(shell go env GOOS)/$(shell go env GOARCH)" + @echo " 分发目录: $(DIST_DIR)/" + +# 环境检查 +.PHONY: check-env +check-env: ## 检查构建环境 + @echo "$(BLUE)🔍 环境检查$(RESET)" + @go version >/dev/null 2>&1 || (echo "$(RED)❌ Go 未安装$(RESET)" && exit 1) + @echo "$(GREEN)✅ Go 环境正常$(RESET)" + @[ -d "$(ASSETS_DIR)" ] || (echo "$(RED)❌ assets 目录缺失$(RESET)" && exit 1) + @echo "$(GREEN)✅ 资源目录存在$(RESET)" + @[ -f "main.go" ] || (echo "$(RED)❌ main.go 文件缺失$(RESET)" && exit 1) + @echo "$(GREEN)✅ 源代码文件存在$(RESET)" + +# 准备目录 +.PHONY: prepare +prepare: ## 准备构建目录 + @echo "$(BLUE)📁 准备构建目录$(RESET)" + @mkdir -p $(DIST_DIR) + @mkdir -p $(WINDOWS_DIR) + @mkdir -p $(MACOS_DIR) + @mkdir -p $(LINUX_DIR) + @mkdir -p $(BUILD_TEMP) + +# 清理 +.PHONY: clean +clean: ## 清理构建文件 + @echo "$(BLUE)🧹 清理构建文件$(RESET)" + @rm -rf $(DIST_DIR) + @rm -rf $(BUILD_TEMP) + @rm -f *.zip *.dmg *.tar.gz + @rm -f $(BINARY_NAME) $(BINARY_NAME).exe + @rm -rf TetrisGame.app + @echo "$(GREEN)✅ 清理完成$(RESET)" + +# Windows 构建 +.PHONY: build-windows-binary +build-windows-binary: check-env prepare + @echo "$(BLUE)🪟 构建 Windows 二进制文件$(RESET)" + GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build $(GO_LDFLAGS_GUI) -o $(BUILD_TEMP)/$(APP_NAME).exe . + @echo "$(GREEN)✅ Windows 二进制文件构建完成$(RESET)" + +.PHONY: create-windows-startup-script +create-windows-startup-script: + @echo "创建 Windows 启动脚本..." + @echo '@echo off' > $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'chcp 65001 >nul' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo 🎮 正在启动 Tetris Game...' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo 🎯 游戏控制:' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo ←→ 左右移动' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo ↑ 旋转方块' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo ↓ 快速下降' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo 空格 瞬间下降' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo L 切换中英文' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo 'echo.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + @echo '"%~dp0$(APP_NAME).exe"' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat + +.PHONY: create-windows-docs +create-windows-docs: + @echo "创建 Windows 说明文档..." + @echo '🎮 Tetris Game - Windows Version v1.0' > $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '📥 Installation: This is a portable version, no installation required.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '🚀 How to Start: Double-click TetrisGame.exe or 启动游戏.bat' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '🎯 Game Controls: ←→ Move, ↑ Rotate, ↓ Soft drop, Space Hard drop, L Language' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '🔧 System Requirements: Windows 10/11 (64-bit)' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + @echo '© 2025 Tetris Game. All rights reserved.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt + +.PHONY: package-windows +package-windows: build-windows-binary + @echo "$(BLUE)📦 打包 Windows 应用$(RESET)" + + # 创建 Windows 应用目录 + @rm -rf $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION) + @mkdir -p $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION) + + # 复制主程序文件 + @cp $(BUILD_TEMP)/$(APP_NAME).exe $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/ + + # 复制资源文件 + @cp -r $(ASSETS_DIR) $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/ + + # 创建启动脚本和文档 + @$(MAKE) create-windows-startup-script + @$(MAKE) create-windows-docs + + # 创建压缩包 + @cd $(WINDOWS_DIR) && zip -r ../$(WINDOWS_ZIP) $(APP_NAME)-Windows-v$(VERSION)/ + + @echo "$(GREEN)✅ Windows 应用打包完成: $(DIST_DIR)/$(WINDOWS_ZIP)$(RESET)" + +# macOS 构建 +.PHONY: build-macos-binary +build-macos-binary: check-env prepare + @echo "$(BLUE)🍎 构建 macOS 二进制文件$(RESET)" + go build $(GO_LDFLAGS) -o $(BUILD_TEMP)/$(BINARY_NAME) . + @echo "$(GREEN)✅ macOS 二进制文件构建完成$(RESET)" + +.PHONY: create-macos-plist +create-macos-plist: + @echo "创建 macOS Info.plist..." + @echo '' > $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' CFBundleDisplayName' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' 俄罗斯方块' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' CFBundleExecutable' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' $(BINARY_NAME)' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' CFBundleIdentifier' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' com.tetrisgame.app' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' CFBundleName' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' $(APP_NAME)' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' CFBundleShortVersionString' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' $(VERSION)' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' CFBundleIconFile' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' app' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' LSApplicationCategoryType' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo ' public.app-category.games' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist + +.PHONY: create-dmg +create-dmg: + @echo "创建 DMG 文件..." + @DMG_SIZE="50m" && \ + TEMP_DMG="$(BUILD_TEMP)/temp_$(MACOS_DMG)" && \ + MOUNT_POINT="$(BUILD_TEMP)/dmg_mount" && \ + rm -rf $$MOUNT_POINT && \ + mkdir -p $$MOUNT_POINT && \ + hdiutil create -size $$DMG_SIZE -fs HFS+ -volname "Tetris Game" $$TEMP_DMG && \ + hdiutil attach $$TEMP_DMG -mountpoint $$MOUNT_POINT && \ + cp -R $(MACOS_DIR)/$(APP_NAME).app $$MOUNT_POINT/ && \ + ln -s /Applications $$MOUNT_POINT/Applications && \ + hdiutil detach $$MOUNT_POINT && \ + hdiutil convert $$TEMP_DMG -format UDZO -o $(DIST_DIR)/$(MACOS_DMG) && \ + rm -f $$TEMP_DMG + +.PHONY: package-macos +package-macos: build-macos-binary + @echo "$(BLUE)📦 打包 macOS 应用$(RESET)" + + # 创建 .app 包结构 + @rm -rf $(MACOS_DIR)/$(APP_NAME).app + @mkdir -p $(MACOS_DIR)/$(APP_NAME).app/Contents/MacOS + @mkdir -p $(MACOS_DIR)/$(APP_NAME).app/Contents/Resources + + # 复制可执行文件 + @cp $(BUILD_TEMP)/$(BINARY_NAME) $(MACOS_DIR)/$(APP_NAME).app/Contents/MacOS/ + @chmod +x $(MACOS_DIR)/$(APP_NAME).app/Contents/MacOS/$(BINARY_NAME) + + # 复制资源文件 + @cp -r $(ASSETS_DIR) $(MACOS_DIR)/$(APP_NAME).app/Contents/Resources/ + + # 创建 Info.plist + @$(MAKE) create-macos-plist + + # 复制应用图标 + @if [ -f "$(ASSETS_DIR)/icons/app.icns" ]; then \ + cp "$(ASSETS_DIR)/icons/app.icns" $(MACOS_DIR)/$(APP_NAME).app/Contents/Resources/; \ + echo "$(GREEN)✅ 已复制应用图标 app.icns$(RESET)"; \ + else \ + echo "$(YELLOW)⚠️ 图标文件 $(ASSETS_DIR)/icons/app.icns 不存在$(RESET)"; \ + fi + + # 创建 DMG + @$(MAKE) create-dmg + + @echo "$(GREEN)✅ macOS 应用打包完成: $(DIST_DIR)/$(MACOS_DMG)$(RESET)" + +# Linux 构建 +.PHONY: build-linux-binary +build-linux-binary: check-env prepare + @echo "$(BLUE)🐧 构建 Linux 二进制文件$(RESET)" + @echo "$(YELLOW)⚠️ 注意: Linux 交叉编译需要 CGO 支持,建议在 Linux 系统上构建$(RESET)" + @if [ "$$(go env GOOS)" = "linux" ]; then \ + go build $(GO_LDFLAGS) -o $(BUILD_TEMP)/$(BINARY_NAME)_linux .; \ + else \ + echo "$(YELLOW)⚠️ 当前不在 Linux 系统,跳过 Linux 构建$(RESET)"; \ + mkdir -p $(BUILD_TEMP); \ + echo "# Linux 构建需要在 Linux 系统上进行" > $(BUILD_TEMP)/$(BINARY_NAME)_linux.txt; \ + fi + @echo "$(GREEN)✅ Linux 二进制文件构建完成$(RESET)" + +.PHONY: package-linux +package-linux: build-linux-binary + @echo "$(BLUE)📦 打包 Linux 应用$(RESET)" + + @if [ "$$(go env GOOS)" = "linux" ] && [ -f "$(BUILD_TEMP)/$(BINARY_NAME)_linux" ]; then \ + echo "正在打包 Linux 应用..."; \ + rm -rf $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION); \ + mkdir -p $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION); \ + cp $(BUILD_TEMP)/$(BINARY_NAME)_linux $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/$(BINARY_NAME); \ + chmod +x $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/$(BINARY_NAME); \ + cp -r $(ASSETS_DIR) $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/; \ + echo '#!/bin/bash' > $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ + echo 'echo "🎮 Starting Tetris Game..."' >> $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ + echo 'cd "$$(dirname "$$0")"' >> $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ + echo './$(BINARY_NAME)' >> $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ + chmod +x $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ + cd $(LINUX_DIR) && tar -czf ../$(LINUX_TAR) $(APP_NAME)-Linux-v$(VERSION)/; \ + echo "$(GREEN)✅ Linux 应用打包完成: $(DIST_DIR)/$(LINUX_TAR)$(RESET)"; \ + else \ + echo "$(YELLOW)⚠️ 跳过 Linux 打包(需要在 Linux 系统上构建)$(RESET)"; \ + mkdir -p $(LINUX_DIR); \ + echo "# Linux 版本需要在 Linux 系统上构建" > $(LINUX_DIR)/README.txt; \ + echo "$(YELLOW)⚠️ Linux 版本跳过$(RESET)"; \ + fi -.PHONY: install -install: ## Install the game to GOPATH/bin - @echo "Installing $(BINARY_NAME)..." - go install $(LDFLAGS) $(MAIN_PATH) - @echo "Installation complete!" +# 主要构建目标 +.PHONY: windows +windows: package-windows ## 构建 Windows 版本 -# Quality assurance targets -.PHONY: test -test: ## Run tests - @echo "Running tests..." - go test -v ./... +.PHONY: macos +macos: package-macos ## 构建 macOS 版本 -.PHONY: test-coverage -test-coverage: ## Run tests with coverage - @echo "Running tests with coverage..." - go test -v -coverprofile=coverage.out ./... - go tool cover -html=coverage.out -o coverage.html - @echo "Coverage report generated: coverage.html" +.PHONY: linux +linux: package-linux ## 构建 Linux 版本 -.PHONY: fmt -fmt: ## Format code - @echo "Formatting code..." - go fmt ./... +.PHONY: all +all: clean windows macos ## 构建所有支持的平台版本 + @if [ "$$(go env GOOS)" = "linux" ]; then \ + $(MAKE) linux; \ + else \ + echo "$(YELLOW)⚠️ 当前平台不支持 Linux 交叉编译,跳过 Linux 构建$(RESET)"; \ + fi + @echo "" + @echo "$(GREEN)🎉 所有平台构建完成!$(RESET)" + @echo "" + @echo "$(BLUE)📋 构建结果:$(RESET)" + @ls -lh $(DIST_DIR)/*.zip $(DIST_DIR)/*.dmg $(DIST_DIR)/*.tar.gz 2>/dev/null || true -.PHONY: vet -vet: ## Run go vet - @echo "Running go vet..." - go vet ./... +# 验证和测试 +.PHONY: verify +verify: ## 验证构建结果 + @echo "$(BLUE)🔍 验证构建结果$(RESET)" + @echo "" + @echo "$(GREEN)构建文件:$(RESET)" + @ls -lh $(DIST_DIR)/ 2>/dev/null || echo "无构建文件" + @echo "" + @if [ -f "$(DIST_DIR)/$(WINDOWS_ZIP)" ]; then \ + echo "$(GREEN)✅ Windows 版本: $(WINDOWS_ZIP)$(RESET)"; \ + unzip -l $(DIST_DIR)/$(WINDOWS_ZIP) | head -10; \ + fi + @if [ -f "$(DIST_DIR)/$(MACOS_DMG)" ]; then \ + echo "$(GREEN)✅ macOS 版本: $(MACOS_DMG)$(RESET)"; \ + fi + @if [ -f "$(DIST_DIR)/$(LINUX_TAR)" ]; then \ + echo "$(GREEN)✅ Linux 版本: $(LINUX_TAR)$(RESET)"; \ + fi -.PHONY: lint -lint: ## Run golangci-lint (requires golangci-lint to be installed) - @echo "Running golangci-lint..." - golangci-lint run +# 开发相关 +.PHONY: run +run: ## 运行游戏(开发模式) + @echo "$(BLUE)🎮 启动游戏$(RESET)" + go run . -.PHONY: check -check: fmt vet test ## Run format, vet, and tests +.PHONY: test +test: ## 运行测试 + @echo "$(BLUE)🧪 运行测试$(RESET)" + go test -v ./... -# Dependency management .PHONY: deps -deps: ## Download dependencies - @echo "Downloading dependencies..." +deps: ## 下载依赖 + @echo "$(BLUE)📦 下载依赖$(RESET)" go mod download - -.PHONY: deps-update -deps-update: ## Update dependencies - @echo "Updating dependencies..." - go mod tidy - go get -u ./... go mod tidy -.PHONY: deps-vendor -deps-vendor: ## Vendor dependencies - @echo "Vendoring dependencies..." - go mod vendor - -# Cleanup targets -.PHONY: clean -clean: ## Clean build artifacts - @echo "Cleaning build artifacts..." - @rm -f $(BINARY_NAME) - @rm -rf $(BUILD_DIR) - @rm -f coverage.out coverage.html - @echo "Clean complete!" - -.PHONY: clean-all -clean-all: clean ## Clean everything including vendor - @echo "Cleaning vendor directory..." - @rm -rf vendor/ - -# Release targets -.PHONY: release -release: clean build-current-platform ## Create release build for current platform - @echo "Creating release package for current platform..." - @mkdir -p $(BUILD_DIR)/releases - @CURRENT_OS=$$(go env GOOS); \ - CURRENT_ARCH=$$(go env GOARCH); \ - if [ "$$CURRENT_OS" = "windows" ]; then \ - cd $(BUILD_DIR) && zip releases/$(BINARY_NAME)-$$CURRENT_OS-$$CURRENT_ARCH.zip $(BINARY_NAME)_$$CURRENT_OS_$$CURRENT_ARCH; \ - else \ - cd $(BUILD_DIR) && tar -czf releases/$(BINARY_NAME)-$$CURRENT_OS-$$CURRENT_ARCH.tar.gz $(BINARY_NAME)_$$CURRENT_OS_$$CURRENT_ARCH; \ - fi - @echo "Release package created in $(BUILD_DIR)/releases/" - @ls -la $(BUILD_DIR)/releases/ - -# Docker targets (optional) -.PHONY: docker-build -docker-build: ## Build Docker image - @echo "Building Docker image..." - docker build -t $(BINARY_NAME):$(VERSION) . - -.PHONY: docker-run -docker-run: ## Run in Docker container - @echo "Running in Docker container..." - docker run --rm -it $(BINARY_NAME):$(VERSION) - -# Info targets -.PHONY: info -info: ## Show build information - @echo "=== Build Information ===" - @echo "Binary name: $(BINARY_NAME)" - @echo "Version: $(VERSION)" - @echo "Go version: $$(go version)" - @echo "Build directory: $(BUILD_DIR)" - @echo "Current platform: $$(go env GOOS)/$$(go env GOARCH)" - @echo "CGO enabled: $$(go env CGO_ENABLED)" - -.PHONY: env -env: ## Show Go environment - @echo "=== Go Environment ===" - @go env - -.PHONY: cross-compile-info -cross-compile-info: ## Show cross-compilation information - @echo "=== Cross-Compilation Information ===" - @echo "Ebitengine requires CGO for cross-compilation." - @echo "To build for other platforms, you need:" - @echo "1. C compiler for target platform" - @echo "2. Platform-specific libraries" - @echo "3. Proper CGO_ENABLED=1 setting" - @echo "" - @echo "Recommended approach:" - @echo "- Build on the target platform directly" - @echo "- Use GitHub Actions or CI/CD for multi-platform builds" - @echo "- Use Docker with multi-stage builds" \ No newline at end of file diff --git a/assets/icons/README.md b/assets/icons/README.md new file mode 100644 index 0000000..3d0cb97 --- /dev/null +++ b/assets/icons/README.md @@ -0,0 +1,89 @@ +# 应用图标目录 + +本目录包含 Tetris 游戏的应用图标文件。 + +## 文件说明 + +### 主要图标文件 +- `app.icns` - macOS 应用图标文件 (96K) + - 格式: Mac OS X icon, "ic12" type + - 包含所有标准尺寸 (16x16 到 1024x1024) + - 支持 Retina 显示屏 (@2x 版本) + +### PNG 图标文件 +- `icon_16.png` - 16x16 像素图标 +- `icon_32.png` - 32x32 像素图标 +- `icon_64.png` - 64x64 像素图标 +- `icon_128.png` - 128x128 像素图标 +- `icon_256.png` - 256x256 像素图标 + +## 图标设计 + +### 设计元素 +- **主题**: 俄罗斯方块彩色块图案 +- **背景**: 深蓝色 (#2c3e50) 圆角矩形 +- **方块颜色**: + - 红色 (#e74c3c) + - 蓝色 (#3498db) + - 橙色 (#f39c12) + - 绿色 (#2ecc71) + - 紫色 (#9b59b6) + - 深橙色 (#e67e22) + - 青绿色 (#1abc9c) + - 深灰色 (#34495e) + +### 技术特性 +- **多分辨率支持**: 适配不同显示密度 +- **圆角设计**: 符合 macOS 设计规范 +- **高光效果**: 增加视觉层次感 +- **白色边框**: 增强方块定义 + +## 构建集成 + +在 macOS 构建过程中,`app.icns` 文件会自动复制到应用包中: + +```bash +# 构建 macOS 版本 +make macos + +# 图标将自动复制到: +# dist/macos/TetrisGame.app/Contents/Resources/app.icns +``` + +## 图标使用 + +### macOS 应用 +- 文件位置: `TetrisGame.app/Contents/Resources/app.icns` +- Info.plist 配置: `CFBundleIconFile = app` +- 显示位置: Finder、Dock、应用启动台 + +### 其他平台 +- Windows: 可使用 PNG 文件转换为 .ico 格式 +- Linux: 直接使用 PNG 文件 + +## 维护说明 + +### 更新图标 +如需更新应用图标: + +1. 替换 `app.icns` 文件 +2. 可选:更新对应的 PNG 文件 +3. 重新构建应用: `make clean && make macos` + +### 创建新图标 +如需从零创建新图标: + +1. 创建 1024x1024 的高分辨率设计 +2. 生成多个尺寸的 PNG 文件 +3. 使用 macOS `iconutil` 工具创建 .icns 文件: + ```bash + iconutil -c icns icon.iconset -o app.icns + ``` + +## 文件完整性 + +所有图标文件的校验和: +- `app.icns`: 96K (Mac OS X icon format) +- 总体设计一致性: ✅ +- 多分辨率覆盖: ✅ +- macOS 兼容性: ✅ \ No newline at end of file diff --git a/assets/icons/app.icns b/assets/icons/app.icns new file mode 100644 index 0000000..31ec769 Binary files /dev/null and b/assets/icons/app.icns differ diff --git a/assets/icons/icon_128.png b/assets/icons/icon_128.png new file mode 100644 index 0000000..c003c1c Binary files /dev/null and b/assets/icons/icon_128.png differ diff --git a/assets/icons/icon_16.png b/assets/icons/icon_16.png new file mode 100644 index 0000000..238a4b1 Binary files /dev/null and b/assets/icons/icon_16.png differ diff --git a/assets/icons/icon_256.png b/assets/icons/icon_256.png new file mode 100644 index 0000000..7c36796 Binary files /dev/null and b/assets/icons/icon_256.png differ diff --git a/assets/icons/icon_32.png b/assets/icons/icon_32.png new file mode 100644 index 0000000..f206c4b Binary files /dev/null and b/assets/icons/icon_32.png differ diff --git a/assets/icons/icon_64.png b/assets/icons/icon_64.png new file mode 100644 index 0000000..7086337 Binary files /dev/null and b/assets/icons/icon_64.png differ diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..d2b73fc --- /dev/null +++ b/build.sh @@ -0,0 +1,267 @@ +#!/bin/bash + +# Tetris Game 自动化构建脚本 +# 支持 Windows、macOS 和 Linux 平台 + +set -e # 遇到错误立即退出 + +# 颜色定义 +BLUE='\033[34m' +GREEN='\033[32m' +YELLOW='\033[33m' +RED='\033[31m' +RESET='\033[0m' + +# 配置 +VERSION="1.0" +BUILD_TIME=$(date '+%Y-%m-%d %H:%M:%S') +GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") + +# 函数:打印带颜色的消息 +print_info() { + echo -e "${BLUE}ℹ️ $1${RESET}" +} + +print_success() { + echo -e "${GREEN}✅ $1${RESET}" +} + +print_warning() { + echo -e "${YELLOW}⚠️ $1${RESET}" +} + +print_error() { + echo -e "${RED}❌ $1${RESET}" +} + +# 函数:显示帮助信息 +show_help() { + echo -e "${BLUE}🎮 Tetris Game 自动化构建脚本${RESET}" + echo "" + echo "用法: $0 [选项] [平台]" + echo "" + echo "平台:" + echo " windows 构建 Windows 版本" + echo " macos 构建 macOS 版本" + echo " linux 构建 Linux 版本" + echo " all 构建所有平台 (默认)" + echo "" + echo "选项:" + echo " -h, --help 显示帮助信息" + echo " -c, --clean 构建前清理" + echo " -v, --verify 构建后验证" + echo " -i, --info 显示构建信息" + echo " --no-color 禁用颜色输出" + echo "" + echo "示例:" + echo " $0 # 构建所有平台" + echo " $0 windows # 仅构建 Windows" + echo " $0 -c all # 清理后构建所有平台" + echo " $0 -cv macos # 清理、构建 macOS 并验证" +} + +# 函数:显示构建信息 +show_info() { + print_info "构建信息" + echo " 版本: v${VERSION}" + echo " 构建时间: ${BUILD_TIME}" + echo " Git 提交: ${GIT_COMMIT}" + echo " Go 版本: $(go version 2>/dev/null || echo '未安装')" + echo " 当前平台: $(go env GOOS 2>/dev/null || echo 'unknown')/$(go env GOARCH 2>/dev/null || echo 'unknown')" + echo " 工作目录: $(pwd)" +} + +# 函数:检查环境 +check_environment() { + print_info "检查构建环境..." + + # 检查 Go + if ! command -v go &> /dev/null; then + print_error "Go 未安装或不在 PATH 中" + exit 1 + fi + print_success "Go 环境正常" + + # 检查必要文件 + if [ ! -f "main.go" ]; then + print_error "main.go 文件不存在" + exit 1 + fi + + if [ ! -d "assets" ]; then + print_error "assets 目录不存在" + exit 1 + fi + + print_success "源代码文件检查通过" +} + +# 函数:清理构建文件 +clean_build() { + print_info "清理构建文件..." + make clean + print_success "清理完成" +} + +# 函数:构建指定平台 +build_platform() { + local platform=$1 + print_info "构建 ${platform} 版本..." + + case $platform in + windows) + make windows + ;; + macos) + make macos + ;; + linux) + make linux + ;; + all) + make all + ;; + *) + print_error "不支持的平台: $platform" + exit 1 + ;; + esac + + print_success "${platform} 构建完成" +} + +# 函数:验证构建结果 +verify_build() { + print_info "验证构建结果..." + make verify + print_success "验证完成" +} + +# 函数:显示构建结果摘要 +show_summary() { + echo "" + print_success "🎉 构建完成!" + echo "" + print_info "构建结果摘要:" + + if [ -d "dist" ]; then + echo " 分发目录: dist/" + + # 显示文件大小 + if [ -f "dist/TetrisGame-Windows-v1.0.zip" ]; then + local size=$(ls -lh dist/TetrisGame-Windows-v1.0.zip | awk '{print $5}') + echo " Windows 版本: TetrisGame-Windows-v1.0.zip (${size})" + fi + + if [ -f "dist/TetrisGame-macOS-v1.0.dmg" ]; then + local size=$(ls -lh dist/TetrisGame-macOS-v1.0.dmg | awk '{print $5}') + echo " macOS 版本: TetrisGame-macOS-v1.0.dmg (${size})" + fi + + if [ -f "dist/TetrisGame-Linux-v1.0.tar.gz" ]; then + local size=$(ls -lh dist/TetrisGame-Linux-v1.0.tar.gz | awk '{print $5}') + echo " Linux 版本: TetrisGame-Linux-v1.0.tar.gz (${size})" + fi + + echo "" + print_info "总计文件数: $(find dist/ -type f -name '*.zip' -o -name '*.dmg' -o -name '*.tar.gz' | wc -l | tr -d ' ')" + + # 计算总大小 + local total_size=$(find dist/ -type f -name '*.zip' -o -name '*.dmg' -o -name '*.tar.gz' -exec ls -l {} \; | awk '{sum += $5} END {print sum}') + if [ -n "$total_size" ] && [ "$total_size" -gt 0 ]; then + local total_mb=$((total_size / 1024 / 1024)) + echo " 总大小: ${total_mb}MB" + fi + else + print_warning "dist 目录不存在" + fi + + echo "" + print_info "使用说明:" + echo " - 查看详细文档: cat BUILD.md" + echo " - 验证构建: make verify" + echo " - 运行游戏: make run" +} + +# 主函数 +main() { + local platform="all" + local clean_first=false + local verify_after=false + local show_info_only=false + + # 解析命令行参数 + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_help + exit 0 + ;; + -c|--clean) + clean_first=true + shift + ;; + -v|--verify) + verify_after=true + shift + ;; + -i|--info) + show_info_only=true + shift + ;; + --no-color) + # 禁用颜色 + BLUE='' + GREEN='' + YELLOW='' + RED='' + RESET='' + shift + ;; + windows|macos|linux|all) + platform=$1 + shift + ;; + *) + print_error "未知参数: $1" + echo "使用 $0 --help 查看帮助" + exit 1 + ;; + esac + done + + # 显示标题 + echo -e "${BLUE}🎮 Tetris Game 自动化构建脚本 v${VERSION}${RESET}" + echo "" + + # 如果只是显示信息 + if [ "$show_info_only" = true ]; then + show_info + exit 0 + fi + + # 检查环境 + check_environment + + # 清理(如果需要) + if [ "$clean_first" = true ]; then + clean_build + fi + + # 构建 + build_platform "$platform" + + # 验证(如果需要) + if [ "$verify_after" = true ]; then + verify_build + fi + + # 显示摘要 + show_summary +} + +# 错误处理 +trap 'print_error "构建过程中发生错误,退出码: $?"' ERR + +# 运行主函数 +main "$@" \ No newline at end of file diff --git a/internal/font/font.go b/internal/font/font.go index 515c457..a52bfa1 100644 --- a/internal/font/font.go +++ b/internal/font/font.go @@ -62,11 +62,29 @@ func NewFontRenderer() *FontRenderer { // loadFromAssetsDirectory 专门扫描 assets/fonts 目录并加载字体文件 func loadFromAssetsDirectory() ([]byte, string) { - assetsPath := "assets/fonts" + // 尝试多个可能的路径 + possiblePaths := []string{ + "assets/fonts", // 开发环境 + "Contents/Resources/assets/fonts", // macOS 应用包内部 + "../Resources/assets/fonts", // macOS 应用包相对路径 + filepath.Join(getExecutableDir(), "assets/fonts"), // 可执行文件同目录 + } + + var assetsPath string + var found bool + + // 查找存在的资源路径 + for _, path := range possiblePaths { + if _, err := os.Stat(path); err == nil { + assetsPath = path + found = true + log.Printf("📁 找到字体目录: %s", path) + break + } + } - // 检查目录是否存在 - if _, err := os.Stat(assetsPath); os.IsNotExist(err) { - log.Printf("📁 assets/fonts 目录不存在,请创建并放入字体文件") + if !found { + log.Printf("📁 未找到 assets/fonts 目录,已尝试路径: %v", possiblePaths) return nil, "" } @@ -87,16 +105,16 @@ func loadFromAssetsDirectory() ([]byte, string) { }) if err != nil { - log.Printf("❌ 扫描 assets/fonts 目录失败: %v", err) + log.Printf("❌ 扫描字体目录失败: %v", err) return nil, "" } if len(fontFiles) == 0 { - log.Printf("📂 assets/fonts 目录为空,请添加字体文件 (.ttf, .ttc, .otf)") + log.Printf("📂 字体目录为空,请添加字体文件 (.ttf, .ttc, .otf)") return nil, "" } - log.Printf("🔍 在 assets/fonts 目录找到 %d 个字体文件", len(fontFiles)) + log.Printf("🔍 在 %s 找到 %d 个字体文件", assetsPath, len(fontFiles)) // 字体优先级:微软雅黑 > 其他中文字体 > 任意字体 fontPriorities := [][]string{ @@ -133,10 +151,20 @@ func loadFromAssetsDirectory() ([]byte, string) { } } - log.Printf("❌ assets/fonts 目录中没有可用的字体文件") + log.Printf("❌ 字体目录中没有可用的字体文件") return nil, "" } +// getExecutableDir 获取可执行文件所在目录 +func getExecutableDir() string { + execPath, err := os.Executable() + if err != nil { + log.Printf("⚠️ 获取可执行文件路径失败: %v", err) + return "." + } + return filepath.Dir(execPath) +} + // tryLoadFont 尝试加载字体文件并验证格式 func tryLoadFont(fontPath string) ([]byte, error) { data, err := os.ReadFile(fontPath) diff --git a/patch/0001-fix-IBlock-disappear-issue.patch b/patch/0001-fix-IBlock-disappear-issue.patch deleted file mode 100755 index 6f8a33c..0000000 --- a/patch/0001-fix-IBlock-disappear-issue.patch +++ /dev/null @@ -1,151 +0,0 @@ -From ffe9242a73abfb3e8ee9b6effd57e64155717bfb Mon Sep 17 00:00:00 2001 -From: yinqiang -Date: Sat, 7 Jun 2025 22:50:07 +0800 -Subject: [PATCH] fix IBlock disappear issue - ---- - block.go | 21 +++++++++++---------- - game.go | 26 +++++++++++++++----------- - 2 files changed, 26 insertions(+), 21 deletions(-) - -diff --git a/block.go b/block.go -index ad276ea..0b3aaee 100644 ---- a/block.go -+++ b/block.go -@@ -14,7 +14,7 @@ type Block struct { - type BlockType int - - const ( -- IBlock BlockType = iota -+ IBlock BlockType = iota + 1 - JBlock - LBlock - OBlock -@@ -32,13 +32,14 @@ type Tetromino struct { - - // Colors for different block types - var BlockColors = map[BlockType]color.Color{ -- IBlock: color.RGBA{0, 255, 255, 255}, // Cyan -- JBlock: color.RGBA{0, 0, 255, 255}, // Blue -- LBlock: color.RGBA{255, 165, 0, 255}, // Orange -- OBlock: color.RGBA{255, 255, 0, 255}, // Yellow -- SBlock: color.RGBA{0, 255, 0, 255}, // Green -- TBlock: color.RGBA{128, 0, 128, 255}, // Purple -- ZBlock: color.RGBA{255, 0, 0, 255}, // Red -+ EmptyBlock: color.RGBA{0, 0, 0, 0}, // Black -+ IBlock: color.RGBA{0, 255, 255, 255}, // Cyan -+ JBlock: color.RGBA{0, 0, 255, 255}, // Blue -+ LBlock: color.RGBA{255, 165, 0, 255}, // Orange -+ OBlock: color.RGBA{255, 255, 0, 255}, // Yellow -+ SBlock: color.RGBA{0, 255, 0, 255}, // Green -+ TBlock: color.RGBA{128, 0, 128, 255}, // Purple -+ ZBlock: color.RGBA{255, 0, 0, 255}, // Red - } - - // TetrominoShapes defines the shape of each tetromino type -@@ -102,8 +103,8 @@ func NewTetromino(blockType BlockType, x, y int) *Tetromino { - shape := TetrominoShapes[blockType] - blocks := make([]Block, 0) - -- for i := 0; i < len(shape); i++ { -- for j := 0; j < len(shape[i]); j++ { -+ for i := range shape { -+ for j := range shape[i] { - if shape[i][j] { - blocks = append(blocks, Block{ - X: j, -diff --git a/game.go b/game.go -index aa9896f..2aa98e9 100644 ---- a/game.go -+++ b/game.go -@@ -24,6 +24,7 @@ const ( - // Game constants - InitialDropInterval = 60 - MinDropInterval = 5 -+ EmptyBlock = 0 - ) - - // Game represents the main game state -@@ -90,9 +91,9 @@ func (g *Game) Draw(screen *ebiten.Image) { - } - - // Draw placed blocks -- for y := 0; y < BoardHeight; y++ { -- for x := 0; x < BoardWidth; x++ { -- if g.board[y][x] != 0 { -+ for y := range BoardHeight { -+ for x := range BoardWidth { -+ if g.board[y][x] != EmptyBlock { - g.drawBlock(screen, x, y, g.board[y][x]) - } - } -@@ -311,7 +312,7 @@ func (g *Game) isColliding() bool { - } - // Check collision with other pieces - if y >= 0 && x >= 0 && x < BoardWidth && y < BoardHeight { -- if g.board[y][x] != 0 { -+ if g.board[y][x] != EmptyBlock { - return true - } - } -@@ -324,6 +325,9 @@ func (g *Game) lockPiece() { - if g.currentPiece == nil { - return - } -+ // if g.currentPiece.BlockType == IBlock { -+ // g.currentPiece.BlockType = IBlock -+ // } - - positions := g.currentPiece.GetAbsolutePositions() - for _, pos := range positions { -@@ -378,8 +382,8 @@ func (g *Game) clearLines() { - - // isLineFull checks if a line is completely filled - func (g *Game) isLineFull(y int) bool { -- for x := 0; x < BoardWidth; x++ { -- if g.board[y][x] == 0 { -+ for x := range BoardWidth { -+ if g.board[y][x] == EmptyBlock { - return false - } - } -@@ -391,15 +395,15 @@ func (g *Game) removeLine(y int) { - for i := y; i > 0; i-- { - copy(g.board[i], g.board[i-1]) - } -- for x := 0; x < BoardWidth; x++ { -- g.board[0][x] = 0 -+ for x := range BoardWidth { -+ g.board[0][x] = EmptyBlock - } - } - - // spawnNewPiece creates a new piece at the top of the board - func (g *Game) spawnNewPiece() { - if g.nextPiece == nil { -- g.nextPiece = NewTetromino(BlockType(rand.Intn(7)), 0, 0) -+ g.nextPiece = NewTetromino(BlockType(rand.Intn(7)+1), 0, 0) - } - - g.currentPiece = g.nextPiece -@@ -409,7 +413,7 @@ func (g *Game) spawnNewPiece() { - } - g.currentPiece.Y = 0 - -- g.nextPiece = NewTetromino(BlockType(rand.Intn(7)), 0, 0) -+ g.nextPiece = NewTetromino(BlockType(rand.Intn(7)+1), 0, 0) - - if g.isColliding() { - g.gameOver = true -@@ -423,7 +427,7 @@ func (g *Game) wouldCollide(piece *Tetromino) bool { - if x < 0 || x >= BoardWidth || y >= BoardHeight { - return true - } -- if y >= 0 && y < BoardHeight && x >= 0 && x < BoardWidth && g.board[y][x] != 0 { -+ if y >= 0 && y < BoardHeight && x >= 0 && x < BoardWidth && g.board[y][x] != EmptyBlock { - return true - } - } --- -2.39.5 (Apple Git-154) -