Files
Sansan 576f9f84f1
Build and Test / build-and-test (push) Has been cancelled
Refactor: Organize language data into separate config functions
2026-05-09 00:41:21 +02:00

432 lines
14 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"runtime"
"github.com/gen2brain/raylib-go/raylib"
)
// Button represents a clickable button with animation state
type Button struct {
Bounds rl.Rectangle
Text string
Color rl.Color
Hovered bool
Clicked bool
Scale float32
Action string
}
// Screen represents different application screens
const (
ScreenMenu = "menu"
ScreenThai = "thai"
ScreenKorean = "korean"
ScreenJapanese = "japanese"
)
// LanguageScreenState holds the state for each language screen
type LanguageScreenState struct {
Textures []rl.Texture2D
ImageFiles []string
ImagePath string
ScrollY int32
Loaded bool
Title string
Color rl.Color
}
// getThaiConfig returns configuration for Thai language screen
func getThaiConfig() LanguageScreenState {
return LanguageScreenState{
ImagePath: "thai/images/",
ImageFiles: []string{
"ก_Ko Kai.png", "ข_Kho Khai.png", "ฃ_Kho Khuat.png", "ค_Kho Khwai.png", "ฅ_Kho Khon.png",
"ฆ_Kho Rakhang.png", "ง_Ngo Ngai.png", "จ_Cho Chan.png", "ฉ_Cho Ching.png", "ช_Cho Chang.png",
"ซ_So So.png", "ฌ_Cho Che.png", "ญ_Yo Ying.png", "ฎ_Do Dek.png", "ฏ_To Tao.png",
"ฐ_To Thong.png", "ฑ_To Thung.png", "ฒ_To Thahan.png", "ณ_No Nen.png", "ด_Do Dek.png",
"ต_To Tao.png", "ถ_To Thung.png", "ท_To Thahan.png", "ธ_Tho Thong.png", "น_No Nu.png",
"บ_Bo Baimai.png", "ป_Po Pla.png", "ผ_Pho Phung.png", "ฝ_Fo Fa.png", "พ_Pho Phan.png",
"ฟ_Fo Fan.png", "ภ_Pho Samphao.png", "ม_Mo Ma.png", "ย_Yo Yak.png", "ร_Ro Rua.png",
"ล_Lo Ling.png", "ว_Wo Waen.png", "ศ_So Sala.png", "ษ_So Ruezi.png", "ส_So Suan.png",
"ห_Ho Hip.png", "ฬ_Lo Chula.png", "อ_O Ang.png", "ฮ_Ho Nokhuk.png",
"ะ_Sara A.png", "ั_Sara Aa.png", "า_Sara Aa.png", "ำ_Sara Am.png", "ิ_Sara I.png",
"ี_Sara Ii.png", "ึ_Sara Ue.png", "ื_Sara Uee.png", "ุ_Sara U.png", "ู_Sara Uu.png",
"เ_Sara E.png", "แ_Sara Ae.png", "โ_Sara O.png", "ใ_Sara Ai Mai Malai.png", "ไ_Sara Ai Mai Muang.png",
"ๅ_Sara Ue.png", "ๆ_Sara Uee.png",
"_Zero.png", "๑_One.png", "๒_Two.png", "๓_Three.png", "๔_Four.png",
"๕_Five.png", "๖_Six.png", "๗_Seven.png", "๘_Eight.png", "๙_Nine.png",
},
ScrollY: 0,
Title: "Thai Characters",
Color: rl.Red,
}
}
// getKoreanConfig returns configuration for Korean language screen
func getKoreanConfig() LanguageScreenState {
return LanguageScreenState{
ImagePath: "korean/images/",
ImageFiles: []string{
"ㄱ_Giyeok.png", "ㄲ_SsangGiyeok.png", "ㄴ_Nieun.png", "ㄷ_Dieut.png", "ㄸ_SsangDieut.png",
"ㄹ_Rieul.png", "ㅁ_Mieum.png", "ㅂ_Pieup.png", "ㅃ_SsangPieup.png", "ㅅ_Siot.png",
"ㅆ_SsangSiot.png", "ㅇ_Ieung.png", "ㅈ_Jieut.png", "ㅉ_SSangJieut.png", "ㅊ_Chieut.png",
"ㅋ_Kieuk.png", "ㅌ_Tieut.png", "ㅍ_Pieup.png", "ㅎ_Hieut.png",
"ㅏ_A.png", "ㅐ_Ae.png", "ㅑ_Ya.png", "ㅒ_Yae.png", "ㅓ_Eo.png",
"ㅔ_E.png", "ㅕ_Yeo.png", "ㅖ_Ye.png", "ㅗ_O.png", "ㅘ_Wa.png",
"ㅙ_Wae.png", "ㅚ_Oe.png", "ㅛ_Yo.png", "ㅜ_U.png", "ㅝ_Wo.png",
"ㅞ_We.png", "ㅟ_Wi.png", "ㅠ_Yu.png", "ㅡ_Eu.png", "ㅢ_Ui.png", "ㅣ_I.png",
"ㄱㅅ_Giyeok-Siot.png", "ㄵ_Nieun-Cieut.png", "ㄶ_Nieun-Hieut.png",
"ㄺ_Rieul-Giyeok.png", "ㄻ_Rieul-Mieum.png", "ㄼ_Rieul-Pieup.png", "ㄽ_Rieul-Siot.png",
"ㄾ_Rieul-Tieut.png", "ㄿ_Rieul-Phup.png", "ㅀ_Rieul-Hieut.png",
"ㅄ_Pieup-Siot.png",
"가_Ga.png", "각_Gak.png", "간_Gan.png", "갈_Gal.png", "감_Gam.png",
"갑_Gap.png", "강_Gang.png", "개_Gae.png", "객_Gaek.png", "건_Geon.png",
"걸_Geol.png", "검_Geom.png", "겁_Geop.png", "게_Ge.png", "격_Gyeok.png",
"견_Gyeon.png", "결_Gyeol.png", "겸_Gyeom.png", "겹_Gyeop.png", "경_Gyeong.png",
"계_Gye.png", "고_Go.png", "곡_Gok.png", "곤_Gon.png", "골_Gol.png",
"공_Gong.png", "과_Gwa.png", "관_Gwan.png", "괄_Gwal.png", "광_Gwang.png",
"귀_Gwi.png", "규_Gyu.png", "균_Gyun.png", "굴_Gul.png", "굼_Gum.png",
"국_Guk.png", "군_Gun.png", "굽_Gup.png", "굿_Gut.png", "그_Geu.png",
},
ScrollY: 0,
Title: "Korean Characters",
Color: rl.Blue,
}
}
// getJapaneseConfig returns configuration for Japanese language screen
func getJapaneseConfig() LanguageScreenState {
return LanguageScreenState{
ImagePath: "japanese/images/",
ImageFiles: []string{
"あ_a.png", "い_i.png", "う_u.png", "え_e.png", "お_o.png",
"か_ka.png", "き_ki.png", "く_ku.png", "け_ke.png", "こ_ko.png",
"さ_sa.png", "し_shi.png", "す_su.png", "せ_se.png", "そ_so.png",
"た_ta.png", "ち_chi.png", "つ_tsu.png", "て_te.png", "と_to.png",
"な_na.png", "に_ni.png", "ぬ_nu.png", "ね_ne.png", "の_no.png",
"は_ha.png", "ひ_hi.png", "ふ_fu.png", "へ_he.png", "ほ_ho.png",
"ま_ma.png", "み_mi.png", "む_mu.png", "め_me.png", "も_mo.png",
"や_ya.png", "ゆ_yu.png", "よ_yo.png",
"ら_ra.png", "り_ri.png", "る_ru.png", "れ_re.png", "ろ_ro.png",
"わ_wa.png", "ゐ_wi.png", "ゑ_we.png", "を_wo.png", "ん_n.png",
"が_ga.png", "ぎ_gi.png", "ぐ_gu.png", "げ_ge.png", "ご_go.png",
"ざ_za.png", "じ_ji.png", "ず_zu.png", "ぜ_ze.png", "ぞ_zo.png",
"だ_da.png", "ぢ_di.png", "づ_du.png", "で_de.png", "ど_do.png",
"ば_ba.png", "び_bi.png", "ぶ_bu.png", "べ_be.png", "ぼ_bo.png",
"ぱ_pa.png", "ぴ_pi.png", "ぷ_pu.png", "ぺ_pe.png", "ぽ_po.png",
},
ScrollY: 0,
Title: "Hiragana Characters",
Color: rl.Green,
}
}
func main() {
// Initialize window
screenWidth := int32(800)
screenHeight := int32(450)
rl.InitWindow(screenWidth, screenHeight, "Learning Raylib in Go")
defer rl.CloseWindow()
// Set target FPS
rl.SetTargetFPS(60)
// Button dimensions and positions
buttonWidth := int32(200)
buttonHeight := int32(50)
buttonSpacing := int32(20)
startY := int32(screenHeight/2) - (buttonHeight*3 + buttonSpacing*2)/2
// Create buttons
thaiBtn := Button{
Bounds: rl.Rectangle{
X: float32(screenWidth/2 - buttonWidth/2),
Y: float32(startY),
Width: float32(buttonWidth),
Height: float32(buttonHeight),
},
Text: "Thai",
Color: rl.LightGray,
Scale: 1.0,
Action: ScreenThai,
}
koreanBtn := Button{
Bounds: rl.Rectangle{
X: float32(screenWidth/2 - buttonWidth/2),
Y: float32(startY + buttonHeight + buttonSpacing),
Width: float32(buttonWidth),
Height: float32(buttonHeight),
},
Text: "Korean",
Color: rl.LightGray,
Scale: 1.0,
Action: ScreenKorean,
}
japaneseBtn := Button{
Bounds: rl.Rectangle{
X: float32(screenWidth/2 - buttonWidth/2),
Y: float32(startY + (buttonHeight+buttonSpacing)*2),
Width: float32(buttonWidth),
Height: float32(buttonHeight),
},
Text: "Japanese",
Color: rl.LightGray,
Scale: 1.0,
Action: ScreenJapanese,
}
buttons := []*Button{&thaiBtn, &koreanBtn, &japaneseBtn}
// Create back button
backBtn := Button{
Bounds: rl.Rectangle{
X: float32(20),
Y: float32(20),
Width: float32(100),
Height: float32(40),
},
Text: "Back",
Color: rl.LightGray,
Scale: 1.0,
Action: ScreenMenu,
}
// Current screen state
currentScreen := ScreenMenu
prevScreen := ScreenMenu
// Language screen states
thaiConfig := getThaiConfig()
koreanConfig := getKoreanConfig()
japaneseConfig := getJapaneseConfig()
languageStates := map[string]*LanguageScreenState{
ScreenThai: &thaiConfig,
ScreenKorean: &koreanConfig,
ScreenJapanese: &japaneseConfig,
}
// Main game loop
for !rl.WindowShouldClose() {
// Get mouse position
mousePos := rl.GetMousePosition()
// Handle screen transitions
if currentScreen != prevScreen {
// Reset button states when changing screens
for _, btn := range buttons {
btn.Clicked = false
btn.Scale = 1.0
}
backBtn.Clicked = false
backBtn.Scale = 1.0
// Reset language screen state when switching to it
if currentScreen != ScreenMenu {
state := languageStates[currentScreen]
if !state.Loaded {
// Load textures
for _, imgName := range state.ImageFiles {
texture := rl.LoadTexture(state.ImagePath + imgName)
if texture.ID != 0 {
state.Textures = append(state.Textures, texture)
} else {
state.Textures = append(state.Textures, rl.Texture2D{})
}
}
state.Loaded = true
}
state.ScrollY = 0
} else {
// Unload textures when leaving language screens
for _, lang := range []string{ScreenThai, ScreenKorean, ScreenJapanese} {
if lang != currentScreen {
state := languageStates[lang]
for _, tex := range state.Textures {
if tex.ID != 0 {
rl.UnloadTexture(tex)
}
}
state.Textures = nil
state.Loaded = false
}
}
}
prevScreen = currentScreen
}
// Update button states and handle clicks
// Handle back button on language screens
if currentScreen != ScreenMenu {
backBtn.Hovered = rl.CheckCollisionPointRec(mousePos, backBtn.Bounds)
// Handle click animation for back button
if backBtn.Clicked {
backBtn.Scale += 0.05
if backBtn.Scale >= 1.1 {
backBtn.Clicked = false
}
} else if backBtn.Scale > 1.0 {
backBtn.Scale -= 0.05
if backBtn.Scale < 1.0 {
backBtn.Scale = 1.0
}
} else {
backBtn.Scale = 1.0
}
// Handle back button click
if backBtn.Hovered && rl.IsMouseButtonPressed(rl.MouseLeftButton) {
backBtn.Clicked = true
backBtn.Scale = 0.95
currentScreen = ScreenMenu
}
}
// Update main menu buttons
for _, btn := range buttons {
btn.Hovered = rl.CheckCollisionPointRec(mousePos, btn.Bounds)
// Handle click animation
if btn.Clicked {
btn.Scale += 0.05
if btn.Scale >= 1.1 {
btn.Clicked = false
}
} else if btn.Scale > 1.0 {
btn.Scale -= 0.05
if btn.Scale < 1.0 {
btn.Scale = 1.0
}
} else {
btn.Scale = 1.0
}
// Handle click - only on menu screen
if currentScreen == ScreenMenu && btn.Hovered && rl.IsMouseButtonPressed(rl.MouseLeftButton) {
btn.Clicked = true
btn.Scale = 0.95
currentScreen = btn.Action
}
}
// Begin drawing
rl.BeginDrawing()
// Clear background
rl.ClearBackground(rl.RayWhite)
// Draw appropriate screen
switch currentScreen {
case ScreenMenu:
// Draw title
rl.DrawText("Main Menu", int32(screenWidth/2)-50, startY-60, 30, rl.Black)
// Draw buttons
for _, btn := range buttons {
// Calculate scaled bounds for animation
scaledWidth := btn.Bounds.Width * btn.Scale
scaledHeight := btn.Bounds.Height * btn.Scale
scaledX := btn.Bounds.X - (scaledWidth-btn.Bounds.Width)/2
scaledY := btn.Bounds.Y - (scaledHeight-btn.Bounds.Height)/2
// Draw button with animation
if btn.Hovered {
rl.DrawRectangleRec(rl.Rectangle{X: scaledX, Y: scaledY, Width: scaledWidth, Height: scaledHeight}, rl.DarkGray)
} else {
rl.DrawRectangleRec(rl.Rectangle{X: scaledX, Y: scaledY, Width: scaledWidth, Height: scaledHeight}, btn.Color)
}
rl.DrawRectangleLinesEx(rl.Rectangle{X: scaledX, Y: scaledY, Width: scaledWidth, Height: scaledHeight}, 2, rl.Black)
// Draw text
textWidth := rl.MeasureText(btn.Text, 20)
textX := int32(scaledX) + int32(scaledWidth)/2 - textWidth/2
textY := int32(scaledY) + int32(scaledHeight)/2 - 10
rl.DrawText(btn.Text, textX, textY, 20, rl.Black)
}
default:
// Language screens
state := languageStates[currentScreen]
// Draw back button
scaledWidth := backBtn.Bounds.Width * backBtn.Scale
scaledHeight := backBtn.Bounds.Height * backBtn.Scale
scaledX := backBtn.Bounds.X - (scaledWidth-backBtn.Bounds.Width)/2
scaledY := backBtn.Bounds.Y - (scaledHeight-backBtn.Bounds.Height)/2
// Draw button with animation
if backBtn.Hovered {
rl.DrawRectangleRec(rl.Rectangle{X: scaledX, Y: scaledY, Width: scaledWidth, Height: scaledHeight}, rl.DarkGray)
} else {
rl.DrawRectangleRec(rl.Rectangle{X: scaledX, Y: scaledY, Width: scaledWidth, Height: scaledHeight}, backBtn.Color)
}
rl.DrawRectangleLinesEx(rl.Rectangle{X: scaledX, Y: scaledY, Width: scaledWidth, Height: scaledHeight}, 2, rl.Black)
// Draw text
textWidth := rl.MeasureText(backBtn.Text, 20)
textX := int32(scaledX) + int32(scaledWidth)/2 - textWidth/2
textY := int32(scaledY) + int32(scaledHeight)/2 - 10
rl.DrawText(backBtn.Text, textX, textY, 20, rl.Black)
// Draw title
rl.DrawText(state.Title, 140, 20, 30, state.Color)
// Grid layout
columns := 7
imageWidth := int32(64)
imageHeight := int32(64)
spacing := int32(10)
startX := int32(20)
startY := int32(60)
// Draw images in grid
for i, texture := range state.Textures {
if texture.ID != 0 {
row := i / columns
col := i % columns
x := startX + int32(col)*(imageWidth+spacing)
y := startY + int32(row)*(imageHeight+spacing) - state.ScrollY
// Draw background for image
rl.DrawRectangle(x, y, imageWidth, imageHeight, rl.LightGray)
// Draw the texture
rl.DrawTexture(texture, int32(x), int32(y), rl.White)
// Draw border
rl.DrawRectangleLines(x, y, imageWidth, imageHeight, rl.Black)
}
}
// Handle scroll with mouse wheel
scroll := rl.GetMouseWheelMove()
if scroll != 0 {
state.ScrollY += int32(scroll) * 10
if state.ScrollY < 0 {
state.ScrollY = 0
}
}
// Draw scroll hint
rl.DrawText("Use mouse wheel to scroll", screenWidth/2-100, screenHeight-30, 16, rl.Gray)
}
// Draw FPS counter
rl.DrawFPS(10, 10)
// End drawing
rl.EndDrawing()
}
}
// Required for raylib-go on some platforms
func init() {
runtime.LockOSThread()
}