Godot Version
Godot 4.7 stable
Question
I had an idea to bring my currently nonfunctional 2D game into 3D, improving it and hopefully making it function along the way. At this stage, I have nothing more than concepts, a blank project, and a rough idea of the basic entity’s scene tree:
*: *Entity3D [.tscn]
|_ AttackSound: AudioStreamPlayer3D
|_ DeathSound: AudioStreamPlayer3D
|_ Sprite: AnimatedSprite3D
|_ AttackRange: Area3D
|_ Collision: CollisionShape3D
|_ DetectRange: Area3D
|_ Collision: CollisionShape3D
|_ GUI: Waypoint-like [.tscn]
|_ Name: Label
|_ HealthBar: TextureProgressBar
|_ ShieldsBar: TextureProgressBar
|_ EnergyBar: TextureProgressBar
What I’d like to have happen is that the AnimatedSprite3D plays an animation such that the entity appears to be looking in a consistent direction from the camera’s point of view. I have 16 different directions that the entity can face.
I don’t particularly want to look at DOOM’s source code, and I doubt it would help me anyway.
Thank you for your help!
Good idea. I still enjoy the old 2d animated characters in 3d, especially if they are in low res. There’s a good tutorial to get started here, I think. Good luck with it.
I try to not use AI, but I’m sure that will provide a helpful basis for my code!
LimboAI is a plugin for behavior trees, useful for controlling character states- not “AI” as in LLM. It’s not necessary for what you are trying to do, and I’m not sure this video does cover what you are trying to do either.
Mathematically I think you’ll want to use a dot product of the camera’s forward direction and the entity’s forward direction, dot products on normalized vectors will give you a value of how similar the two vectors are, if they point in the same direction the dot product returns 1, if perpendicular 0, if opposite -1, and any value in between is also represented. This dot product can be acos’d into an angle value which can then be converted into an index of your 16 facing directions (though the dot product won’t tell if it’s facing left/right so there are more issues)
var look_dot: float = me.global_basis.z.dot(enemy.global_basis.z)
var angle: float = acos(look_dot)
const ANIMATION_DIRECTION: Array[String] = [
"down", "right_down", "right", "right_up", "up", "up_left", "left", "left_down",
]
var angle_index: int = roundi((angle + PI) / TAU * ANIMATION_DIRECTION.size())
$AnimatedSprite3D.play(ANIMATION_DIRECTION[angle_index])
Along these lines but again the dot product won’t discern left from right so maybe it’s a bad route, maybe it needs a little patch to get the rest of the way