FS Parkour — More Climbable Walls
OK, so I figured out what I was doing wrong. Part of it was that I was using the exiting CreatePoint function, and that had its own…
FS Parkour — More Climbable Walls
OK, so I figured out what I was doing wrong. Part of it was that I was using the exiting CreatePoint function, and that had its own built-in assumptions and offsets. Here’s my current code.
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace FS_ParkourSystem
{
public static class ClimbingPointUtil
{
private static int pointCount;
public static int totalPointCount;
public static void BakeGrid(GameObject obj, float horizontalDistanceBetweenPoints, float verticalDistanceBetweenPoints, bool alternateRows, float progress)
{
Debug.Log("Code changed");
horizontalDistanceBetweenPoints = Mathf.Max(0.05f, horizontalDistanceBetweenPoints);
verticalDistanceBetweenPoints = Mathf.Max(0.05f, verticalDistanceBetweenPoints);
var curRot = obj.transform.eulerAngles;
obj.transform.eulerAngles = Vector3.zero;
// Get the exact world boundaries of the mesh
Bounds bounds = obj.GetComponent<MeshRenderer>().bounds;
float xLength = bounds.size.x;
float yLength = bounds.size.y;
float zLength = bounds.size.z;
// Calculate exactly how many points fit cleanly WITHIN the actual dimensions
int numPointsX = Mathf.Max(1, Mathf.FloorToInt(xLength / horizontalDistanceBetweenPoints));
int numPointsY = Mathf.Max(1, Mathf.FloorToInt(yLength / verticalDistanceBetweenPoints));
int numPointsZ = Mathf.Max(1, Mathf.FloorToInt(zLength / horizontalDistanceBetweenPoints));
// Center the grid elements symmetrically inside the actual mesh faces
float xStartOffset = (xLength - (numPointsX - 1) * horizontalDistanceBetweenPoints) / 2f;
float yStartOffset = (yLength - (numPointsY - 1) * verticalDistanceBetweenPoints) / 2f;
float zStartOffset = (zLength - (numPointsZ - 1) * horizontalDistanceBetweenPoints) / 2f;
Vector3 point = Vector3.zero;
// Loop vertically (Y Axis)
for (int v = 0; v < numPointsY; ++v)
{
point.y = bounds.min.y + yStartOffset + (v * verticalDistanceBetweenPoints);
// Determine if this row is staggered
bool isStaggeredRow = alternateRows && (v % 2 == 1);
float staggerOffset = isStaggeredRow ? (horizontalDistanceBetweenPoints / 2f) : 0f;
// Generate Z faces
for (int h = 0; h < numPointsX; h++)
{
float calculatedX = bounds.min.x + xStartOffset + (h * horizontalDistanceBetweenPoints) + staggerOffset;
// Boundary guard: Make sure alternating/staggered points don't spill off the edge
if (calculatedX >= bounds.min.x && calculatedX <= bounds.max.x)
{
point.x = calculatedX;
// Front Face (snapped precisely to max Z)
point.z = bounds.max.z;
CreatePoint(obj, point, Vector3.forward);
// Back Face (snapped precisely to min Z)
point.z = bounds.min.z;
CreatePoint(obj, point, Vector3.back);
}
}
// Generate X faces
for (int h = 0; h < numPointsZ; h++)
{
float calculatedZ = bounds.min.z + zStartOffset + (h * horizontalDistanceBetweenPoints) + staggerOffset;
// Boundary guard for staggered rows on the side faces
if (calculatedZ >= bounds.min.z && calculatedZ <= bounds.max.z)
{
point.z = calculatedZ;
// Right Face (snapped precisely to max X)
point.x = bounds.max.x;
CreatePoint(obj, point, Vector3.right);
// Left Face (snapped precisely to min X)
point.x = bounds.min.x;
CreatePoint(obj, point, Vector3.left);
}
}
EditorUtility.DisplayProgressBar("Generating Points", $"Creating grid climbpoints - {obj.name}", (float)v / numPointsY);
}
EditorUtility.ClearProgressBar();
obj.transform.eulerAngles = curRot;
}
private static void CreatePoint(GameObject parent, Vector3 point, Vector3 dir = new Vector3())
{
var pointObj = new GameObject();
pointObj.name = $"Climb Point {pointCount}";
pointObj.transform.SetParent(parent.transform);
pointObj.transform.position = point;
if (dir != Vector3.zero)
pointObj.transform.forward = dir;
var climbPoint = pointObj.AddComponent<ClimbPoint>();
climbPoint.enabled = false;
climbPoint.MountPoint
Undo.RegisterCreatedObjectUndo(pointObj, "Created Climb Point");
pointCount++;
}
}
}

It’s not perfect. It doesn’t build points to mount the top, it starts too low for something on the ground (since we can jump up a meter or two to the first point), and the corners are a bit of a mess, making transitioning around them clumsy. One last thing…
메타데이터
- post_id
- 7e3ca8bc9cd6
- slug
- fs-parkour-more-climbable-walls-7e3ca8bc9cd6
- url
- https://medium.com/@sean.duggan/fs-parkour-more-climbable-walls-7e3ca8bc9cd6
- canonical_url
- https://medium.com/@sean.duggan/fs-parkour-more-climbable-walls-7e3ca8bc9cd6
- author_url
- https://medium.com/@sean.duggan
- status
- ok
- fetched_at
- 2026-06-09 15:37:30