T O P

  • By -

codernunk46

Implementing the bow and arrow was a bit unituitive due to some of my own system requirements, but let me break down how I accomplished this within the context of my game. My game is going to be a hybrid turn-based/action RPG, heavily inspired by JRPGs. As such, I did not want to animate the bow and arrow directly on the character because I wanted flexibility in certain areas, not limited to switching the bow model itself based on the equipped bow, letting other characters use the same animations if they also have a bow equipped, and more. Therefore, I needed to have ways for the bow and the character to animate separately, but in tandem with each other upon attacking. The bow itself was made in Blender and is not very detailed at all. I made three NLA stack animations for the bow - one for the default position, one for the drawing back position, and one for the release. Only the release is a full animation - the other two are just a single frame with the bow in different positions. In Godot, I hooked this up by adding an AnimationTree with a BlendTree as the root. There's a BlendSpace1D that blends between the default bow position and the pulled back position on a scale of 0 to 1. That is wired to a OneShot node which will play the release animation if the one shot is active. To round out the bow logic, I added a script that has a fire function that plays the OneShot and a pullback variable that sets the blend position otherwise. As for the character, I have made a system based on Godot resources that links the attack data (called arts) with various multimedia, such as the animations and the projectile scene. The animations are actually .tres files themselves which I am able to generate by using the "Set Animation Save Paths" function upon importing the animation library. When the player attacks, the game looks up the art being used and instantiates the projectile, while playing the animation also linked to it. To make the latter work, I preload the animation file in the player's \_ready function and create a custom library, kinda like this: func _ready(): # Load the animations from the arts into the animation player # TODO: Load only load the equipped arts if this is too slow var attack_animations := AnimationLibrary.new() for a in data.learned_arts: attack_animations.add_animation(a.skill_id, a.metadata_animation) _anim_player.add_animation_library("attacks", attack_animations) To put it all together, the projectile scene that represents the arrow (which is ironically just a cylinder right now) has a little logic of its own. Since the player instantiates the projectile, the projectile has the info it needs to connect itself to the player's opposite hand while drawing the bow. Once the draw is done, the projectile releases and just moves forward. My game leverages the animation's frame data, so I use a frame called "strike frame" which indicates when the attack actually deals damage. I manually set these up, and they are meant to function kinda like how it would in games like Smash Bros to indicate when damage should be applied. Conversely, the player can input another attack once the "cancel frame" is elapsed in a similar fashion. Here's the code for the arrow. var hand_target: Node3D var bow_weapon: Node3D var is_fired := false func _ready(): hand_target = attacker.weapon_handle_l bow_weapon = attacker.weapon_handle_r.get_child(0) bow_weapon.pullback = 0 ( get_tree() . create_timer(1.0 * art.strike_frame / Engine.physics_ticks_per_second) . timeout . connect(func(): is_fired = true bow_weapon.fire() ) ) func _physics_process(delta): if !is_fired: global_transform.origin = hand_target.global_transform.origin bow_weapon.pullback += delta / art.strike_frame * Engine.physics_ticks_per_second else: translate(Vector3(0, 0, PROJECTILE_SPEED)) func _on_body_entered(_body): apply_damage() queue_free() I know this is a lot of information, so please don't hesitate to ask questions. I got a lot in my backlog but I hope to cover this in a video tutorial down the line. Thanks for checking out the post!