Map v3: Shuto Night Loop — Tokyo landmark circuit
CI / quality (push) Successful in 55s

The straight strip becomes a closed rounded-rect loop (~7,400 studs/lap)
built from centerline samples, Shuto-C1 style. Landmark zones:

- Daikoku Futo PA: drivable meet lot off the south straight (guardrail
  gap entrance), painted bays, flood-light towers, bilingual sign —
  cars now SPAWN at Daikoku like a proper meet
- Rainbow Bridge over the east straight: white suspension towers with
  beacons, cross beams, rainbow-colored rail lights
- Odaiba beyond the bridge: blocky Unicorn Gundam (glowing eyes, horn,
  pink psycho-frame strips) + 16-cabin neon ferris wheel
- Yamate-style tunnel enclosing the whole north straight
- Tokyo Tower replica (orange/white tiers, two lit decks, antenna) west
- Tatsumi PA overlook pad NE
- City-core skyline inside the loop + outer ring skipping landmark zones
- Bilingual green highway signs via SurfaceGui (JP + EN)

Gameplay contract preserved: SpawnPad/FinishLine/KillWall names intact,
kill walls hug every road edge except the Daikoku entrance.
This commit is contained in:
2026-07-22 02:38:47 -04:00
parent dae30fd22e
commit 0fc0d0ae22
2 changed files with 584 additions and 222 deletions
+574 -219
View File
@@ -1,36 +1,56 @@
--!strict
--[[
MapBuilder.luau (SERVER)
Builds the "Tokyo expressway" map entirely from code — ZERO manual Studio
building. v2 (M2 groundwork): the straight highway now runs through a
sequence of FEATURES so driving it is actually interesting:
v3 — "Shuto Night Loop": a Tokyo-expressway-inspired CIRCUIT, still built
100% from code. The straight strip is gone; the road is now a closed
rounded-rectangle loop (~7,400 studs/lap) modelled on the Shuto C1 vibe,
with real-Tokyo landmark zones:
seg 0-1 open start (spawn pad)
seg 2 overhead gantry arches
seg 3 TUNNEL (enclosed, neon-striped ceiling)
seg 4 jump ramps (side-by-side launch + landing, optional — road
continues flat around them)
seg 5-6 open run to the finish line
seg 7 finish + runoff
SOUTH straight — Daikoku Futo PA: the legendary meet spot. A big
drivable parking area off the expressway with painted
bays, light towers, and the spawn pad. Cars spawn HERE.
EAST straight — Rainbow Bridge: white suspension towers, cross beams,
rainbow-lit rails. Odaiba sits beyond it: a blocky
Unicorn-Gundam-style statue + a giant neon ferris
wheel (Palette Town wheel).
NORTH straight — Yamate-style tunnel: long enclosed bore with strip
lights (the C1/Yamate underground feel).
WEST straight — City skyline run past a Tokyo Tower replica
(orange/white, twin decks, antenna).
Everywhere — procedural neon skyline inside and outside the loop,
Tatsumi-PA-style overlook pad (visual, NE).
Neon skyline blocks flank the whole route outside the guardrails for the
night-city mood. Everything is still named parts (SpawnPad, FinishLine,
KillWall_*) so gameplay code keeps working when this is replaced by a
modeled map later.
NOT geographically accurate — it's a themed driving loop, not a map of
Tokyo. Gameplay parts keep their contract names (SpawnPad, FinishLine,
KillWall_*) so nothing else changes.
]]
local Workspace = game:GetService("Workspace")
local MapBuilder = {}
-- Loop geometry ----------------------------------------------------------------
local ROAD_WIDTH = 60
local SEGMENT_LENGTH = 400
local NUM_SEGMENTS = 8 -- total length = 3200 studs of highway
local HX = 1200 -- half-extent X
local HZ = 800 -- half-extent Z
local CORNER_R = 300
local STEP = 60 -- straight sample spacing
local ARC_STEPS = 12 -- samples per 90-degree corner
local WALL_HEIGHT = 26
local NEON_PINK = Color3.fromRGB(255, 40, 120)
local NEON_BLUE = Color3.fromRGB(40, 160, 255)
local NEON_TEAL = Color3.fromRGB(40, 230, 200)
local RAINBOW = {
Color3.fromRGB(255, 60, 60),
Color3.fromRGB(255, 160, 40),
Color3.fromRGB(250, 230, 60),
Color3.fromRGB(80, 230, 90),
Color3.fromRGB(60, 150, 255),
Color3.fromRGB(170, 90, 255),
}
local UP = Vector3.new(0, 1, 0)
local function part(props: { [string]: any }): Part
local p = Instance.new("Part")
@@ -49,232 +69,582 @@ local function det(seed: number): number
return x - math.floor(x)
end
-- Road deck ------------------------------------------------------------------
local function buildRoad(parent: Folder)
for i = 0, NUM_SEGMENTS - 1 do
local z = -(i * SEGMENT_LENGTH) - SEGMENT_LENGTH / 2
-- Green highway sign with bilingual text ---------------------------------------
local function makeSign(text: string, cf: CFrame, parent: Instance)
local board = part({
Name = "Sign",
Size = Vector3.new(30, 9, 1),
CFrame = cf,
Color = Color3.fromRGB(18, 90, 60),
Material = Enum.Material.SmoothPlastic,
})
board.Parent = parent
local gui = Instance.new("SurfaceGui")
gui.Face = Enum.NormalId.Front
gui.CanvasSize = Vector2.new(600, 180)
gui.Parent = board
local label = Instance.new("TextLabel")
label.Size = UDim2.fromScale(1, 1)
label.BackgroundTransparency = 1
label.Font = Enum.Font.GothamBold
label.TextColor3 = Color3.new(1, 1, 1)
label.TextScaled = true
label.Text = text
label.Parent = gui
end
-- Centerline samples ------------------------------------------------------------
type Sample = { pos: Vector3, piece: string }
local function genSamples(): { Sample }
local samples: { Sample } = {}
local sx = HX - CORNER_R
local sz = HZ - CORNER_R
local function push(pos: Vector3, piece: string)
table.insert(samples, { pos = pos, piece = piece })
end
local function arc(cx: number, cz: number, a0: number, piece: string)
for i = 1, ARC_STEPS do
local a = a0 + (i / ARC_STEPS) * (math.pi / 2)
push(Vector3.new(cx + CORNER_R * math.sin(a), 0, cz + CORNER_R * math.cos(a)), piece)
end
end
-- South straight (Daikoku side), heading +X
local x = -sx
while x <= sx do
push(Vector3.new(x, 0, HZ), "south")
x += STEP
end
arc(sx, sz, 0, "corner_se")
-- East straight (Rainbow Bridge), heading -Z
local z = sz - STEP
while z >= -sz do
push(Vector3.new(HX, 0, z), "east")
z -= STEP
end
arc(sx, -sz, math.pi / 2, "corner_ne")
-- North straight (Yamate tunnel), heading -X
x = sx - STEP
while x >= -sx do
push(Vector3.new(x, 0, -HZ), "north")
x -= STEP
end
arc(-sx, -sz, math.pi, "corner_nw")
-- West straight (Tokyo Tower run), heading +Z
z = -sz + STEP
while z <= sz do
push(Vector3.new(-HX, 0, z), "west")
z += STEP
end
arc(-sx, sz, 3 * math.pi / 2, "corner_sw")
return samples
end
-- Daikoku PA entrance gap on the south straight's OUTER side -------------------
local DAIKOKU_GAP_HALF = 270
local function isDaikokuGap(mid: Vector3, piece: string, outer: boolean): boolean
return piece == "south" and outer and math.abs(mid.X) < DAIKOKU_GAP_HALF
end
-- The loop road itself ----------------------------------------------------------
local function buildLoop(map: Folder, samples: { Sample })
local roadFolder = Instance.new("Folder")
roadFolder.Name = "Expressway"
roadFolder.Parent = map
local n = #samples
for i = 1, n do
local a = samples[i]
local b = samples[(i % n) + 1]
local delta = b.pos - a.pos
local len = delta.Magnitude + 2
local mid = (a.pos + b.pos) / 2
local dir = delta.Unit
local right = dir:Cross(UP) -- always points OUTWARD on this loop
local cf = CFrame.lookAt(mid, mid + dir)
local road = part({
Name = "Road_" .. i,
Size = Vector3.new(ROAD_WIDTH, 2, SEGMENT_LENGTH),
Position = Vector3.new(0, 0, z),
Size = Vector3.new(ROAD_WIDTH, 2, len),
CFrame = cf,
Color = Color3.fromRGB(28, 28, 34),
Material = Enum.Material.Asphalt,
})
road.Parent = parent
road.Parent = roadFolder
local line = part({
Name = "Lane_" .. i,
Size = Vector3.new(1, 2.1, SEGMENT_LENGTH),
Position = Vector3.new(0, 0.1, z),
Size = Vector3.new(1, 2.1, len),
CFrame = cf * CFrame.new(0, 0.1, 0),
Color = Color3.fromRGB(230, 200, 60),
Material = Enum.Material.Neon,
})
line.Parent = parent
line.Parent = roadFolder
local inTunnel = a.piece == "north"
for _, side in ipairs({ -1, 1 }) do
local outer = side == 1
if isDaikokuGap(mid, a.piece, outer) then
continue
end
local off = right * (side * (ROAD_WIDTH / 2))
local rail = part({
Name = "Guardrail",
Size = Vector3.new(1.5, 4, len),
CFrame = CFrame.lookAt(mid + off, mid + off + dir) * CFrame.new(0, 2, 0),
Color = Color3.fromRGB(180, 180, 190),
Material = Enum.Material.Metal,
})
rail.Parent = map
local woff = right * (side * (ROAD_WIDTH / 2 + 2))
local wall = part({
Name = "KillWall",
Size = Vector3.new(2, WALL_HEIGHT, len + 6),
CFrame = CFrame.lookAt(mid + woff, mid + woff + dir) * CFrame.new(0, WALL_HEIGHT / 2, 0),
Transparency = 1,
CanCollide = true,
})
wall.Parent = map
-- Rainbow rail lights on the bridge; neon pylons elsewhere (not in tunnel)
if a.piece == "east" then
local lamp = part({
Name = "BridgeLight",
Size = Vector3.new(1.2, 1.2, 1.2),
CFrame = CFrame.new(mid + off + Vector3.new(0, 4.6, 0)),
Color = RAINBOW[(i % #RAINBOW) + 1],
Material = Enum.Material.Neon,
})
lamp.Parent = map
elseif not inTunnel and i % 3 == 0 then
local pylon = part({
Name = "Pylon",
Size = Vector3.new(1, 14, 1),
CFrame = CFrame.new(mid + right * (side * (ROAD_WIDTH / 2 + 3)) + Vector3.new(0, 7, 0)),
Color = outer and NEON_PINK or NEON_BLUE,
Material = Enum.Material.Neon,
})
pylon.Parent = map
end
end
-- Yamate tunnel bore over the north straight -----------------------------
if inTunnel then
local h = 22
for _, side in ipairs({ -1, 1 }) do
local woff = right * (side * (ROAD_WIDTH / 2 + 1.5))
local wallT = part({
Name = "TunnelWall",
Size = Vector3.new(3, h, len + 2),
CFrame = CFrame.lookAt(mid + woff, mid + woff + dir) * CFrame.new(0, h / 2, 0),
Color = Color3.fromRGB(38, 38, 46),
Material = Enum.Material.Concrete,
})
wallT.Parent = map
end
local ceiling = part({
Name = "TunnelCeiling",
Size = Vector3.new(ROAD_WIDTH + 6, 2, len + 2),
CFrame = cf * CFrame.new(0, h + 1, 0),
Color = Color3.fromRGB(30, 30, 38),
Material = Enum.Material.Concrete,
})
ceiling.Parent = map
if i % 2 == 0 then
local strip = part({
Name = "TunnelLight",
Size = Vector3.new(ROAD_WIDTH * 0.5, 0.6, 2),
CFrame = cf * CFrame.new(0, h - 0.5, 0),
Color = i % 4 == 0 and NEON_BLUE or NEON_TEAL,
Material = Enum.Material.Neon,
})
strip.Parent = map
end
end
end
end
-- Guardrails, kill walls, pylons ----------------------------------------------
local function buildBarriers(map: Folder, totalLength: number)
for _, side in ipairs({ -1, 1 }) do
local x = side * (ROAD_WIDTH / 2)
local rail = part({
Name = "Guardrail_" .. (side == -1 and "L" or "R"),
Size = Vector3.new(1.5, 4, totalLength),
Position = Vector3.new(x, 2, -totalLength / 2),
Color = Color3.fromRGB(180, 180, 190),
-- Daikoku Futo PA ----------------------------------------------------------------
local function buildDaikoku(map: Folder)
local folder = Instance.new("Folder")
folder.Name = "DaikokuPA"
folder.Parent = map
local z0 = HZ + ROAD_WIDTH / 2 -- pad starts at the road's outer edge
local depth = 220
local halfW = 260
local pad = part({
Name = "DaikokuPad",
Size = Vector3.new(halfW * 2, 2, depth),
CFrame = CFrame.new(0, 0, z0 + depth / 2),
Color = Color3.fromRGB(34, 34, 40),
Material = Enum.Material.Asphalt,
})
pad.Parent = folder
-- Painted parking bays (two rows, like the real lot's herringbone rows)
for row = 0, 1 do
local zRow = z0 + 70 + row * 90
for bx = -5, 5 do
local lineP = part({
Name = "BayLine",
Size = Vector3.new(1, 2.1, 22),
CFrame = CFrame.new(bx * 42, 0.1, zRow),
Color = Color3.fromRGB(230, 230, 235),
Material = Enum.Material.SmoothPlastic,
})
lineP.Parent = folder
end
end
-- Light towers (the tall lot floods) + perimeter kill walls
for _, corner in ipairs({
{ -halfW + 20, z0 + 30 },
{ halfW - 20, z0 + 30 },
{ -halfW + 20, z0 + depth - 20 },
{ halfW - 20, z0 + depth - 20 },
}) do
local px, pz = corner[1], corner[2]
local pole = part({
Name = "LightPole",
Size = Vector3.new(2, 34, 2),
CFrame = CFrame.new(px, 17, pz),
Color = Color3.fromRGB(120, 120, 130),
Material = Enum.Material.Metal,
})
rail.Parent = map
pole.Parent = folder
local head = part({
Name = "LightHead",
Size = Vector3.new(8, 1.5, 8),
CFrame = CFrame.new(px, 34.5, pz),
Color = Color3.fromRGB(255, 240, 200),
Material = Enum.Material.Neon,
})
head.Parent = folder
end
local wall = part({
Name = "KillWall_" .. (side == -1 and "L" or "R"),
Size = Vector3.new(2, WALL_HEIGHT, totalLength),
Position = Vector3.new(x + side * 2, WALL_HEIGHT / 2, -totalLength / 2),
-- Perimeter walls (invisible) on the three non-road sides
local wallDefs = {
{ Vector3.new(halfW * 2 + 4, WALL_HEIGHT, 2), CFrame.new(0, WALL_HEIGHT / 2, z0 + depth + 1) },
{ Vector3.new(2, WALL_HEIGHT, depth + 4), CFrame.new(-halfW - 1, WALL_HEIGHT / 2, z0 + depth / 2) },
{ Vector3.new(2, WALL_HEIGHT, depth + 4), CFrame.new(halfW + 1, WALL_HEIGHT / 2, z0 + depth / 2) },
}
for _, def in ipairs(wallDefs) do
local w = part({
Name = "KillWall_PA",
Size = def[1],
CFrame = def[2],
Transparency = 1,
CanCollide = true,
})
wall.Parent = map
for i = 0, math.floor(totalLength / 200) do
local pylon = part({
Name = "Pylon",
Size = Vector3.new(1, 14, 1),
Position = Vector3.new(x + side * 3, 7, -(i * 200)),
Color = side == -1 and NEON_PINK or NEON_BLUE,
Material = Enum.Material.Neon,
})
pylon.Parent = map
end
w.Parent = folder
end
-- Spawn pad (cars appear here — Daikoku is the meet) -----------------------
local spawn = part({
Name = "SpawnPad",
Size = Vector3.new(120, 1, 60),
CFrame = CFrame.new(0, 1.2, z0 + 130),
Color = Color3.fromRGB(20, 220, 120),
Material = Enum.Material.Neon,
Transparency = 0.4,
})
spawn.Parent = folder
makeSign("大黒PA DAIKOKU PA", CFrame.new(0, 12, z0 + 4) * CFrame.Angles(0, math.pi, 0), folder)
end
-- Overhead gantry arches (segment 2) -------------------------------------------
local function buildGantries(map: Folder)
-- Rainbow Bridge towers over the east straight -----------------------------------
local function buildRainbowBridge(map: Folder)
local folder = Instance.new("Folder")
folder.Name = "Gantries"
folder.Name = "RainbowBridge"
folder.Parent = map
local segStart = 2 * SEGMENT_LENGTH
for g = 0, 3 do
local z = -(segStart + 60 + g * 90)
for _, tz in ipairs({ 250, -250 }) do
for _, side in ipairs({ -1, 1 }) do
local post = part({
Name = "GantryPost",
Size = Vector3.new(2, 24, 2),
Position = Vector3.new(side * (ROAD_WIDTH / 2 - 2), 12, z),
Color = Color3.fromRGB(60, 60, 70),
Material = Enum.Material.DiamondPlate,
local tx = HX + side * (ROAD_WIDTH / 2 + 5)
local tower = part({
Name = "BridgeTower",
Size = Vector3.new(6, 95, 6),
CFrame = CFrame.new(tx, 47.5, tz),
Color = Color3.fromRGB(235, 235, 240),
Material = Enum.Material.Concrete,
})
post.Parent = folder
tower.Parent = folder
local beacon = part({
Name = "TowerBeacon",
Size = Vector3.new(2, 2, 2),
CFrame = CFrame.new(tx, 96, tz),
Color = Color3.fromRGB(255, 80, 80),
Material = Enum.Material.Neon,
})
beacon.Parent = folder
end
local beam = part({
Name = "GantryBeam",
Size = Vector3.new(ROAD_WIDTH, 2.5, 2.5),
Position = Vector3.new(0, 24, z),
Color = g % 2 == 0 and NEON_TEAL or NEON_PINK,
Material = Enum.Material.Neon,
Name = "TowerBeam",
Size = Vector3.new(ROAD_WIDTH + 22, 4, 5),
CFrame = CFrame.new(HX, 62, tz),
Color = Color3.fromRGB(235, 235, 240),
Material = Enum.Material.Concrete,
})
beam.Parent = folder
end
makeSign(
"レインボーブリッジ RAINBOW BRIDGE",
CFrame.new(HX, 14, 330) * CFrame.Angles(0, math.pi / 2, 0),
folder
)
end
-- Tunnel (segment 3): walls + ceiling with neon strips ---------------------------
local function buildTunnel(map: Folder)
-- Odaiba: blocky Unicorn-Gundam-style statue + giant ferris wheel ----------------
local function buildOdaiba(map: Folder)
local folder = Instance.new("Folder")
folder.Name = "Tunnel"
folder.Name = "Odaiba"
folder.Parent = map
local zCenter = -(3 * SEGMENT_LENGTH) - SEGMENT_LENGTH / 2
local tunnelHeight = 22
local gx, gz = HX + 150, 480 -- statue stands beyond the bridge's south end
local white = Color3.fromRGB(235, 235, 240)
for _, side in ipairs({ -1, 1 }) do
local wall = part({
Name = "TunnelWall_" .. (side == -1 and "L" or "R"),
Size = Vector3.new(3, tunnelHeight, SEGMENT_LENGTH),
Position = Vector3.new(side * (ROAD_WIDTH / 2 + 1.5), tunnelHeight / 2, zCenter),
Color = Color3.fromRGB(38, 38, 46),
Material = Enum.Material.Concrete,
local function block(name: string, size: Vector3, cf: CFrame, color: Color3, mat: Enum.Material?)
local b = part({
Name = name,
Size = size,
CFrame = cf,
Color = color,
Material = mat or Enum.Material.SmoothPlastic,
})
wall.Parent = folder
b.Parent = folder
return b
end
local ceiling = part({
Name = "TunnelCeiling",
Size = Vector3.new(ROAD_WIDTH + 6, 2, SEGMENT_LENGTH),
Position = Vector3.new(0, tunnelHeight + 1, zCenter),
Color = Color3.fromRGB(30, 30, 38),
Material = Enum.Material.Concrete,
})
ceiling.Parent = folder
-- Base plinth
block(
"GundamBase",
Vector3.new(40, 4, 40),
CFrame.new(gx, 2, gz),
Color3.fromRGB(60, 60, 70),
Enum.Material.Concrete
)
-- Legs
block("GundamLegL", Vector3.new(7, 20, 9), CFrame.new(gx - 6, 14, gz), white)
block("GundamLegR", Vector3.new(7, 20, 9), CFrame.new(gx + 6, 14, gz), white)
-- Hips + torso
block("GundamHips", Vector3.new(16, 6, 10), CFrame.new(gx, 27, gz), white)
block("GundamTorso", Vector3.new(15, 14, 10), CFrame.new(gx, 37, gz), white)
block("GundamChest", Vector3.new(9, 5, 3), CFrame.new(gx, 39, gz - 6), Color3.fromRGB(60, 90, 220))
block("GundamCore", Vector3.new(4, 3, 2), CFrame.new(gx, 34, gz - 6), Color3.fromRGB(230, 60, 60))
-- Shoulders + arms
block("GundamShoulderL", Vector3.new(6, 5, 7), CFrame.new(gx - 11, 42, gz), white)
block("GundamShoulderR", Vector3.new(6, 5, 7), CFrame.new(gx + 11, 42, gz), white)
block("GundamArmL", Vector3.new(4.5, 16, 5), CFrame.new(gx - 11, 32, gz), white)
block("GundamArmR", Vector3.new(4.5, 16, 5), CFrame.new(gx + 11, 32, gz), white)
-- Head with glowing eyes + unicorn horn
block("GundamHead", Vector3.new(6, 5.5, 5.5), CFrame.new(gx, 47, gz), white)
block("GundamEyes", Vector3.new(4, 1, 0.6), CFrame.new(gx, 47.5, gz - 2.8), NEON_TEAL, Enum.Material.Neon)
block(
"GundamHorn",
Vector3.new(0.8, 6, 0.8),
CFrame.new(gx, 53, gz - 1) * CFrame.Angles(math.rad(15), 0, 0),
Color3.fromRGB(250, 220, 90),
Enum.Material.Neon
)
-- Psycho-frame glow strips on the legs/torso (the Unicorn's pink frame)
block("GundamFrameL", Vector3.new(1, 14, 1), CFrame.new(gx - 6, 14, gz - 4.6), NEON_PINK, Enum.Material.Neon)
block("GundamFrameR", Vector3.new(1, 14, 1), CFrame.new(gx + 6, 14, gz - 4.6), NEON_PINK, Enum.Material.Neon)
-- Neon ceiling strips light the tunnel (one every 50 studs, alternating).
for i = 0, math.floor(SEGMENT_LENGTH / 50) do
local z = -(3 * SEGMENT_LENGTH) - i * 50
local strip = part({
Name = "TunnelLight",
Size = Vector3.new(ROAD_WIDTH * 0.5, 0.6, 2),
Position = Vector3.new(0, tunnelHeight - 0.5, z),
Color = i % 2 == 0 and NEON_BLUE or NEON_TEAL,
-- Giant ferris wheel (Palette Town) -----------------------------------------
local wx, wz = HX + 240, 120
local radius = 55
local hub = CFrame.new(wx, radius + 24, wz)
block(
"WheelSupportL",
Vector3.new(4, radius + 26, 4),
CFrame.new(wx - 18, (radius + 24) / 2, wz) * CFrame.Angles(0, 0, math.rad(-14)),
Color3.fromRGB(120, 120, 130),
Enum.Material.Metal
)
block(
"WheelSupportR",
Vector3.new(4, radius + 26, 4),
CFrame.new(wx + 18, (radius + 24) / 2, wz) * CFrame.Angles(0, 0, math.rad(14)),
Color3.fromRGB(120, 120, 130),
Enum.Material.Metal
)
block("WheelHub", Vector3.new(6, 6, 6), hub, Color3.fromRGB(200, 200, 210), Enum.Material.Metal)
for k = 1, 16 do
local ang = (k / 16) * math.pi * 2
local cab = part({
Name = "WheelCabin",
Size = Vector3.new(4, 4, 4),
Shape = Enum.PartType.Ball,
CFrame = hub * CFrame.new(math.cos(ang) * radius, math.sin(ang) * radius, 0),
Color = RAINBOW[(k % #RAINBOW) + 1],
Material = Enum.Material.Neon,
})
strip.Parent = folder
cab.Parent = folder
if k % 2 == 0 then
local spoke = part({
Name = "WheelSpoke",
Size = Vector3.new(0.8, radius, 0.8),
CFrame = hub * CFrame.Angles(0, 0, ang) * CFrame.new(0, radius / 2, 0),
Color = Color3.fromRGB(150, 150, 160),
Material = Enum.Material.Metal,
})
spoke.Parent = folder
end
end
makeSign("お台場 ODAIBA", CFrame.new(HX + 60, 12, 300) * CFrame.Angles(0, math.pi / 2, 0), folder)
end
-- Jump ramps (segment 4): launch + landing pair on the right half ---------------
local function buildRamps(map: Folder)
-- Tokyo Tower replica on the west side --------------------------------------------
local function buildTokyoTower(map: Folder)
local folder = Instance.new("Folder")
folder.Name = "Ramps"
folder.Name = "TokyoTower"
folder.Parent = map
local zStart = 4 * SEGMENT_LENGTH + 100
local rampX = ROAD_WIDTH / 4 -- right half of the road; left half stays flat
-- Launch ramp: a wedge sloping up in the direction of travel (-Z).
local launch = Instance.new("WedgePart")
launch.Anchored = true
launch.Name = "RampLaunch"
launch.Size = Vector3.new(ROAD_WIDTH / 2 - 4, 10, 48)
-- WedgePart slopes from its -Z (tall) to +Z (thin edge); car travels -Z,
-- so face the thin edge toward the approaching car (+Z toward car = yaw 180).
launch.CFrame = CFrame.new(rampX, 5, -zStart) * CFrame.Angles(0, math.rad(180), 0)
launch.Color = Color3.fromRGB(50, 50, 62)
launch.Material = Enum.Material.Metal
launch.TopSurface = Enum.SurfaceType.Smooth
launch.Parent = folder
local edge = part({
Name = "RampEdgeGlow",
Size = Vector3.new(ROAD_WIDTH / 2 - 4, 0.8, 1),
Position = Vector3.new(rampX, 10.4, -zStart - 24),
Color = NEON_PINK,
local tx, tz = -HX - 220, 0
local orange = Color3.fromRGB(235, 100, 40)
local levels = {
{ w = 64, h = 50, c = orange },
{ w = 44, h = 45, c = Color3.fromRGB(240, 240, 245) },
{ w = 28, h = 45, c = orange },
{ w = 15, h = 40, c = Color3.fromRGB(240, 240, 245) },
}
local y = 0
for li, lv in ipairs(levels) do
local sec = part({
Name = "TowerSection" .. li,
Size = Vector3.new(lv.w, lv.h, lv.w),
CFrame = CFrame.new(tx, y + lv.h / 2, tz),
Color = lv.c,
Material = Enum.Material.Metal,
})
sec.Parent = folder
y += lv.h
end
-- Observation decks + antenna
local deck1 = part({
Name = "MainDeck",
Size = Vector3.new(36, 8, 36),
CFrame = CFrame.new(tx, 98, tz),
Color = Color3.fromRGB(250, 245, 235),
Material = Enum.Material.Neon,
})
edge.Parent = folder
-- Landing ramp: mirrored wedge further down so clean jumps land smooth.
local landing = Instance.new("WedgePart")
landing.Anchored = true
landing.Name = "RampLanding"
landing.Size = Vector3.new(ROAD_WIDTH / 2 - 4, 10, 60)
landing.CFrame = CFrame.new(rampX, 5, -(zStart + 150))
landing.Color = Color3.fromRGB(50, 50, 62)
landing.Material = Enum.Material.Metal
landing.TopSurface = Enum.SurfaceType.Smooth
landing.Parent = folder
deck1.Parent = folder
local deck2 = part({
Name = "TopDeck",
Size = Vector3.new(20, 6, 20),
CFrame = CFrame.new(tx, 152, tz),
Color = Color3.fromRGB(250, 245, 235),
Material = Enum.Material.Neon,
})
deck2.Parent = folder
local antenna = part({
Name = "Antenna",
Size = Vector3.new(2, 40, 2),
CFrame = CFrame.new(tx, 200, tz),
Color = orange,
Material = Enum.Material.Neon,
})
antenna.Parent = folder
end
-- Neon skyline: procedural building blocks flanking the route -------------------
local function buildSkyline(map: Folder, totalLength: number)
-- Tatsumi-style overlook pad (visual scenery, NE corner outside) ------------------
local function buildTatsumi(map: Folder)
local folder = Instance.new("Folder")
folder.Name = "TatsumiPA"
folder.Parent = map
local px, pz = HX - 380, -HZ - 120
local pad = part({
Name = "TatsumiPad",
Size = Vector3.new(160, 2, 80),
CFrame = CFrame.new(px, 0, pz),
Color = Color3.fromRGB(34, 34, 40),
Material = Enum.Material.Asphalt,
})
pad.Parent = folder
for i = 0, 4 do
local lamp = part({
Name = "TatsumiLamp",
Size = Vector3.new(1, 12, 1),
CFrame = CFrame.new(px - 70 + i * 35, 6, pz - 30),
Color = Color3.fromRGB(255, 240, 200),
Material = Enum.Material.Neon,
})
lamp.Parent = folder
end
makeSign("辰巳PA TATSUMI PA", CFrame.new(px, 11, pz + 30), folder)
end
-- Neon skyline: towers inside the loop (city core) and outside ---------------------
local function buildSkyline(map: Folder)
local folder = Instance.new("Folder")
folder.Name = "Skyline"
folder.Parent = map
local accents = { NEON_PINK, NEON_BLUE, NEON_TEAL, Color3.fromRGB(200, 120, 255) }
for _, side in ipairs({ -1, 1 }) do
local n = 0
local z = -80
while z > -totalLength do
n += 1
local seed = side * 1000 + n
local width = 40 + det(seed) * 60
local depth = 40 + det(seed + 1) * 60
local height = 40 + det(seed + 2) * 160
local gap = 30 + det(seed + 3) * 70
local x = side * (ROAD_WIDTH / 2 + 50 + det(seed + 4) * 90 + width / 2)
local function tower(seed: number, x: number, z: number)
local width = 40 + det(seed) * 50
local depth = 40 + det(seed + 1) * 50
local height = 50 + det(seed + 2) * 170
local t = part({
Name = "Tower",
Size = Vector3.new(width, height, depth),
CFrame = CFrame.new(x, height / 2 - 10, z),
Color = Color3.fromRGB(16, 16, 24),
Material = Enum.Material.Slate,
})
t.Parent = folder
local accent = accents[(math.floor(seed) % #accents) + 1]
local band = part({
Name = "TowerBand",
Size = Vector3.new(width + 0.4, 2 + det(seed + 5) * 4, depth + 0.4),
CFrame = CFrame.new(x, height * (0.35 + det(seed + 6) * 0.4), z),
Color = accent,
Material = Enum.Material.Neon,
Transparency = 0.2,
})
band.Parent = folder
local roof = part({
Name = "TowerRoof",
Size = Vector3.new(width * 0.3, 1.5, depth * 0.3),
CFrame = CFrame.new(x, height - 9, z),
Color = accent,
Material = Enum.Material.Neon,
})
roof.Parent = folder
end
local tower = part({
Name = "Tower",
Size = Vector3.new(width, height, depth),
Position = Vector3.new(x, height / 2 - 10, z - depth / 2),
Color = Color3.fromRGB(16, 16, 24),
Material = Enum.Material.Slate,
})
tower.Parent = folder
-- Lit window band + rooftop accent (2 parts per tower, cheap).
local accent = accents[(n % #accents) + 1]
local band = part({
Name = "TowerBand",
Size = Vector3.new(width + 0.4, 2 + det(seed + 5) * 4, depth + 0.4),
Position = Vector3.new(x, height * (0.4 + det(seed + 6) * 0.4), z - depth / 2),
Color = accent,
Material = Enum.Material.Neon,
Transparency = 0.2,
})
band.Parent = folder
local roof = part({
Name = "TowerRoof",
Size = Vector3.new(width * 0.3, 1.5, depth * 0.3),
Position = Vector3.new(x, height - 9, z - depth / 2),
Color = accent,
Material = Enum.Material.Neon,
})
roof.Parent = folder
z = z - depth - gap
-- City core inside the loop
local seed = 1
for gx = -2, 2 do
for gz = -1, 1 do
seed += 7
local x = gx * 300 + (det(seed) - 0.5) * 120
local z = gz * 300 + (det(seed + 3) - 0.5) * 120
tower(seed, x, z)
end
end
-- Outer ring (skip landmark zones: Odaiba east, Tokyo Tower west-center,
-- Daikoku south-center)
for i = 1, 26 do
seed += 11
local ang = (i / 26) * math.pi * 2
local rad = 1750 + det(seed + 4) * 350
local x = math.cos(ang) * rad
local z = math.sin(ang) * rad * 0.75
local skip = (x > HX and math.abs(z) < 620) -- Odaiba
or (x < -HX and math.abs(z) < 260) -- Tokyo Tower
or (z > HZ and math.abs(x) < 420) -- Daikoku
if not skip then
tower(seed, x, z)
end
end
end
@@ -288,61 +658,46 @@ function MapBuilder.build(): Folder
local map = Instance.new("Folder")
map.Name = "Map"
local roadFolder = Instance.new("Folder")
roadFolder.Name = "Expressway"
roadFolder.Parent = map
local samples = genSamples()
buildLoop(map, samples)
buildDaikoku(map)
buildRainbowBridge(map)
buildOdaiba(map)
buildTokyoTower(map)
buildTatsumi(map)
buildSkyline(map)
local totalLength = SEGMENT_LENGTH * NUM_SEGMENTS
buildRoad(roadFolder)
buildBarriers(map, totalLength)
buildGantries(map)
buildTunnel(map)
buildRamps(map)
buildSkyline(map, totalLength)
-- Spawn pad (where cars appear) at the start ------------------------------
local pad = part({
Name = "SpawnPad",
Size = Vector3.new(ROAD_WIDTH - 6, 1, 40),
Position = Vector3.new(0, 1.5, -20),
Color = Color3.fromRGB(20, 220, 120),
Material = Enum.Material.Neon,
Transparency = 0.4,
})
pad.Parent = map
-- Finish line at the far end ----------------------------------------------
-- Finish line across the south straight just past the Daikoku exit --------
local finish = part({
Name = "FinishLine",
Size = Vector3.new(ROAD_WIDTH, 1, 6),
Position = Vector3.new(0, 1.5, -totalLength + 30),
CFrame = CFrame.new(420, 1.5, HZ),
Color = Color3.fromRGB(240, 240, 240),
Material = Enum.Material.Neon,
Transparency = 0.3,
})
finish.Parent = map
-- End wall so you can't sail off the far edge ------------------------------
local endWall = part({
Name = "KillWall_End",
Size = Vector3.new(ROAD_WIDTH + 8, WALL_HEIGHT, 2),
Position = Vector3.new(0, WALL_HEIGHT / 2, -totalLength - 1),
Transparency = 1,
CanCollide = true,
})
endWall.Parent = map
-- A floor far below to catch anything that clips through (safety net) ------
-- Safety net floor under everything ----------------------------------------
local floor = part({
Name = "SafetyFloor",
Size = Vector3.new(ROAD_WIDTH * 4, 2, totalLength + 400),
Position = Vector3.new(0, -60, -totalLength / 2),
Size = Vector3.new((HX + 700) * 2, 2, (HZ + 700) * 2),
CFrame = CFrame.new(0, -60, 0),
Transparency = 1,
CanCollide = true,
})
floor.Parent = map
-- Ground plane far below road level (the "bay" the expressway floats over)
local ground = part({
Name = "Ground",
Size = Vector3.new((HX + 700) * 2, 2, (HZ + 700) * 2),
CFrame = CFrame.new(0, -12, 0),
Color = Color3.fromRGB(10, 12, 20),
Material = Enum.Material.Slate,
})
ground.Parent = map
map.Parent = Workspace
return map
end