From 964d9987be04080124df0b950a58337c7a909dec Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 1 Oct 2026 20:40:13 +0200 Subject: [PATCH] Track src modules; stop ignoring .odin files Co-Authored-By: Claude Opus 5.5 --- .gitignore | 1 - AGENTS.md | 77 ++++++++++++++ main.odin | 64 +++++++++--- odin.json | 2 +- src/assets/assets.odin | 18 ++++ src/card/card.odin | 81 +++++++++++++++ src/memory/memory.odin | 218 +++++++++++++++++++++++++++++++++++++++ src/screens/screens.odin | 113 ++++++++++++++++++++ src/themes/themes.odin | 40 +++++++ 9 files changed, 597 insertions(+), 17 deletions(-) create mode 100644 AGENTS.md create mode 100644 src/assets/assets.odin create mode 100644 src/card/card.odin create mode 100644 src/memory/memory.odin create mode 100644 src/screens/screens.odin create mode 100644 src/themes/themes.odin diff --git a/.gitignore b/.gitignore index f7b8fc3..630e722 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # Odin -*.odin *.odin.cache # Build artifacts diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..79e9918 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,77 @@ +# HanjaKanaMun - Project Plan + +## Overview +Odin + raylib multilingual memory card game for learning Japanese (Hiragana/Katakana), Korean (Hangul), and Thai scripts. + +## Current Status + +### Completed +- [x] Created AGENTS.md project plan +- [x] Created src/ directory structure with subdirectories (themes, card, memory, screens, assets) +- [x] Separated themes into themes/themes.odin (colors, constants) +- [x] Separated card logic into card/card.odin (Card struct, rendering, click detection) +- [x] Separated memory game into memory/memory.odin (game state, logic) +- [x] Separated screens into screens/screens.odin (UI screens, buttons) +- [x] Added font loading in assets/assets.odin +- [x] Fixed card positioning (removed -40 offset that pushed cards off screen) +- [x] Fixed card selection (now allows selection in both WAITING and FIRST states) +- [x] Added flip animations for cards (visual feedback when flipping) +- [x] Improved visual styling (rounded corners, theme colors) + +### In Progress +- [ ] Fix Japanese font rendering (TTF loading fails in raylib with "Failed to process TTF font data") + +### Pending +- [ ] Add keyboard support for card selection (1-9, A-L, etc.) +- [ ] Add proper Japanese font that works with raylib +- [ ] Add Korean and Thai language support +- [ ] Add more animations (win screen, transitions) +- [ ] Add sound effects +- [ ] Add score tracking and high scores +- [ ] Add difficulty levels +- [ ] Test all changes work together + +## Known Issues +1. **Font rendering**: Japanese characters show as "?" - raylib's TTF loader fails with CJK fonts. Current workaround: using default font with romanji characters (A, I, U, etc.) +2. **Keyboard support**: Not yet implemented + +## File Structure +``` +HanjaKanaMun/ +├── AGENTS.md # Project plan (this file) +├── README.md # Project overview +├── odin.json # Odin config +├── main.odin # Entry point only +├── src/ +│ ├── themes/ +│ │ └── themes.odin # Color themes, styling constants +│ ├── card/ +│ │ └── card.odin # Card struct and rendering +│ ├── memory/ +│ │ └── memory.odin # Memory game logic +│ ├── screens/ +│ │ └── screens.odin # Screen management (main menu, language screens) +│ └── assets/ +│ └── assets.odin # Font loading, resource management +└── assets/ # Font files, images (future) + └── DroidSansJapanese.ttf +``` + +## Next Steps +1. **Font rendering**: Try alternative approaches: + - Use raylib's LoadFontFromImage to create font from bitmap + - Use pre-converted font files + - Use system fonts via platform-specific APIs + - Use a different font format that raylib supports + +2. **Keyboard support**: Add number/letter keys to select cards + +3. **Testing**: Verify all current changes work together + +## Notes +- NO rm -rf or starting over +- Make small, incremental changes +- Test after each change +- Keep existing functionality working +- All code is now properly separated into modules +- Game is playable with mouse (romanji characters display correctly) diff --git a/main.odin b/main.odin index d673aeb..162a4c6 100644 --- a/main.odin +++ b/main.odin @@ -1,21 +1,55 @@ package main -import "core:fmt" -import "core:os" import raylib "vendor:raylib" +import themes "src/themes" +import screens "src/screens" +import memory "src/memory" +import assets "src/assets" + +current_screen: i32 = themes.MAIN_MENU +mouse_x: i32 +mouse_y: i32 main :: proc() { - width: i32 = 800 - height: i32 = 450 - - raylib.InitWindow(width, height, "HanjaKanaMun") - defer raylib.CloseWindow() - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() - raylib.ClearBackground(raylib.WHITE) - raylib.EndDrawing() - } + raylib.InitWindow(themes.SCREEN_WIDTH, themes.SCREEN_HEIGHT, cstring("HanjaKanaMun")) + defer raylib.CloseWindow() + + assets.load_fonts() + defer assets.unload_fonts() + + raylib.SetTargetFPS(60) + memory.init_memory_game() + + for !raylib.WindowShouldClose() { + mouse_x = raylib.GetMouseX() + mouse_y = raylib.GetMouseY() + + if raylib.IsKeyPressed(raylib.KeyboardKey.ESCAPE) { + current_screen = themes.MAIN_MENU + } + + if current_screen == themes.JAPANESE_MEMORY { + delta_time := raylib.GetFrameTime() + memory.update_memory_game(delta_time, mouse_x, mouse_y) + } + + raylib.BeginDrawing() + + if current_screen == themes.MAIN_MENU { + current_screen = screens.draw_main_menu(mouse_x, mouse_y) + } else if current_screen == themes.JAPANESE_SCREEN { + current_screen = screens.draw_japanese_screen(mouse_x, mouse_y) + if current_screen == themes.JAPANESE_MEMORY { + memory.init_memory_game() + } + } else if current_screen == themes.JAPANESE_MEMORY { + current_screen = memory.draw_memory_game(mouse_x, mouse_y) + } else if current_screen == themes.KOREAN_SCREEN { + current_screen = screens.draw_korean_screen(mouse_x, mouse_y) + } else if current_screen == themes.THAI_SCREEN { + current_screen = screens.draw_thai_screen(mouse_x, mouse_y) + } + + raylib.EndDrawing() + } } diff --git a/odin.json b/odin.json index 2651c95..1bd70ac 100644 --- a/odin.json +++ b/odin.json @@ -2,7 +2,7 @@ "name": "HanjaKanaMun", "path": ".", "source_dir": ".", - "include_dirs": ["vendor"], + "include_dirs": ["vendor", "src"], "rays": [ { "name": "raylib", diff --git a/src/assets/assets.odin b/src/assets/assets.odin new file mode 100644 index 0000000..b6bbb47 --- /dev/null +++ b/src/assets/assets.odin @@ -0,0 +1,18 @@ +package assets + +import raylib "vendor:raylib" + +japanese_font: raylib.Font + +load_fonts :: proc() { + // Use raylib's default font for now + japanese_font = raylib.GetFontDefault() +} + +unload_fonts :: proc() { + // Don't unload the default font +} + +get_font :: proc() -> raylib.Font { + return japanese_font +} diff --git a/src/card/card.odin b/src/card/card.odin new file mode 100644 index 0000000..9d15b44 --- /dev/null +++ b/src/card/card.odin @@ -0,0 +1,81 @@ +package card + +import raylib "vendor:raylib" +import themes "../themes" +import assets "../assets" + +Card :: struct { + x: i32, + y: i32, + character: cstring, + is_face_up: bool, + is_matched: bool, + pair_id: i32, + flip_progress: f32, // 0 = face down, 1 = face up + is_flipping: bool, + flip_direction: bool, // true = to face up, false = to face down +} + +draw_card :: proc(card: ^Card, mouse_x, mouse_y: i32, theme_color: raylib.Color) { + draw_color := theme_color + if card.is_matched { + draw_color = themes.LIGHT_GRAY + } + + is_hovered := mouse_x >= card.x && mouse_x <= card.x + themes.CARD_WIDTH && + mouse_y >= card.y && mouse_y <= card.y + themes.CARD_HEIGHT + if is_hovered && !card.is_face_up && !card.is_matched && !card.is_flipping { + draw_color = raylib.Color{ + byte(f32(theme_color.r) * 0.8), + byte(f32(theme_color.g) * 0.8), + byte(f32(theme_color.b) * 0.8), + theme_color.a, + } + } + + // Draw card background with rounded corners + raylib.DrawRectangleRounded(raylib.Rectangle{f32(card.x), f32(card.y), f32(themes.CARD_WIDTH), f32(themes.CARD_HEIGHT)}, 0.2, 10, draw_color) + raylib.DrawRectangleRoundedLines(raylib.Rectangle{f32(card.x), f32(card.y), f32(themes.CARD_WIDTH), f32(themes.CARD_HEIGHT)}, 0.2, 10, themes.BLACK) + + // Handle flip animation + if card.is_flipping { + // Draw the flip animation + flip_angle := card.flip_progress * 180.0 + if !card.flip_direction { + flip_angle = 180.0 - flip_angle + } + + // Draw the card as a rectangle that's rotating + center_x := f32(card.x + themes.CARD_WIDTH / 2) + center_y := f32(card.y + themes.CARD_HEIGHT / 2) + + // For simplicity, just show the character when flip_progress > 0.5 + show_face := card.flip_progress > 0.5 + if card.flip_direction { + show_face = card.flip_progress >= 0.5 + } else { + show_face = card.flip_progress < 0.5 + } + + if show_face || card.is_face_up || card.is_matched { + font := assets.get_font() + text_w := raylib.MeasureText(card.character, 40) + text_x := card.x + (themes.CARD_WIDTH - text_w) / 2 + text_y := card.y + (themes.CARD_HEIGHT - 40) / 2 - 8 + raylib.DrawTextEx(font, card.character, raylib.Vector2{f32(text_x + 1), f32(text_y + 1)}, 40.0, 0, themes.BLACK) + raylib.DrawTextEx(font, card.character, raylib.Vector2{f32(text_x), f32(text_y)}, 40.0, 0, themes.WHITE) + } + } else if card.is_face_up || card.is_matched { + font := assets.get_font() + text_w := raylib.MeasureText(card.character, 40) + text_x := card.x + (themes.CARD_WIDTH - text_w) / 2 + text_y := card.y + (themes.CARD_HEIGHT - 40) / 2 - 8 + raylib.DrawTextEx(font, card.character, raylib.Vector2{f32(text_x + 1), f32(text_y + 1)}, 40.0, 0, themes.BLACK) + raylib.DrawTextEx(font, card.character, raylib.Vector2{f32(text_x), f32(text_y)}, 40.0, 0, themes.WHITE) + } +} + +is_card_clicked :: proc(card: ^Card, mouse_x, mouse_y: i32) -> bool { + return mouse_x >= card.x && mouse_x <= card.x + themes.CARD_WIDTH && + mouse_y >= card.y && mouse_y <= card.y + themes.CARD_HEIGHT +} diff --git a/src/memory/memory.odin b/src/memory/memory.odin new file mode 100644 index 0000000..7120cd8 --- /dev/null +++ b/src/memory/memory.odin @@ -0,0 +1,218 @@ +package memory + +import raylib "vendor:raylib" +import themes "../themes" +import card "../card" +import assets "../assets" + +MemoryState :: enum { + WAITING, + FIRST, + SECOND, + OVER, +} + +memory_cards: [24]card.Card +memory_state: MemoryState +memory_first: i32 +memory_second: i32 +memory_matches: i32 +memory_moves: i32 +memory_time: f32 +memory_flip: f32 + +init_memory_game :: proc() { + hiragana_chars: [12]cstring = {"あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し"} + romanji_chars: [12]cstring = {"A", "I", "U", "E", "O", "KA", "KI", "KU", "KE", "KO", "SA", "SHI"} + + for i := 0; i < 12; i += 1 { + memory_cards[i*2] = card.Card{ + x = 0, y = 0, + character = romanji_chars[i], + is_face_up = false, + is_matched = false, + pair_id = i32(i), + flip_progress = 0.0, + is_flipping = false, + flip_direction = false, + } + memory_cards[i*2+1] = card.Card{ + x = 0, y = 0, + character = romanji_chars[i], + is_face_up = false, + is_matched = false, + pair_id = i32(i), + flip_progress = 0.0, + is_flipping = false, + flip_direction = false, + } + } + + for i := 0; i < 100; i += 1 { + a := i % 24 + b := (i * 7) % 24 + temp := memory_cards[a] + memory_cards[a] = memory_cards[b] + memory_cards[b] = temp + } + + total_w := themes.GRID_COLS * (themes.CARD_WIDTH + themes.CARD_SPACING) - themes.CARD_SPACING + total_h := themes.GRID_ROWS * (themes.CARD_HEIGHT + themes.CARD_SPACING) - themes.CARD_SPACING + start_x := (themes.SCREEN_WIDTH - total_w) / 2 + start_y := (themes.SCREEN_HEIGHT - total_h) / 2 + + for i := 0; i < 24; i += 1 { + row := i32(i) / themes.GRID_COLS + col := i32(i) % themes.GRID_COLS + memory_cards[i].x = start_x + col * (themes.CARD_WIDTH + themes.CARD_SPACING) + memory_cards[i].y = start_y + row * (themes.CARD_HEIGHT + themes.CARD_SPACING) + } + + memory_state = MemoryState.WAITING + memory_first = -1 + memory_second = -1 + memory_matches = 0 + memory_moves = 0 + memory_time = 0.0 + memory_flip = 0.0 +} + +update_memory_game :: proc(delta_time: f32, mouse_x, mouse_y: i32) { + memory_time += delta_time + + if memory_state == MemoryState.SECOND { + memory_flip += delta_time + if memory_flip >= themes.FLIP_DELAY { + if memory_first >= 0 && memory_second >= 0 { + if memory_cards[memory_first].pair_id == memory_cards[memory_second].pair_id { + memory_cards[memory_first].is_matched = true + memory_cards[memory_second].is_matched = true + memory_matches += 1 + } else { + memory_cards[memory_first].is_flipping = true + memory_cards[memory_first].flip_direction = false + memory_cards[memory_first].flip_progress = 0.0 + memory_cards[memory_second].is_flipping = true + memory_cards[memory_second].flip_direction = false + memory_cards[memory_second].flip_progress = 0.0 + } + } + memory_state = MemoryState.WAITING + memory_flip = 0.0 + memory_first = -1 + memory_second = -1 + } + } + + // Update flip animations + for i := 0; i < 24; i += 1 { + if memory_cards[i].is_flipping { + memory_cards[i].flip_progress += delta_time * 3.0 // Flip speed + if memory_cards[i].flip_progress >= 1.0 { + memory_cards[i].flip_progress = 1.0 + memory_cards[i].is_flipping = false + memory_cards[i].is_face_up = memory_cards[i].flip_direction + } + } + } + + if memory_state == MemoryState.WAITING || memory_state == MemoryState.FIRST { + for i := 0; i < 24; i += 1 { + if !memory_cards[i].is_matched && !memory_cards[i].is_flipping { + if card.is_card_clicked(&memory_cards[i], mouse_x, mouse_y) && + raylib.IsMouseButtonPressed(raylib.MouseButton.LEFT) { + memory_cards[i].is_flipping = true + memory_cards[i].flip_direction = true + memory_cards[i].flip_progress = 0.0 + memory_moves += 1 + if memory_first == -1 { + memory_first = i32(i) + memory_state = MemoryState.FIRST + } else if i32(i) != memory_first { + memory_second = i32(i) + memory_state = MemoryState.SECOND + } + break + } + } + } + } + + if memory_matches >= 12 { + memory_state = MemoryState.OVER + } +} + +draw_memory_game :: proc(mouse_x, mouse_y: i32) -> i32 { + raylib.ClearBackground(themes.JAPAN_BACKGROUND) + + font := assets.get_font() + title: cstring = "Memory Game - Japanese" + title_w := raylib.MeasureText(title, themes.TITLE_FONT_SIZE) + title_x := (themes.SCREEN_WIDTH - title_w) / 2 + raylib.DrawTextEx(font, title, raylib.Vector2{f32(title_x + 4), 54}, f32(themes.TITLE_FONT_SIZE), 0, themes.BLACK) + raylib.DrawTextEx(font, title, raylib.Vector2{f32(title_x), 50}, f32(themes.TITLE_FONT_SIZE), 0, themes.JAPAN_PRIMARY) + + info_text := raylib.TextFormat("Moves: %d | Time: %.1fs", memory_moves, memory_time) + info_w := raylib.MeasureText(info_text, themes.SUBTITLE_FONT_SIZE) + info_x := (themes.SCREEN_WIDTH - info_w) / 2 + raylib.DrawTextEx(font, info_text, raylib.Vector2{f32(info_x), 150}, f32(themes.SUBTITLE_FONT_SIZE), 0, themes.DARK_GRAY) + + for i := 0; i < 24; i += 1 { + card.draw_card(&memory_cards[i], mouse_x, mouse_y, themes.JAPAN_PRIMARY) + } + + back_w := themes.BUTTON_WIDTH + back_h := themes.BUTTON_HEIGHT + back_x := (themes.SCREEN_WIDTH - back_w) / 2 + back_y := themes.SCREEN_HEIGHT - 100 + back_hovered := mouse_x >= back_x && mouse_x <= back_x + back_w && + mouse_y >= back_y && mouse_y <= back_y + back_h + back_color := themes.JAPAN_PRIMARY + if back_hovered { + back_color = themes.JAPAN_ACCENT + } + raylib.DrawRectangle(back_x, back_y, back_w, back_h, back_color) + raylib.DrawRectangleLines(back_x, back_y, back_w, back_h, themes.BLACK) + back_text: cstring = "Back" + back_text_w := raylib.MeasureText(back_text, themes.BUTTON_FONT_SIZE) + back_text_x := back_x + (back_w - back_text_w) / 2 + back_text_y := back_y + (back_h - themes.BUTTON_FONT_SIZE) / 2 + raylib.DrawTextEx(font, back_text, raylib.Vector2{f32(back_text_x), f32(back_text_y)}, f32(themes.BUTTON_FONT_SIZE), 0, themes.WHITE) + + if back_hovered && raylib.IsMouseButtonPressed(raylib.MouseButton.LEFT) { + return themes.JAPANESE_SCREEN + } + + if memory_state == MemoryState.OVER { + raylib.DrawRectangle(0, 0, themes.SCREEN_WIDTH, themes.SCREEN_HEIGHT, raylib.Color{0, 0, 0, 128}) + + win_text: cstring = "Congratulations! You Win!" + win_w := raylib.MeasureText(win_text, 48) + win_x := (themes.SCREEN_WIDTH - win_w) / 2 + raylib.DrawTextEx(font, win_text, raylib.Vector2{f32(win_x), f32(themes.SCREEN_HEIGHT / 2 - 60)}, 48, 0, themes.WHITE) + + stats_text := raylib.TextFormat("Moves: %d | Time: %.1fs", memory_moves, memory_time) + stats_w := raylib.MeasureText(stats_text, 32) + stats_x := (themes.SCREEN_WIDTH - stats_w) / 2 + raylib.DrawTextEx(font, stats_text, raylib.Vector2{f32(stats_x), f32(themes.SCREEN_HEIGHT / 2)}, 32, 0, themes.WHITE) + + again_text: cstring = "Play Again" + again_w := raylib.MeasureText(again_text, themes.BUTTON_FONT_SIZE) + again_x := (themes.SCREEN_WIDTH - again_w) / 2 + again_y := themes.SCREEN_HEIGHT / 2 + 60 + again_hovered := mouse_x >= again_x && mouse_x <= again_x + again_w && + mouse_y >= again_y && mouse_y <= again_y + themes.BUTTON_FONT_SIZE + + again_color := themes.JAPAN_PRIMARY + if again_hovered { + again_color = themes.JAPAN_ACCENT + } + raylib.DrawTextEx(font, again_text, raylib.Vector2{f32(again_x), f32(again_y)}, f32(themes.BUTTON_FONT_SIZE), 0, again_color) + + if again_hovered && raylib.IsMouseButtonPressed(raylib.MouseButton.LEFT) { + init_memory_game() + } + } + return themes.JAPANESE_MEMORY +} diff --git a/src/screens/screens.odin b/src/screens/screens.odin new file mode 100644 index 0000000..c975d7c --- /dev/null +++ b/src/screens/screens.odin @@ -0,0 +1,113 @@ +package screens + +import raylib "vendor:raylib" +import themes "../themes" +import assets "../assets" + +draw_button :: proc(x, y, w, h: i32, text: cstring, base_color, hover_color: raylib.Color, mouse_x, mouse_y: i32) -> bool { + is_hovered := mouse_x >= x && mouse_x <= x + w && mouse_y >= y && mouse_y <= y + h + color := base_color + if is_hovered { + color = hover_color + } + raylib.DrawRectangle(x, y, w, h, color) + raylib.DrawRectangleLines(x, y, w, h, themes.BLACK) + font := assets.get_font() + text_w := raylib.MeasureText(text, themes.BUTTON_FONT_SIZE) + text_x := x + (w - text_w) / 2 + text_y := y + (h - themes.BUTTON_FONT_SIZE) / 2 + raylib.DrawTextEx(font, text, raylib.Vector2{f32(text_x), f32(text_y)}, f32(themes.BUTTON_FONT_SIZE), 0, themes.WHITE) + return is_hovered && raylib.IsMouseButtonPressed(raylib.MouseButton.LEFT) +} + +draw_title :: proc(text: cstring, y: i32, color: raylib.Color) { + font := assets.get_font() + text_w := raylib.MeasureText(text, themes.TITLE_FONT_SIZE) + x := (themes.SCREEN_WIDTH - text_w) / 2 + raylib.DrawTextEx(font, text, raylib.Vector2{f32(x + 4), f32(y + 4)}, f32(themes.TITLE_FONT_SIZE), 0, themes.BLACK) + raylib.DrawTextEx(font, text, raylib.Vector2{f32(x), f32(y)}, f32(themes.TITLE_FONT_SIZE), 0, color) +} + +draw_centered_text :: proc(text: cstring, y: i32, font_size: i32, color: raylib.Color) { + font := assets.get_font() + text_w := raylib.MeasureText(text, font_size) + x := (themes.SCREEN_WIDTH - text_w) / 2 + raylib.DrawTextEx(font, text, raylib.Vector2{f32(x + 4), f32(y + 4)}, f32(font_size), 0, themes.BLACK) + raylib.DrawTextEx(font, text, raylib.Vector2{f32(x), f32(y)}, f32(font_size), 0, color) +} + +draw_main_menu :: proc(mouse_x, mouse_y: i32) -> i32 { + raylib.ClearBackground(themes.WHITE) + + draw_title("HanjaKanaMun", 100, themes.JAPAN_PRIMARY) + draw_centered_text("Learn Japanese, Korean, and Thai", 180, themes.SUBTITLE_FONT_SIZE, themes.DARK_GRAY) + + button_w := themes.BUTTON_WIDTH + button_h := themes.BUTTON_HEIGHT + button_space: i32 = 40 + total_w := button_w * 3 + button_space * 2 + start_x := (themes.SCREEN_WIDTH - total_w) / 2 + start_y := themes.SCREEN_HEIGHT / 2 + 100 + + if draw_button(start_x, start_y, button_w, button_h, "Japanese", themes.JAPAN_PRIMARY, themes.JAPAN_ACCENT, mouse_x, mouse_y) { + return themes.JAPANESE_SCREEN + } + + if draw_button(start_x + button_w + button_space, start_y, button_w, button_h, "Korean", themes.KOREA_PRIMARY, themes.KOREA_ACCENT, mouse_x, mouse_y) { + return themes.KOREAN_SCREEN + } + + if draw_button(start_x + i32(button_w) + i32(button_space) + i32(button_w) + i32(button_space), start_y, button_w, button_h, "Thai", themes.THAI_PRIMARY, themes.THAI_ACCENT, mouse_x, mouse_y) { + return themes.THAI_SCREEN + } + + return themes.MAIN_MENU +} + +draw_japanese_screen :: proc(mouse_x, mouse_y: i32) -> i32 { + raylib.ClearBackground(themes.WHITE) + + draw_title("Japanese", 100, themes.JAPAN_PRIMARY) + draw_centered_text("Select a game to play", 180, themes.SUBTITLE_FONT_SIZE, themes.DARK_GRAY) + + button_w := themes.BUTTON_WIDTH + button_h := themes.BUTTON_HEIGHT + button_space := 40 + start_y := themes.SCREEN_HEIGHT / 2 + start_x := (themes.SCREEN_WIDTH - button_w) / 2 + + if draw_button(start_x, start_y, button_w, button_h, "Memory Game", themes.JAPAN_PRIMARY, themes.JAPAN_ACCENT, mouse_x, mouse_y) { + return themes.JAPANESE_MEMORY + } + + back_y := i32(start_y) + i32(button_h) + i32(button_space) + if draw_button(start_x, back_y, button_w, button_h, "Back", themes.JAPAN_PRIMARY, themes.JAPAN_ACCENT, mouse_x, mouse_y) { + return themes.MAIN_MENU + } + + return themes.JAPANESE_SCREEN +} + +draw_korean_screen :: proc(mouse_x, mouse_y: i32) -> i32 { + raylib.ClearBackground(themes.WHITE) + draw_title("Korean", 100, themes.KOREA_PRIMARY) + draw_centered_text("Coming Soon", 180, themes.SUBTITLE_FONT_SIZE, themes.DARK_GRAY) + + if draw_button((themes.SCREEN_WIDTH - themes.BUTTON_WIDTH) / 2, themes.SCREEN_HEIGHT / 2, themes.BUTTON_WIDTH, themes.BUTTON_HEIGHT, "Back", themes.KOREA_PRIMARY, themes.KOREA_ACCENT, mouse_x, mouse_y) { + return themes.MAIN_MENU + } + + return themes.KOREAN_SCREEN +} + +draw_thai_screen :: proc(mouse_x, mouse_y: i32) -> i32 { + raylib.ClearBackground(themes.WHITE) + draw_title("Thai", 100, themes.THAI_PRIMARY) + draw_centered_text("Coming Soon", 180, themes.SUBTITLE_FONT_SIZE, themes.DARK_GRAY) + + if draw_button((themes.SCREEN_WIDTH - themes.BUTTON_WIDTH) / 2, themes.SCREEN_HEIGHT / 2, themes.BUTTON_WIDTH, themes.BUTTON_HEIGHT, "Back", themes.THAI_PRIMARY, themes.THAI_ACCENT, mouse_x, mouse_y) { + return themes.MAIN_MENU + } + + return themes.THAI_SCREEN +} diff --git a/src/themes/themes.odin b/src/themes/themes.odin new file mode 100644 index 0000000..7ba7633 --- /dev/null +++ b/src/themes/themes.odin @@ -0,0 +1,40 @@ +package themes + +import raylib "vendor:raylib" + +SCREEN_WIDTH: i32 = 1280 +SCREEN_HEIGHT: i32 = 720 + +JAPAN_PRIMARY: raylib.Color = raylib.Color{230, 57, 70, 255} +JAPAN_ACCENT: raylib.Color = raylib.Color{253, 184, 190, 255} +JAPAN_BACKGROUND: raylib.Color = raylib.Color{250, 245, 245, 255} +KOREA_PRIMARY: raylib.Color = raylib.Color{0, 71, 160, 255} +KOREA_ACCENT: raylib.Color = raylib.Color{180, 180, 255, 255} +KOREA_BACKGROUND: raylib.Color = raylib.Color{245, 248, 255, 255} +THAI_PRIMARY: raylib.Color = raylib.Color{165, 25, 49, 255} +THAI_ACCENT: raylib.Color = raylib.Color{255, 180, 200, 255} +THAI_BACKGROUND: raylib.Color = raylib.Color{255, 245, 248, 255} +WHITE: raylib.Color = raylib.Color{255, 255, 255, 255} +BLACK: raylib.Color = raylib.Color{0, 0, 0, 255} +DARK_GRAY: raylib.Color = raylib.Color{64, 64, 64, 255} +LIGHT_GRAY: raylib.Color = raylib.Color{200, 200, 200, 255} +CARD_BACK_COLOR: raylib.Color = raylib.Color{40, 40, 50, 255} + +BUTTON_WIDTH: i32 = 240 +BUTTON_HEIGHT: i32 = 60 +TITLE_FONT_SIZE: i32 = 72 +SUBTITLE_FONT_SIZE: i32 = 24 +BUTTON_FONT_SIZE: i32 = 24 + +CARD_WIDTH: i32 = 100 +CARD_HEIGHT: i32 = 140 +CARD_SPACING: i32 = 15 +GRID_ROWS: i32 = 4 +GRID_COLS: i32 = 6 +FLIP_DELAY: f32 = 1.0 + +MAIN_MENU: i32 = 0 +JAPANESE_SCREEN: i32 = 1 +JAPANESE_MEMORY: i32 = 2 +KOREAN_SCREEN: i32 = 3 +THAI_SCREEN: i32 = 4