Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AnimationPlayer "seek" behaves differently in Godot 4.2. #85600

Closed
TheFoxKnocks opened this issue Dec 1, 2023 · 22 comments
Closed

AnimationPlayer "seek" behaves differently in Godot 4.2. #85600

TheFoxKnocks opened this issue Dec 1, 2023 · 22 comments

Comments

@TheFoxKnocks
Copy link

TheFoxKnocks commented Dec 1, 2023

Godot version

v4.2.stable.official [46dc277]

System information

Godot v4.2.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3080 (NVIDIA; 31.0.15.3623) - 12th Gen Intel(R) Core(TM) i9-12900KF (24 Threads)

Issue description

Here's code I'm using, which worked totally fine and without problems in Godot 4.1:

func attack_state():
	# Grab the current frame of animation.
	anim_frame = anim.current_animation_position

	if movement_vector.x == 0 and movement_vector.y == 0:
		anim.play(str(character) + "/Attack")
	else:
		anim.play(str(character) + "/Run_Attack")
	# Make sure that the animation retains its position to allow for seamless
	# Attack and Run Attack transitioning.
	anim.seek(anim_frame)

This is called whenever the player is attacking, detected and ran inside _physics_process.

In Godot 4.1, it would play the animations correctly. In Godot 4.2, it displays the first frame of animation and does not properly play the animation. This is either a change in seek or current_animation_position (or both), where it's now continuously grabbing the first frame of animation and only playing that.

I wasn't aware that this had changed, so if there's a new way to approach this, I'd love to know about it.

Steps to reproduce

Example given above.

Minimal reproduction project

MinimalReproductionProject.zip

@TheFoxKnocks
Copy link
Author

I tested this again by exporting the game without Debug, and the animations actually play properly there, but it also lags the game pretty intensely when it's happening.

@Lippanon
Copy link

Lippanon commented Dec 1, 2023

Can you please provide a Minimal Reproduction Project to make it easier to troubleshoot?
Perhaps related to recent PRs: #85221 / #85366

@TheFoxKnocks
Copy link
Author

Can you please provide a Minimal Reproduction Project to make it easier to troubleshoot? Perhaps related to recent PRs: #85221 / #85366

Not to be rude but making such a project is not something I want to do. One of those PRs you linked to says it was completed, has the fix for those specific bugs been fixed in 4.2 already? Like, are they live on the stable version?

Because they definitely sound like the problem I'm experiencing.

@AThousandShips
Copy link
Member

AThousandShips commented Dec 1, 2023

We'd prefer a minimum reproduction project to be able to test it, so if you're not able or willing to do that it will likely be closed because it's hard to test

@TheFoxKnocks
Copy link
Author

If you think it's the same bug then we can close this in favour of them, but otherwise we'd prefer a minimum reproduction project to be able to test it, so if you're not able or willing to do that it will likely be closed because it's hard to test

I don't mind, but I was curious to know if those have fixes pushed or how that works. I'm relatively new to the whole Github thing, none-the-less Godot's Github. I'd be interested in testing fixes to see if it resolves the problem.

@AThousandShips
Copy link
Member

Likely caused by those PRs I think is what was meant here 🙂

@TheFoxKnocks
Copy link
Author

TheFoxKnocks commented Dec 1, 2023

Likely caused by those PRs I think is what was meant here 🙂

Ah, thanks. So, I went ahead and started working on a project and the issue doesn't involve any of that. Just this:

func _physics_process(_delta):
	anim.play("idle")
	
	# Test key is defined as "E" on your keyboard.
	if Input.is_action_pressed("test_key"):
		test_run()


func test_run():
	# Testing was originally being done with the following 2 variables not commented out.
	# However, it was discovered that the problem persists even without them.
	#var anim_frame = anim.current_animation_position
	
	anim.play("run")
	
	#anim.seek(anim_frame)

Just the act of having it play another anim has that other anim freeze. I can provide this project, but I don't know what I should be exporting and where I would even do it.

Unrelated, I don't know why it keeps chopping my code blocks up like this.

@AThousandShips
Copy link
Member

You need to use three back ticks for multi line code, fixed for you but keep in mind

@TheFoxKnocks
Copy link
Author

You need to use three back ticks for multi line code, fixed for you but keep in mind

Ah, just like Discord then. Good to know.

How should I go about exporting the project? Apologies, new to this sort of thing like I said.

@AThousandShips
Copy link
Member

See the instructions from the issue report:

  • A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the .godot folder in the archive (but keep project.godot).
  • Drag and drop a ZIP archive to upload it. Do not select another field until the project is done uploading.
  • Note for C# users: If your issue is not Mono-specific, please upload a minimal reproduction project written in GDScript or VisualScript. This will make it easier for contributors to reproduce the issue locally as not everyone has a Mono setup available.

@TheFoxKnocks
Copy link
Author

MinimalReproductionProject.zip

Let me know if that's alright?

Thank you, by the way.

@TokageItLab
Copy link
Member

TokageItLab commented Dec 2, 2023

From what I have seen of the MRP, it is not working correctly as of 4.1.1. By the way, the reason this code is not working is in the GDScript, play() resets if a different animation is played. If you look at the gdscript, you will see that it always plays "idle" before "run", so the reset is happening at this time; it is a wrong way for playback.

@TokageItLab TokageItLab closed this as not planned Won't fix, can't repro, duplicate, stale Dec 2, 2023
@TheFoxKnocks
Copy link
Author

From what I have seen of the MRP, it is not working correctly as of 4.1.1. By the way, the reason this code is not working is in the GDScript, play() resets if a different animation is played. If you look at the gdscript, you will see that it always plays "idle" before "run", so the reset is happening at this time; it is a wrong way for playback.

This actually worked in my project with 4.1.3 just fine. But, if it's a case of where it shouldn't have worked and I was just somehow getting lucky that it was, then that's totally fair, but that's why I thought it was a bug.

I would be interested in learning what the correct way to approach this is instead.

@TokageItLab
Copy link
Member

TokageItLab commented Dec 2, 2023

just don't play different animations before playing "run"

func _physics_process(_delta):
	# Test key is defined as "E" on your keyboard.
	if Input.is_action_pressed("test_key"):
		test_run()
	else:
		anim.play("idle")

@TheFoxKnocks
Copy link
Author

TheFoxKnocks commented Dec 2, 2023

just don't play different animations before playing "run"

func _physics_process(_delta):
	# Test key is defined as "E" on your keyboard.
	if Input.is_action_pressed("test_key"):
		test_run()
	else:
		anim.play("idle")

In the test project, if the idle animation is commented out and you hold E, the run animation plays, but it's slower than when you let go of E (and the run animation continues to play because it's no longer reverting back to idle).

Is this intentional? Is there a better way to seamlessly transition between animations?

The wall I'm running into here is that 4.2's change to this system made tackling this very tricky. If I have an attack animation (player is idle), and a run_attack animation (player is running) with the same number of frames, and the player can idle or run at any point in the animation freely, then I want Godot to transition between the two smoothly.

I was achieving this with grabbing the frame and applying it, but it's inconsistent in Godot 4.2.

@TokageItLab
Copy link
Member

TokageItLab commented Dec 2, 2023

func _physics_process(_delta):
	# Test key is defined as "E" on your keyboard.
	if Input.is_action_pressed("test_key"):
		play_by_swapping("run")
	else:
		play_by_swapping("idle")


func play_by_swapping(animation_name: String):
	# Testing was originally being done with the following 2 variables not commented out.
	# However, it was discovered that the problem persists even without them.
	var anim_frame = anim.current_animation_position if anim.is_playing() else 0
	anim.play(animation_name)
	anim.seek(anim_frame)

There is currently a bug in seek(), but it should work correctly after #85569 merge.

@TheFoxKnocks
Copy link
Author

func _physics_process(_delta):
	# Test key is defined as "E" on your keyboard.
	if Input.is_action_pressed("test_key"):
		play_by_swapping("run")
	else:
		play_by_swapping("idle")


func play_by_swapping(animation_name: String):
	# Testing was originally being done with the following 2 variables not commented out.
	# However, it was discovered that the problem persists even without them.
	var anim_frame = anim.current_animation_position
	anim.play(animation_name)
	anim.seek(anim_frame)

This works, thank you, but... I don't quite understand why this works and the old code didn't? It looks very very similar. I know it's very off-topic to ask, but could you tell me why this works and the previous didn't? Is it related to the bug you edited your comment with?

@TokageItLab
Copy link
Member

I don't know since that MRP doesn't seem to work in 4.1.3 either. Perhaps you were trying a different code.

@refeals
Copy link

refeals commented Dec 3, 2023

Happened to me too. Running my project in 4.2 broke the animations that use seek method. Went back to 4.1.3 and it's all fine.

I can provide a small project to reproduce it, but doesn't seem too different from what's above. This is pretty much the code:

func update_anim():
	# ...
	if p.velocity.x == 0:
		p.animation_player.play("idle")
	else:
		var current_animation_position = p.animation_player.current_animation_position
		p.animation_player.play("run")
		p.animation_player.seek(current_animation_position)

Seems like the implementation for seek changed in 4.2. The animation would lock on the first frame forever. Commenting the last line would fix the lock, but animations obviously don't work as expected. Adding a true to the second parameter removes the lock, but still doesn't work as expected. I don't think the third parameter changed anything.

@TokageItLab
Copy link
Member

RC had a serious bug in the seek, but it should be fixed in stable and later versions, so please try newer versions as much as possible.

@TheFoxKnocks
Copy link
Author

RC had a serious bug in the seek, but it should be fixed in stable and later versions, so please try newer versions as much as possible.

This is with stable. Is there a new update I'm not aware of? I included my version in the main post.

@refeals
Copy link

refeals commented Dec 6, 2023

@TheFoxKnocks I think he meant to wait for newer versions, probably 4.2.1 or something like that. Plus help testing on new RCs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants