Is it possible to make crosshair tween more smoother

Sorry to ask again, but what does tweenTop and what does tweenBottom? Both use a yoyo effect?

tweenTop moves the reticle up on the y axis with the dynamicScale variable which is a number (depending on the number it moves further away from its original pos). Initially I thought yoyo would automatically revert tween back to its original spot but that did not work so I created a tweenBottom that then moves the reticle back down to 0 on the y axis (to its original position) I just left the yoyo in there I should remove it.

The dynamicOutSpeed and InSpeed are the speed at which the reticles move.

I think you need to add .repeat(1). Try to use one tween first because otherwise you are unable to see whatā€™s going on.

Alright, so first of all, you donā€™t want to use update method, which is executed every frame. That will stop/start tween every frame. All you need is a mouse down/up event, really.

Secondly, you donā€™t want to use yoyo. Instead, get the farthest local position and tween between original and that position. This is because every time you start a new tween, you are reading the current position of the reticle, so yoyo will return it to whereever it is currently, rather than to the starting position.

And lastly, you want one tween for spreading reticle out, and another for inward motion. When mouse is clicked down, you stop any inward motion, and start spreading out. When mouse is released, you do the opposite.

    initialize() {
        const topReticle = this.topReticle;
        const maxOutPosition = new pc.Vec2(0, 1); // or whatever is the position at maximum spread
        const localPosition = topReticle.getLocalPosition();
        const originalPos = localPosition.clone();
        const dynamicOutSpeed = 0.5; // or whatever speed you have

        this.topTweenOut = topReticle.tween(localPosition)
            .to(maxOutPosition, dynamicOutSpeed, pc.Linear)
            .loop(false);

        this.topTweenIn = topReticle.tween(localPosition)
            .to(originalPos, dynamicOutSpeed, pc.Linear)
            .loop(false);

        this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
        this.app.mouse.on(pc.EVENT_MOUSEUP, this.onMouseUp, this);
    }

    onMouseDown() {
        this.topTweenIn.stop();
        this.topTweenOut.start();
    }

    onMouseUp() {
        this.topTweenOut.stop();
        this.topTweenIn.start();
    }

2 Likes

Wow thank you @LeXXik this is really good! I did the same for all 4 reticles and the animation is really smooth. Just what I was looking for, this helped me learn a lot.

As for not using the tween in the update function I did not know this. Following that I have 2 questions I would like to ask:

Previously on the const maxOutPosition = new pc.Vec2(0, 1) I originally had an attribute tied in here called dynamicScale instead of the 1. That would allow me to change the spread amount in real time since it was in the update function. But because this is now inside the init() Iā€™m having trouble implementing this as I cannot change the value at run time anymore. What would be the best way to get around this?

Another question that is related to the above is that I have a large number of attributes on my crosshair script that do various things like (change size of crosshair, change reticle thickness, reticle height, reticle colour etc.). I put all these inside the update function too so I could update these values in real time as well. What I want to know if this is the correct way to do this? Could I optimise this better somehow or is it fine as it is?

Would appreciate your guidance :slight_smile:

also I noticed that you used es6 class syntax I think which also made me excited :smiley:

Not sure what you mean by ā€œreal timeā€, but you can change your tween duration at any point by assigning it a new value like this:

this.topTweenIn.duration = 1.5;

If you are changing something gradually, every frame, for example, moving an entity bit by bit every frame, then it must be done by updating its property in an update method. There is no other way (except shaders) and it is absolutely fine to do so.

The question you should ask yourself, if you really need that property to be changing every single frame, or just on some events, like with the mouse click. For example, changing a color: if you do a gradual transition shade by shade from frame to frame - then you need an update method. If instead your color change is instantenous, then you only need a single frame and you can change it on some event instead.

A frame has a limited budget of time for various operations, like changing a color of an element. You have about 16 ms per frame for a 60 FPS experience. The more you do during that frame, the less time you have for something else. If something does not need to be done each and every frame (like a moving object), donā€™t use the update method.

2 Likes

By real time I mean

1

When I change those values it updates during launch. The dynamicScale is now inside the init() instead of update() like: maxOutPosition = new pc.Vec2(0, dynamicScale) so I cannot change the dynamicScale during launch anymore.

I guess when I have something like a menu/gui then I will need to fire mouse events instead to change the size of the crosshair or colour etc. whilst the game is running. For now I am just using this as a workaround to make it so I can change the values quickly without having to re-launch every time.

You can listen the attribute change event and act on it. You can find more details in the manual:

https://developer.playcanvas.com/en/user-manual/scripting/script-attributes/#updating-attributes

2 Likes

Thanks that looks exactly like what I want. I will check that out!

Thanks for all your help.

Also thank you too for your help @Albertos

1 Like