Objective Indicator System

In modern games, many include an objective indicator system similar to the one shown below:

I’ve attempted to implement something similar, but my efforts haven’t been successful. I’m struggling to make progress and could really use some assistance. Could anyone help me out?

Hi @Rafael_Alves!

Which part do you have trouble with?

The part of the Ui i try a 3D UI but the indicator does not was fixed at the objective point, try to render in world and ui layer and so on… I’ve created the objective system, but the ui part is not good

I tried to create a similar system, but unfortunately I was unable to make this stable. Below some related topics about this.

Thanks i’ll be updating my advances at this post

1 Like

Progress

The objective indicator is done, but i’m having problems to show the distance of the objective to the player… This is happening because the way i found to create the objective indicator’s not using the ui system…

The demo

Demo Video

And a little of my inventory system on the demo too.

Good job so far.

You can create a child entity of the object and add a text element to show the distance. Give it a script to always face the camera.

The problem I personal had was showing the indicator on the right position when the object was behind the camera, if I remember correctly.

Can you share the script of the indicator? It will be nice to create an example project.

Dang what game is that?

Objective Indicator

var PointToTarget = pc.createScript('pointToTarget');

PointToTarget.attributes.add('target', { type: 'entity', title: 'Target' });
PointToTarget.attributes.add('distanceFromA', { type: 'number', default: 5, title: 'Distance from A' });
PointToTarget.attributes.add('minDistance', { type: 'number', default: 10, title: 'Min Distance for Indicator' });

PointToTarget.prototype.initialize = function() {
    const player = this.entity.parent || this.app.root.findByName("player");

    if (!player || !this.target) {
        this.entity.render.enabled = false;
    }

    this.cameraEntity = player.findByName("Camera");
    if (this.cameraEntity) 
        this.camera = this.cameraEntity.camera; 
};

PointToTarget.prototype.update = function(dt) {
    if (!(this.camera && this.target)) {
        this.entity.enabled = false;
        return;
    }

    const positionA = this.cameraEntity.getPosition();
    const targetPosition = this.target.getPosition();
    
    const distanceToTarget = positionA.distance(targetPosition);

    if (distanceToTarget < this.minDistance) {
        this.entity.render.enabled = false;
        return;
    }else this.entity.render.enabled = true;

    this.entity.enabled = true;

    const direction = new pc.Vec3();
    direction.sub2(targetPosition, positionA).normalize();

    const newPosition = new pc.Vec3();
    newPosition.copy(positionA).add(direction.scale(this.distanceFromA));

    this.entity.setPosition(newPosition);
    this.entity.lookAt(targetPosition);

    this._clampToScreen(newPosition);
};

PointToTarget.prototype._clampToScreen = function(worldPosition) {
    const screenPosition = new pc.Vec3();
    this.camera.worldToScreen(worldPosition, screenPosition);

    const padding = 10;
    screenPosition.x = pc.math.clamp(screenPosition.x, padding, this.app.graphicsDevice.width - padding);
    screenPosition.y = pc.math.clamp(screenPosition.y, padding, this.app.graphicsDevice.height - padding);

    const clampedPosition = new pc.Vec3();
    this.camera.screenToWorld(screenPosition.x, screenPosition.y, screenPosition.z, clampedPosition);

    const dist = clampedPosition.distance(this.cameraEntity.getPosition());

    if (dist <= 0.8) {
        const direction = new pc.Vec3();
        direction.sub2(clampedPosition, this.cameraEntity.getPosition()).normalize();

        clampedPosition.copy(this.cameraEntity.getPosition()).add(direction.scale(0.8));
    }

    this.entity.setPosition(clampedPosition);
};

I’m workin in a version that spawn the indicator based in objectives and change the objective reading gameState, this version is actually simple

1 Like

Thanks for sharing!

It works well, but I have a few notes.

  • If you use postUpdate instead of update you get a more smooth result.

  • When the target is behind the camera, the indicator is not visible. I remember now, I personally also wasn’t be able to get the indicator on the right position when the target was behind the camera.

  • It currently doesn’t work correctly on a mobile device with Device Pixel Ratio enabled. Personally I always enable this option in the project settings, to get a good looking project on mobile devices as well.

Thanks for the advice! I’ve switched to using postUpdate as you suggested, and it’s definitely giving smoother results.

Regarding the indicator visibility when the target is behind the camera, I’ve tried clamping the position to create an imaginary circle around the player. While it hasn’t fully solved the issue with objects behind the camera, I believe this approach has potential—it just needs some refinement.

As for the Device Pixel Ratio could you guide me on how to enable this? I’m still quite new to PlayCanvas

I expect the indicator to be on the bottom of the screen when the target is behind the camera. Basically the same as when the target is in front of the camera, the indicator is on top of the screen.

You can enable this option in the project settings.

The page below give you some more information about this option.

1 Like