updated
This commit is contained in:
@@ -76,24 +76,23 @@ local COL_BALL_SHD = 0x444444
|
||||
|
||||
local BALL_RADIUS = 8 -- px (screen drawing radius)
|
||||
local BALL_WORLD_R = 5 -- physics sphere radius in world units
|
||||
-- Initial tangential speed (world units / s)
|
||||
local BALL_SPEED_MIN = 700
|
||||
local BALL_SPEED_MAX = 1000
|
||||
-- Initial tangential speed (world units / s) — very fast launch
|
||||
local BALL_SPEED_MIN = 1800
|
||||
local BALL_SPEED_MAX = 2800
|
||||
-- Gravity (world units / s²)
|
||||
local GRAVITY = 1800
|
||||
-- Bowl cone half-angle from horizontal (radians) — steeper = faster slide
|
||||
-- Bowl cone half-angle from horizontal (radians)
|
||||
local BOWL_SLOPE = math.pi / 9 -- 20 degrees
|
||||
-- Pocket well is deeper — steeper slope
|
||||
local POCKET_SLOPE = math.pi / 5 -- 36 degrees
|
||||
-- Restitution on bowl surface normal bounce
|
||||
-- Restitution on wall bounce
|
||||
local RESTITUTION_WALL = 0.82
|
||||
local RESTITUTION_POCKET = 0.68
|
||||
-- Rolling friction: velocity multiplier per second on the bowl surface
|
||||
local FRICTION_ROLL = 0.988 -- per frame on track
|
||||
local FRICTION_POCKET = 0.970 -- per frame in pocket
|
||||
-- Ball drops from track into pocket ring when its radial position
|
||||
-- crosses the inner deflector radius
|
||||
local BOUNCE_KICK_MAX = 0.08 -- rad random angular kick on rim bounce
|
||||
-- Rolling friction: multiplier per frame — strong enough to stop cleanly
|
||||
local FRICTION_ROLL = 0.975 -- per frame (~0.43/s at 33fps — decays in ~5s)
|
||||
local FRICTION_POCKET = 0.955 -- pocket damps faster
|
||||
-- Stop when horizontal speed drops below this — no wiggle
|
||||
local STOP_SPEED = 18 -- px/s
|
||||
local BOUNCE_KICK_MAX = 0.08 -- rad
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- GPU / pixel primitives
|
||||
@@ -242,74 +241,62 @@ end
|
||||
local ballX, ballY = 0, 0
|
||||
|
||||
-- Repair the wheel pixels inside a circle of radius r centred on (cx,cy).
|
||||
-- Re-rasterises all wedges clipped to that bounding box, then chrome on top.
|
||||
-- This replaces the old flat-colour eraseBall which left coloured smears.
|
||||
-- Single pass: for every pixel in the bounding box, compute the correct
|
||||
-- wheel colour and paint it. No flat-colour approximation.
|
||||
local function repairWheelPatch(cx, cy, r)
|
||||
cx = math.floor(cx); cy = math.floor(cy)
|
||||
-- Bounding box for the patch
|
||||
local px0 = cx - r; local px1 = cx + r
|
||||
local py0 = cy - r; local py1 = cy + r
|
||||
|
||||
-- For each wedge, re-rasterise only within this bounding box
|
||||
-- Pre-compute per-wedge geometry (angle extents) once
|
||||
local halfArc = math.pi / NUM_POCKETS
|
||||
local wedges = {}
|
||||
for slotIdx = 1, NUM_POCKETS do
|
||||
local halfArc = math.pi / NUM_POCKETS
|
||||
local midAngle = FIXED_ROTOR + (slotIdx - 1) * TWO_PI / NUM_POCKETS
|
||||
local a0 = midAngle - halfArc
|
||||
local a1 = midAngle + halfArc
|
||||
local arc = (a1 - a0) % TWO_PI
|
||||
|
||||
local num = WHEEL_ORDER[slotIdx]
|
||||
local col = pocketColor(num)
|
||||
|
||||
local ri, ro = R_POCKET_IN, R_POCKET_OUT
|
||||
|
||||
for sy = py0, py1 do
|
||||
local runStart = nil
|
||||
for sx = px0, px1 do
|
||||
local dx = sx - CX; local dy = sy - CY
|
||||
local dist = math.sqrt(dx*dx + dy*dy)
|
||||
local inRing = dist >= ri and dist <= ro
|
||||
local rel = (math.atan2(dy, dx) - a0) % TWO_PI
|
||||
local inWedge = rel <= arc
|
||||
if inRing and inWedge then
|
||||
if not runStart then runStart = sx end
|
||||
else
|
||||
if runStart then
|
||||
px_rect(runStart, sy, sx - runStart, 1, col)
|
||||
runStart = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if runStart then
|
||||
px_rect(runStart, sy, px1 - runStart + 1, 1, col)
|
||||
end
|
||||
end
|
||||
local mid = FIXED_ROTOR + (slotIdx - 1) * TWO_PI / NUM_POCKETS
|
||||
wedges[slotIdx] = {
|
||||
a0 = mid - halfArc,
|
||||
arc = TWO_PI / NUM_POCKETS,
|
||||
col = pocketColor(WHEEL_ORDER[slotIdx]),
|
||||
}
|
||||
end
|
||||
|
||||
-- Repaint chrome rings and background that overlap the patch,
|
||||
-- in inside-out priority order using elseif so each pixel is set once.
|
||||
for sy = py0, py1 do
|
||||
for sx = px0, px1 do
|
||||
local dx = sx - CX; local dy = sy - CY
|
||||
local d = math.sqrt(dx*dx + dy*dy)
|
||||
local dx = sx - CX
|
||||
local dy = sy - CY
|
||||
local d = math.sqrt(dx*dx + dy*dy)
|
||||
local col
|
||||
|
||||
-- Determine correct colour for this pixel, inside-out priority
|
||||
if d <= R_HUB - 4 then
|
||||
px_rect(sx, sy, 1, 1, COL_HUB)
|
||||
col = COL_HUB
|
||||
elseif d <= R_HUB then
|
||||
px_rect(sx, sy, 1, 1, COL_HUB_RING)
|
||||
col = COL_HUB_RING
|
||||
elseif d <= R_POCKET_IN - 2 then
|
||||
col = COL_HUB -- gap between hub ring and inner rim
|
||||
elseif d <= R_POCKET_IN then
|
||||
-- gap between hub ring and inner rim — plain hub bg
|
||||
px_rect(sx, sy, 1, 1, COL_HUB)
|
||||
elseif d <= R_POCKET_IN + 2 then
|
||||
px_rect(sx, sy, 1, 1, COL_RIM)
|
||||
col = COL_RIM
|
||||
elseif d <= R_POCKET_OUT then
|
||||
-- inside pocket ring — wedge already painted above
|
||||
-- Pocket ring: find which wedge this pixel belongs to
|
||||
local angle = math.atan2(dy, dx)
|
||||
for _, w in ipairs(wedges) do
|
||||
local rel = (angle - w.a0) % TWO_PI
|
||||
if rel <= w.arc then
|
||||
col = w.col
|
||||
break
|
||||
end
|
||||
end
|
||||
if not col then col = COL_HUB end -- fallback
|
||||
elseif d <= R_POCKET_OUT + 2 then
|
||||
px_rect(sx, sy, 1, 1, COL_RIM)
|
||||
col = COL_RIM
|
||||
elseif d <= R_OUTER - 6 then
|
||||
px_rect(sx, sy, 1, 1, COL_TRACK)
|
||||
col = COL_TRACK
|
||||
elseif d <= R_OUTER then
|
||||
px_rect(sx, sy, 1, 1, COL_RIM)
|
||||
col = COL_RIM
|
||||
end
|
||||
-- d > R_OUTER: outside wheel, leave as-is (ball never goes there)
|
||||
|
||||
if col then px_rect(sx, sy, 1, 1, col) end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -545,7 +532,7 @@ local function spin()
|
||||
|
||||
-- Settled when horizontal speed is very low
|
||||
local hspd = math.sqrt(vx*vx + vy*vy)
|
||||
if hspd < 5 then break end
|
||||
if hspd < STOP_SPEED then break end
|
||||
end
|
||||
|
||||
eraseBall3()
|
||||
|
||||
Reference in New Issue
Block a user