Spaces:
Sleeping
Sleeping
File size: 34,942 Bytes
b666577 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 | import { useState } from 'react';
import { motion } from 'framer-motion';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
const carControllerScript = `
-- 車輛控制腳本
-- 常數設定
local FORWARD_FORCE = 15000 -- 前進力量
local REVERSE_FORCE = 8000 -- 後退力量
local TURN_SPEED = 2.5 -- 轉向速度
local MAX_SPEED = 60 -- 最大速度 (studs/秒)
local BRAKE_FORCE = 10000 -- 剎車力量
-- 獲取車輛模型及其組件
local car = script.Parent
local body = car:WaitForChild("Body") -- 車身主體
local frontLeftWheel = car:WaitForChild("FrontLeftWheel")
local frontRightWheel = car:WaitForChild("FrontRightWheel")
local rearLeftWheel = car:WaitForChild("RearLeftWheel")
local rearRightWheel = car:WaitForChild("RearRightWheel")
-- 獲取車輪連接點
local flHinge = car:WaitForChild("FLHinge")
local frHinge = car:WaitForChild("FRHinge")
local rlHinge = car:WaitForChild("RLHinge")
local rrHinge = car:WaitForChild("RRHinge")
-- 設置車輛控制
local vehicleSeat = car:WaitForChild("VehicleSeat")
-- 當玩家進入車輛時
vehicleSeat.Changed:Connect(function(property)
if property == "Occupant" then
local player = vehicleSeat.Occupant
if player then
-- 玩家進入車輛
print("玩家進入車輛")
else
-- 玩家離開車輛
print("玩家離開車輛")
end
end
end)
-- 主要控制循環
game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
if not vehicleSeat.Occupant then return end
local throttle = vehicleSeat.ThrottleFloat -- -1 到 1 之間的值
local steer = vehicleSeat.SteerFloat -- -1 到 1 之間的值
-- 計算車輛當前速度
local velocity = body.Velocity
local speed = velocity.Magnitude
-- 應用前進/後退力量
local forceVector = body.CFrame.LookVector
local force = Vector3.new(0, 0, 0)
if throttle > 0 then
-- 前進
force = forceVector * FORWARD_FORCE * throttle
elseif throttle < 0 then
-- 後退
force = forceVector * -REVERSE_FORCE * math.abs(throttle)
end
-- 限制最大速度
if speed > MAX_SPEED and throttle > 0 then
force = Vector3.new(0, 0, 0)
end
-- 應用轉向
local turnAngle = steer * TURN_SPEED * deltaTime
if math.abs(throttle) > 0.1 then -- 只有在移動時才轉向
body.CFrame = body.CFrame * CFrame.Angles(0, turnAngle, 0)
end
-- 應用力量到車身
body:ApplyForce(force)
-- 旋轉車輪
local wheelRotationSpeed = speed * 0.5
if throttle > 0 then
-- 前進時車輪正向旋轉
flHinge.AngularVelocity = wheelRotationSpeed
frHinge.AngularVelocity = wheelRotationSpeed
rlHinge.AngularVelocity = wheelRotationSpeed
rrHinge.AngularVelocity = wheelRotationSpeed
elseif throttle < 0 then
-- 後退時車輪反向旋轉
flHinge.AngularVelocity = -wheelRotationSpeed
frHinge.AngularVelocity = -wheelRotationSpeed
rlHinge.AngularVelocity = -wheelRotationSpeed
rrHinge.AngularVelocity = -wheelRotationSpeed
else
-- 停止時車輪不旋轉
flHinge.AngularVelocity = 0
frHinge.AngularVelocity = 0
rlHinge.AngularVelocity = 0
rrHinge.AngularVelocity = 0
end
-- 轉向前輪
frontLeftWheel.CFrame = frontLeftWheel.CFrame * CFrame.Angles(0, steer * 0.5, 0)
frontRightWheel.CFrame = frontRightWheel.CFrame * CFrame.Angles(0, steer * 0.5, 0)
end)
-- 設置攝影機
local function setupCamera(player)
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
-- 設置第三人稱攝影機
humanoid.CameraOffset = Vector3.new(0, 2, 0)
end
vehicleSeat.Changed:Connect(function(property)
if property == "Occupant" and vehicleSeat.Occupant then
local player = game.Players:GetPlayerFromCharacter(vehicleSeat.Occupant.Parent)
if player then
setupCamera(player)
end
end
end)
`;
const scoringSystemScript = `
-- 計分系統腳本
-- 常數設定
local CHECKPOINTS_TO_COMPLETE = 8 -- 完成一圈所需的檢查點數量
local FINISH_MESSAGE = "恭喜完成比賽!"
-- 服務引用
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 創建遠端事件用於更新UI
local checkpointEvent = Instance.new("RemoteEvent")
checkpointEvent.Name = "CheckpointEvent"
checkpointEvent.Parent = ReplicatedStorage
-- 玩家數據儲存
local playerData = {}
-- 初始化玩家數據
local function initPlayerData(player)
playerData[player.UserId] = {
checkpointsPassed = 0,
lastCheckpoint = 0,
raceCompleted = false,
startTime = 0,
finishTime = 0
}
end
-- 當玩家加入遊戲時
Players.PlayerAdded:Connect(function(player)
initPlayerData(player)
-- 創建計分UI
local scoreGui = Instance.new("ScreenGui")
scoreGui.Name = "RaceScoreGui"
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 200, 0, 100)
frame.Position = UDim2.new(0.85, -100, 0, 10)
frame.BackgroundTransparency = 0.5
frame.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
frame.Parent = scoreGui
local checkpointLabel = Instance.new("TextLabel")
checkpointLabel.Name = "CheckpointLabel"
checkpointLabel.Size = UDim2.new(1, 0, 0.5, 0)
checkpointLabel.Text = "檢查點: 0/" .. CHECKPOINTS_TO_COMPLETE
checkpointLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
checkpointLabel.BackgroundTransparency = 1
checkpointLabel.Parent = frame
local timeLabel = Instance.new("TextLabel")
timeLabel.Name = "TimeLabel"
timeLabel.Size = UDim2.new(1, 0, 0.5, 0)
timeLabel.Position = UDim2.new(0, 0, 0.5, 0)
timeLabel.Text = "時間: 0.00"
timeLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
timeLabel.BackgroundTransparency = 1
timeLabel.Parent = frame
scoreGui.Parent = player.PlayerGui
-- 當玩家角色加入時
player.CharacterAdded:Connect(function(character)
-- 重置玩家數據
initPlayerData(player)
-- 更新UI
checkpointEvent:FireClient(player, "reset", 0, CHECKPOINTS_TO_COMPLETE)
end)
end)
-- 當玩家離開遊戲時
Players.PlayerRemoving:Connect(function(player)
playerData[player.UserId] = nil
end)
-- 設置檢查點觸發器
local function setupCheckpoint(checkpoint, checkpointNumber)
checkpoint.Touched:Connect(function(hit)
local character = hit.Parent
local player = Players:GetPlayerFromCharacter(character)
if player and not playerData[player.UserId].raceCompleted then
local data = playerData[player.UserId]
-- 確保檢查點按順序通過
if checkpointNumber == (data.lastCheckpoint % CHECKPOINTS_TO_COMPLETE) + 1 then
data.checkpointsPassed = data.checkpointsPassed + 1
data.lastCheckpoint = checkpointNumber
-- 如果是第一個檢查點且剛開始比賽,記錄開始時間
if checkpointNumber == 1 and data.startTime == 0 then
data.startTime = tick()
end
-- 更新UI
checkpointEvent:FireClient(player, "update", data.checkpointsPassed, CHECKPOINTS_TO_COMPLETE)
-- 檢查是否完成比賽 (完成一圈8字形)
if data.checkpointsPassed >= CHECKPOINTS_TO_COMPLETE then
data.raceCompleted = true
data.finishTime = tick() - data.startTime
-- 通知玩家完成比賽
checkpointEvent:FireClient(player, "complete", data.finishTime)
-- 顯示完成訊息
game.StarterGui:SetCore("ChatMakeSystemMessage", {
Text = FINISH_MESSAGE .. "\\n完成時間: " .. string.format("%.2f", data.finishTime) .. " 秒",
Color = Color3.fromRGB(0, 255, 0),
Font = Enum.Font.SourceSansBold
})
end
end
end
end)
end
-- 尋找並設置所有檢查點
local function setupAllCheckpoints()
local checkpoints = workspace:FindFirstChild("Checkpoints")
if checkpoints then
for i, checkpoint in ipairs(checkpoints:GetChildren()) do
if checkpoint:IsA("BasePart") and checkpoint.Name:match("Checkpoint%d+") then
local number = tonumber(checkpoint.Name:match("%d+"))
if number then
setupCheckpoint(checkpoint, number)
end
end
end
else
warn("找不到檢查點資料夾!請確保在工作區中有一個名為 'Checkpoints' 的資料夾,其中包含命名為 'Checkpoint1', 'Checkpoint2' 等的檢查點。")
end
end
-- 設置客戶端UI更新
local function setupClientUI()
local clientScript = Instance.new("LocalScript")
clientScript.Name = "RaceUIUpdater"
clientScript.Source = [[
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local checkpointEvent = ReplicatedStorage:WaitForChild("CheckpointEvent")
local player = game.Players.LocalPlayer
local scoreGui = player.PlayerGui:WaitForChild("RaceScoreGui")
local frame = scoreGui:WaitForChild("Frame")
local checkpointLabel = frame:WaitForChild("CheckpointLabel")
local timeLabel = frame:WaitForChild("TimeLabel")
local startTime = 0
local isRacing = false
-- 更新時間顯示
game:GetService("RunService").RenderStepped:Connect(function()
if isRacing and startTime > 0 then
local currentTime = tick() - startTime
timeLabel.Text = "時間: " .. string.format("%.2f", currentTime)
end
end)
-- 處理檢查點事件
checkpointEvent.OnClientEvent:Connect(function(action, value, total)
if action == "update" then
checkpointLabel.Text = "檢查點: " .. value .. "/" .. total
-- 如果是第一個檢查點,開始計時
if value == 1 and not isRacing then
startTime = tick()
isRacing = true
end
elseif action == "complete" then
isRacing = false
timeLabel.Text = "完成時間: " .. string.format("%.2f", value)
checkpointLabel.TextColor3 = Color3.fromRGB(0, 255, 0)
timeLabel.TextColor3 = Color3.fromRGB(0, 255, 0)
elseif action == "reset" then
isRacing = false
startTime = 0
checkpointLabel.Text = "檢查點: 0/" .. total
timeLabel.Text = "時間: 0.00"
checkpointLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
timeLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
end
end)
]]
clientScript.Parent = ReplicatedStorage
end
-- 初始化
setupAllCheckpoints()
setupClientUI()
print("賽車計分系統已初始化!")
`;
export default function Lesson2Page() {
const [activeSection, setActiveSection] = useState('intro');
const scrollToSection = (sectionId: string) => {
setActiveSection(sectionId);
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
};
return (
<div className="flex flex-col md:flex-row gap-6">
{/* Sidebar Navigation */}
<div className="md:w-1/4 lg:w-1/5">
<div className="bg-white rounded-xl shadow-md p-6 sticky top-24">
<h3 className="text-lg font-bold text-gray-800 mb-4">課程目錄</h3>
<nav className="space-y-2">
<button
onClick={() => scrollToSection('intro')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'intro'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
課程簡介
</button>
<button
onClick={() => scrollToSection('part1')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'part1'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
賽車模型建構
</button>
<button
onClick={() => scrollToSection('part2')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'part2'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
8字形賽道設計
</button>
<button
onClick={() => scrollToSection('part3')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'part3'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
車輛控制系統
</button>
<button
onClick={() => scrollToSection('part4')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'part4'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
計分系統
</button>
<button
onClick={() => scrollToSection('part5')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'part5'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
完善與匯出
</button>
<button
onClick={() => scrollToSection('summary')}
className={`w-full text-left px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeSection === 'summary'
? 'bg-green-100 text-green-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
總結與挑戰
</button>
</nav>
</div>
</div>
{/* Main Content */}
<div className="md:w-3/4 lg:w-4/5">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
<div className="bg-gradient-to-r from-green-600 to-teal-600 rounded-xl p-8 mb-8 text-white">
<h1 className="text-3xl md:text-4xl font-bold mb-4">Roblox 基礎入門第二課 - 創造我的世界:賽車遊戲學習</h1>
<p className="text-lg opacity-90">
學習建構賽車模型、設計賽道、編寫控制腳本與計分系統
</p>
</div>
{/* Course Introduction */}
<section id="intro" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">課程簡介</h2>
<div className="bg-white rounded-xl shadow-md p-6">
<p className="text-gray-700 mb-4">
本課程將帶領學習者建構一個完整的賽車遊戲,包含四輪車模型、8字形賽道、車輛控制系統與計分機制。通過實際操作,學習者將掌握 Roblox Studio 中的模型建構、程式控制與遊戲機制設計等核心技能。
</p>
<h3 className="text-xl font-bold text-green-700 mb-3">課程目標</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-700">
<li>在 Roblox Studio 中建構可操作的四輪車模型</li>
<li>設計並實現 8 字形賽道與檢查點系統</li>
<li>編寫車輛控制腳本,實現前進、後退、左右轉向功能</li>
<li>設計計分機制,追蹤賽車完成圈數並判定比賽完成</li>
</ul>
<h3 className="text-xl font-bold text-green-700 mt-6 mb-3">前置準備</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-700">
<li>已安裝最新版本的 Roblox Studio</li>
<li>具備 Roblox Studio 基本操作能力(第一課內容)</li>
<li>了解基本的 Lua 程式語法</li>
</ul>
</div>
</section>
{/* Part 1: Car Model Construction */}
<section id="part1" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">第一部分:賽車模型建構</h2>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 1:創建新專案</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700">
<li>打開 Roblox Studio</li>
<li>選擇「基礎模板」創建新專案</li>
<li>保存專案,命名為「RaceCarGame」</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 2:建立車身基本結構</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>在工作區中插入一個方塊部件(Part)</li>
<li>調整車身尺寸與位置:Size: 6, 2, 10 (寬, 高, 長), Position: 0, 3, 0 (X, Y, Z), 命名為「Body」</li>
<li>設置車身外觀:選擇喜歡的顏色, Material: SmoothPlastic, Anchored: false</li>
<li>設置物理屬性:CanCollide: true, Massless: false, CustomPhysicalProperties: true (Density: 1, Friction: 0.3, Elasticity: 0.2)</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 3:創建車輪</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>創建前左輪:插入圓柱體(Cylinder), Size: 2, 0.5, 2, Position: -3, 2, 3.5, Orientation: 0, 0, 90, 命名為「FrontLeftWheel」</li>
<li>創建前右輪:複製前左輪, Position: 3, 2, 3.5, 命名為「FrontRightWheel」</li>
<li>創建後左輪:複製前左輪, Position: -3, 2, -3.5, 命名為「RearLeftWheel」</li>
<li>創建後右輪:複製前左輪, Position: 3, 2, -3.5, 命名為「RearRightWheel」</li>
<li>設置車輪外觀:Color: 黑色, Material: Rubber, CanCollide: true</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 4:連接車輪與車身</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>創建前左輪連接點:使用 HingeConstraint, Attachment0 連接 Body, Attachment1 連接 FrontLeftWheel, 命名為「FLHinge」</li>
<li>設置前左輪連接點屬性:ActuatorType: Motor, AngularVelocity: 0, MotorMaxTorque: 1000</li>
<li>重複上述步驟,為其他三個車輪創建連接點 (FRHinge, RLHinge, RRHinge)</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 5:添加車身細節</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-700 mb-4">
<li>創建擋風玻璃:使用方塊部件, 設置大小、位置、顏色(淺藍)、透明度(0.5)、材質(Glass)</li>
<li>創建前燈:使用兩個小方塊部件, 放置在車身前部, 設置顏色(黃/白), 可選添加 PointLight</li>
<li>創建後燈:使用兩個小方塊部件, 放置在車身後部, 設置顏色(紅)</li>
<li>創建座椅與方向盤:使用方塊和圓環部件</li>
</ul>
</div>
<div className="bg-white rounded-xl shadow-md p-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 6:添加駕駛座</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>插入 VehicleSeat:放置在車身上方中央, 命名為「VehicleSeat」</li>
<li>設置 VehicleSeat 屬性:MaxSpeed: 60, Torque: 200, TurnSpeed: 2.5</li>
<li>將所有部件組織到一個模型中:選中所有部件, 右鍵「Group」, 命名為「RaceCar」</li>
</ol>
</div>
</section>
{/* Part 2: Figure-8 Track Design */}
<section id="part2" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">第二部分:8字形賽道設計</h2>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 1:規劃賽道布局</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>創建賽道基礎平面:插入大型方塊部件, Size: 100, 1, 100, Position: 0, 0, 0, Color: 綠色, Material: Grass, Anchored: true</li>
<li>規劃 8 字形賽道路徑:在基礎平面上方繪製, 確保寬度足夠(12-15 studs), 彎道半徑適當</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 2:建構賽道</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>創建賽道部件:使用多個方塊部件組合成 8 字形, 設置大小、位置、顏色(灰色)、材質(Concrete)、Anchored: true</li>
<li>使用 Union 工具合併賽道部件...賽道部件, 點擊「Model」{'>'}「Union」, 命名為「Track...</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 3:添加賽道邊界</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>創建護欄:沿賽道外圍放置方塊部件, 設置大小、顏色(紅白相間)、材質(SmoothPlastic)、Anchored: true</li>
<li>調整彎道處的護欄:使用多個小段護欄拼接, 確保護欄緊貼賽道邊緣</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 4:創建檢查點系統</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>創建檢查點資料夾:在工作區創建 Folder, 命名為「Checkpoints」</li>
<li>創建檢查點觸發器:在關鍵位置插入方塊部件, Size: 賽道寬度, 5, 1, Transparency: 0.8, CanCollide: false, 命名為「Checkpoint1」、「Checkpoint2」等, 按順序排列</li>
<li>創建起點/終點線:在賽道上創建明顯的起點/終點線, 與第一個檢查點重合</li>
</ol>
</div>
</section>
{/* Part 3: Vehicle Control System */}
<section id="part3" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">第三部分:車輛控制系統</h2>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 1:創建車輛控制腳本</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>在 RaceCar 模型中添加腳本, 命名為「CarController」</li>
<li>編寫車輛控制腳本(見下方代碼)</li>
<li>保存腳本</li>
</ol>
<SyntaxHighlighter language="lua" style={vscDarkPlus} className="rounded-lg">
{carControllerScript}
</SyntaxHighlighter>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 2:測試車輛控制</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>點擊「Play」按鈕進入測試模式</li>
<li>使用 W/A/S/D 或方向鍵駕駛車輛</li>
<li>測試加速、轉向和剎車功能</li>
<li>點擊「Stop」按鈕退出測試模式</li>
</ol>
</div>
<div className="bg-white rounded-xl shadow-md p-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 3:調整車輛控制參數</h3>
<p className="text-gray-700 mb-4">
根據測試結果調整 CarController 腳本中的參數:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-700">
<li>FORWARD_FORCE, REVERSE_FORCE, MAX_SPEED:調整速度與力量</li>
<li>TURN_SPEED:調整轉向靈敏度</li>
<li>物理屬性:調整車身和車輪的 Density, Friction, Elasticity</li>
</ul>
</div>
</section>
{/* Part 4: Scoring System */}
<section id="part4" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">第四部分:計分系統</h2>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 1:創建計分系統腳本</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>在 ServerScriptService 中添加腳本, 命名為「ScoringSystem」</li>
<li>編寫計分系統腳本(見下方代碼)</li>
<li>保存腳本</li>
</ol>
<SyntaxHighlighter language="lua" style={vscDarkPlus} className="rounded-lg">
{scoringSystemScript}
</SyntaxHighlighter>
</div>
<div className="bg-white rounded-xl shadow-md p-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 2:測試計分系統</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700 mb-4">
<li>確保所有檢查點已正確設置在 Checkpoints 資料夾中</li>
<li>點擊「Play」按鈕進入測試模式</li>
<li>駕駛車輛通過檢查點</li>
<li>觀察計分 UI 是否正確更新(檢查點數量和時間)</li>
<li>完成一圈 8 字形賽道,確認比賽完成提示是否顯示</li>
<li>點擊「Stop」按鈕退出測試模式</li>
</ol>
</div>
</section>
{/* Part 5: Refinement and Export */}
<section id="part5" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">第五部分:完善與匯出</h2>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 1:完善遊戲細節</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-700">
<li>添加遊戲說明 GUI:包含控制說明和遊戲目標</li>
<li>添加環境裝飾:樹木、建築、天空盒等</li>
<li>添加音效:車輛引擎聲、比賽開始/完成音效</li>
</ul>
</div>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 2:最終測試與調整</h3>
<ul className="list-disc pl-6 space-y-2 text-gray-700">
<li>進行全面測試:車輛控制、檢查點、計分、性能</li>
<li>根據測試結果進行調整:優化物理、調整檢查點、修復問題</li>
</ul>
</div>
<div className="bg-white rounded-xl shadow-md p-6">
<h3 className="text-xl font-bold text-green-700 mb-3">步驟 3:匯出專案</h3>
<ol className="list-decimal pl-6 space-y-2 text-gray-700">
<li>保存專案:File {'>'}Save</li>
<li>發布到 Roblox:File {'>'}Publish to Roblox</li>
<li>匯出模型(可選):選中 RaceCar 模型, File {'>'}Export Selection</li>
</ol>
</div>
</section>
{/* Summary and Challenge */}
<section id="summary" className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-bold text-gray-800 mb-4">總結</h2>
<div className="bg-white rounded-xl shadow-md p-6 mb-6">
<p className="text-gray-700 mb-4">
在本課程中,我們成功建構了一個完整的賽車遊戲,包含四輪車模型、8字形賽道、車輛控制系統與計分機制。通過這個項目,學習者掌握了 Roblox Studio 中的模型建構、程式控制與遊戲機制設計等核心技能。
</p>
<p className="text-gray-700 mb-4">
這些技能可以應用於更複雜的遊戲開發項目,例如多人賽車遊戲、障礙賽車場、開放世界駕駛遊戲、車輛模擬器等。
</p>
</div>
<div className="bg-gradient-to-r from-green-50 to-teal-50 rounded-xl shadow-md p-6 mb-6">
<h3 className="text-xl font-bold text-green-700 mb-3">進階挑戰</h3>
<p className="text-gray-700 mb-4">
想要進一步提升您的賽車遊戲?嘗試以下挑戰:
</p>
<ul className="list-disc pl-6 space-y-2 text-gray-700">
<li>添加多人競賽功能</li>
<li>實現車輛損壞系統</li>
<li>添加不同類型的車輛</li>
<li>創建更複雜的賽道,包含坡道、跳台等</li>
<li>添加道具系統(如加速、護盾等)</li>
</ul>
</div>
<div className="bg-gradient-to-r from-blue-50 to-green-50 rounded-xl shadow-md p-6">
<h3 className="text-xl font-bold text-blue-700 mb-3">資源推薦</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<a href="https://create.roblox.com/docs" target="_blank" rel="noopener noreferrer" className="bg-white p-4 rounded-lg shadow hover:shadow-md transition-shadow">
<h4 className="font-bold text-blue-800 mb-2">Roblox 開發者文檔</h4>
<p className="text-gray-700">官方開發文檔,包含詳細的 API 參考和教程</p>
</a>
<a href="https://developer.roblox.com/en-us/articles/vehicles" target="_blank" rel="noopener noreferrer" className="bg-white p-4 rounded-lg shadow hover:shadow-md transition-shadow">
<h4 className="font-bold text-blue-800 mb-2">Roblox 車輛系統教程</h4>
<p className="text-gray-700">官方關於車輛系統的詳細教程</p>
</a>
<a href="https://www.lua.org/manual/5.1/" target="_blank" rel="noopener noreferrer" className="bg-white p-4 rounded-lg shadow hover:shadow-md transition-shadow">
<h4 className="font-bold text-blue-800 mb-2">Lua 程式設計指南</h4>
<p className="text-gray-700">學習 Lua 語言的官方手冊</p>
</a>
<a href="https://devforum.roblox.com/" target="_blank" rel="noopener noreferrer" className="bg-white p-4 rounded-lg shadow hover:shadow-md transition-shadow">
<h4 className="font-bold text-blue-800 mb-2">Roblox 開發者論壇</h4>
<p className="text-gray-700">與其他開發者交流,獲取幫助和分享經驗</p>
</a>
</div>
</div>
</section>
{/* Navigation Buttons */}
<div className="flex justify-between mt-12">
<a
href="/lesson1"
className="px-6 py-3 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition-colors flex items-center"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M9.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L7.414 9H15a1 1 0 110 2H7.414l2.293 2.293a1 1 0 010 1.414z" clipRule="evenodd" />
</svg>
上一課:基礎入門
</a>
<a
href="/lesson3"
className="px-6 py-3 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors flex items-center"
>
下一課:互動機關
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 ml-2" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</a>
</div>
</motion.div>
</div>
</div>
);
}
|