Gameplay · guide
Arenas, battlegrounds and objectives
Four composable objective types with one signed capture meter, so a contested point is frozen rather than slowly losing, and a new battleground is a map plus a .vxdef.
Edit this page on GitHubDocuments
What it is#
A PvpMap is a match's shape: how many teams, how big, what it takes to win, how long it runs, and
its objectives. A PvpMatch is one being played. There are four PvpObjectiveKinds — capture
point, payload, flag return and resource control — and the list is meant to stay short.
What it is for#
Doc 28: *"a small set of composable node types with scoring and win conditions, so a new battleground
is a map plus a .vxdef"*. Every battleground anybody has shipped is these four arranged differently.
Using it#
Compile a PvpLibrary, make a PvpMatch, Join people to teams, tell it who is standing on each
objective with Occupy, and Tick it.
⚠ Occupy is told who is there rather than working it out. Deciding who is inside a capture radius
needs the physics scene, and a PvP library that owned that would be a second interest query.
⚠ Progress is one signed meter. Taking a point back pushes the owner's meter down to nothing and then pushes its own up; two per-team meters would flip a point the instant the last defender dies.
⚠ A contested objective is frozen in both directions, not slowed. Otherwise head-count is the whole game and standing on a point you already hold is worth doing.
⚠ Contesting freezes the capture, not the scoring — you keep the points until the flag flips.
⚠ The clock is checked after the score, so reaching the winning number as time expires is a win. ⚠ A draw is a real outcome; inventing a tiebreak here would be inventing one for every game.
Examples#
A three-point battleground:
# Assets/Pvp/basin.vxdef!PvpMapDefinitiondisplayName: The Basinkind: Battlegroundscene: maps/basinteams: 2teamSize: 10scoreToWin: 1500timeLimit: 900objectives: - { id: mine, kind: ResourceControl, captureSeconds: 8, pointsPerTick: 1, tickSeconds: 2 } - { id: farm, kind: ResourceControl, captureSeconds: 8, pointsPerTick: 1, tickSeconds: 2, startingOwner: 0 } - { id: flag, kind: FlagReturn, captureSeconds: 2, pointsOnCapture: 100 }Running one:
using Vixen.Gameplay;using Vixen.Gameplay.Pvp;static class Basin { public static bool Step(PvpMatch match, int objective, int red, int blue, float delta) { // Whoever is inside the radius is the scene's answer, not this library's. match.Occupy(objective, [red, blue]); return match.Tick(delta); } public static string Result(PvpMatch match) => match.Outcome switch { MatchOutcome.Draw => "drawn", MatchOutcome.Running => "still going", _ => $"team {match.Winner}" };}Watching a point change hands:
using Vixen.Gameplay.Pvp;static class Announcer { public static void Listen(PvpMatch match) => match.Captured += (state, team) => Say(team < 0 ? $"{state.Objective.Id} is neutral" : $"team {team} took {state.Objective.Id}"); static void Say(string what) { }}See also#
- Instances — G6's other half.
- Combat — what kills the person standing on the point.
- Gameplay tags — what flagging is.