Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions studio/app/core/project_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
*(f"LPT{i}" for i in range(1, 10)),
}

PROJECT_TEMPLATE_DIRS = {
"basic": "basic",
"game-ui": "GameUIStarter",
}

@dataclass(slots=True)
class ProjectInfo:
root: Path
Expand Down Expand Up @@ -74,13 +79,23 @@ def validate_project_name(name: str) -> str:
def project_path(self, name: str) -> Path:
return self.default_projects_root / self.validate_project_name(name)

def create_project(self, name: str, metadata: dict | None = None, sdk_metadata: dict | None = None) -> ProjectInfo:
def create_project(
self,
name: str,
metadata: dict | None = None,
sdk_metadata: dict | None = None,
template_id: str = "basic",
) -> ProjectInfo:
name = self.validate_project_name(name)
destination = self.project_path(name)
if destination.exists():
raise FileExistsError(destination)

template = self.engine_root / "templates" / "basic"
template_key = str(template_id or "basic").strip().lower()
template_dir = PROJECT_TEMPLATE_DIRS.get(template_key)
if not template_dir:
raise ValueError(f"Unknown project template: {template_id}")
template = self.engine_root / "templates" / template_dir
if not template.is_dir():
raise FileNotFoundError(f"Project template not found: {template}")

Expand All @@ -101,6 +116,7 @@ def create_project(self, name: str, metadata: dict | None = None, sdk_metadata:
appid = payload.get("appid")
payload.update(dict(metadata))
payload["name"] = name
payload["project_template"] = template_key
if appid is not None:
payload["appid"] = appid
descriptor.write_text(
Expand All @@ -111,8 +127,10 @@ def create_project(self, name: str, metadata: dict | None = None, sdk_metadata:
if sdk_metadata:
sdk_dir = destination / ".luas30"
sdk_dir.mkdir(parents=True, exist_ok=True)
sdk_payload = dict(sdk_metadata)
sdk_payload["project_template"] = template_key
(sdk_dir / "mre_sdk.json").write_text(
json.dumps(dict(sdk_metadata), indent=2, ensure_ascii=False) + "\n",
json.dumps(sdk_payload, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)

Expand Down
42 changes: 32 additions & 10 deletions studio/app/ui/mediatek_mre_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class MediaTekProjectConfig:
ram_label: str
compat_profile: str
mre_api: str
template_id: str
template_label: str

def project_metadata(self) -> dict:
return {
Expand All @@ -48,6 +50,8 @@ def project_metadata(self) -> dict:
"mre_api": self.mre_api,
"single_vxp": True,
"project_wizard": "mediatek-mre-sdk-v1",
"project_template": self.template_id,
"project_template_label": self.template_label,
}

def sdk_metadata(self) -> dict:
Expand All @@ -71,9 +75,16 @@ def sdk_metadata(self) -> dict:
"heap_label": self.ram_label,
"compat_profile": self.compat_profile,
"mre_api": self.mre_api,
"project_template": self.template_id,
"project_template_label": self.template_label,
}


PROJECT_TEMPLATES = (
("basic", "Basic Starter · canvas + input tối giản"),
("game-ui", "Game UI Starter · splash + menu + HUD + pause"),
)

RESOLUTIONS = (
("240x320", "240x320 (QVGA - Chuẩn Nokia)", 240, 320),
("320x240", "320x240 (QVGA - Ngang)", 320, 240),
Expand Down Expand Up @@ -230,6 +241,12 @@ def __init__(
self.ram.addItem(label, value)
self.ram.setCurrentIndex(self.ram.findData(1024))

self.template = QComboBox()
self.template.setObjectName("MRECombo")
for template_id, label in PROJECT_TEMPLATES:
self.template.addItem(label, template_id)
self.template.setCurrentIndex(self.template.findData("game-ui"))

self.path_preview = QLabel()
self.path_preview.setObjectName("MREPathPreview")
self.path_preview.setWordWrap(True)
Expand All @@ -242,23 +259,26 @@ def __init__(
self._label(grid, "Nhà phát triển (VENDOR)", 2, 0, 1, 2)
grid.addWidget(self.vendor, 3, 0, 1, 2)

self._label(grid, "Màn hình (Resolution)", 4, 0)
self._label(grid, "Chipset MediaTek", 4, 1)
grid.addWidget(self.resolution, 5, 0)
grid.addWidget(self.chipset, 5, 1)
self._label(grid, "Mẫu dự án (Template)", 4, 0, 1, 2)
grid.addWidget(self.template, 5, 0, 1, 2)

self._label(grid, "Màn hình (Resolution)", 6, 0)
self._label(grid, "Chipset MediaTek", 6, 1)
grid.addWidget(self.resolution, 7, 0)
grid.addWidget(self.chipset, 7, 1)

self._label(grid, "Dung lượng Heap RAM cấp phát", 6, 0, 1, 2)
grid.addWidget(self.ram, 7, 0, 1, 2)
self._label(grid, "Dung lượng Heap RAM cấp phát", 8, 0, 1, 2)
grid.addWidget(self.ram, 9, 0, 1, 2)

hint = QLabel(
"AppID được tạo tự động. MTK6260 mặc định dùng profile Nokia 225 / "
"S30+ native; đường dẫn MRE SDK dùng cấu hình chung trong Settings."
"Game UI Starter có sẵn splash, menu, HUD, pause và game-over. "
"AppID được tạo tự động; đường dẫn MRE SDK dùng cấu hình chung trong Settings."
)
hint.setObjectName("MREDialogHint")
hint.setWordWrap(True)
grid.addWidget(hint, 8, 0, 1, 2)
grid.addWidget(hint, 10, 0, 1, 2)

grid.addWidget(self.path_preview, 9, 0, 1, 2)
grid.addWidget(self.path_preview, 11, 0, 1, 2)
root.addWidget(body)

footer = QFrame()
Expand Down Expand Up @@ -373,4 +393,6 @@ def configuration(self) -> MediaTekProjectConfig:
ram_label=self.ram.currentText(),
compat_profile=str(compat),
mre_api=str(api),
template_id=str(self.template.currentData() or "basic"),
template_label=self.template.currentText(),
)
2 changes: 2 additions & 0 deletions studio/app/vxpui/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ def create_project_from_template(self) -> None:
name,
metadata=config.project_metadata(),
sdk_metadata=config.sdk_metadata(),
template_id=config.template_id,
)
except FileExistsError as exc:
NoticeDialog("Dự án đã tồn tại", f"Đã có dự án trùng tên:\n{exc}", self, error=True).exec()
Expand All @@ -977,6 +978,7 @@ def create_project_from_template(self) -> None:
f"Project created: {info.root}"
+ (f" | AppID {appid}" if appid else "")
+ f" | {config.chipset_id} | {config.screen_width}x{config.screen_height}"
+ f" | {config.template_label}"
)

def open_project_dialog(self) -> None:
Expand Down
36 changes: 36 additions & 0 deletions templates/GameUIStarter/.luas30/ui_design.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"format": "LuaS30 UI Design",
"version": 2,
"canvas": {
"width": 240,
"height": 320
},
"current": "menu",
"screens": [
{
"id": "splash",
"name": "Splash",
"items": []
},
{
"id": "menu",
"name": "Main Menu",
"items": []
},
{
"id": "game",
"name": "Game HUD",
"items": []
},
{
"id": "pause",
"name": "Pause",
"items": []
},
{
"id": "gameover",
"name": "Game Over",
"items": []
}
]
}
51 changes: 51 additions & 0 deletions templates/GameUIStarter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Game UI Starter

Mẫu game nhẹ cho LuaS30 IDE / MediaTek MRE, ưu tiên màn hình 240×320 và thiết bị RAM thấp.

## Có sẵn

- Splash screen dạng đồ họa procedural, không cần asset ngoài.
- Main Menu: Play, How To Play, Settings, About, Exit.
- HUD trong game: HP, score và mục tiêu thu thập.
- Pause menu và Game Over / Mission Complete.
- Điều khiển keypad Nokia/S30+: 2/4/6/8, 5 và 0.
- Theme riêng trong `src/theme.lua`.
- UI component nhẹ trong `src/ui.lua`.
- Gameplay demo trong `src/game.lua`.
- Không dùng ảnh nền lớn nên phù hợp MRE/MTK6260 và dễ thay bằng asset của game thật.

## Cấu trúc

```text
GameUIStarter/
├── main.lua
├── conf.lua
├── project.json
├── src/
│ ├── game.lua
│ ├── theme.lua
│ └── ui.lua
└── .luas30/
└── ui_design.json
```

## Điều khiển

| Phím | Chức năng |
| --- | --- |
| 2 / ↑ | Lên |
| 8 / ↓ | Xuống |
| 4 / ← | Trái |
| 6 / → | Phải |
| 5 / OK | Chọn |
| 0 / Back | Quay lại / Pause |

## Tùy biến nhanh

1. Đổi palette trong `src/theme.lua`.
2. Đổi tên game và menu trong `main.lua`.
3. Thay gameplay demo ở `src/game.lua`.
4. Giữ các hàm UI trong `src/ui.lua` để tái sử dụng cho nhiều màn hình.
5. Có thể thêm sprite/audio vào `assets/` sau mà không phải đổi kiến trúc state/menu.

Mẫu mặc định dùng đồ họa hình học để chạy ngay sau khi tạo project.
7 changes: 7 additions & 0 deletions templates/GameUIStarter/conf.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
config = {
name = "Game UI Starter",
screen_width = 240,
screen_height = 320,
fps = 15
}
return config
Loading
Loading