Building, destruction, achievements
Three systems built into KHIM, each turned on from a server Script in a few lines.
Player building
Let players build with blocks - a sandbox, a base-builder, a bridge game - with no tool to script, no messages and no checks to write. The engine does all three.
-- A Script in ServerService
building.enabled = true -- players get a Build button and the B key
building.limit = 200 -- blocks one player may have down at once (100 to start; up to 2,000)
building.reach = 32 -- units from their character (up to 200)
building.blockSize = 2 -- units a side, and the grid blocks snap to (0.5 to 16)
building.loose = false -- true: blocks are unanchored, so towers topple
building.keepOnLeave = false -- true: a player's blocks stay after they leave
building.removeAny = false -- true: anyone may break anyone's blocksPlaying: B (or the dock's block button) turns build mode on. An outline follows the pointer - lime where the block can go, red where it can't, with why. Click to place. The build bar picks the shape (Q), the colour (C), the material (V), place or break (X); R turns the block.
The server checks everything: in reach, nothing in the way, not inside a player, under the limit, against something solid. A modified app can't build in mid-air or across the map.
Your own rules on top:
building.placed:connect(function(player, block)
if block.position.y > 100 then building.remove(block) end -- no sky towers
end)
building.removed:connect(function(player, block) -- player is nil when the game removed it
end)
print(building.count(player)) -- how many blocks they have down
local mine = building.blocks(player) -- their blocks (all blocks with no player)
building.remove(block, true) -- remove one, shattering itA block is an ordinary part named Block, tagged Built, with the attribute BuilderId (its builder's account number) - so tags.each("Built", ...), touched and destruction all work on it. To save a build, store each block's position, colour and shape in a data store.
The Sandbox template on KHIM Engine's Home is a world with building turned on.
Destruction
destruction breaks things, and keeps what breaks under control (server Scripts).
-- A wall hit by a rocket breaks into pieces thrown away from the hit
local pieces = destruction.shatter(world.Wall, {force = 60, radius = 12, center = hitPosition})
-- A blast: joints and welds break, loose parts fly, players take damage, parts in reach shatter
destruction.explode(barrel.position, {force = 80, radius = 15, damage = 40, fracture = true})
destruction.detach(world.Bridge) -- its welds and joints break: it falls
destruction.repair(world.Wall) -- back as it was (a round's reset)
destruction.clear() -- remove every piece now
print(destruction.debrisCount())| Function | Options |
|---|---|
shatter(part, options) | force (40), radius, center, pieces. Returns the pieces |
explode(position or part, options) | force (60), radius (12), damage (0), fracture (false), breakAnchored (false). Returns how many parts it reached |
detach(part) | Breaks its welds and joints |
repair(part) | Puts a shattered part back |
Keeping it in check - destruction.configure{...}:
| Setting | Default | |
|---|---|---|
maxDebris | 200 | Pieces alive at once; past it the oldest goes |
lifetime | 12 | Seconds a piece lasts |
maxPieces | 16 | Pieces from one break |
piecesPerStep | 96 | Pieces all breaks may make in one step |
simulationDistance | 300 | Pieces farther than this from every player sleep |
Achievements
Award a player one of your game's achievements; their KHIM profile shows it, with your game's name.
world.Coin.touched:connect(function(hit)
local player = players.fromPart(hit)
if player then
achievements.award(player, "first-coin", "First coin", "Pick up a coin.")
end
end)- The key (
"first-coin") is 1-40 letters, digits,_or-. The first award of a key names it and describes it. - It returns
truewhen this call gave it,falsewhen the player already had it from this server, or is a guest. Calling it every frame costs nothing. - At most 100 achievements a game. Server Scripts only.
Timers, spawners and moving parts
Rounds, waves and droppers often need no script either: see Timer, Spawner and Motion in Touch, prompts and zones.
A round loop
A common shape for a round-based game:
-- Script (ServerService)
local ROUND, INTERMISSION = 120, 15
while true do
chat.send("Next round in " .. INTERMISSION .. " seconds")
task.wait(INTERMISSION)
for _, player in players.all() do
player:teleport(world.Arena.position + vec3(0, 5, 0))
end
world.Scoreboard:setAttribute("TimeLeft", ROUND)
for left = ROUND, 1, -1 do
world.Scoreboard:setAttribute("TimeLeft", left)
task.wait(1)
end
chat.send("Round over!")
destruction.clear()
for _, player in players.all() do
player:teleport(world.Lobby.position + vec3(0, 5, 0))
end
end