mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
-- Our wanderer will always choose a point on a circle of this radius.
|
||||
local WanderCircleRadius = 4.0
|
||||
|
||||
-- Number of seconds to wait before we start checking if there's ground in front of us.
|
||||
local GroundCheckDelay = 0
|
||||
-- Downwards stud distance we should check to see if there's ground at our intended destination
|
||||
local GroundCheckDistance = 50
|
||||
|
||||
-- Information related to random spawns.
|
||||
local SpawnChance = 0.0005 -- 0.05% chance to spawn elsewhere
|
||||
|
||||
|
||||
-- Some helpful variables related to the player.
|
||||
local Player = Game.Players.LocalPlayer
|
||||
while Player.Character == nil do wait() end
|
||||
local Character = Player.Character
|
||||
local Humanoid = Character:WaitForChild("Humanoid")
|
||||
local Torso = Humanoid.Torso
|
||||
|
||||
local PlayerID = string.gsub(Player.Name, "Player", "")
|
||||
|
||||
local Terrain = Game.Workspace.Terrain
|
||||
|
||||
-- Create a randomtable with precomputed random numbers.
|
||||
-- We can't control the fact other people can call PRNG;
|
||||
-- so, this table creates a reproducibly random set.
|
||||
local function initrand(seed)
|
||||
randomstats = {}
|
||||
|
||||
local randomtable = {}
|
||||
math.randomseed(seed)
|
||||
for i = 1,0xFFFF+1 do
|
||||
randomtable[i] = math.random()
|
||||
end
|
||||
|
||||
randomstats.seed = seed
|
||||
randomstats.randomtable = randomtable
|
||||
randomstats.randomindex = 0
|
||||
randomstats.timescalled = 0
|
||||
end
|
||||
|
||||
-- Choose the next precomputed random value and update our randomstats.
|
||||
-- Cycle the random values once we reach the end.
|
||||
local function random()
|
||||
randomstats.timescalled = randomstats.timescalled + 1
|
||||
randomstats.randomindex = 1 + randomstats.randomindex % #randomstats.randomtable
|
||||
return randomstats.randomtable[randomstats.randomindex]
|
||||
end
|
||||
|
||||
-- Given a CurrentIndex and a Table, calculate the next valid index
|
||||
-- in the Table using a circular indexing mechanism.
|
||||
local function NextIndex(CurrentIndex, Table)
|
||||
return 1 + (CurrentIndex % #Table)
|
||||
end
|
||||
|
||||
local function SetupTeleportLocations()
|
||||
TeleportLocations = {}
|
||||
TeleportLocationIdx = 0
|
||||
|
||||
local Radius = 350
|
||||
local i = 1
|
||||
local j = 1
|
||||
-- Create 10 valid teleport locations in a circle.
|
||||
while i <= 10 and j <= 1000 do
|
||||
local Angle = random()
|
||||
local x = math.cos(Angle) * Radius
|
||||
local z = math.sin(Angle) * Radius
|
||||
local Origin = Vector3.new(x, 500, z)
|
||||
|
||||
local ray = Ray.new(Origin, Vector3.new(0, -500, 0))
|
||||
local part, endPoint = Game.Workspace:FindPartOnRay(ray)
|
||||
if part ~= nil then
|
||||
TeleportLocations[i] = endPoint + Vector3.new(0, 3.0, 0)
|
||||
i = i + 1
|
||||
end
|
||||
j = j + 1
|
||||
end
|
||||
|
||||
if #TeleportLocations < 1 then
|
||||
TeleportLocations[1] = Torso.Position
|
||||
end
|
||||
end
|
||||
|
||||
local function TryTeleport(ForceTeleport)
|
||||
if ForceTeleport or random() <= SpawnChance then
|
||||
TeleportLocationIdx = NextIndex(TeleportLocationIdx, TeleportLocations)
|
||||
return TeleportLocations[TeleportLocationIdx]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-- project a circle at the player's location and find a random point on that circle
|
||||
-- return the theta and the target location
|
||||
--
|
||||
-- theta can be passed back into this function if you want another target in
|
||||
-- the same direction as before
|
||||
local function Wander(ChangeDirection, WanderTheta)
|
||||
if ChangeDirection then
|
||||
WanderTheta = random() * 2 * math.pi
|
||||
end
|
||||
local circleLocation = Torso.Position
|
||||
local rotateX = WanderCircleRadius * math.cos(WanderTheta)
|
||||
local rotateY = WanderCircleRadius * math.sin(WanderTheta)
|
||||
local circleOffset = Vector3.new(rotateX, 0, rotateY)
|
||||
local WanderTarget = circleLocation + circleOffset
|
||||
return WanderTheta, WanderTarget
|
||||
end
|
||||
|
||||
-- cast a downward ray directly beneath where we expect to walk
|
||||
-- to see if there's any ground present
|
||||
local function GroundInFront(WanderTarget, StartTime)
|
||||
if tick() - StartTime < GroundCheckDelay then
|
||||
return true
|
||||
end
|
||||
|
||||
local ray = Ray.new(WanderTarget, Vector3.new(0, -1, 0) * GroundCheckDistance)
|
||||
local part, endPoint = Game.Workspace:FindPartOnRay(ray)
|
||||
return part ~= nil
|
||||
end
|
||||
|
||||
local function IsTargetBlocked(WanderTarget)
|
||||
local CharSize = Character:GetModelSize()
|
||||
local UnitVecMult = 5
|
||||
|
||||
-- for several rays directed in front of us, see if we can find anything
|
||||
for rad = -math.pi / 2.0, math.pi / 2.0, math.pi / 4.0 do
|
||||
for yDelta = -CharSize.y / 2.0, CharSize.y / 2.0 + 0.1, 0.1 do
|
||||
local direction = (WanderTarget - Torso.Position).unit
|
||||
direction = direction + Vector3.new(math.cos(rad), 0, math.sin(rad))
|
||||
|
||||
local origin = Torso.Position + Vector3.new(0, yDelta, 0)
|
||||
|
||||
local ray = Ray.new(origin, UnitVecMult * direction)
|
||||
local part, endPoint = Game.Workspace:FindPartOnRayWithIgnoreList(ray, {Character, Terrain})
|
||||
if part ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
initrand(PlayerID * 1000)
|
||||
|
||||
local ScriptStartDelay = 5
|
||||
print(string.format("Starting Player%d in %d seconds...", PlayerID, ScriptStartDelay))
|
||||
wait(ScriptStartDelay)
|
||||
|
||||
SetupTeleportLocations()
|
||||
print("Start walking...")
|
||||
|
||||
local WanderTheta, WanderTarget = Wander(true, 0.0)
|
||||
|
||||
local StartTime = tick()
|
||||
local PrintHeading = true
|
||||
while not _G.EndGame do
|
||||
-- First, try to teleport somewhere, based on a statistical chance.
|
||||
local TeleportLocation = TryTeleport()
|
||||
if TeleportLocation then
|
||||
local msg = string.format("Teleporting to location (%f, %f, %f)",
|
||||
TeleportLocation.x, TeleportLocation.y, TeleportLocation.z)
|
||||
print(msg)
|
||||
Torso.CFrame = CFrame.new(TeleportLocation.x, TeleportLocation.y, TeleportLocation.z)
|
||||
print("Waiting 3 seconds before moving again.")
|
||||
wait(3)
|
||||
-- Otherwise, find a heading and march towards it.
|
||||
else
|
||||
WanderTheta, WanderTarget = Wander(false, WanderTheta)
|
||||
|
||||
local PrintedBlockedMessage = false
|
||||
local BlockedCount = 0
|
||||
-- If we get blocked, try to find a new heading and go for that. If we don't find
|
||||
-- a new heading after a few tries, teleport to a new location. If we got blocked
|
||||
-- because no ground was in front of us, mark it as an error.
|
||||
while IsTargetBlocked(WanderTarget) or not GroundInFront(WanderTarget, StartTime) do
|
||||
if not PrintedBlockedMessage then
|
||||
if not GroundInFront(WanderTarget, StartTime) then
|
||||
-- throw some sort of error here
|
||||
-- and print our seed and random number iteration number
|
||||
-- along with CFrame information
|
||||
local pos = WanderTarget
|
||||
local rs = randomstats
|
||||
local error = string.format("Ground expected at target (%f, %f, %f), "..
|
||||
"randomstats: {seed=%d, randomindex=%d, timescalled=%d}",
|
||||
pos.x, pos.y, pos.z,
|
||||
rs.seed, rs.randomindex, rs.timescalled)
|
||||
if _G.TestingError == nil then
|
||||
_G.TestingError = error
|
||||
end
|
||||
print(error)
|
||||
end
|
||||
|
||||
print("Finding new heading...")
|
||||
PrintedBlockedMessage = true
|
||||
end
|
||||
|
||||
BlockedCount = BlockedCount + 1
|
||||
if 20 == BlockedCount then
|
||||
local TeleportLocation = TryTeleport(true)
|
||||
local msg = string.format("Still blocked. Teleporting to location (%f, %f, %f)",
|
||||
TeleportLocation.x, TeleportLocation.y, TeleportLocation.z)
|
||||
print(msg)
|
||||
Torso.CFrame = CFrame.new(TeleportLocation.x, TeleportLocation.y, TeleportLocation.z)
|
||||
PrintHeading = false
|
||||
break
|
||||
end
|
||||
|
||||
PrintHeading = true
|
||||
|
||||
WanderTheta, WanderTarget = Wander(true, WanderTheta)
|
||||
end
|
||||
|
||||
if PrintHeading then
|
||||
PrintHeading = false
|
||||
local Pos = Torso.Position
|
||||
print(string.format("Heading is %.3f away from (%f, %f, %f)", WanderTheta, Pos.x, Pos.y, Pos.z))
|
||||
end
|
||||
|
||||
Humanoid:MoveTo(WanderTarget, Terrain)
|
||||
|
||||
wait()
|
||||
end
|
||||
end
|
||||
|
||||
print("Caught _G.EndGame.")
|
||||
Reference in New Issue
Block a user