← Back to list

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…

Sean Duggan · 2026-05-27 05:28 · 0 claps · 2.3 min read
#unity #fantacode-studios #climbing-system #parkour-system #editor-tool
Open on Medium ↗
Wiki topics: 🎮 · Gaming 🏔️ · Outdoor & Adventure

FS Parkour — More Climbable Walls

[embed]FS Parkour — Climbable Walls So, the Fantacode Studios Parkour and Climbing asset lets you place specific climbable points on a wall, and includes a…medium.com

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