title: How to make 2D lighting in JavaScript

text:
# Question
Title: How to make 2D lighting in JavaScript
I am making a recreation of the 2D voxel game Terraria in JavaScript. Like most sandbox games, Terraria has lighting, but because I am using JavaScript, performance is going to be an issue.

I have thought of a few ways I might do this:

One idea I have is to create a brightness map that stores a brightness value between 0 and 1 for each *corner* of a block, then draws a gradient on top of each block based on those values. But you already know this will take too long to render.

Another idea I have, is to draw the whole thing black, then draw partially transparent circles of colors over that. This would allow me to have colored lights. But I don't want to code an entire lighting system that may also take too long to render.

What are some of the concepts used by most games to create 2D lighting effects, and which are the fastest?

I have seen this question but it doesn't actually describe how to make the lightmap.

# Answer
Have a look at ray casting.

The simplest approach is to cast rays from the center, which gives a reasonable approximate answer:

A more advanced & precise version would only at angles where the walls begin or end:

The above examples were taken from this tutorial on 2D visibility from Red Blob Games.

Best performance will be achieved with WebGL. In my implementation I am doing all the calculations on the CPU and then drawing the shape with FAN mode and then rendering a circular gradient where shadows are cutoff.
> 2 votes

# Answer
Sorry for reviving the question, I know its already answered, but I came up with my own solution that does require an offscreen canvas, but it is pretty fast.

(WASD to move camera, scroll wheel for zooming, click and drag on walls to move them, press space to create polygon vertex, press enter to create the polygon.)

(check out the calculateLighting function for the main light code.)

Working Example:

```
/**
 * @type { HTMLCanvasElement }
 */
var scene = document.getElementById("scene");
var ctx = scene.getContext("2d");

var vWidth = window.innerWidth;
var vHeight = window.innerHeight;

var targetFPS = 60;

var lastTimestamp = performance.now();
var fps = 1000;

var displayFPS = 1000;

function calculateFPS() {
    var delta = (performance.now() - lastTimestamp) / 1000;
    lastTimestamp = performance.now();
    fps = Math.trunc(1 / delta);
}

var friction = 0.8;
var worldScale = 1;
var zoomingDampener = 0.98;

var keysDown = [];

var mouse = {
    x: 0,
    y: 0,
    down: false,
    rightdown: false
}

var polyPoints = [];

var updateLoop;
var updateFPS;

function resizeCanvas() {
    vWidth = window.innerWidth;
    vHeight = window.innerHeight;
    scene.width = vWidth * window.devicePixelRatio;
    scene.height = vHeight * window.devicePixelRatio;

    // tWidth = window.innerWidth;
    // tHeight = window.innerHeight;
    // scene.width = tWidth;
    // scene.height = tHeight;
}

resizeCanvas();

function random(min, max) {
    return Math.random() * (max - min) + min;
}

function clamp(min, max, value) {
    if (value < min) {
        return min;
    }

    if (value > max) {
        return max;
    }

    return value;
}

function lerp(start, end, t) {
    return start + (end - start) * clamp(0, 1, t);
}

function degreesToRadians(degrees) {
    return degrees * Math.PI / 180;
}

function radiansToDegrees(radians) {
    return radians * 180 / Math.PI;
}

function snapNumberToGrid(number, gridSize) {
    return Math.floor(number / gridSize) * gridSize;
}

function getCenterOfPolygon(vertices) {
    var x = 0;
    var y = 0;
    for (var i = 0; i < vertices.length; i++) {
        x += vertices[i].x;
        y += vertices[i].y;
    }
    return {
        x: x / vertices.length,
        y: y / vertices.length
    };
}

function rectangleToRectangleCollisionDetection(obj1, obj2) {
    if (obj1.x + obj1.width > obj2.x && obj1.x < obj2.x + obj2.width &&
        obj1.y + obj1.height > obj2.y && obj1.y < obj2.y + obj2.height) {
        return true;
    }

    return false;
}

function rectangleToRectangleCollisionResolution(obj1, obj2) {
    var vx = ((obj2.x + (obj2.width / 2)) - (obj1.x + (obj1.width / 2)));
    var vy = ((obj2.y + (obj2.height / 2)) - (obj1.y + (obj1.height / 2)));

    var dir = Math.atan2(vy, vx);

    if (Math.abs(vx / obj2.width) > Math.abs(vy / obj2.height)) {
        if (vx > 0) {
            obj1.x = obj2.x - obj1.width;
        } else {
            obj1.x = obj2.x + obj2.width;
        }
    } else {
        if (vy > 0) {
            obj1.y = obj2.y - obj1.height;
        } else {
            obj1.y = obj2.y + obj2.height;
        }
    }
}

function pointToRectangleCollisionDetection(obj1, obj2) {
    if (obj1.x > obj2.x && obj1.x < obj2.x + obj2.width &&
        obj1.y > obj2.y && obj1.y < obj2.y + obj2.height) {
        return true;
    }

    return false;
}

function rectangleToCircleCollisionDetection(rectangle, circle) {
    var testX = circle.x;
    var testY = circle.y;

    if (circle.x < rectangle.x) {
        testX = rectangle.x;
    } else if (circle.x > rectangle.x + rectangle.width) {
        testX = rectangle.x + rectangle.width;
    }

    if (circle.y < rectangle.y) {
        testY = rectangle.y;
    } else if (circle.y > rectangle.y + rectangle.height) {
        testY = rectangle.y + rectangle.height;
    }

    var distX = circle.x - testX;
    var distY = circle.y - testY;
    var distance = Math.sqrt((distX * distX) + (distY * distY));

    if (distance <= circle.radius) {
        return true;
    }
    return false;
}

function circleToCircleCollisionDetection(obj1, obj2) {
    var dx = obj2.x - obj1.x;
    var dy = obj2.y - obj1.y;
    var distance = Math.sqrt((dx * dx) + (dy * dy));

    if (distance <= obj1.radius + obj2.radius) {
        return true;
    }

    return false;
}

function pointToCircleCollisionDetection(point, circle) {
    var dx = point.x - circle.x;
    var dy = point.y - circle.y;
    var distance = Math.sqrt((dx * dx) + (dy * dy));

    if (distance <= circle.radius) {
        return true;
    }

    return false;
}

function pointToLineCollisionDetection(point, line) {
    var d1 = Math.sqrt((point.x - line.x1) * (point.x - line.x1) + (point.y - line.y1) * (point.y - line.y1));
    var d2 = Math.sqrt((point.x - line.x2) * (point.x - line.x2) + (point.y - line.y2) * (point.y - line.y2));

    var lineLen = Math.sqrt((line.x1 - line.x2) * (line.x1 - line.x2) + (line.y1 - line.y2) * (line.y1 - line.y2));

    var buffer = 0.2;

    if (d1 + d2 >= lineLen - buffer && d1 + d2 <= lineLen + buffer) {
        return true;
    }

    return false;
}

function pointToPolygonCollisionDetection(point, vertices) {
    var collision = false;

    for (var i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
        var xi = vertices[i].x, yi = vertices[i].y;
        var xj = vertices[j].x, yj = vertices[j].y;

        var intersect = ((yi > point.y) !== (yj > point.y)) &&
            (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);

        if (intersect) {
            collision = !collision;
        }
    }

    return collision;
}

class Vertex2D {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

class Light {
    constructor(x, y, radius, color, intensity, isStatic = false) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
        this.intensity = intensity;
        this.static = isStatic;
        this.computeLighting = true;
        this.staticRays = [];
    }
}

class Wall {
    constructor(x, y, width, height, color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    }
}

class WallCircle {
    constructor(x, y, radius, color) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
    }
}

class WallPoly {
    constructor(vertices = [], color) {
        this.vertices = vertices;
        this.color = color;
    }
}

function calculateLighting(lights, walls) {
    // Light Calculation
    ctx.save();

    // Check if light is in wall
    for (var light of lights) {
        var continueLoop = false;

        for (var wall of walls) {
            if (wall instanceof WallCircle) {
                if (pointToCircleCollisionDetection(light, wall)) {
                    continueLoop = true;
                    break;
                }
            } else if (wall instanceof WallPoly) {
                if (pointToPolygonCollisionDetection(light, wall.vertices)) {
                    continueLoop = true;
                    break;
                }
            }
        }

        if (continueLoop == true) {
            continue;
        }

        // var grad = ctx.createRadialGradient(light.x, light.y, 0, light.x, light.y, light.radius);
        // grad.addColorStop(0, light.color);
        // grad.addColorStop(1, "transparent");

        // Create array that stores all of the shadow quads for the light

        var allQuads = [];

        // Calculate all shadow quads for each wall and add them to the allQuads array
        for (var wall of walls) {
            if (wall instanceof WallPoly) {
                for (var i = 0; i < wall.vertices.length; i++) {
                    var vertex1 = wall.vertices[i];
                    var otherIndex = (i + 1) % wall.vertices.length;
                    var vertex2 = wall.vertices[otherIndex];

                    var quad = [];

                    var v1endv = Math.atan2(vertex1.y - light.y, vertex1.x - light.x);
                    var v2endv = Math.atan2(vertex2.y - light.y, vertex2.x - light.x);

                    quad.push(vertex1);

                    quad.push(new Vertex2D(vertex1.x + (Math.cos(v1endv) * light.radius * 50), vertex1.y + (Math.sin(v1endv) * light.radius * 50)));

                    quad.push(new Vertex2D(vertex2.x + (Math.cos(v2endv) * light.radius * 50), vertex2.y + (Math.sin(v2endv) * light.radius * 50)));

                    quad.push(vertex2);

                    allQuads.push(quad);
                }
            }
        }

        // Draw the lights with shadow quads
        var tmpCanvas = document.createElement("canvas");
        var tmpCtx = tmpCanvas.getContext("2d");

        tmpCanvas.width = vWidth * window.devicePixelRatio;
        tmpCanvas.height = vHeight * window.devicePixelRatio;

        // tmpCtx.scale(scale, scale);
        tmpCtx.scale(window.devicePixelRatio, window.devicePixelRatio);
        tmpCtx.scale(worldScale, worldScale);
        tmpCtx.translate(-(camera.x - (vWidth / (worldScale * 2))), -(camera.y - (vHeight / (worldScale * 2))));

        var grad = tmpCtx.createRadialGradient(light.x, light.y, 0, light.x, light.y, light.radius);
        grad.addColorStop(0, light.color);
        grad.addColorStop(1, "transparent");

        tmpCtx.save();
        tmpCtx.globalCompositeOperation = "lighter";

        tmpCtx.fillStyle = grad;
        tmpCtx.beginPath();
        tmpCtx.arc(light.x, light.y, light.radius, 0, Math.PI * 2);
        tmpCtx.fill();
        tmpCtx.closePath();
        tmpCtx.restore();

        tmpCtx.save();
        tmpCtx.globalCompositeOperation = "destination-out";
        for (var i = 0; i < allQuads.length; i++) {
            var cQuad = allQuads[i];
            tmpCtx.fillStyle = "rgba(0, 0, 0, 1)";
            tmpCtx.beginPath();
            tmpCtx.moveTo(cQuad[0].x, cQuad[0].y);
            for (var j = 1; j < cQuad.length; j++) {
                tmpCtx.lineTo(cQuad[j].x, cQuad[j].y);
            }
            tmpCtx.closePath();
            tmpCtx.fill();
        }
        tmpCtx.restore();

        // Draw the light to the main canvas
        ctx.save();
        ctx.globalCompositeOperation = "lighter";
        ctx.drawImage(tmpCanvas, camera.x - (vWidth / 2) / worldScale, camera.y - (vHeight / 2) / worldScale, vWidth / worldScale, vHeight / worldScale);
        ctx.restore();
    }
    ctx.restore();
}

var walls = [];

function createShapeObj(x, y, radiusX, radiusY, sides, color, rotation = 0) {
    rotation = degreesToRadians(rotation);
    var shape = new WallPoly([], color);
    sides = Math.round(sides);
    var increment = 2 * Math.PI / sides;
    var currentSide = 0;
    // shape.vertices.push(new Vertex2D(x + (Math.cos(currentSide + rotation) * radiusX), y + (Math.sin(currentSide + rotation) * radiusY)));
    for (var i = 0; i < sides; i++) {
        currentSide += increment;
        shape.vertices.push(new Vertex2D(x + (Math.cos(currentSide + rotation) * radiusX), y + (Math.sin(currentSide + rotation) * radiusY)));
    }

    return shape;
}

function createRectangle(x, y, width, height, color) {
    var vertices = [
        new Vertex2D(x, y),
        new Vertex2D(x + width, y),
        new Vertex2D(x + width, y + height),
        new Vertex2D(x, y + height)
    ];

    walls.push(new WallPoly(vertices, color));
}

function drawShape(x, y, radiusX, radiusY, sides, color, rotation = 0) {
    sides = Math.round(sides);
    ctx.save();
    ctx.fillStyle = color;
    var increment = 2 * Math.PI / sides;
    var currentSide = 0;
    ctx.beginPath();
    ctx.moveTo(x + (Math.cos(currentSide + rotation) * radiusX), y + (Math.sin(currentSide + rotation) * radiusY));
    for (var i = 0; i < sides; i++) {
        currentSide += increment;
        ctx.lineTo(x + (Math.cos(currentSide + rotation) * radiusX), y + (Math.sin(currentSide + rotation) * radiusY));
    }
    ctx.fill();
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
}

function createShape(x, y, radiusX, radiusY, sides, color, rotation = 0) {
    rotation = degreesToRadians(rotation);
    var shape = new WallPoly([], color);
    sides = Math.round(sides);
    var increment = 2 * Math.PI / sides;
    var currentSide = 0;
    // shape.vertices.push(new Vertex2D(x + (Math.cos(currentSide + rotation) * radiusX), y + (Math.sin(currentSide + rotation) * radiusY)));
    for (var i = 0; i < sides; i++) {
        currentSide += increment;
        shape.vertices.push(new Vertex2D(x + (Math.cos(currentSide + rotation) * radiusX), y + (Math.sin(currentSide + rotation) * radiusY)));
    }

    walls.push(shape);
}

for (var i = 0; i < 6; i++) {
        createRectangle(random(-vWidth / 2, vWidth / 2), random(-vHeight / 2, vHeight / 2), 50, 50, "#808080");
}

var lights = [
    new Light(-128, 0, 512, "#00cc40", 1),
    new Light(128, 0, 512, "#0080ff", 1)
    // new Light(0, 64, 256, "#0000ff", 1)
    // new Light(200, 200, 256, "#801020", 1)
];

var theta = 0;

var selectedWall = null;

createShape(0, 0, 32, 32, 6, "#0080ff", 0);

class Camera {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.velX = 0;
        this.velY = 0;
        this.acceleration = 1;
    }
}

var camera = new Camera(0, 0);

function main() {
    calculateFPS();

    if (worldScale <= 0) {
        worldScale = 0;
    }

    theta += 0.05;

    if (mouse.down == true) {
        if (selectedWall != null) {
            if (selectedWall instanceof Wall) {
                // selectedWall.x += e.movementX / worldScale;
                // selectedWall.y += e.movementY / worldScale;

                // selectedWall.x = mouse.x - (selectedWall.width / 2);
                // selectedWall.y = mouse.y - (selectedWall.height / 2);

                selectedWall.x = lerp(selectedWall.x, mouse.x - (selectedWall.width / 2), 0.2);
                selectedWall.y = lerp(selectedWall.y, mouse.y - (selectedWall.height / 2), 0.2);
            } else if (selectedWall instanceof WallCircle) {
                // selectedWall.x = e.movementX / worldScale;
                // selectedWall.y = e.movementY / worldScale;

                // selectedWall.x = mouse.x;
                // selectedWall.y = mouse.y;

                selectedWall.x = lerp(selectedWall.x, mouse.x, 0.2);
                selectedWall.y = lerp(selectedWall.y, mouse.y, 0.2);
            } else if (selectedWall instanceof WallPoly) {
                var center = getCenterOfPolygon(selectedWall.vertices);
                for (var i = 0; i < selectedWall.vertices.length; i++) {
                    var vert = selectedWall.vertices[i];

                    var offsetX = vert.x - center.x;
                    var offsetY = vert.y - center.y;

                    // vert.x += e.movementX / worldScale;
                    // vert.y += e.movementY / worldScale;

                    // vert.x = mouse.x + offsetX;
                    // vert.y = mouse.y + offsetY;

                    vert.x = lerp(vert.x, mouse.x + offsetX, 0.2);
                    vert.y = lerp(vert.y, mouse.y + offsetY, 0.2);
                }
            } else if (selectedWall instanceof Light) {
                // selectedWall.x = mouse.x;
                // selectedWall.y = mouse.y;

                selectedWall.x = lerp(selectedWall.x, mouse.x, 0.2);
                selectedWall.y = lerp(selectedWall.y, mouse.y, 0.2);
            }
        }
    }

    if (keysDown["w"]) {
        camera.velY -= camera.acceleration;
    }

    if (keysDown["a"]) {
        camera.velX -= camera.acceleration;
    }

    if (keysDown["s"]) {
        camera.velY += camera.acceleration;
    }

    if (keysDown["d"]) {
        camera.velX += camera.acceleration;
    }

    camera.velX *= friction;
    camera.velY *= friction;

    camera.x += camera.velX;
    camera.y += camera.velY;

    ctx.save();
    ctx.scale(window.devicePixelRatio, window.devicePixelRatio);

    ctx.clearRect(0, 0, vWidth, vHeight);
    ctx.fillStyle = "#101520";
    ctx.fillRect(0, 0, vWidth, vHeight);

    ctx.scale(worldScale, worldScale);
    ctx.translate(-(camera.x - (vWidth / (worldScale * 2))), -(camera.y - (vHeight / (worldScale * 2))));

    for (var wall of walls) {
        ctx.fillStyle = wall.color;
        if (wall instanceof Wall) {
            ctx.fillRect(wall.x, wall.y, wall.width, wall.height);
        } else if (wall instanceof WallCircle) {
            ctx.beginPath();
            ctx.arc(wall.x, wall.y, wall.radius, 0, Math.PI * 2);
            ctx.fill();
            ctx.closePath();
        } else if (wall instanceof WallPoly) {
            ctx.beginPath();
            ctx.moveTo(wall.vertices[0].x, wall.vertices[0].y);
            for (var i = 1; i < wall.vertices.length; i++) {
                ctx.lineTo(wall.vertices[i].x, wall.vertices[i].y);
            }
            ctx.closePath();
            ctx.fill();
        }
    }

    calculateLighting(lights, walls);

    if (polyPoints.length > 0) {
        ctx.strokeStyle = "#ff0000";
        ctx.beginPath();
        ctx.moveTo(polyPoints[0].x, polyPoints[0].y);

        for (var i = 1; i < polyPoints.length; i++) {
            var point = polyPoints[i];

            ctx.lineTo(point.x, point.y);
        }

        ctx.lineTo(mouse.x, mouse.y);
        ctx.stroke();
        ctx.closePath();
    }

    ctx.restore();

    ctx.save();
    ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
    ctx.textBaseline = "top";
    ctx.textAlign = "left";
    ctx.font = " 14px arial";
    ctx.fillStyle = "#ffffff";
    ctx.fillText(`FPS: ${displayFPS}`, 5, 5);
    ctx.restore();

    // requestAnimationFrame(main);
}

updateLoop = setInterval(main, 1000 / targetFPS);

updateFPS = setInterval(function () {
    displayFPS = fps;
}, 1000);

// main();

window.addEventListener("keydown", (e) => {
    // e.preventDefault();
    keysDown[e.key] = true;

    if (e.key === " ") {
        polyPoints.push(new Vertex2D(mouse.x, mouse.y));
    }
});

window.addEventListener("keyup", (e) => {
    e.preventDefault();
    keysDown[e.key] = false;

    if (e.key === "Enter" && polyPoints.length > 1) {
        walls.push(new WallPoly(polyPoints, "#208040"));
        polyPoints = [];
    }
});

window.addEventListener("resize", resizeCanvas);

window.addEventListener("mousedown", (e) => {
    if (e.button === 0) {
        mouse.down = true;
    } else if (e.button === 2) {
        mouse.rightdown = true;
    }

    if (selectedWall == null) {
        var lightPoints = [];

        for (var i = 0; i < lights.length; i++) {
            var light = lights[i];
            lightPoints.push(light);
        }

        var rt = false;

        for (var i = 0; i < lightPoints.length; i++) {
            var lp = lightPoints[i];

            if (pointToCircleCollisionDetection(mouse, { x: lp.x, y: lp.y, radius: 25 }) == true) {
                selectedWall = lp;
                rt = true;
                break;
            }
        }

        if (rt == true) {
            return;
        }

        for (var i = 0; i < walls.length; i++) {
            var wall = walls[i];

            if (wall instanceof Wall) {
                if (pointToRectangleCollisionDetection(mouse, wall)) {
                    selectedWall = wall;
                    break;
                }
            } else if (wall instanceof WallCircle) {
                if (pointToCircleCollisionDetection(mouse, wall)) {
                    selectedWall = wall;
                    break;
                }
            } else if (wall instanceof WallPoly) {
                if (pointToPolygonCollisionDetection(mouse, wall.vertices)) {
                    selectedWall = wall;
                    break;
                }
            }
        }
    }
});

scene.addEventListener("click", () => {
    // polyPoints.push(new Vertex2D(mouse.x, mouse.y));
});

window.addEventListener("mouseup", (e) => {
    selectedWall = null;
    mouse.down = false;
    mouse.rightdown = false;
});

window.addEventListener("contextmenu", (e) => {
    e.preventDefault();
});

// scene.onclick = function () {
//     scene.requestPointerLock();
// }

window.onwheel = function (e) {
    if (event.wheelDelta) {
        if (event.wheelDelta > 0) {
            worldScale /= zoomingDampener;
            return -1;
        } else {
            worldScale *= zoomingDampener;
            return 1;
        }
    }

    if (event.deltaY < 0) {
        worldScale /= zoomingDampener;
        return -1;
    } else {
        worldScale *= zoomingDampener;
        return 1;
    }
}

window.addEventListener("mousemove", (e) => {
    mouse.x = (e.clientX + (camera.x * worldScale) - (vWidth / 2)) / worldScale;
    mouse.y = (e.clientY + (camera.y * worldScale) - (vHeight / 2)) / worldScale;

    // lights[0].x = mouse.x;
    // lights[0].y = mouse.y;
});

window.onerror = function (ev) {
    alert(ev)
}
```

```
:root {
    --light-samples: "100";
}

*,
*:before,
*:after {
    font-family: roboto, Arial, Helvetica, sans-serif, system-ui;
    padding: 0px 0px;
    margin: 0px 0px;
    box-sizing: border-box;
}

body {
    color: #ffffff;
  background: #000000;
}

canvas {
    display: block;
    width: 100%;
    height: 100%;
}
```

```
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="scene"></canvas>
</body>
</html>
```
> 0 votes

---
Tags: 2d, javascript, lighting, html-canvas, lightmap
---


# Question
Title: The bottom of the player capsule collider is going into the ground box collider
The bottom part of the player capsule collider is going inside the ground collider. I am using a raycast for detecting whether the plauer is grounded; an object (sphere) that is present on the bottom bound of the capsule collider is responsible for firing the raycast.

I think when the bottom part of the collider (including) the sphere is going inside the ground, my `isGrounded` variable is getting set to false, and the player character is transitioning from the landing to falling animation instead of running, which is not the desired behavior of course. I don't know why this is happening. I have been trying to find the solution for 2 days now and I can't seem to find the solution or reason behind the problem

* I am updating the size and center of the collider at runtime during different animations like jump, slide, and land (back to default size). I can provide code if needed.
* I am also moving the object responsible for the ray according to the size of the box collider using a `collider.bounds` and `extents` — will provide code if needed.

**More details and code about how ground detection works**

These two methods in the character control script are responsible for spawning and repositioning the object that fires ray on runtime. rayEmitter is a `GameObject` variable where prefab is added and Emitter is another `GameObject` variable. As you can tell RayEmitter object is spawning on the collider position.

```
  public void IntialSetup_of_RayEmitter()
    {
        Emitter = Instantiate(RayEmitter, Vector3.zero, Quaternion.identity);
        Emitter.transform.parent = transform;
        Reposition_RayEmitter();
    }

    public void Reposition_RayEmitter()
    {
        float bottom = cCollider.bounds.center.y - cCollider.bounds.extents.y;
        float side = cCollider.bounds.center.x - cCollider.bounds.extents.x;
        float front = cCollider.bounds.center.z + cCollider.bounds.extents.z;

        Emitter.transform.localPosition = new Vector3(side + 0.3f, bottom + 0.03f, front - 0.3f) - this.transform.position;
    }

```

these two methods are responsible for recentering and resizing the capsule collider at runtime, here I am using a bool `RepostionEmitter` as it turns true I am calling the reposition method **Above** on FixedUpdate, initially variable starts as false as it becomes true after updating size and center call reposition.

```
 private void UpdateCenter()
    {
        if (!UpdateNow)
        {
            return;
        }
        else if (Vector3.SqrMagnitude(cCollider.center - targetCenter_C) > 0.01f)
        {
            cCollider.center = Vector3.Lerp(cCollider.center, targetCenter_C,
                Time.deltaTime * CenterUpdate_Speed_C);
            RepostionEmiter = true;
        }
    }

    private void UpdateSize()
    {
        if (!UpdateNow)
        {
            return;
        }
        else
        {
            cCollider.height = Mathf.Lerp(cCollider.height, targetHeight,
                Time.deltaTime * SizeUpdate_Speed_C);
            RepostionEmiter = true;
        }
    }

 private void FixedUpdate()
    {
        if (StartRun)
        {
            if (isGrounded())
            {
                Grounded = true;
            }
            else
            {
                Grounded = false;
            }
        }

        ApplyGravity();
        RepostionEmiter = false;
        UpdateCenter();
        UpdateSize();

        if (RepostionEmiter)
        {
            Reposition_RayEmitter();
        }
    }

```

This bool method just a fire ray and detects the Grounded variable, I was also checking grounded or not using `Rigidbody` velocity but I had to remove it due to Dashing mechanisms during the dash especially if performed after the jump or double jump means in the air I don't want any different kind of velocity like gravity, etc to affect the dashing and it's forward force character just need to move forward during dash i am using `AddForce` for that, so you can imagine when I was doing that grounded variable was becoming true as i was messing with velocity during dash and due to that player was able to perform countless dashes in air and some other problems too.

```
 public bool isGrounded()
    {
        //if (Mathf.Abs(RIGIDBODY.velocity.y) <= 0.01f)
        //{
        //    return true;
        //}

        RaycastHit hit;

        if (Physics.Raycast(Emitter.transform.position, Vector3.down, out hit, rayDistance))
        {
            if (hit.collider.CompareTag("Ground"))
            {
                //Debug.Log(hit.collider.gameObject.tag);
                return true;
            }
        }
        return false;
    }

```

last thing and I think I should mention just in case, I am using something called a `Statemachine pattern` to control the logic/behavior of the character For example; this scriptable object containing code is present on all the animation state that needs to check if player is grounded or not.

```
using UnityEngine;

namespace EndlessRunning
{
[CreateAssetMenu(fileName = "New Object", menuName = "ScriptableObject/Ability/GroundDector")]
public class GroundDector : ScriptableObjectData
{
    public override void OnEnter(PlayerStateBase playerStateBase, Animator animator, AnimatorStateInfo stateInfo)
    {
    }

    public override void OnUpdate(PlayerStateBase playerStateBase, Animator animator, AnimatorStateInfo stateInfo)
    {
        if (playerStateBase.characterControl.Grounded)
        {
            animator.SetBool(HashManger.Instance.DicMainParameters[AnimatorParameters.Grounded], true);
        }
        else
        {
            animator.SetBool(HashManger.Instance.DicMainParameters[AnimatorParameters.Grounded], false);
        }
    }

    public override void OnExit(PlayerStateBase playerStateBase, Animator animator, AnimatorStateInfo stateInfo)
    {
    }
}

```

}

**That is how different player movements are being handled Overall my scene does not have anything related to that just objects that are responsible for** `cameraControl`, and `Spawning character` according to the selected character from character select scene These systems are completely separate, and decoupled from movement and has nothing to do with it.

**Character Inspector**

# Answer
> 0 votes
1. I can't believe it took me 2 days to figure out what was the problem. solution is way too simple. All I had to do was to set the ray emitter object red sphere a bit higher so when the character hits the ground and the collider gets updated object does not penetrate the ground collider like it does in the picture above also have to increase the length of the ray.
2. Another issue is with the updating of the collider If the update size and center speed are set to a very high value like 500 or 5000 then during the collider update emitter object gets pushed inside the ground.

now when the character hits the ground sphere stays a bit higher from the ground and does not return `isGrounded` false.

**For setting the sphere higher I just add 0.3 in the bottom position in the reposition method**

```
 float bottom = cCollider.bounds.center.y - cCollider.bounds.extents.y;
 float side = cCollider.bounds.center.x - cCollider.bounds.extents.x;
 float front = cCollider.bounds.center.z + cCollider.bounds.extents.z;

 Emitter.transform.localPosition = new Vector3(side + 0.3f, bottom + 0.3f, front - 0.3f) - this.transform.position;

```

***I hope it helps if anyone face similar issue in future***

---
Tags: unity, c#, collision-detection, collider, character-controller
---


# Question
Title: Modifying LibGDX vector2's seems to do nothing
I have a piece of code similar to this:

```
Vector2 test = new Vector2().setLength(20).setAngleDeg(45);

```

But when I'm trying to print its contents (such as `test.len()` or `test.x`) it just outputs 0. I've tried different variations, such as `test.set(test.setAngleDeg(x))` or simply `test.setAngleDeg(x)`, but these also seem to not work, I'm assuming there's something about the class I don't understand.

I'm sorry if it's common knowledge, I just had trouble finding an answer. Thanks in advance!

# Answer
Taking a look at the source code, we can see that:

* `setLength` scales the vector to the given length while preserving its angle. But if the vector was a zero vector, then it doesn't *have* an angle, and the method gives up and does nothing.
* `setAngle` keeps the vector's current length and changes only its angle.

So starting with a new default vector `(0, 0)`, calling `setLength` is a no-op, because it doesn't know what direction the vector should point — a zero vector doesn't point anywhere. So you still get a zero vector, and calling `setAngle` on it results in a zero vector again (length unchanged).

You really need to set both length and direction at once for this to be meaningful when starting with a zero vector, something like:

```
public static Vector2 MakePolar(float angleDegrees, float length) {

    float radians = angleDegrees * MathUtils.degreesToRadians;
    return new Vector2(
           length * MathUtils.cos(radians),
           length * MathUtils.sin(radians)
    );
}

```

You could also do it like this:

```
Vector2 test = new Vector2(length, 0).rotateDeg(angleDegrees);

```

(Though this will involve strictly more math ops than the all-in-one function above. `rotate` functions handle the case where the vector has non-zero values in both x and y components, so the added generality is a little redundant in this case if it doesn't get inlined to let the compiler eliminate the zero terms)
> 1 votes

---
Tags: java, libgdx, vector
---


# Question
Title: How to train a reinforcement learning algorithm in Unreal?
I know I can use ONNX plugins to use pretrained Deep Learning models in Unreal Engine 5, like style transfer, object detection, etc.

I want to build a basic reinforcement learning project and would be happy to code it from scratch like a q-learning algorithm, but I am finding it is quit difficult to do that. I saw that we can convert Python PyTorch scripts into `.onnx` format to use it in Unreal Engine (C++), but there is no documentation I found on how to use `.onnx` files in UE5 or 4.

I am trying to build a model for a basic explore and exploitation task. A character will be there on the floor and an object will be there. The character has to find a path on the floor to reach the object (terminal state).

# Answer
> 2 votes
Starting in UE 5.3 they added Learning Agents, a plugin that allows you to train agents via reinforcement and imitation learning. See here for more.

Side note: using reinforcement learning for path finding is usually not recommended. Read this Stack Exchange question & answers for more.

# Answer
> -1 votes
The short answer is not directly.

Unreal is not designed for ML training tasks.

You can collect a dataset by logging an actor's movements and the notable collisions for training, and train on that data externally.

The A\* algorithm and the built-in Navigation system make reinforcement AI learning for navigation unneeded. Given the bias of the limited sample size and lack of diversity, the generic ML application of the data collected would be mostly useless.

# Answer
> -1 votes
There is a plugin called MindMaker which we can use to build reinforcement learning models in Unreal Engine itself.

---
Tags: c++, python, unreal, reinforcement-learning, machine-learning
---


# Question
Title: How to calculate angular momentum of two colliding bodies about their shared center of mass in 2D?
I'm following this guide to implementing collisions in 2D physics.

It shows this diagram, but I don't understand how to calculate the values of `Da` and `Db`.

> **Apply conservation of angular momentum**
>
> choose to measure all angular momentums around the common centre of mass (`Pm`).
>
> Because this is inelastic case I have assumed that, on collision, the two objects stick together instantly, held on these relative positions and rotating about their common centre of mass. I could not find a way to allow them to be fixed normal to the direction of impact but allow them to slide along the point of imact. (because both objects are rotating).
>
> before the collision angular momentum is the sum of the angular momentums due to spin + the sum of angular momentums due orbiting about `Pm`.
>
> ```
> Ia * Wa + Da * Ma Va + Ib * Wb + Db * Mb Vb
>
> ```
>
> after the collision the angular momentum about the same point is
>
> ```
> Wf ( Ma * (Pa-Pm)^2 + Ia +Mb * (Pb-Pm)^2 + Ib)
>
> ```
>
> By conservation of angular momentum these two are equal:
>
> ```
> Ia * Wa + Da * Ma Va + Ib * Wb + Db * Mb Vb = Wf ( Ma * (Ra-Rm)^2 + Ia +Mb * (Rb-Rm)^2 + Ib)
>
> Wf = (Ia * Wa + Da * Ma Va + Ib * Wb + Db * Mb Vb) /( Ma * (Ra-Rm)^2 + Ia +Mb * (Rb-Rm)^2 + Ib)
>
> ```
>
> where:
>
> ```
> Rm = common centre of mass = (Ra * Ma + Rb * Mb )/ (Ma + Mb)
>
> Rb - Rm = (Rb Ma + Rb Mb - Ra * Ma - Rb * Mb)/ (Ma + Mb) = (Rb - Ra) * Ma / (Ma + Mb)
>
> Ra - Rm = (Ra Ma + Ra Mb - Ra * Ma - Rb * Mb)/ (Ma + Mb) = (Ra - Rb) * Mb / (Ma + Mb)
>
> ```

How can I compute `Da` and `Db` as used in these formulas?

# Answer
> 0 votes
We can see in the diagram that \\$D\_a\\$ is the component of the separation distance between \\$\vec P\_a\\$ and \\$\vec P\_m\\$, measured along the axis perpendicular to \\$\vec V\_a\\$, and likewise for the \\$b\\$ versions.

So we could calculate \\$D\_a\\$ with a little trigonometry. Let's define the "radius" vector of A's position offset from the shared center of mass as \\$\vec r\_a = \vec P\_a - \vec P\_m\\$. We can think of this vector as the hypotenuse of a right triangle, with the "adjacent" side parallel to \\$\vec V\_a\\$, and then \\$D\_a\\$ is the length of the "opposite" side. That means \\$D\_a = ||r\_a|| \sin \theta\_a\\$, where \\$\theta\_a\\$ is the angle between \\$\vec r\_a\\$ and \\$\vec V\_a\\$.

But wait... once we multiply \\$D\_a\\$ by \\$|| V\_a||\\$, we'd have the product of the lengths of two vectors and the sine of the angle between them... that sounds a lot like a cross product! That means \\$D\_a M\_a V\_a\\$ is just the usual expression for angular momentum of a mass around a point: \\$\vec r \times \vec p\\$, where \\$\vec r\\$ is the offset of the mass from the pivot point, and \\$ \vec p\\$ is the mass's linear momentum.

We can calculate this as though we had three dimensions for the cross product, then just clip out the z component as our scalar.

$$\begin{align} &\vec r \times \vec p\\ &= (\vec P\_a - \vec P\_m) \times M\_a \vec V\_a\\ &= \begin{bmatrix}{P\_a}\_x - {P\_m}\_x\\\{P\_a}\_y - {P\_m}\_y\\0\end{bmatrix} \times \begin{bmatrix}M\_a {V\_a}\_x\\M\_a {V\_a}\_y\\0\end{bmatrix}\\ &= \begin{bmatrix}0 \\ 0 \\ ({P\_a}\_x - {P\_m}\_x) M\_a{V\_a}\_y - ({P\_a}\_y - {P\_m}\_y) M\_a{V\_a}\_x\end{bmatrix} \end{align} $$

So you can use that z component in place of the product \\$D\_a M\_a ||V\_a||\\$:

$$\begin{align} D\_a M\_a ||V\_a|| &= ({P\_a}\_x - {P\_m}\_x) M\_a{V\_a}\_y - ({P\_a}\_y - {P\_m}\_y) M\_a{V\_a}\_x\\ D\_a &= \frac{ ({P\_a}\_x - {P\_m}\_x) {V\_a}\_y - ({P\_a}\_y - {P\_m}\_y) {V\_a}\_x} {||V\_a||} \end{align} $$

...and likewise for `Db`. The nice thing about calculating it this way is we don't need to explicitly compute the angle or use any trigonometric functions. We do need a square root to get the scalar speed in the denominator, but chances are you're using that elsewhere anyway.

---
Tags: physics, mathematics, geometry, collision-resolution
---


# Question
Title: How to use Camera.cullingMask to selectively render certain objects?
The documentation of this method doesn't provide any examples of implementing it. I don't understand how it works or even how I should use it to only render particular objects while not rendering others.

# Answer
1. Go to Edit \> Project Settings \> Tags and Layers \> Layers and create a layer called something like "Invisible".
2. Select the object you don't want the camera to draw. Set its layer to your newly-created "Invisible" layer using the drop-down at the top of the inspector.

You can also set gameObject.layer in code, using LayerMask.NameToLayer() to get the corresponding layer index integer for a given layer name.
3. Select the camera. Set its culling mask in the inspector to have a checkmark beside all layers you want to see, and no check beside the "Invisible" layer.

You can also set this through code. The culling mask is just a bitmask, where the \\$i^{th}\\$ bit is 1 if the camera should draw layer \\$i\\$. LayerMask.GetMask() lets you provide a list of layer names to include in the mask, if you don't want to do the bit-twiddling yourself.
> 1 votes

---
Tags: unity, c#, rendering
---


# Question
Title: Error in directional light shadow projection matrix
I have VC++ code for DX9 that draws shadows perfectly.

```
D3DXVECTOR4 lightDirection(0.707f, -0.707f, 0.707f, 0.0f);
D3DXPLANE groundPlane(0.0f, -1.0f, 0.0f, 0.0f);

D3DXMATRIX S;

D3DXMatrixShadow(
        &S,
        &lightDirection,
        &groundPlane);

D3DXMATRIX T;
D3DXMatrixTranslation(
        &T,
        vPos.x,
        vPos.y,
        vPos.z);

D3DXMATRIX W = matWorldPerson *T* S;
if(FAILED(p_d3d_Device->SetTransform(D3DTS_WORLD, &W))) return;

if(FAILED(pMeshRes->DrawSubset( i ))) return;

```

Then I change the calculation of the shadow matrix, and now shadows in my scene are drawn distorted:

```
D3DXVECTOR4 lightDirection(0.707f, -0.707f, 0.707f, 0.0f);
D3DXVECTOR4 groundPlane(0.0f, -1.0f, 0.0f, 0.0f);

D3DXMATRIX S;

float k = D3DXVec4Dot(&groundPlane, &lightDirection);

S = D3DXMATRIX(
        groundPlane.x * lightDirection.x + k,   groundPlane.x * lightDirection.y,       groundPlane.x * lightDirection.z,       groundPlane.x * lightDirection.w,

        groundPlane.y * lightDirection.x,       groundPlane.y * lightDirection.y + k,   groundPlane.y * lightDirection.z,       groundPlane.y * lightDirection.w,

        groundPlane.z * lightDirection.x,       groundPlane.z * lightDirection.y,       groundPlane.z * lightDirection.z + k,   groundPlane.z * lightDirection.w,

        groundPlane.w * lightDirection.x,       groundPlane.w * lightDirection.y,       groundPlane.w * lightDirection.z,       groundPlane.w * lightDirection.w + k    );

```

Where did I make a mistake?

# Answer
For curiosity I tried to change D3DXMatrixShadow() onto my func for calculation shadow matrix, no other reason.

```
    S = D3DXMATRIX(
        k - groundPlane.x * lightDirection.x,       -groundPlane.x * lightDirection.y,      -groundPlane.x * lightDirection.z,      -groundPlane.x * lightDirection.w,

        -groundPlane.y * lightDirection.x,      k - groundPlane.y * lightDirection.y,       -groundPlane.y * lightDirection.z,      -groundPlane.y * lightDirection.w,

        -groundPlane.z * lightDirection.x,      -groundPlane.z * lightDirection.y,      k - groundPlane.z * lightDirection.z,       -groundPlane.z * lightDirection.w,

        -groundPlane.w * lightDirection.x,      -groundPlane.w * lightDirection.y,      -groundPlane.w * lightDirection.z,      k - groundPlane.w * lightDirection.w    );

```

This is right software calculation of shadow matrix for DX9. Described here (link below).

http://www.it.hiof.no/~borres/j3d/explain/shadow/p-shadow.html
> 0 votes

---
Tags: matrix, linear-algebra, directx9, shadow-mapping
---


# Question
Title: Isolating a mesh so it doesn't interact with Raycasts in Unity
My problem is as follows: I have a a convex hull of some points. Given a point that's outside of said convex hull, I would like to find the closest point on the convex hull.

To that end, I have a representation of the convex hull as a mesh which I plan on adding as a `gameObject` and simply use `Collider.ClosestPoint`.

Given this, the mesh created from the convex hull clearly shouldn't be mixed in with other meshes in the game for which collision means something.

I see 3 options to isolate the mesh:

1. Have it in a separate layer from the rest of the objects and never including that layer in raycasts.
2. Enabling its collider only when performing the `Collider.ClosestPoint` operation and immediately disabling it afterwards.
3. Having the object be isolated to a separate world

Option 1 is a problem as I am developing an SDK and I don't want to count on the people using the SDK not to do raycasts with the default layer mask (which includes all layers except `Ignore raycast layer`) Option 2 just doesn't feel right as a programmer.

This leaves me with option 3. Problem here is that not only do I not know how to do this, my attempt to follow the instructions fails right off the bat because I can't find this `PhysicsWorldIndexAuthoring` component, and I cannot find any code examples either.

So, how do I go about creating a new world and placing a `gameObject` there so it doesn't interact with anything else, or are there other options to achieve my goal of isolating my mesh?

# Answer
> 0 votes
1. is not an option for you
2. is also too expensive (in addition to be not desireable)
3. relates to ECS

My advise would be to continue the raycast behind the object hit, tagging it as such, then going after the other potential colliders hit by the same ray / see RaycastAll

Voila.

---
Tags: unity, c#
---


# Question
Title: What are known game mechanics to disallow player to become infinitely rich still keeping it fun to progress?
I want to make an online game with a leaderboard. A player should be able to gather tools/resources to continue exploring/harvesting. The problem I want to solve is that **someone can find a way to harvest things like money, food, ammo, crafting resources, etc. infinitely but I don't want it to happen**, because: 1) it can potentially ruin the leaderboard 2) it potentially disconnects old players from new players because they become interested in different things having nothing to talk about to share the gaming experience. The player should sometimes to be forced to go back to start but it should be still fun.

---

For example, games about zombies. AFAIK, the game Project Zomboid had **zombies amount growing and resouces were limited** in such way that you was losing in any way. Why would it be still fun? Because there is a challenge in **how many days you can survive**.

Another example -- Realm of the Mad God. There you get into the leaderboard only when you die. So once you reach the goal you start from the level 1 again. **You can't be in the leaderboard and keep progressing**. Why doesn't it ruin the fun? Maybe because you don't lose the loot that you've saved in a "vault" and while you are now level 1 and can't use most of your loot immediatelly it's still there, not lost.

Rogue games like Nethack, Stone Soup, Cogmind -- basically the world has limited size and once you clean the level you have **nothing else to do other than go to the next level**. It's still fun because once you master your skills in the game the **competition changes from maximizing your progress to minimizing steps you've used to reach the end goal**. Like spent steps, time, abilities used, etc.

Rust -- in this one players are playing against each other and you lose almost everything when your base is raided. The base is an object in 3d world and to raid it the opponent have to make nearly a straight hole to the center. So **the amount of resources you have to spend on armoring your base is X^3 where X is amount of resources needed to raid you**. This makes it impossible to infinitely armor yourself and so finally you get raided anyway. Why is it still fun? Maybe because everything gets wiped once in few weeks and **there are game updates** that make it not boring to start again because the game will be a bit different.

There is a game mechanic in The Elder Scrolls Online that prevents trading guilds becoming infinitely rich as I understand. I'm not the guild owner and so I can be wrong but every week there is a bidding that **forces guilds to pay as much as they can to win a bid** to, simply saying, have a benefit during the week. AFAIK all the bids are gone and this is how the amount of money the guilds have in the MMO game with no wipes is limited.

---

I want my game to have some sort of "death" that would reset the progress to effectively keep players away from having infinitely large base, amount of money, etc. while still being fun to start again. What are some other game mechanics for this that I missed?

# Answer
Basically what you are asking for are rougelike / rougelite game elements. While rougelike games tend to have a permadeath with none to only a bit next game benefits, rougelite games tend to give more options for the next play session, based an your last one. Rougelike games often also lets you keep some of your progress, like the dungeon you already explored, some loot etc.

Depending on your type of game, there are several mechanics you can apply.

For example Rouge Legacy is a rougelite platformer, where you dwelve through a randomly generated dungeon to find 4 bosses and then defeat the end boss. You gather gold, find spells and level up along the way. When you die, you keep your gold and level, but you play a decendant of you, that starts with a class and an biological trait. Some of these traits are quite hard (like vertigo - playing upside down - monocromatic - playing in grayscale - to gay - still dont know what it does). Only then you can spend the gold you gathered before on your castle to buy permanent upgrades or to unlock certain classes or other bonuses.

This means to unlock some of the content, you have to die and basically start from new.

Other games give you this option to reset the game, but with a few bonuses. Idle games often give that option to add a multiplier to some incomes or generate unique currency to spend on new things.

Idle Territory for example lets you start with one tile, where you can build a building like a wheat field. Then you can hire people, producing x goods per second. Then you can abdication to reset all tiles and get gold equal to 10% of your combined per-second-production. Your tiles get resetted and you can buy tiles with gold, 1 gold for the first and 10x more for every following tile. Then you can build more buildings like forests, quarries, temples etc. There are several kinds of resets in this game, that can give you different kinds of benefits.

So what you should be looking for are options to open up the gameplay by sacrificing something. More income after releasing a certain amount of stuff a player has, new bonuses or buildings after giving away some of it. The top spot in the leaderboard is interesting only for so long until someone comes steamrolling over to take first place and just flies away.
> 1 votes

# Answer
## Frequent resets

Depending on the style of your game and its progression curve, you could take a lesson from Path of Exile (PoE).
It is a Diablo like Hack & Slash game with a strong drive on trading and aquiring different currencies.
The game is organized in "leagues" which last 3-4 months. Every league starts with all players having nothing and having to grind up from zero, but it also introduces new gameplay elements and balance changes keeping the game fresh and incentivizing changing your playstyle.
At the end of the league your progress is not erased but moved to a permanent league where you can enjoy your riches, however this permanent league is very underpopulated in contrast to the time limited leagues. This "migration" takes the edge of the reset for those who don't enjoy losing all progress.
> 1 votes

---
Tags: game-mechanics, leaderboards, progression
---


# Question
Title: How to hide things from noclipping players?
I am specifically working in Garry's Mod, and I am wondering if there might be a way to hide things from players using `noclip` to travel outside the bounds of the level.

What I mean is, in some maps, there are rooms far away from the main map that are only meant to be accessed and seen via puzzles or other forms of obscurity, and I would like to create rooms like this in my maps potentially.

The issue is, players who noclip might be able to visually see these rooms. (Which is an expected part of gmod sandbox gameplay anyways and not really a cheat)

Although I know of ways to prevent them from actually reaching the room, my question is if there are ways to make these rooms invisible to noclipping players visually, either through tricking the rendering engine somehow, or even through LUA.

I've seen some maps where parts of the map were not visible during noclip, although not intentionally, and it makes me wonder if there's a way to do that on purpose.

# Answer
> 0 votes
If you can prevent players from reaching the room then you can surround the room with a solid cube. That cube can then be textured with a greenscreen type effect to show the skybox and hide it from casual view.

Another option is to exclude the room from rendering until a certain trigger (that provides access normally) happens.

In most games this means that the textures and visual geometry of that room aren't loaded yet but the collision geometry is. Because textures take up a lot more space on the gpu than the collision geometry on the cpu.

---
Tags: modding, source-engine
---


title: Would slo mo work for multiplayer?

text:
# Question
Title: Would slo mo work for multiplayer?
I have hardly any programming knowledge but I want to get into game design but I have a question would slo mo work in multiplayer if used in this way. Where the player experience the game 10 times slower and everyone else saw him going 10 times faster would that work or is it just not possible.

# Answer
As per your description, you want a player to see the other moving faster than normal. You can do that, that is an speed boost. But the other player won't see everything going slower. That won't work.

*In this answer I try to reiterate some things a couple times to try to avoid misunderstanding.*

---

To wrap our heads around this, I invite you to think of two kind of clocks:

* There is a world clock, which will be the clock for the player in the real world. I'll assume it is the same for all players, as that is sufficient to understand the case at hand.
* And there are game clocks, each with the the current time in the game world, for a player. These are multiple, because time passes differently for different players.

Now, for your setup we would have that:

* For Player A 1 minute in world clock is 1 minute in game clock.
* For Player B 1 minute in world clock is 6 seconds (i.e. 0.1 minutes) in game clock

*The logic below also works if you have one player with a game clock going faster than the world clock (experiencing the game faster than normal), and the other have normal time. However, I'm doing it this way because you want one player to see the game slower.*

Here, Player B sees everything going slower (including Player A, for which there must be a recording of what Player A did so it can be played back slower for Player B). To reiterate: Player B would have to see what Player A did in *the past*. This is viable, given a recording of what Player A did and plays it back for Player B.

But Player A could not see Player B... Why? Well, what would Player A see Player B doing, if Player B has not done it yet? - The game won't be able to show to Player A what Player B is doing... Because Player B has not done it yet!

Think about this way: When is 1 minute in game clock?

* For Player A, 1 minute in game clock is 1 minute in world clock.
* For Player B, 1 minute in game clock is 10 minutes in world clock.

Thus Player A, 1 minute into the game, would have to see what Player B will be doing 9 minutes in the future. But the game has no way to know what will Player B do.

*I suppose you could try to have the game predict what Player B would do, but that is bound to be wrong. Instead I would suggest you can come up with some narrative justification for why the player can't be seen.*

---

Now, let us think about these players interacting:

* If Player A attacks Player B... Remember that Player B has not reached Player A's present game time. Instead Player A attack would be recorded and played back slower for Player B. At which point perhaps the attack might land, in which case Player B takes damage.
* If Player B attacks Player A, it would be attacking *the past* of Player A.

I'll assume that we make it impossible to push around the recording of Player A. If we let it happen, and correct for it, the result will be teleporting Player A on their present without an apparent reason why, which is not a good player experience.

However, you might do something with damage, have it play some animation, or something. But think about it for the point of view Player A... If Player B kills the recording Player A, then the first idea would be to have Player A suddenly die wherever it is at their present, which again is not good player experience.

Thus, it seems to me that interaction is either not viable, or a very bad experience for the players. And the mechanic is basically recording a ghost of the players that are experiencing game time faster.

---

If the effect is temporary we find both problems and solutions.

For example both players start playing with matching game clocks, but then one of the players speeds up their own game clock (or slows down the game clock of everything else, same difference)… But only for a while.

After that effect is over, then what? Logic suggest that the players that were experiencing game time faster would have to be held idle until the rest of the players catch up to their present. That is not good, it is boring gameplay.

Another option is to switch roles: those experiencing game time faster start experiencing it slower, and viceversa... Until their game time matches.

A more interesting solution is allow the players that were experiencing game time faster to appear at the present of the other players right away. *You can conceptualize this as their characters traveling to the past.* This means that the other players would have to deal with both the recorded ghosts and the actual players at same time.

This sounds like a boon for the players experiencing game time faster, and not the other way around. It would be like this: The player activates the ability, which makes the game both start recording what the player does (during which time the player cannot see other players) and playing it back slower for the other players... And after a while, the game stops recording and drops the player back in with both the other players (co-existing with the slowed down playback). *Thus, if you want the playback to look as if it is moving at normal speed, the player would have to move much faster during the recording.*

This also poses a few solutions for what happens if ghost takes damage:

* You can redirect damage from the ghost to the player in real time. This means that attacking the ghost is a viable way to harm the player.
* Or you might have the ability cost health, which will also be the health that the ghost will have. Then if the ghost finishes, you can have the game replenish the health the ghost had left to the player. On the other hand, if the ghost dies, it does not affect the player. *In my opinion, this is the best version of this mechanic.*

Furthermore, this approach allows versions of the mechanic where a bot handle what the ghost does if - for example - something knocks it out diverging from the recording, or if you want the ghost to stick around after the recording finished.

*But no player is seeing everything going slow.*

---

If we say that interaction is not possible, then you could have a player play in slow motion, and have it recorded... *With anticipation.* Then the other player can see the playback of what this player did, moving faster.

*With anticipation* is key here. Since the recording cannot be played back at meanwhile it is being recorded but faster. There is no way to play it back faster than it is being recorded, while it is being recorded... Because it would have to playback what has not been recorded yet!

Of course, the player doing this recording cannot see what the regular player will do, since the recording has to be done with anticipation, meaning that at the time of recording the other players have not played their corresponding part yet.

I don't think this is a great experience either. What you have is a ghost of a player doing a solo gameplay. But hey, you have a player seeing everything in the game going slower (except the other players, who this player does not see at all), and then everybody else sees said player going faster.
> 1 votes

# Answer
As others have stated it's not possible to have different timeframes for different players, because at some point you need to be able able to send information back in time. That said you may be able to do something interesting if you can incorporate the real world flaw (of not being able to travel backwards in time) into the games cannon in some way.

For example the multiplayer mod for KSP (Kerbal Space Program) allows multiple players to start in the same timeframe. This doesn't cause an issue since updates can be sent in (near) real time between the players as they each take actions.

Then a player can accelerate time - in single player this just calculates how every ship in the universe will move (at a faster rate).

For the player that accelerates time, they see the same thing they would in single player all the updates are calculated based on the moment they "jumped". For all the other players the ship that the "jumper" was controlling effectively becomes unmanned - it just continues to orbit with no new actions taking effect.

Effectively there are now two games going on. The one in the "present" and the one in the "future" - each has its own state which are disconnected from each other.

KSP allows any players "in the past" to jump forward in order to "sync up" with a player in the future. When this occurs there are several possible situations:

* A ship exists that wasn't controlled/interacted with by either player - in this case the future prediction should be the same in both timelines so it shouldn't be a problem.
* A ship was only controlled by the first "jumper" in that case when the second player syncs up the second player now see the new position - this isn't a problem since they see the new position as they jump forward in time.
* A ship was only controlled by the second "jumper" - this is a little jarring because the first "jumper" will see the ship change state/position when the second player jumps into their timeline.
* If a ship is controlled by both players it will be a problem as one could have destroyed the ship and the other moved it - in short there is a conflict.

KSP "resolves" this conflict by cloning said ship so both players now both see a ship in the "moved" position and wreckage where the ship was crashed.

---

Taking this idea to its logical conclusion....

You can record any actions taken by a future player and play them back when a later player gets to the same point.

For actions taken in the "present" state you could calculate the impact on a future game and apply them to those players games.

However at some point there will be at least two problems:

* In the future games changes may occur with no context (an item just disappears because it was moved in the past).
* There will inevitably be conflicts - the future player stood on a block to reach a ledge then the block was deleted by the earlier player.

You may be able to get around these issues by using a movie trope such as "you are protected from **SPECIFIC** past changes by the time vortex"...

Where the specific protections are anything you can't easily code around.

---

However I am not sure the work to do this is worth it - unless you can come up with a really cool way to incorporate it into the core of your game.
> 1 votes

# Answer
Its a relatvie question so lets break it down this way.

Your question suggest that Because player A is relatively faster, it sees everything slower. Because player B,C,D is relatively slower, it sees player A faster.

Uhh yes. it can simply done by making player A have faster input and player B,C,D have slower input.

But such design is often called "latency" or "lagging" if not set with a theme.

But if you meant all of them A,B,C,D sees the game as normal speed and it magically is different in speed at third party perspective.

No, its impossible unless physically we can bends time.
> 0 votes

# Answer
> Where the player experience the game 10 times slower and everyone else saw him going 10 times faster would that work or is it just not possible.

Let's say this is a racing game. Solution is simple, have player A drive a Ferrari and have players B,C,D drive old VW Beetles.

Problems arise if/when you want to have interactions with the World - it needs a clock to run by too (in a certain light, it can be thought of Player E). And now you need to choose that clock, will it be suited for Ferrari's speed, or to Beetle's speed. Still, **not impossible if you slightly bend the "experience the game X times slower" condition :-)**
> 0 votes

---
Tags: game-design, multiplayer
---


# Question
Title: How to make ranged RTS units move to their firing range from an opponent using flow fields?
I am trying to make a simple real-time strategy game (only the battle system of units fighting each other; no building, no economy, only battles and victory). I am using flow fields to make the units move.

I don't know how to make the AI take the right actions when I completing a move.

For example, I have a ranged unit, its behavior should move to its firing distance from the enemy and stop (or orbit/strafe in a circle around the enemy) and attack the enemy. But in my current code, the ranged unit just follows the flow field to move close to the enemy.

I don't know how to make it flee from the enemy until it gets to its attack range.

There is a way is recreate the flow fields to direct the unit to its flee positions from an enemy, but there are many ranged units, and their enemy is same. I don't know if it's right to create many flow fields for the units which have the same target.

I can't find a solution for this condition, I want my AI to behave more freely and not only follow the flow fields.

# Answer
Instead of a flow field (storing direction to travel at each point), consider using a distance field (storing the distance to the closest enemy at each point).

From a distance field, you can quickly determine the flow direction: it's just the gradient of the field. That means you can check the neighbours of a cell, and move in the direction the distance is decreasing (approach) or increasing (flee) most/fastest.

That lets you get both approach and flee behaviours from one data structure. And it also answers the question "how far", so a unit trying to maintain a set distance can climb up the distance field when it's currently too close, and roll down the distance field when it's currently too far.
> 0 votes

# Answer
A simple solution to this would be to have two flow fields:

* An "Attack" flow field.
* A "Retreat" flow field.

If the ranged unit is too far away it uses the attack flow field to move closer to the target and if it is too close it uses the retreat field to move away. If the unit is "just right" it stops moving.

A very simple retreat field would just be the reverse of the attack field, however this would be problematic, because it would simply repel units - possibly into impassable terrain.

A better retreat field would be a field that targets a position the unit had a while back - so it retreats back the way it came or you could be a bit more intelligent - targeting a friendly base or large group of friendly units.

However this entire design has a fatal flaw - it assumes you are only facing a single enemy unit (or tightly grouped set of enemy units) if you have two groups of enemy units simply moving towards one may bring you under fire from the other.

If initiating new attack you may be able to solve this by careful target selection (only picking off straggler enemy units), however if the AI unit gets enveloped it probably won't pick the optimum strategy.
> 0 votes

---
Tags: ai, path-finding, rts
---


title: How to implement game speed setting?

text:
# Question
Title: How to implement game speed setting?
In games like Europa Universalis or Hearts of Iron, there is a way to set game speed. This affects how long does e.g. one in-game day take in real-life time.

At first, I thought this mechanism was independent from framerate, i.e. measuring actual time passed, but that cannot be true: For example, speed 5 is faster on a faster machine than on a slower machine. Still, on both machines, the proportional difference between speed 5 and speed 1 is the same. And you can still take actions while the game is paused (speed = 0).

How is this implemented? In the context of the Godot engine (and gdscript), which provides `_process` and `_physics_process` methods, what is the right approach to achieve this?

# Answer
**Frame rate dependent**

If you want to trigger events in a frame dependent way, then you are going to count frames.

That is, you will have code like this:

```
var frame_count := 0

func _process(_delta:float) -> void:
    frame_count += 1

```

And then based on the accumulated value, you trigger your event.

*What advantage is there in doing it that way? I don't know. In fact, In Godot this is the approach that will require more code, as everything that would make this task easier is frame rate independent out of the box.*

---

**Frame rate independent**

Please notice that you might instead of an counter `int` make an accumulator `float` and increment it by `delta`, making this frame independent. The result would be a poor-man's `Timer`.

In fact, you could use a `Timer`, or a `SceneTreeTimer`, or other time keeping solutions (e.g. `Time.get_ticks_msec()`) to trigger events.

You can also take advantage of `Animation`s (using an `AnimationPlayer`), for example to change the sky and lights for a day-night cycle.

---

If you wanted a frame independent way to slow down or speed up your game, you can use `Engine.time_scale`.

---

**Note**: You probably don't want the time to keep going while the game is paused. Please refer to Pausing games and process mode. You can also handle `NOTIFICATION_PAUSED` and `NOTIFICATION_UNPAUSED` in the `_notification` virtual method.
> 2 votes

# Answer
I think these kinds of games usually separate their simulation from their regular update and render loops. That allows them to rapidly update the sim while keeping a normal framerate for rendering.

Two primary approaches to increase game speed come to mind:

1. Increase delta time passed to your sim\_update()
2. Increase the number of times you call sim\_update()

The first tends to be easier (and it's likely similar to using `Engine.time_scale`). However, it can cause issues on fast mode where entities may make large leaps in their individual updates that modify the outcome of the sim.

This comment from Limeox explains:

> Say some object goes invincible for 0.5 seconds and is about to take two damaging hits, one at 0.45s and one at 0.55s. If your delta is 0.01 seconds, the first hit will be blocked and the second one won't, as the effect has worn off by then. If it is 0.2 seconds, the effect may now block both, or neither, depending on when it is removed relative to the hits. Or you could have the "second" hit blocked, because it simulates first, then the effect is removed, then the "first" one hits?

> By just simulating more ticks, this wouldn't happen. Of course, by pushing those occurrences closer together (hits at 0.499s and 0.501s), you can construct similar issues. But, and this is the important point, the behavior will be identical regardless of game speed. After all the result doesn't need to be 100% correct (especially in the case of physics, you'd go insane). It just needs to be 100% consistent at all speeds.

So instead, you can do #2 and update your sim more frequently to ensure the result of each update is the same, but occurs at a faster rate. Of course, this means your sim update must be fast enough that you can afford to run it multiple times in 33ms to still hit 30 FPS on fast mode. But by decoupling it from animations, fx, sound, and any other presentation elements, you can likely avoid a great deal of cpu time.

For gdscript, that means you'd have something like this:

```
@export_range(1, 5) var game_speed := 3
var sim

func _process(delta):
    for i in game_speed:
        sim.update(delta)
    sim.apply_to_world.emit()

```

Everything processed in `sim` wouldn't use `_process` or `_physics_process`. Likely, you wouldn't want to rely on a general physics simulation at all. `apply_to_world` pushes the sim changes out so everything can grab the latest state for presentation.
> 0 votes

# Answer
I assume you are from Poland like me but lets keep it in English, I hope you will understand my poor english :). I am making a strategy/managment game now and I had same questions like you. I came with Idea using Timer. So, I have one Timer that clicks every 0.05 second (lowest recommended by Godot documentation). I have global variable which keep value of 1440.0 which is the number of minutes of full day. I have following speed settings:

* Normal - with every tick of TImer vaule of 2 (minutes) are substracted from 1440 - the day last 36 seconds
* 2x speed - with every tick of TImer vaule of 4 (minutes) are substracted from 1440 - the day last 18 seconds
* 4x speed - with every tick of Timer vaule of 8 (minutes) are substracted from 1440 - the day last 9 seconds
* Pause

When 1440 counter reaches 0, I am adding +1 day and resetting the counter.

I have also global variable holding timescale (1, 2 and 4) which are used as multiplayers for all animations, speed variables, shaders and particle emmiting speed.

I wanted this approach as I wanted to separate speed of simulation from speed of GUI which also consist of animated windows/frames, floating labels etc, I also have animated drag and drop elements. I guess changing Engine.time\_scale would affect whole game including GUI. Also when I was testing stuff with Engine.time\_scale I noticed some stuttering of simulation, animations when time scale was set to 2 or 4.

I don't know if this approach is good one as I am pretty new to GameDev (around 3 years of hobby game making) but it suits my needs so far. Not that much of a code, I have one Singleton that holds variables (day, month, years counters, time of day, continuous timer which keep time passed from start of game) and one Node+script that is controlling time in my game.

I am open to other ideas :)
> 0 votes

---
Tags: gdscript, godot-4
---


# Question
Title: "ArgumentNullException: Value cannot be null" for AudioSource.PlayOneShot
I am working on a game and I am trying to add a sound effect.

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody playerbody;
    private Animator playerAnim;
    private bool grounded;
    public bool gameover;
    public float jumpforce;
    public float gravmod;
    public ParticleSystem explosion;
    public ParticleSystem dirt;
    public AudioClip jumpSound;
    public AudioClip crashSound;
    private AudioSource playerAudio;

    // Start is called before the first frame update
    void Start()
    {
        playerbody = GetComponent<Rigidbody>();
        playerAnim = GetComponent<Animator>();
        playerAudio = GetComponent<AudioSource>();
        Physics.gravity *= gravmod;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space) && grounded && gameover == false)
        {
            playerAudio.PlayOneShot(jumpSound, 1.0f);
            playerbody.AddForce(Vector3.up * jumpforce, ForceMode.Impulse);
            playerAnim.SetTrigger("Jump_trig");
            grounded = false;
            dirt.Stop();
        }
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Ground"))
        {
            grounded = true;
            dirt.Play();
        }
        if (collision.gameObject.CompareTag("Obstacle"))
        {
            playerAudio.PlayOneShot(crashSound, 1.0f);
            gameover = true;
            playerAnim.SetBool("Death_b", true);
            playerAnim.SetInteger("DeathType_int", 1);
            explosion.Play();
            dirt.Stop();
        }
    }
}

```

At `playerAudio.PlayOneShot`, it just won't play and the rest of that part of the code stops working. It returns `ArgumentNullException: Value cannot be null` even though `jumpSound` and `crashSound` are both clearly defined. What is wrong?

# Answer
> 2 votes
Change your code like this:

```
void Start()
{
    playerbody = GetComponent<Rigidbody>();
    playerAnim = GetComponent<Animator>();
    playerAudio = GetComponent<AudioSource>();
    Physics.gravity *= gravmod;

    //log error messages indicating which GameObject is missing a reference value
    if (playerAudio == null) {
        Debug.LogError($"{nameof(playerAudio)} is null on {gameObject.name}", this);
    }
    if (playerAnim == null) {
        Debug.LogError($"{nameof(playerAnim)} is null on {gameObject.name}", this);
    }
    if (crashSound == null) {
        Debug.LogError($"{nameof(crashSound)} is null on " + gameObject.name, this);
    }
}

```

This will log error messages if references are missing. Logging like this should usually be the first thing you try when code isn't working like it should.

You can also use `Assert.IsNotNull()`, e.g.:

```
Assert.IsNotNull(crashSound, $"{nameof(crashSound)} is null on {gameObject.name}");

```

# Answer
> 1 votes
I got the same error while doing the guided practice project from Unity Learn.

I have fixed it by adding an Audio Source component in the Play:

1. Select the Play `gameObject` in the Hierarchy
2. Click the *Add Component* button in the Inspector and select "audioSource"

Hope my answer could help other Unity learners.

# Answer
> 0 votes
If your sound effects are defined but the code still won't run, its possible that the game object the script is attached to has no audio source component. You can add that under the inspector manually by selecting the object in hierarchy and adding said component, as Bing said.

Here's a short tutorial clip if it helps you: https://www.youtube.com/shorts/WbuQNmbwecc

Alternatively, you could try checking if the game object has an audio source to begin with and, if it does not have an audio source, add one in script.

You could try this:

    public class PlayerController : MonoBehaviour
    {
       // Insert all your other variables above this
       public AudioClip jumpSound;
       public AudioClip crashSound;
       private AudioSource playerAudio;

       // Start is called before the first frame update
       void Start()
       {
           // This is a bool that checks if the game object has an AudioSource or not.
           // It returns false if there is no AudioSource, and vice versa

           if(!TryGetComponent<AudioSource>(out AudioSource source))
           {
              gameObject.AddComponent<AudioSource>(); //
           }

           // Afterwards, we can get our AudioSource the usual way
           playerAudio = GetComponent<AudioSource>();
       }
    }
```

---
Tags: unity, c#
---


# Question
Title: Avoid player getting stuck with underpowered character
For a sidescrolling shooter I’m working on, I got stuck on the following: The game allows the player to buy upgrades for their character. This oppertunity comes in the form of a shop that sits at the end of each world (containing a couple of levels each).

Now, it’s entirely possible that the player does not purchase any upgrade (extra health, stronger weapons, etc) because they lack the money for it, or simply choose not to. This potentially causes them to move to the next levels being slightly/very underpowered, only able to fix their situation once they completed the full world again.

I’m looking for some advice on how to best mitigate this issue. The conflicting features seem to be:

* Upgrades are not always available
* The player has the choice not to purchase them
* The levels get more difficult every world

Some ways to solve this, inelegantly:

* Make upgrades automatically unlock, but that takes away some of the player autonomy I want to include.
* Only scale the difficulty once an upgrade is purchased, but this feels a bit silly
* Allow the player to restart from an earlier world, so they can make different choices and/or play better (to be able to afford an upgrade this time around) — obviously not ideal either.

It's worth pointing out that this game follows a “campaign” like structure. For a rouguelite, simply having to try again would suffice, but I want to avoid making the player retry anything more than just their current level.

# Answer
> 43 votes
I think you should embrace the choice to deliberately underpower themselves as another expression of player autonomy. This is a play pattern you'll often see in speedrunning communities, or players showing off for a stream: "look, I'm so good at this, I can get X far / beat the game with just the starting loadout!" — even/especially in notoriously challenging games like Souls-likes.

So that's a vote against forced upgrades or scaling difficulty to match the upgrade level.

Scaling difficulty to upgrades also risks hitting the other side of the Red Queen effect: rather than needing to upgrade just to avoid falling behind, now even *when* the player upgrades, they *can't get ahead*. The difficulty scaling adjusting to balance out upgrades can rob the player of a tangible sense of growth or impact of their choices. Ideally you'll usually want the difficulty steps slightly offset from the upgrade opportunities, so players have a chance to use their new toys at the old difficulty and feel how much more powerful they are now, before the challenge escalates to demand that new power just to survive.

---

An alternative approach you could take is to offer backup upgrades "just in time" when it becomes a problem. Say, if the player dies twice on the same world, a rescue ship picks them up to drop them at the start of the current level again, and the player has a choice to purchase upgrades from the rescue ship.

This way, a player who's successfully playing the game with a lower upgrade level than you planned for doesn't get pressured/badgered into buying upgrades they don't need: the rescue ship never comes to them.

But a player who thought they could do one more world without upgrades and discovers they were wrong has an opportunity to fix the mistake after a limited amount of frustration/setback that you can control, by choosing how many deaths trigger the rescue.

Players are disincentivized from just upgrading willy-nilly because they have to die for it — something they'll often avoid out of pride or to avoid delays/re-doing sections, even beyond any extra penalties you might impose. A death counter reported on the game-end screens can be enough to strongly motivate players to keep that number low. You can even add a range of randomness so the rescue, they can't predict exactly how many deaths it will take. The net effect is that players will mostly try to survive the whole world and upgrade at the regular shop as intended. This can be further incentivized by giving the world-end shop better selection than the just-in-time version.

You can also limit the rescues/upgrades obtained on rescue to the number of upgrades passed up, if desired, to allow the player to use it only to catch up to where you planned them to be, rather than cheese it to get further ahead. But I might recommend letting the player buy past the planned upgrade level — this gives some in-built player-controlled difficulty and can improve the game's accessibility, while staying unobtrusive to players who don't want or need it.

This can of course take different forms depending on your game's fiction: a wormhole anomaly littered with junk you can salvage for upgrades, an ancient alien vessel with mysterious motives, divine intervention, or maybe you don't even dress it up in fiction at all and just present it as a non-diegetic menu like the "Continue?" screens of old.

# Answer
> 17 votes
One of my favourite games from childhood, Zeliard, solved this particularly well I think. The player could always go back to previous worlds, re-visit old shops, look for missed treasure, etc. The maps were often asymmetrical and going back was often different from going forward (e.g. could just jump off some ledge going back, versus finding some long way to climb it going forward), making this more interesting. Also, in more advanced worlds the player could get items that made traversing earlier worlds different and much easier (e.g. boots for higher jumps, ability to go through fire or water, better weapons), this made these "backwards trips" much less painful than they sound, and often fun and interesting. I may be mis-remembering some details but that was the gist of it, and I think it can work well if done right.

# Answer
> 7 votes
There are many solutions:

* Allow backtracking. Two approaches:
    + Allow grinding. Many games allow you to replay old stages to grind for money or experience to get strong enough to clear the next stage. Some people prefer to be overpowered all the time. **This means players can always win.**
    + Allow backtracking, but cap the rewards. Think along the lines of mobile games where you get 0-3 stars for clearing a level and you use stars as currency to unlock something. **If a bad build is possible with max stars, then this doesn't completely solve the problem.**
    + (Side note) You can also make backtracking a standard part of the game, by making some rewards unobtainable until later progress has been made (as suggested by Eugene Osovetsky. I want to say the Metroid games do this, but i haven't played them in years--Cereza and the Lost Demon definitely does this well.
* Allow respec. Maybe once per char or with some sort of reasonable cost. If the character uses their respec chance, they can get all their money back (at once), then maybe they get presented with all of the items they've seen so far with the chance to repurchase, smarter. This can make the game trivial though--for roguelikes it's sad when you try for a specific build but RNG doesn't go your way and you end up very weak, but that rarity is what makes it fun. If you could always make the most of whatever the RNG gives you, the game becomes much much easier.
* Don't make a failing build possible. If the player doesn't have enough money, you can still give them a free item for clearing the level that is enough to go by. In this case, money doesn't make you "strong enough", it makes the game simpler (overpowered) or more interesting (more unique toys. fight with a gun instead of a sword, etc).
* Consider intermingled systems. If you use a level-up system and backtracking, even if the player can't get money from backtracking they should still eventually get strong enough just from levelups to be able to progress.
* Make bad builds possible and part of the learning experience. Assuming your game isn't insanely long, you can just let players restart when their build fails. Throw in some RNG and you have a "rogue-like". Trying new builds or making the best of what is presented to you in each run becomes the fun part. **GG, try something new next time!**
* Embrace the difficulty. As long as there are no unwinnable situations, being difficult is not actually bad. Just make sure there are no places where you need a minimum jump strength to clear and no bosses/enemies/scenarios that deal unavoidable damage greater than the player's HP. If you have an HP system, consider making some attacks percent-based rather than fixed number based. **It's not a problem, it's a feature**
* From a comment by a user without a username: You can let the player know that they are becoming underpowered. If YOU know that they are underpowered, then you can let a dialog or NPC tell them. Or you can do something similar to what Genshin Impact does with "artifacts" (equipment)--have a dialog/GUI element that shows what *other players* choose.
* Simpler than the last suggestion--write "Recommended!" or "Recommended for newbies!" under some set of items that gives the player at least the minimal viable build.

---

A few side notes:

* Games where you're *expected* to die a million times as you learn attack patterns, etc, to pass the game are called 死にゲー (she-knee-gay) in Japanese. The first and last options fall under this category. Dark Souls and the original Super Mario games fall under this category.
* Unwinnable situations are okay if it's a game built for replay. The concept of a "DPS check" is when there is an opponent that you cannot defeat unless you can do a certain amount of damage quickly--timed fights or opponents that heal. A health/armor check is when you take a guaranteed hit and if your HP is too low, you cannot win. You can extend this logic to things like jumping or money, etc, which create hurdles for the player in your replayable game. "Remember, DPS check at level 12, health check at level 25, money check at 30!"

# Answer
> 5 votes
Offer the shop also at the beginning of each level but with a caveat. You have to complete a short bonus level at (current difficulty - 1) to access it. It could be about rescuing the shop keeper or opening up his blocked trading routes etc...

Also consider making the "end of world shop" better than the "start of level shop" for example by having a broader selection or discounts. Keeping the difficulty slightly below the current difficulty ensures that the player is always able to reach the "start of level shop" since he has already proven he can mange that content to reach the current level.

# Answer
> 1 votes
Maybe you could make the player choose between 3 upgrades at the end of each world. The upgrades should be free and it should be mandatory to pick one.

This way the player gets rewarded for finishing several levels and he gets to choose his play style for the next few levels.

Possible upgrades could be more powerful but slower / faster but weaker projectiles, more shield / health, faster or more maneuverable ship etc.

This system is similar to what you can find in games like Vampire Survivors where every level you HAVE to pick an upgrade for your character and thus you can influence the way you play one upgrade at a time.

# Answer
> 1 votes
If:

* you are ok with giving players access to the shop more often than once per world, and
* you have some kind of overworld map or mission-select menu,

you could allow players to access the shop at any time they aren't in a level. This ensures that upgrade decisions are still impactful since you're locked into them for the duration of a level (or at least until you quit out of it), but gives the player plenty of opportunities to dig themselves out of a hole.

# Answer
> 1 votes
As @DMGregory said, I think you should allow players to have the option of going through the game without buying any upgrades, as a sort of self-imposed challenge. I released a scrolling shooter of my own last year (a bullet hell game, to be precise), and I decided to do exactly that: allow players to leave the upgrades screen at the end of each level without buying anything.

My exact approach was one that hasn't been mentioned yet: if the player doesn't buy any upgrades, either by choice or because they can't afford to, they're given some kind of gameplay bonus in exchange. In my case, it was a score multiplier that increased every time they cleared a stage without buying anything. This created an inherent risk/reward system: if you made the game harder for yourself, either by accident or by choice, you got more points for it.

If your game doesn't focus on high-scores, you can think of some other gameplay benefit to provide players, that will reward them for choosing not to upgrade (or compensate them if they do it by accident or necessity). There have already been plenty of good suggestions about this in the other answers.

# Answer
> 1 votes
Here's a slightly different suggestion. If you're worried about players getting stuck, how about offering a special "repair shop" when they've failed? This way, if they struggle, they've got the option of purchasing upgrades.

You could require them to fail a number of times before they see it. This way, it won't impact players that haven't been having any problems (or just the occasional failure), so your main use case still works as intended, and you've got this system to help people that are struggling.

# Answer
> 0 votes
Another approach I've seen here is to make upgrades and rewards increase in expense while providing more or less linear benefit. E.g. Your first +5 armor costs 10 hardtogetium, your second costs 20, your third costs 30 and so on. Similarly, the rewards you get for blowing up a level 1 Ugly is 1 hardtogetium, a level 2 is 2, a level 3 is 3, and so on.

If you only have a small number of upgrade paths this can feel like railroading - it makes no sense to boost your weapons a little if you can bring your armor up to par for the same price. But if you have multiple options it opens up more strategies. E.g. do you have moderately good missiles and lasers, or super missiles? Etc.

# Answer
> 0 votes
Let players set game difficulty.

Easy difficulty: players are able to replay previous worlds/levels *with their current upgrades*, upgrades they buy in these retries of course stay; or make each subsequent shop automatically have all of the unbought equipment from previous shops, so that they can grind their way to whatever they wish to buy just by replaying the current level over and over again; etc.

Hard difficulty: None of the above is included. By design, players *can* get locked out by choosing what to buy poorly or by failing to obtain enough coins in previous levels, etc. Put a warning that players are expected to know the game beforehand before attmpting Hard difficulty. That way, also, easier levels will no longer be just a waste of time when replaying the game, to be 'skipped' in order to get to harder levels ASAP; it will actually matter how well you pass easier levels. Especially so if you will have to plan your upgrades for harder levels, so that they are not as perfect for easier levels as they could be.

# Answer
> 0 votes
You're talking about difficulty in general. Instead of scaling difficulty you can add increase the number of challenges the player faces instead, i.e. damage types, movement patterns, different enemy behaviour etc.. This way a player has different approaches but doesn't feel 'weak'.

Personally I like the idea with a mandatory upgrade at the end of each world and temporary power-ups inside a level. This way you hand the player all the tools to complete the game. You could also add loadouts that the player chooses before each level. This allows for player automomy and allows individual challenges

# Answer
> -1 votes
For player that intentionally not buying any stuff. Its their choice, they will learn it the hard way. Let them be.

For player that cannot buy any stuff because they didn't beat the whole level, it's either your level is too hard or they are too weak.

Essentially the actual problem is player may not fully utilize their money due to simply a mis match of money.

Introduce debt system where user can have -10 debt or even -100 debt and only allow debt when money is \>0.

So money can be fully utilize.

---
Tags: game-design, difficulty, progression
---


# Question
Title: Grid-Based pathfinding with object size. Avoid colliding into big-enough spaces
I already implemented a Grid-Based pathfinding algorithm and I works. I also updated it so it takes into account the objects size and ignores paths where the object wont fit. However, I ran into a problem.

My project so the object get a list of the cell it must traverse to get to the objective and when the current cell is the next one in the list, it removes it and waits for that to happen in the next cell. But this leads into a problem, beacuse sometimes the object should theoretically fit into a space but I wont place exactly in the middle of the aperture and wont be able to traverse.

I would like to know if this is a common problem in gamedev, and if so, what is the general approach.

What I've tried:

* Checking if the colliding is happening (for instance) if the left side of the object, if so, moving it to the right until it fits. It work but doesn't feel to elegant.
* Making it so the paths are expressed into an offset grid system, so the object moves between cells. This work for the case of two-cells-sized object, but when it comes to three cells we get into the same problem.

Thank you.

# Answer
> 0 votes
Grow the obstacle such that the narrow paths get narrower and then path find using the standard sized object:

The red part in the grid is the expansion of the obstacles while the red part on the object is the part that got cut off.

That way the object will position itself correctly. but for object collision the respective red parts don't collide with each other.

---
Tags: path-finding
---


# Question
Title: How to rotate NavMeshAgent toward its movement direction?
I'm working on a 2D game in XY plane. I've created enemies using NavMeshAgent and I've gave my agents way pints to move between them. The problem is that I don't know how to rotate them in the direction they are moving or vector of the velocity (blue arrow). The front of the agent is in the direction of Y axis(green arrow). Note that updateRotation isn't an option, That will rotate agent and make it disappear(agent rotates 90 degree around X axis).

*Blue arrow is vector of the velocity*

Please provide a code along your ideas.

```
    void FaceTarget()
    {
        Vector3 lookTarget = agent.velocity.normalized;
        float angel = Vector3.Angle(lookTarget, Vector3.up);
        transform.rotation = Quaternion.Euler(0,0,angel);
    }

```

I've tried this code, It calculates the angel between the vector of the velocity and local Y axis. Desired output is that agent rotates toward its movement direction. In the actual output, agent rotates, But in some points, It's not toward the movement direction. I know the problem is that angels range is \[0,180\], not \[0,360\], But I couldn't figure out any solution for it.

# Answer
> 0 votes
You can avoid the trig and angles by using the `LookRotation` helper method in a slightly different way:

```
void FaceTarget() {
    var vel = agent.velocity;
    vel.z = 0;

    if (vel != Vector3.zero) {
        transform.rotation = Quaternion.LookRotation(
                                Vector3.forward,
                                vel
        );
    }
}

```

This uses the fact that `LookRotation` points the object's local z+ axis (blue arrow on the local translation gizmo) to point toward the first argument. Here we provide the global z+ direction, so the sprite stays correctly oriented in the XY plane.

Then `LookRotation` twists the object around that vector so that its local y+ axis (green arrow) points toward the second argument. By providing the velocity, we neatly rotate the front of the unit to face its velocity, without needing to compute the angle explicitly.

# Answer
> 0 votes
I've solved it with help of ChatGpt. Here's the code

```
void FaceTarget()
{
    if (agent.velocity != Vector3.zero)
    {
        Vector3 moveDirection = new Vector3(agent.velocity.x, agent.velocity.y, 0f);
        if (moveDirection != Vector3.zero)
        {
            float angel = Mathf.Atan2(moveDirection.x, moveDirection.y) * Mathf.Rad2Deg;
            transform.rotation = Quaternion.AngleAxis(angel, Vector3.back);
        }
    }

}

```

---
Tags: unity, 2d, rotation, navmesh
---