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

Animations can no longer be "local to scene" #82421

Open
KnightNine opened this issue Sep 27, 2023 · 10 comments
Open

Animations can no longer be "local to scene" #82421

KnightNine opened this issue Sep 27, 2023 · 10 comments

Comments

@KnightNine
Copy link

Godot version

4.1

System information

Windows 10

Issue description

I can no longer modify an animation keyframes of an AnimationPlayer from one scene instance without that modifying it across all instances of that scene (resource_local_to_scene = true does not work seem to work for animations)

Setting resource_local_to_scene = true for the AnimationLibrary containing the animations doesn't seem to fix this issue either.


Example Code For Added Context:

extends Node2D
@onready var instance1 = get_node("instance scene")
@onready var instance2 = get_node("instance scene2")
# Called when the node enters the scene tree for the first time.
func _ready():
	#change animation color of instance1 to blue->red->blue
	var animplayer = instance1.get_node("ColorRect/AnimationPlayer")
	var anim:Animation = animplayer.get_animation("Test/new_animation")
	#this is already true within the scene 
	anim.resource_local_to_scene = true
	
	anim.track_set_key_value( 0, 0, Color.BLUE )
	anim.track_set_key_value( 0, 2, Color.BLUE )
	
	animplayer.play("Test/new_animation")
	
	#leave instance 2 white->red->white
	instance2.get_node("ColorRect/AnimationPlayer").play("Test/new_animation")
	
	#result: both turn blue

animation oof

So ultimately I'm forced to create multiple duplicate scenes for minor animation changes if there's no workaround for this.

Steps to reproduce

  1. create two scenes: one as the main and one to instance from.
  2. create a node in the latter scene to animate (e.g a ColorRect)
  3. create an AnimationPlayer to animate the node with a looping animation (e.g. make the ColorRect switch back and forth between two colors)
  4. make the Animation and the Animation Library local to scene
  5. instantiate these scenes into your main scene.
  6. create a script for the main scene that modifies the animation keyframes of one instance and starts the animations within _ready()
  7. run the project

Minimal reproduction project

GodotTest.zip

@bitsawer
Copy link
Member

bitsawer commented Sep 27, 2023

Considering the title, I assume this worked at some point in the past with some Godot version? Can you give a working Godot version so we might be able to consider this as a regression? Also possibly related: #82348 (comment), this might be a duplicate of that issue if this behavior is a bug.

Looks like the Animations in the AnimationLibrary are not duplicated even with resource_local_to_scene enabled. However, this might be intentional to save some memory as most people probably don't modify the animations directly. A workaround is pretty easy, duplicate the animation manually and add it with a new name.

extends Node2D
@onready var instance1 = get_node("instance scene")
@onready var instance2 = get_node("instance scene2")
# Called when the node enters the scene tree for the first time.
func _ready():
    #change animation color of instance1 to blue->red->blue
    var animplayer = instance1.get_node("ColorRect/AnimationPlayer") as AnimationPlayer
    var anim:Animation = animplayer.get_animation("Test/new_animation")
    var lib = animplayer.get_animation_library("Test") as AnimationLibrary
    #this is already true within the scene
    #anim.resource_local_to_scene = true

    anim = anim.duplicate()
    anim.track_set_key_value( 0, 0, Color.BLUE )
    anim.track_set_key_value( 0, 2, Color.BLUE )

    lib.add_animation("new_animation2", anim)
    animplayer.play("Test/new_animation2")

    #leave instance 2 white->red->white
    instance2.get_node("ColorRect/AnimationPlayer").play("Test/new_animation")

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    pass

@KnightNine
Copy link
Author

So this is still somewhat annoying when working with animations modified based on a value which may change based on context, I have to make a temporary animation and then delete it after it has been run so I don't end up piling up on a bunch of unused animations. Not having the option for local_to_scene animations just creates work and things to keep track of when you need to have variations of an animation.

hopefully this gets fixed eventually.

@DDarby-Lewis
Copy link

I am using animations modified per scene for character creation, e.g. modify arm length or head size. But not being able to set this as unique per scene is a killer to that way of working. Does anyone know how to reinstate this feature?

@KnightNine
Copy link
Author

KnightNine commented Nov 27, 2023

@bitsawer

Considering the title, I assume this worked at some point in the past with some Godot version?

Sorry didn't notice you asked till now. Yes it worked in 3.5

@LeifintheWind
Copy link

LeifintheWind commented Dec 10, 2023

Looks like the Animations in the AnimationLibrary are not duplicated even with resource_local_to_scene enabled. However, this might be intentional to save some memory as most people probably don't modify the animations directly. A workaround is pretty easy, duplicate the animation manually and add it with a new name.

Certainly could be used to save memory in general, but needing a workaround because resource_local_to_scene doesn't do anything is certainly frustrating. I've got a case where speech bubble sizes are controlled via animation. If there are two bubble scenes (instantiated separately) up at the same time, changes to their animation keys will change all of them.

In the first image, just one bubble sizes its width correctly via animation controller. In the second image, the smaller bubble was created before the first one was done animating. This results in the larger bubble's animation incorrectly sizing the width to be that of the smaller bubble.

image

image

@blDraX
Copy link

blDraX commented Jan 20, 2024

Thanks for this report. Unfortunately this issue also just cost me an hour. I couldn't figure out why modifying the animation in code during runtime would change it for all instances despite "Local to Scene" being checked. Glad I found this thread, that explains it.

I agree that it's counter intuitive that the property just doesn't work. If this is indeed the behaviour (I fail to understand why though?), maybe a debugger warning makes sense when this option is turned on for animations to make this transparent?

For others facing this issue: I used implemented the functionality I wanted using Tweens instead.

@Dartkun
Copy link

Dartkun commented Apr 25, 2024

Also lost an hour to this. Really frustrating that it doesn't work as you would expect it to.

Snaiel added a commit to Snaiel/Godot4ThirdPersonCombatPrototype that referenced this issue Jul 14, 2024
HOLY CRAP THAT WAS A HORRIBLE EXPERIENCE

I needed to modify the animated colors but doing so
would change for both the enemy and the player.

saw this reddit thread:
"Changing keyframes of animation player through
code changes it of every instance. Need help."

okay... someone said to just check Local to Scene.
fixed right? NOPE.

WHY? i dont know bro.

finally came across:
godotengine/godot#82421
Animations can no longer be "local to scene"

ah right it doesnt work lmao. bruh.

workaround: duplicate animation library, remove
original library, add duplicate library. for any animations,
duplicate the animation, remove the animation from the
library, add the duplicate animation to the library.
@Snaiel
Copy link

Snaiel commented Jul 14, 2024

Lost several hours to this. Workaround: duplicate the animation library and animations.

# Duplicate the animation library inside the animation player
var animation_player: AnimationPlayer = $AnimationPlayer
var animation_library: AnimationLibrary = animation_player.get_animation_library(&"")
animation_library = animation_library.duplicate()
animation_player.remove_animation_library(&"")
animation_player.add_animation_library(&"", animation_library)
# Duplicate the animation you want to modify
var animation_name: StringName = &"my_animation"
var animation = animation_player.get_animation(animation_name)
animation = animation.duplicate()
animation_library.remove_animation(animation_name)
animation_library.add_animation(animation_name, animation)

# Modify the animation
animation.track_set_key_value(...)

Here's a helper function

func _duplicate_animation(animation_name: StringName) -> Animation:
	var animation = animation_player.get_animation(animation_name)
	animation = animation.duplicate()
	_animation_library.remove_animation(animation_name)
	_animation_library.add_animation(animation_name, animation)
	return animation

var animation_name: StringName = &"my_animation"
_duplicate_animation(animation_name).track_set_key_value(...)
# or
var animation: Animation = _duplicate_animation(animation_name)
animation.track_set_key_value(...)
animation.track_set_key_value(...)
animation.track_set_key_value(...)

@Snaiel
Copy link

Snaiel commented Jul 14, 2024

Whoops, glossed over bitsawer's comment. I really should read through these issue properly...

@archentity
Copy link

Lost several hours to this. Workaround: duplicate the animation library and animations.

# Duplicate the animation library inside the animation player
var animation_player: AnimationPlayer = $AnimationPlayer
var animation_library: AnimationLibrary = animation_player.get_animation_library(&"")
animation_library = animation_library.duplicate()
animation_player.remove_animation_library(&"")
animation_player.add_animation_library(&"", animation_library)
# Duplicate the animation you want to modify
var animation_name: StringName = &"my_animation"
var animation = animation_player.get_animation(animation_name)
animation = animation.duplicate()
animation_library.remove_animation(animation_name)
animation_library.add_animation(animation_name, animation)

# Modify the animation
animation.track_set_key_value(...)

Here's a helper function

func _duplicate_animation(animation_name: StringName) -> Animation:
	var animation = animation_player.get_animation(animation_name)
	animation = animation.duplicate()
	_animation_library.remove_animation(animation_name)
	_animation_library.add_animation(animation_name, animation)
	return animation

var animation_name: StringName = &"my_animation"
_duplicate_animation(animation_name).track_set_key_value(...)
# or
var animation: Animation = _duplicate_animation(animation_name)
animation.track_set_key_value(...)
animation.track_set_key_value(...)
animation.track_set_key_value(...)

Not even this workaround would work for me. It's like they deliberately made animations specifically difficult to implement. This is almost enough to make me want to switch engines.

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

9 participants