Files
justice/www/html/Game/public/editor.html
T
2026-05-02 16:59:09 +00:00

314 lines
34 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<title>Editor ฉาก — Game</title>
<link rel="stylesheet" href="css/style.css?v=20260427-canvas-pixel">
</head>
<body>
<div class="container editor-page">
<h1>Editor ฉาก</h1>
<div class="editor-toolbar-wrap">
<div class="editor-toolbar-grid">
<section class="editor-card" aria-labelledby="editor-card-game-label">
<h2 class="editor-card__title" id="editor-card-game-label">ประเภทเกม</h2>
<div class="editor-card__row">
<label class="editor-field-grow">เลือกโหมด
<select id="game-type">
<option value="zep">เดินอิสระ (ZEP)</option>
<option value="lobby">ห้องโถง (รอผู้เล่น)</option>
<option value="gauntlet">พรมแดงสุดท้าย (Last Light)</option>
<option value="frogger">กบข้ามถนน</option>
<option value="quiz">เกมตอบคำถาม (ถูก/ผิด)</option>
<option value="quiz_carry">ตอบคำถาม — หยิบคำตอบมาวางกลาง</option>
<option value="quiz_battle">Quiz Battle — โดม A B C (กด E)</option>
<option value="stack">สลับจังหวะลงตึก (Stack)</option>
<option value="jump_survive">กระโดดให้รอด (Jump Survival)</option>
<option value="space_shooter">ยิงยานอวกาศ (Space Shooter)</option>
<option value="balloon_boss">ลูกโป้งยิงบอส (Mega Virus)</option>
</select>
</label>
</div>
<div class="game-type-hint editor-card__hint" id="game-type-hint" role="note" aria-labelledby="editor-card-game-label"></div>
<div id="editor-quiz-carry-countdown-wrap" class="editor-card__row editor-card__row--wrap" style="display:none;gap:0.65rem 1rem;align-items:center;margin-top:0.45rem;" aria-label="หยิบมาวาง พรีวิวนับถอยหลัง">
<label class="editor-field-nogrow" style="display:flex;align-items:center;gap:0.35rem;cursor:pointer;">
<input type="checkbox" id="carry-embed-countdown-highlight" checked>
<span>พรีวิว: ไฮไลต์โซนตัวเลือกตอนนับ 3-2-1</span>
</label>
<label class="editor-field-nogrow">สีขอบไฮไลต์
<input type="color" id="carry-embed-countdown-color" value="#ffb44a" title="สีขอบเรืองรอบช่องตัวเลือก (ตรงกับโซนที่วาดเป็น ตัวเลือก 1–16 บนกริด)">
</label>
<label class="editor-field-grow">ตำแหน่งเลข 3-2-1
<select id="carry-embed-countdown-anchor" title="ตามกริด = วาดช่องในโหมด «ตำแหน่งเลข 3-2-1» · อัตโนมัติ = โซนทองหรือโซนกลาง">
<option value="grid">ตามกริดที่วาด (โหมดวาดด้านล่าง)</option>
<option value="map" selected>บนแมป — โซนทอง (คำถาม) หรือโซนกลาง</option>
<option value="screen">กลางจอ (ม่านทึบ)</option>
</select>
</label>
</div>
</section>
<section class="editor-card" aria-labelledby="editor-card-map-label">
<h2 class="editor-card__title" id="editor-card-map-label">โหลด / ตั้งชื่อฉาก</h2>
<div class="editor-card__row editor-card__row--wrap">
<label>แก้จากฉากเดิม <select id="map-load"><option value="">โหลดรายการ...</option></select></label>
<button type="button" id="btn-load">โหลดฉาก</button>
<label class="editor-field-grow">ชื่อฉาก <input type="text" id="map-name" placeholder="ชื่อฉาก (ไม่ซ้ำ)"></label>
</div>
</section>
<section class="editor-card" aria-labelledby="editor-card-grid-label">
<h2 class="editor-card__title" id="editor-card-grid-label">ขนาดกริด</h2>
<div class="editor-card__row editor-card__row--wrap">
<label>กว้าง <input type="number" id="map-w" value="20" min="10" max="50"></label>
<label>สูง <input type="number" id="map-h" value="15" min="10" max="40"></label>
<label>ขนาดไทล์ <input type="number" id="tile-size" value="32" min="16" max="64"></label>
<label title="ลงจากมุมซ้ายบนของจุดเกิด — เน้นขยายแนวตั้งก่อน (เช่น 4 = สูง 4 ช่อง)">ตัวละคร สูง (แนวตั้ง) <input type="number" id="character-cells-h" value="1" min="1" max="4"></label>
<label title="ไปทางขวาจากมุมซ้ายบน — แนวนอน">× กว้าง (แนวนอน) <input type="number" id="character-cells-w" value="1" min="1" max="4"></label>
<div class="editor-footprint-row editor-footprint-row--wall" role="group" aria-labelledby="editor-fp-wall-head">
<div id="editor-fp-wall-head" class="editor-footprint-row__head">ชนกำแพง · กล่องตรวจ</div>
<label class="editor-footprint-row__field" title="เฉพาะกำแพง (โหมดวาดกำแพง / objects = เดินไม่ได้) — แนวนอนกลางใต้ร่าง · เล็กกว่าตัว = หัว/ลำตัวทับสไปรต์กำแพงได้ · โซน interactive / hub / อื่น ๆ ใช้ขนาดตัวด้านบน" aria-describedby="editor-character-collision-hint">กว้าง <input type="number" id="character-collision-w" value="1" min="1" max="4" aria-label="ชนกำแพง กว้าง (ช่องกริด)"></label>
<label class="editor-footprint-row__field" title="เฉพาะกำแพง — สูงจากเท้าขึ้นมา · น้อยกว่าสูงตัว = ส่วนบนไม่ชนกำแพง · โซนอื่นใช้สูงตัวด้านบน" aria-describedby="editor-character-collision-hint">× สูง <input type="number" id="character-collision-h" value="1" min="1" max="4" aria-label="ชนกำแพง สูงจากเท้า (ช่องกริด)"></label>
</div>
<div class="editor-footprint-row editor-footprint-row--no-overlap" role="group" aria-labelledby="editor-fp-nooverlap-head">
<div id="editor-fp-nooverlap-head" class="editor-footprint-row__head">โซนห้ามซ้อน · กล่องตรวจ</div>
<label class="editor-footprint-row__field" title="กล่องตรวจทับโซน «ห้ามซ้อนผู้เล่น» (เทียบชนกำแพง) — แนวนอนกลางใต้ร่าง · 0 = เต็มความกว้างตัว" aria-describedby="editor-character-collision-hint">กว้าง <input type="number" id="block-player-separation-w" value="0" min="0" max="4" step="1" aria-label="โซนห้ามซ้อน กว้างกล่องตรวจ (ช่องกริด)"></label>
<label class="editor-footprint-row__field" title="กล่องตรวจทับโซน «ห้ามซ้อนผู้เล่น» — สูงจากเท้าขึ้นมา · 0 = เต็มสูงตัว" aria-describedby="editor-character-collision-hint">× สูง <input type="number" id="block-player-separation-h" value="0" min="0" max="4" step="1" aria-label="โซนห้ามซ้อน สูงกล่องตรวจจากเท้า (ช่องกริด)"></label>
</div>
<button type="button" id="btn-new">สร้างกริดใหม่</button>
<p id="editor-character-collision-hint" class="editor-card__hint" style="margin:0.4rem 0 0;width:100%;max-width:44rem;line-height:1.45;">
<strong>ชนกำแพง กว้าง×สูง</strong> ใช้แค่ตรวจชน <strong>กำแพง</strong> (ช่องวาด «กำแพง») เท่านั้น
· <strong>interactive</strong> · <strong>โซนห้ามซ้อน</strong> · <strong>hub / ส่งคำตอบ quiz carry</strong> · โซนคำถาม/ตัวเลือก ฯลฯ ยังใช้พื้นที่ตัวละครตาม
<strong>สูง (แนวตั้ง) × กว้าง (แนวนอน)</strong> เหมือนเดิม — ในเกม (<code>play.js</code>) แยกฟังก์ชันชนกำแพงกับ footprint โซนแล้ว · <strong>ห้ามซ้อน กว้าง×สูง</strong> = กำหนดกล่องตรวจทับโซนห้ามซ้อน (ชิดเท้า+กลางแนวนอน เหมือนชนกำแพง) ไม่ใช่การขยายรอบร่าง
</p>
</div>
</section>
<section class="editor-card editor-card--wide" aria-labelledby="editor-card-draw-label">
<h2 class="editor-card__title" id="editor-card-draw-label">เครื่องมือวาด</h2>
<p class="editor-draw-build-hint" style="margin:0 0 0.4rem;font-size:0.74rem;color:#9ece6a;line-height:1.35;">มีโหมด <strong>รูปบนกริด</strong> ในเมนู «โหมดวาด» — ถ้าไม่เห็นข้อความนี้หรือไม่มีเมนูนั้น = หน้าเว็บยังเป็นไฟล์เก่า (ลอง <strong>Ctrl+F5</strong> หรืออัปโหลด <code>editor.html</code> / <code>js/editor.js</code> ขึ้นเซิร์ฟใหม่)</p>
<div class="editor-card__row editor-card__row--wrap">
<label class="editor-field-drawmode">โหมดวาด
<select id="draw-mode" title="จัดกลุ่มตามประเภท — ตัวเลือกที่ไม่ใช้กับโหมดเกมจะถูกซ่อน">
<optgroup label="พื้นฐาน / ทุกโหมด">
<option value="wall">กำแพง (เดินไม่ได้)</option>
<option value="noOverlap">โซนห้ามซ้อนผู้เล่น</option>
<option value="cellImage">รูปบนกริด (อัปโหลด / เลือกจากคลัง)</option>
<option value="interactive">โซน interactive (จุดกด/ใช้ได้)</option>
<option value="spawnArea" id="draw-mode-option-spawn-area">พื้นที่สุ่มจุดเกิด (ฟ้า — ผู้เล่นใหม่สุ่มในช่องนี้)</option>
<option value="lobbyPlayerSpawn" id="draw-mode-option-lobby-spawn" hidden>จุดเกิดผู้เล่น 1–6 (ลำดับเข้า P1…P6)</option>
<option value="startGame" id="draw-mode-option-start-game">พื้นที่เริ่มเกม (host ยืนแล้วกดเริ่มได้)</option>
<option value="color">สีช่อง (ทาสีบนกริด)</option>
</optgroup>
<optgroup label="พรมแดงสุดท้าย">
<option value="gauntletPlayerSpawn" id="draw-mode-option-gauntlet-player-spawn" hidden>ลำดับเกิด 1–6 (คลิกซ้ายตามลำดับ)</option>
<option value="gauntletLaserStart" id="draw-mode-option-gauntlet-laser-start" hidden>เลเซอร์: แถวต้น (ขอบบนของแถบ)</option>
<option value="gauntletLaserEnd" id="draw-mode-option-gauntlet-laser-end" hidden>เลเซอร์: แถวปลาย (ขอบล่างของแถบ)</option>
</optgroup>
<optgroup label="Stack">
<option value="stackRelease" id="draw-mode-option-stack-release" hidden>จุดปล่อยตึก (crane / ด้านบน)</option>
<option value="stackLand" id="draw-mode-option-stack-land" hidden>จุดซ้อนตึก (แพลตฟอร์มรองรับ)</option>
</optgroup>
<optgroup label="ตอบคำถาม (ยืนโซน ถูก/ผิด)">
<option value="quizTrue" id="draw-mode-option-quiz-true">โซน ถูก (ตอบ จริง)</option>
<option value="quizFalse" id="draw-mode-option-quiz-false">โซน ผิด (ตอบ เท็จ)</option>
<option value="quizQuestion" id="draw-mode-option-quiz-question">พื้นที่โชว์ข้อความคำถาม</option>
</optgroup>
<optgroup label="Quiz Battle">
<option value="quizBattlePath" id="draw-mode-option-quiz-battle-path" hidden>เส้นทางเดิน (ม่วง — วาดอย่างน้อย 1 ช่อง = จำกัดเดินเฉพาะเส้นทาง)</option>
<option value="quizBattleDome" id="draw-mode-option-quiz-battle-dome" hidden>โดมคำถาม (ช่องกด E ในเกม)</option>
</optgroup>
<optgroup label="กระโดดให้รอด">
<option value="jumpSurvivePlatform" id="draw-mode-option-jump-platform" hidden>แพลตฟอร์ม (ยืนได้ — ลอยขึ้นตามกล้องในเกม)</option>
</optgroup>
<optgroup label="ยิงยานอวกาศ">
<option value="shooterSpawnPaint" id="draw-mode-option-shooter-spawn" hidden>จุดเกิดยาน ผู้เล่น 1–6 (เลือกช่อง P ด้านขวา)</option>
</optgroup>
<optgroup label="ลูกโป้งยิงบอส">
<option value="balloonBossPlayerPaint" id="draw-mode-option-balloon-boss-player" hidden>จุดเกิดผู้เล่น 1–6 (เลือก P ด้านขวา)</option>
<option value="balloonBossBossPaint" id="draw-mode-option-balloon-boss-boss" hidden>จุดเกิดบอส (คลิกช่องเดียว — กลางจอในเกม)</option>
</optgroup>
<optgroup label="หยิบมาวาง (โซนกลาง + ตัวเลขช่อง)">
<option value="quizCarryHub" id="draw-mode-option-quiz-carry-hub" class="quiz-carry-mode-opt" hidden>โซนกลาง (วางคำตอบ + โชว์คำถาม)</option>
<option value="quizCarryOpt1" class="quiz-carry-mode-opt" hidden>ตัวเลือก 1</option>
<option value="quizCarryOpt2" class="quiz-carry-mode-opt" hidden>ตัวเลือก 2</option>
<option value="quizCarryOpt3" class="quiz-carry-mode-opt" hidden>ตัวเลือก 3</option>
<option value="quizCarryOpt4" class="quiz-carry-mode-opt" hidden>ตัวเลือก 4</option>
<option value="quizCarryOpt5" class="quiz-carry-mode-opt" hidden>ตัวเลือก 5</option>
<option value="quizCarryOpt6" class="quiz-carry-mode-opt" hidden>ตัวเลือก 6</option>
<option value="quizCarryOpt7" class="quiz-carry-mode-opt" hidden>ตัวเลือก 7</option>
<option value="quizCarryOpt8" class="quiz-carry-mode-opt" hidden>ตัวเลือก 8</option>
<option value="quizCarryOpt9" class="quiz-carry-mode-opt" hidden>ตัวเลือก 9</option>
<option value="quizCarryOpt10" class="quiz-carry-mode-opt" hidden>ตัวเลือก 10</option>
<option value="quizCarryOpt11" class="quiz-carry-mode-opt" hidden>ตัวเลือก 11</option>
<option value="quizCarryOpt12" class="quiz-carry-mode-opt" hidden>ตัวเลือก 12</option>
<option value="quizCarryOpt13" class="quiz-carry-mode-opt" hidden>ตัวเลือก 13</option>
<option value="quizCarryOpt14" class="quiz-carry-mode-opt" hidden>ตัวเลือก 14</option>
<option value="quizCarryOpt15" class="quiz-carry-mode-opt" hidden>ตัวเลือก 15</option>
<option value="quizCarryOpt16" class="quiz-carry-mode-opt" hidden>ตัวเลือก 16</option>
<option value="carryEmbedCountdown" class="quiz-carry-mode-opt" hidden>ตำแหน่งเลข 3-2-1 (กริด cyan · พรีวิว embed)</option>
</optgroup>
</select>
</label>
<span id="cell-color-wrap" class="editor-cell-color" style="display:none;">
<label>สี <input type="color" id="cell-color" value="#24283b" title="สี"></label>
<label>Alpha <input type="range" id="cell-alpha" min="0" max="100" value="100" title="ความโปร่งใส 0=ใส 100=ทึบ"> <span id="cell-alpha-value">100</span>%</label>
</span>
<div id="editor-grid-image-tools" class="editor-grid-image-tools" style="display:none;">
<div class="editor-grid-image-size-row">
<label>กว้าง (ช่อง) <input type="number" id="grid-image-brush-w" value="1" min="1" max="24" title="จำนวนช่องกริดแนวนอน"></label>
<label>สูง (ช่อง) <input type="number" id="grid-image-brush-h" value="1" min="1" max="24" title="จำนวนช่องกริดแนวตั้ง"></label>
</div>
<div id="grid-sprite-carry-bind-wrap" class="editor-grid-image-carry-bind-row" style="display:none;" title="quiz carry: สไปรต์ที่ไม่ทับช่องโซนตัวเลือก — ต้องผูกข้อเองถึงจะสลับรูปหยิบแล้ว">
<label>ผูกสไปรต์กับข้อ (หยิบแล้ว)
<select id="grid-sprite-carry-bind">
<option value="auto">อัตโนมัติ (ช่องที่ทับโซนตัวเลือก)</option>
<option value="1">ข้อ 1</option>
<option value="2">ข้อ 2</option>
<option value="3">ข้อ 3</option>
<option value="4">ข้อ 4</option>
<option value="5">ข้อ 5</option>
<option value="6">ข้อ 6</option>
<option value="7">ข้อ 7</option>
<option value="8">ข้อ 8</option>
<option value="9">ข้อ 9</option>
<option value="10">ข้อ 10</option>
<option value="11">ข้อ 11</option>
<option value="12">ข้อ 12</option>
<option value="13">ข้อ 13</option>
<option value="14">ข้อ 14</option>
<option value="15">ข้อ 15</option>
<option value="16">ข้อ 16</option>
</select>
</label>
<span class="editor-hint-inline">Alt+คลิกซ้ายบนสไปรต์ = ใส่/เปลี่ยนผูก · รายการ &quot;อัตโนมัติ&quot; = ล้างผูก</span>
</div>
<div class="editor-grid-image-gallery-wrap">
<span class="editor-grid-image-gallery-label">คลังรูป (คลิกเลือก)</span>
<p class="editor-grid-image-gallery-note">สองช่องคือรูปที่บันทึกในแมป (ก่อนหยิบ / หยิบแล้ว) — ไม่อัปเดตตามการหยิบในห้อง · ทดสอบ idle/held ให้เปิดหน้าเล่น หลังบันทึกแมป</p>
<div id="grid-cell-image-gallery" class="grid-cell-image-gallery" role="listbox" aria-label="คลังรูปบนกริด"></div>
</div>
<div class="editor-grid-image-upload-row">
<label>อัปโหลดเข้าคลัง <input type="file" id="grid-cell-image-upload" accept="image/*"></label>
<input type="file" id="grid-cell-image-held-upload" accept="image/*" hidden tabindex="-1" aria-hidden="true" title="อัปโหลดรูปตอนถือ (quiz carry)">
<button type="button" id="btn-grid-image-remove-from-lib" title="ลบรูปที่เลือกในคลัง (สไปรต์ที่ใช้รูปนี้จะหาย)">ลบจากคลัง</button>
</div>
</div>
<label class="editor-toggle" title="ปิด = ไม่วาดกริด/ช่องฉาก แต่ยังแสดงรูปที่วาดบนกริด · Off = hide tile grid, grid images still show"><input type="checkbox" id="show-map-in-game" checked> โชว์กริดในเกม</label>
<button type="button" id="btn-clear-gauntlet-spawns" hidden title="ล้างรายการจุดเกิดพรมแดงที่กำหนดเอง">ล้างลำดับ 16</button>
<button type="button" id="btn-clear-gauntlet-laser-span" hidden title="ล้างช่วงแนวตั้งของเลเซอร์ — กลับไปเต็มความสูงแมป (ไม่ต้องเปลี่ยนรูปจาก Admin)">ล้างช่วง laser</button>
<label id="shooter-slot-paint-wrap" class="editor-field-grow" style="display:none;" title="ช่องผู้เล่นลำดับที่ 1–6 ตรงกับคนในเกม (คุณ = ลำดับแรกจาก join)">ช่องเกิดยาน P
<select id="shooter-slot-paint">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</label>
<label id="balloon-boss-slot-paint-wrap" class="editor-field-grow" style="display:none;" title="ลำดับ P1–P6 เหมือนยิงยาน">ช่องเกิดผู้เล่น P
<select id="balloon-boss-slot-paint">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</label>
<button type="button" id="btn-clear-shooter-spawns" hidden title="ล้างจุดเกิดยานทั้งหมด">ล้างจุดเกิดยาน</button>
<button type="button" id="btn-clear-balloon-boss-spawns" hidden title="ล้างจุดเกิดผู้เล่น + บอส">ล้างจุดเกิดบอสโหมด</button>
<div id="lobby-spawn-wrap" class="editor-card__row" style="display:none;flex-wrap:wrap;gap:0.35rem 0.75rem;align-items:center;width:100%;">
<label class="editor-field-grow" title="ใช้เมื่อเข้าห้อง/ทดลองเล่น (ไม่รวมพรมแดง·ยิงยาน·บอส·กบที่มีจุดเกิดแยก)">จุดเกิดผู้เล่น
<select id="lobby-spawn-mode">
<option value="random">สุ่มในพื้นที่ฟ้า — ไม่มีฟ้าใช้ปุ่มตั้งจุดเกิด</option>
<option value="fixed">คงที่ — จุดเดียว (ปุ่มตั้งจุดเกิด)</option>
<option value="slots6">6 จุดตามลำดับเข้า (P1…P6)</option>
</select>
</label>
</div>
<label id="lobby-slot-paint-wrap" class="editor-field-grow" style="display:none;" title="คนแรกที่เข้าห้อง = P1 ตามลำดับ join">ช่องเกิด P
<select id="lobby-slot-paint">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</label>
<button type="button" id="btn-clear-lobby-spawns" hidden title="ล้างจุด P1–P6 บนแผนที่">ล้างจุด P1P6</button>
<button type="button" id="btn-spawn">ตั้งจุดเกิด</button>
</div>
<div class="editor-card__row editor-card__row--actions">
<button type="button" id="btn-save" class="editor-btn-primary">บันทึกฉาก</button>
<button type="button" id="btn-play-test" title="บันทึกฉากแล้วเท่านั้น — เปิดแท็บใหม่เล่นทดสอบด้วยตัวละครตัวแรกที่สร้าง (จาก /Game/character.html)">ทดลองเล่น</button>
</div>
</section>
</div>
<div id="frogger-lanes-wrap" class="frogger-lanes" style="display:none;">
<h3 id="frogger-lanes-title">ตั้งค่าแถว — กบข้ามถนน</h3>
<p class="legend" id="frogger-lanes-legend">แถวบน (y=0) = ปลายทาง · แถวล่าง = จุดเกิด · ถนน/น้ำ ตั้งความเร็ว ทิศทาง และ <strong>ระยะห่าง</strong> (ยิ่งมากยิ่งห่าง เกมง่ายขึ้น)</p>
<div id="frogger-lanes-table"></div>
</div>
<section class="editor-card editor-card--bg" aria-labelledby="editor-card-bg-label">
<h2 class="editor-card__title" id="editor-card-bg-label">พื้นหลัง</h2>
<div class="editor-card__row editor-card__row--wrap">
<label>รูปแผนที่ <input type="file" id="bg-image" accept="image/*"></label>
<button type="button" id="btn-clear-bg">ลบรูปพื้นหลัง</button>
</div>
<div id="editor-bg-scroll-block" class="editor-bg-scroll-block" hidden>
<p class="legend" style="margin:0.5rem 0 0.35rem;line-height:1.45"><strong>เลื่อนพื้นหลังแนวตั้ง</strong> (เฉพาะฉากรหัส <code>mnpz6rkp</code>) — รูป intro ต่อด้วย loop · บันทึกฉากแล้วหน้าเล่นใช้ค่าเดียวกัน · <em>English:</em> Intro + looping strip; saved in map JSON.</p>
<div class="editor-card__row editor-card__row--wrap" style="align-items:center;gap:0.75rem 1rem">
<label class="editor-bg-scroll-check"><input type="checkbox" id="editor-bg-scroll-enabled"> เปิดเลื่อน / Enable scroll</label>
<label>ความเร็ว px/s <input type="number" id="editor-bg-scroll-speed" min="8" max="400" step="4" value="56" style="width:5rem" title="ความเร็วการเลื่อนแนวตั้ง"></label>
<label>ทิศทาง
<select id="editor-bg-scroll-direction" title="เริ่มชิดล่าง intro แล้วเลื่อนเข้า loop ใต้ intro — ล่าง→บน = พิกเซลไหลขึ้น · บน→ล่าง = พลิกมุมมองในกรอบจอให้ไหลลง (strip เดิม)">
<option value="up" selected>ล่าง → บน (ไหลขึ้น)</option>
<option value="down">บน → ล่าง (ไหลลง)</option>
</select>
</label>
</div>
<div class="editor-card__row editor-card__row--wrap" style="margin-top:0.35rem">
<label>รูปต้นทาง (intro) <input type="file" id="editor-bg-scroll-intro-file" accept="image/*"></label>
<label>รูปลูป (loop) <input type="file" id="editor-bg-scroll-loop-file" accept="image/*"></label>
<button type="button" id="editor-bg-scroll-reset-assets">คืนรูปเริ่มจากเซิร์ฟ / Reset to bundled</button>
</div>
</div>
</section>
<section class="editor-card editor-card--help" aria-labelledby="editor-card-help-label">
<h2 class="editor-card__title" id="editor-card-help-label">วิธีใช้บนกริด</h2>
<ul class="editor-help-list legend editor-legend-short">
<li><strong>คลิกซ้าย</strong> = วาด · <strong>คลิกขวา</strong> = ลบ · ลากค้างได้</li>
<li>โหมดหลัก: กำแพง · โซนห้ามซ้อน · โซน interactive</li>
<li><strong>พื้นที่สุ่มจุดเกิด</strong> (ฟ้าอ่อน) — ไม่วาดช่องนี้ได้ ใช้ปุ่ม «ตั้งจุดเกิด»</li>
<li><strong>พื้นที่เริ่มเกม</strong> (ห้องโถง — ส้ม) — host ยืนแล้วกดเริ่ม</li>
<li><strong>ถามตอบ</strong>: โซนถูก/ผิด + พื้นที่คำถาม (ทอง)</li>
<li><strong>หยิบมาวาง</strong>: ม่วง = โซนกลาง (กำแพง) · <strong>ทอง</strong> = พื้นที่โชว์ข้อความคำถามบนแผนที่ (ถ้าไม่วาดทอง ข้อความไปที่โซนม่วง) · <strong>interactive เขียว</strong> = ยืนแล้วกด F ส่งคำตอบ · โหมดวาด <strong>ตัวเลือก 116</strong> = ช่องบนกริดตรงกับลำดับ <code>choices</code> · พรีวิวนับ <strong>3-2-1</strong> ไฮไลต์โซนข้อถูก (หรือใส่ <code>countdownHighlightSlot</code> 116 ต่อข้อใน <code>quizQuestions</code>) · <code>correctIndex</code> / <code>answerTrue</code></li>
<li><strong>Stack</strong>: โหมดวาดจุดปล่อย (ฟ้า) · จุดซ้อนตึก (ชมพู) · ถ้าอัปโหลดรูปทาง FTP ใช้โฟลเดอร์ <code>Game/public/img/TowerBlock</code> (ไม่มีช่องว่าง) — ชื่อ <code>Tower block</code> มี space มักได้ FTP <strong>550</strong></li>
<li><strong>กระโดดให้รอด</strong>: โหมด <strong>แพลตฟอร์ม</strong> (ฟ้าอมเขียว) · กำแพง = ขอบซ้ายขวา/บน · Space / W = กระโดด</li>
<li><strong>ลูกโป้งยิงบอส</strong>: จุดเกิดผู้เล่น P1–P6 + <strong>จุดเกิดบอส</strong> 1 ช่อง · ในเกมเดินช้า ยิงมีดีเลย์ · ลูกโป้งหมด = ตกรอบ</li>
<li><strong>สีช่อง</strong>: เลือกโหมดสี + Alpha แล้วคลิกบนกริด</li>
<li><strong>รูปบนกริด</strong>: โหมด «รูปบนกริด» — ตั้งกว้าง×สูง (ช่อง) · เลือกรูปจากแกลเลอรี · คลิกซ้ายวาง (ทับสไปรต์ที่ทับกัน) · คลิกขาวางลบทั้งแผ่น · บันทึกฉากเก็บเป็น <code>gridImageSprites</code> (ไฟล์ใหญ่ = JSON ใหญ่)</li>
<li>ปิด «โชว์กริดในเกม» = ซ่อนกริด/กำแพงในเกม (รูปพื้นหลังยังแสดง)</li>
</ul>
</section>
</div>
<div class="editor-workspace">
<div class="canvas-wrap"><canvas id="editor-canvas"></canvas></div>
<p class="legend" id="editor-status">บันทึกแล้วจะได้รหัสฉาก ใช้รหัสนี้ตอนสร้างห้องในล็อบบี้</p>
</div>
</div>
<script src="js/version.js?v=0.0169"></script>
<script src="js/editor.js?v=20260502-towerblock-ftp-hint"></script>
<div class="version-tag">v —</div>
</body>
</html>