Is it possible to make crosshair tween more smoother

Hello

So I have been experimenting with tween in order to create a dynamic crosshair. So far I got something which works well, the only problem is the animation is a bit laggy/jittery in the editor when I spam click the mouse button. Is there anyway I could make it more smoother so when the reticles are moving up and down they do not blur.

Here is what it looks like:

Here is the code snippet I used for all 4 individual crosshair reticles (inside the update function):

if (this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT)) {
        this.topReticle.tween(this.topReticle.getLocalPosition())
        .to(new pc.Vec2(0, this.dynamicScale), dynamicOutSpeed, pc.Linear)
        .loop(false)
        .yoyo(true)
        .start();
    }
    else {
        this.topReticle.tween(this.topReticle.getLocalPosition())
        .to(new pc.Vec2(0, 0), dynamicInSpeed, pc.Linear)
        .loop(false)
        .yoyo(true)
        .start();
    }

Because you click rapidly, a new tween may start, while another one is still in progress. You should stop an old tween first, before starting a new one with entity.tween.stop() .

2 Likes

As an alternative to the solution of @LeXXik, you could also wait for the old tween to finish before starting a new one. I did something similar in the post below.

1 Like

I added this to my script but the reticle still overlaps and becomes blurry when you rapid click. It seems still the same unless I implemented it wrong?

I just added this.topReticle.tween(this.topReticle.getLocalPosition()).stop() underneath the start tween.

It should be this.topReticle.tween.stop() before starting a new one.

2 Likes

When I try that I get: this.topReticle.tween.stop is not a function

Hmm, I was under impression it would work. Need to check sources to see if that chaining is not valid.

Anyhow, you can save the tween into a variable, and call a stop on it:

if (this.tween) this.tween.stop();
this.tween = this.topReticle.tween( // your tween code
2 Likes

Sorry I am very confused how to implement this altogether.

I thought this would work as an example:

this.tween = false;
    
this.tweenUp = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, this.dynamicScale), dynamicOutSpeed, pc.Linear).loop(false).yoyo(true);
this.tweenDown = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, 0), dynamicInSpeed, pc.Linear).loop(false).yoyo(true);
    
    if (this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT)) {
        this.tween = true;
        this.tweenUp.start();
    }
    else {
        this.tweenDown.start();
    }
    
    if (this.tween) {
        // statement to stop all tweens
        this.tweenUp.stop();
        this.tweenDown.stop();
        // left
        // right
    }

Whatever I tried i can not get it to work. I think I am missing something easy but I feel very confused where I am going wrong. :frowning:

As far as I can see I think it should more look something like below.

    this.tweenUp = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, this.dynamicScale), dynamicOutSpeed, pc.Linear).loop(false).yoyo(true);
    this.tweenDown = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, 0), dynamicInSpeed, pc.Linear).loop(false).yoyo(true);
    
    if (this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT)) {
        this.tweenDown.stop();
        this.tweenUp.start();
    }
    else {
        this.tweenUp.stop();
        this.tweenDown.start();
    }
2 Likes

This is how I did it originally without converting them to variables, but It still seems the same. The reticle overlaps itself causing a blurry image the more you click it.

You should try to imagine what your code does when you press the left button several times in a row. Your description matches what I imagine. Your tween will start and stop one after the other causing you to see short movements.and makes it look bad, like your first video. That’s why I suggested before to wait for the tween to finish before you start another one.

1 Like

In the code below I have added the function to know if the tween is complete. I don’t run the new tween until the old tween is finished. I haven’t been able to test this yet, so I’m curious what the result will be. Hopefully you don’t get a syntax error because I’m not a tween expert.

    this.tweenUp = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, this.dynamicScale), dynamicOutSpeed, pc.Linear).loop(false).yoyo(true).on('complete', function () { this.tweenUpIsComplete = true; });
    this.tweenDown = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, 0), dynamicInSpeed, pc.Linear).loop(false).yoyo(true).on('complete', function () { this.tweenDownIsComplete = true; });
    
    if (this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT)) {
        if (this.tweenUpIsComplete && this.tweenDownIsComplete) {
            this.tweenUpIsComplete = false;
            this.tweenUp.start();
        }
    }
    else if (this.tweenUpIsComplete && this.tweenDownIsComplete) {
        this.tweenDownIsComplete = false;
        this.tweenDown.start();
    }
1 Like

Quick note here for the ‘complete’ portion here. Make sure you pass the correct scope when writing the anonymous function, that way the correct prototype is updated. The tween declarations would need to be updated to:

    this.tweenUp = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, this.dynamicScale), dynamicOutSpeed, pc.Linear).loop(false).yoyo(true).on('complete', function () { this.tweenUpIsComplete = true; }, this);
    this.tweenDown = this.topReticle.tween(this.topOutline.getLocalPosition()).to(new pc.Vec2(0, 0), dynamicInSpeed, pc.Linear).loop(false).yoyo(true).on('complete', function () { this.tweenDownIsComplete = true; }, this);
3 Likes

Thank you @eproasim! Also don’t forget to add the two rules below to your initialize function, otherwise the tweens will never start.

this.tweenUpIsComplete = true;
this.tweenDownIsComplete = true;
2 Likes

Thanks for the replies guys.

I used your method Albertos but the animation is very delayed. I played around with the speed of the reticles and made them faster but then the animation bugs out where if you spam lmb it looks like there is 10 reticles on the screen.

I dont know if I implemented LeXXiks suggestion correctly where everytime you click the tween stops and a new one starts.

Can you show the result please and do you have a example of what you try to achieve? I mean what does the crosshair has to do when you press the button, when you hold the button and when you release the button?

The video that I uploaded. The same as that but the only problem is that the reticles overlap making it look blurry.

Here are videos from a game that has something similar:

I’m trying LeXXiks suggestion but the problem is everytime I use stop() the tween overlaps the start() function so the animation never happens.

if (this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT)) {
        this.tween = true;
        this.tweenTop.start();
    }
    else {
        this.tween = false;
        this.tweenBottom.start();
    }
    
    if (this.tween && this.tweenTop) {
        // console.log('test') Here shows 'test' whenever you click or hold
        // but as soon as you add this.tweenTop.stop() below the animation never plays.
        this.tweenTop.stop();
    }

It seems your logic is wrong. If you start tweenTop in your first statement you stop tweenTop immediately in your last statement.

Im not sure what tweenTop and tweenBottom exactly is or do. Can you explain that please?

TweenTop and tweenBottom is same as TweenUp and TweenDown previously. I just used another name for testing purpose. So its just the top reticle (topReticle) tweening up and down functions.

Here is what I created in PlayCanvas to replicate the above video:

It is fine when the reticle is thin but when you make it thicker then the animation blurryness is more visible.

another problem is that: i made an attribute that changes the thickness of the individual reticles together but sometimes the left and right reticles look different to the top and bottom ones (left and right have more colour and look better while the top and bottom look out of colour and blurry) but that is not important for now.