Ballex ver.1.7.0 Update
This update focuses on adding a brand-new version of the level editor, as well as fixing and optimizing parts of the game.
You can experience the new level editor by selecting "Launch BME 4" when starting the game.
## Game Updates
-
Added compatibility with custom maps made with BME4; checkpoints expanded to 99.
-
Added Steam Cloud Save support.
-
Fixed some achievement issues, relaxed achievement requirements; achievements can now be unlocked on custom maps.
-
Fixed multiple cross-map variable pollution issues.
-
Fixed an issue where speed was not reset to zero when restarting the game.
## New BME4, a Brand-New Level Editor
-
Freely import 3D models / textures / audio.
-
Write logic scripts using Miniscript.
-
Import maps produced by the old editor and continue working on them (not a perfect conversion).
-
The road generator replaces the A/S road tool, making it easier to create roads.
-
Check more changes and features after updating.
## Overview of Game APIs Available to Scripts in BME4
The following is for map makers' reference; if you only play the game, you can ignore the content below.
// ---------- Conventions ----------
id / targetID = item ID (throws CannotFindItemException if invalid)
vec2 / vec3 = numeric list [x,y] / [x,y,z]
quat = quaternion list [x,y,z,w]
xform = [px,py,pz, qx,qy,qz,qw, sx,sy,sz] (10 elements, rotation as quaternion)
Color = [r,g,b] or [r,g,b,a] (0..1)
Physics* functions = targetID can also be the ID of an ItemLink, acting on the rigidbody carried by its linked entity
// ---------- Variable Manager ----------
GetIntVariableValue(variableName: string): number; // Reads int variable (including G_* game variables)
GetFloatVariableValue(variableName: string): number; // Reads float variable
GetBoolVariableValue(variableName: string): number; // Reads bool variable, returns 1/0
GetNumberListVariableValue(variableName: string): list; // Reads numeric list variable
SetIntVariableValue(variableName: string, variableValue: number): void;
SetFloatVariableValue(variableName: string, variableValue: number): void;
SetBoolVariableValue(variableName: string, variableValue: boolean): void;
SetNumberListVariableValue(variableName: string, variableValue: list): void;
// ---------- Math Conversion ----------
QuaternionToEuler(value: quat): vec3;
EulerToQuaternion(value: vec3): quat;
// ---------- Physics (acts on physics objects; targetID can also be an ItemLink) ----------
PhysicsSetLinearVelocity(targetID: number, value: vec3): void;
PhysicsSetAngularVelocity(targetID: number, value: vec3): void;
PhysicsGetLinearVelocity(targetID: number): vec3;
PhysicsGetAngularVelocity(targetID: number): vec3;
PhysicsSetMass(targetID: number, value: number): void;
PhysicsGetMass(targetID: number): number;
PhysicsSetLinearDamping(targetID: number, value: number): void;
PhysicsGetLinearDamping(targetID: number): number;
PhysicsSetAngularDamping(targetID: number, value: number): void;
PhysicsGetAngularDamping(targetID: number): number;
PhysicsBreakJoint(targetID: number): void; // Breaks the specified joint (targetID = joint object's ID)
PhysicsCheckExists(targetID: number): boolean; // Whether the physics object exists (missing linked entity is treated as nonexistent)
PhysicsCheckDuringDestroy(targetID: number): boolean; // Whether it is in the death-zone shrink destruction process (from the shrink animation playing to before actual destruction)
PhysicsRaycast(startPosition: vec3, direction: vec3, length: number): list;
// Scene raycast, returns hit list, each entry [itemID, hitX, hitY, hitZ, normalX, normalY, normalZ]
// Only returns hits on physics objects (including physics objects under linked entities)
PhysicsMouseRaycast(length: number): list;
// Mouse raycast (length is usually a large value), each entry [itemID, hitX, hitY, hitZ, normalX, normalY, normalZ]
SetPhysicsObjectRenderMesh(targetID: number, meshPath: string): void;
SetPhysicsObjectRenderMaterials(targetID: number, materialPaths: list): void;
SetPhysicsObjectColliderToSphere(targetID: number, radius: number, offset: vec3): void;
SetPhysicsObjectColliderToBox(targetID: number, size: vec3, offset: vec3): void;
SetPhysicsObjectColliderToMesh(targetID: number, meshPath: string): void;
// ---------- Audio (audio objects) ----------
PlayAudio(targetID: number): boolean;
PauseAudio(targetID: number): boolean;
StopAudio(targetID: number): boolean;
SetAudioVolume(targetID: number, volume: number): void;
// ---------- Transform & Activation ----------
GetTransform(targetID: number): xform;
SetTransform(targetID: number, transform: xform): void;
SetActive(targetID: number, isActive: number): void; // 0/1
// ---------- Mechanisms & Flow ----------
Execute(targetID: number): boolean; // Triggers another executor
GetSection(): number; // Current section (CurrentSavePoint, 0 = start)
SetSection(section: number): void; // Force-activates section (0 = start; out-of-range values are automatically clamped to [0, total checkpoint count])
CallRestart(): boolean; // Restarts the current level (same as ESC restart; repeated calls during fade-out are invalid)
CallSuicide(): boolean; // Suicides (same as ESC suicide; counted in stats)
// ---------- Light / Environment ----------
SetLightIntensity(targetID: number, value: number): void;
SetLightColor(targetID: number, value: vec3): void; // [r,g,b], alpha is always 1
SetFogDensity(fogDensity: number): void;
SetFogDistance(near: number, far: number): void;
SetGravity(gravity: vec3): void;
SetFogDensity(fogDensity: number): void; // 0 = fog off
SetFogColor(color: vec3|vec4): void;
// ---------- Spawning & Destruction ----------
Instantiate(id: number, transform: xform): number; // Clones object at runtime, returns new ID
Destroy(targetID: number): void; // Destroys object (for joint objects, breaks joints first)
// ---------- Particles (particle objects) ----------
PlayParticle(targetID: number): void;
PauseParticle(targetID: number): void;
StopParticle(targetID: number): void;
// ---------- VFX (spawned at a fixed position, auto-destroy after 10 seconds) ----------
SpawnVfx(vfxType: string, position: vec3): boolean; // Returns true on success
SpawnVfxPRS(vfxType: string, position: vec3, rotation: vec3, scale: vec3): boolean;
// rotation is Euler angles; returns true on success
// vfxType: "StartLife" | "Explosion" | "Steam" | "SwitchBallPartA" | "SwitchBallPartB"
// | "CollectLife" | "CollectCure" | "CollectScore"
// ---------- Screen FX & Camera ----------
ShowScreenEdgeFx(Type: string, intensity: number): void; // Type: "Damaged" | "Health" | "Life" | "Score" | "Key"
ClearScreenEdgeFx(Type: string): void; // Immediately clears the specified edge; pass "" to clear all
SetCameraHeight(height: number): void; // Same as the camera trigger function
CameraShake(): void; // Shakes the camera once
// ---------- Input ----------
CheckKeyDown(keyIndex: number): boolean; // Keyboard; keyIndex = Unity KeyCode integer
CheckKeyUp(keyIndex: number): boolean;
CheckKeyHold(keyIndex: number): boolean;
CheckMouseDown(keyIndex: number): boolean; // Mouse button: 0 left / 1 right / 2 middle
CheckMouseUp(keyIndex: number): boolean;
CheckMouseHold(keyIndex: number): boolean;
GetMousePosition(): vec2; // Mouse screen position
GetMouseScrollDelta(): vec2; // Scroll wheel delta
// ---------- Path (path objects) ----------
WayPathStart(targetID: number): boolean;
WayPathStop(targetID: number): boolean;
WayPathPause(targetID: number): boolean;
WayPathResume(targetID: number): boolean;
// ---------- World-Space Text Objects ----------
SetText(targetID: number, text: string): void; // Supports "\n" escape for line breaks
GetText(targetID: number): string;
SetTextColor(targetID: number, color: vec3|vec4): void; // [r,g,b] (a=1) or [r,g,b,a]
GetTextColor(targetID: number): vec4; // Always returns [r,g,b,a]
SetTextSize(targetID: number, size: number): void; // In-game fontSize = size × 10
GetTextSize(targetID: number): number;
// ---------- Script UI (standalone canvas above the game HUD; handle 0 is treated as null) ----------
UICreate(elementType: string): number; // "Panel" | "Text" | "Image"; returns a handle
UIDestroy(id: number): boolean;
UIGetCanvasSize(): vec2; // Canvas reference 1920×1080
UIHideGameUI(): void; // Hides the game HUD
UIShowGameUI(): void; // Restores the game HUD
// Layout
UISetPosition(id: number, x: number, y: number): void;
UIGetPosition(id: number): vec2;
UISetSize(id: number, width: number, height: number): void;
UIGetSize(id: number): vec2;
UISetScale(id: number, x: number, y: number): void;
UIGetScale(id: number): vec2;
UISetRotation(id: number, degrees: number): void; // 0..360
UIGetRotation(id: number): number;
UISetAnchorMin(id: number, x: number, y: number): void;
UIGetAnchorMin(id: number): vec2;
UISetAnchorMax(id: number, x: number, y: number): void;
UIGetAnchorMax(id: number): vec2;
UISetPivot(id: number, x: number, y: number): void;
UIGetPivot(id: number): vec2;
UISetEnabled(id: number, enabled: boolean): void;
UIGetEnabled(id: number): boolean;
UISetParent(id: number, parentId: number): void; // 0 = attach back to the script UI root container
UIGetParent(id: number): number;
// Appearance
UISetColor(id: number, r: number, g: number, b: number, a: number): void;
UIGetColor(id: number): vec4;
UISetAlpha(id: number, alpha: number): void;
UIGetAlpha(id: number): number;
UISetMask(id: number, enabled: boolean): void;
UIGetMask(id: number): boolean;
UISetMaskable(id: number, maskable: boolean): void;
UIGetMaskable(id: number): boolean;
UISetShowMaskGraphic(id: number, show: boolean): void;
UIGetShowMaskGraphic(id: number): boolean;
UISetRaycastTarget(id: number, enabled: boolean): void;
UIGetRaycastTarget(id: number): boolean;
UISetRaycastEvent(id: number, enabled: boolean): void; // Must be enabled before UIGetClicked can poll clicks
UIGetRaycastEvent(id: number): boolean;
UIGetClicked(id: number): boolean; // Set on click, cleared after reading
// Text
UISetText(targetID: number, text: string): void;
UIGetText(targetID: number): string;
UISetFontSize(id: number, size: number): void;
UIGetFontSize(id: number): number;
UISetTextAlignH(id: number, align: string): void; // "Left" | "Center" | "Right"
UIGetTextAlignH(id: number): string;
UISetTextAlignV(id: number, align: string): void; // "Top" | "Middle" | "Bottom"
UIGetTextAlignV(id: number): string;
UISetTextWrapping(id: number, wrapping: boolean): void;
UIGetTextWrapping(id: number): boolean;
// Texture
UISetTexture(id: number, path: string): void; // Empty string = white placeholder image
UIGetTexture(id: number): string;
UISetUVRect(id: number, x: number, y: number, width: number, height: number): void;
UIGetUVRect(id: number): list; // [x,y,width,height]
UISetAspectRatioMode(id: number, mode: string): void;
// "None" | "WidthControlsHeight" | "HeightControlsWidth" | "FitInParent" | "EnvelopeParent"
UIGetAspectRatioMode(id: number): string;
UISetAspectRatio(id: number, ratio: number): void;
UIGetAspectRatio(id: number): number;
// ---------- Other ----------
GetLanguage(): string; // Gets the current game language: "English" | "Chinese"
## Overview of Global Variables in BME4
G_Score: number; // Score (Float, writable; writing triggers UI refresh)
G_Time: number; // Level time in milliseconds (Int, read-only)
G_Durability: number; // Durability (Float, writable; writing triggers UI refresh; synchronously deducts the same amount from wet durability)
G_SecondaryDurability: number; // Wet durability (Float, writable; automatically clamped to 0..G_Durability; writing triggers UI refresh)
G_Life: number; // Life (Int, writable; automatically clamped to 0..10)
G_Key: number; // Keys (Int, writable; automatically clamped to 0..5)
G_Temperature: number; // Temperature (Float, writable; writing triggers UI refresh)
G_CameraDirection: number; // Camera direction enum (Int, read-only)
G_PlayerVelocity: number; // Ball speed (Float, read-only)
G_PlayerPositionX: number; // Ball position X (Float, read-only)
G_PlayerPositionY: number; // Ball position Y (Float, read-only)
G_PlayerPositionZ: number; // Ball position Z (Float, read-only)
G_CurrentBallType: number; // Current ball type (Int, writable — writing switches the ball type)
G_IsSwitching: boolean; // Ball-switching animation in progress (Bool, read-only)
G_Section: number; // Current section/checkpoint (Int, writable — writing force-activates it, same as SetSection)
G_IsTestingMap: boolean; // Whether currently in map testing mode (Bool, read-only)
G_IsTimerEnabled: boolean; // Whether the timer is running (Bool, read-only)
Комментарии 0
Гостевые никнеймы не подтверждают личность. Все комментарии проходят проверку владельцем сайта.
Обсуждение ещё не началось.