v4.2.2
Question
Issues (listed in the same order they are presented in the video):
- When whipping (attackB), if I aim while doing it, the whip (
arm
sprite) will face directly forward right before ending.- Related issue (basically the same thing, but I also show it in the video), if I buffer turning around you can see the whip go straight forward in the other direction even if I’m aiming it.
- If I whip and then whip again immediately after the first one ends, I get stuck moving in
last_direction
, only being able to stop it by whipping again (attackB) or shooting (attackA → attackB). - This one isn’t able to be shown in the video, but if I’m facing right (unflipped), aiming the whip is normal (sort of). Up is up, right is right, etc. However, if I face left (flipped), when aiming up becomes down, right becomes left, etc.
Video
Code
(See attackA() ← involves the arm_aim variable that is used in the whip attack, shoot() ← involves arm_aim (I believe), and attackB() ← the actual whip attack
extends CharacterBody2D
var direction: = Vector2.ZERO
var arm_aim = Vector2.ZERO
var whip_aim: float = 0
var last_direction: Vector2 = Vector2.RIGHT
var is_rolling = false
var is_aiming = false
var is_shooting = false
var can_flip = true
var is_whipping = false
var flash_timer: Timer
var whip_timer: Timer
var bullet = preload("res://scenes/cowboyBullet.tscn")
var flash_scene = preload("res://scenes/cowboyFlash.tscn")
@export var speed: int = 75
@onready var anim_player = $AnimationPlayer
@onready var sprite = $Sprite2D
@onready var pivot = $"Shoulder Pivot"
@onready var arm = $"Shoulder Pivot/Arm"
@onready var bullet_spawn = $"Shoulder Pivot/Arm/Bullet Spawn"
@onready var flash_spawn = $"Flash Spawn"
func _ready():
anim_player.animation_finished.connect(_on_animation_finished)
func _process(delta):
movement()
rolling()
attackA()
attackB()
func _physics_process(delta):
velocity = direction * speed
if is_shooting == true:
velocity = Vector2.ZERO
move_and_slide()
func movement():
if not is_rolling and not is_shooting and not is_whipping:
direction = Input.get_vector("p1left", "p1right", "p1up", "p1down").normalized()
if direction.length() > 0:
anim_player.play("cowboyRun")
else:
anim_player.play("cowboyIdle")
if direction.length() > 0:
last_direction = direction.normalized()
else:
direction = Input.get_vector("p1left", "p1right", "p1up", "p1down").normalized()
if direction.length() == 0:
direction = last_direction
if can_flip == true:
if direction.x < 0:
sprite.flip_h = true
pivot.scale.x = -1
pivot.position = Vector2(-2, -0.5)
elif direction.x > 0:
sprite.flip_h = false
pivot.scale.x = 1
pivot.position = Vector2(2, -0.5)
func rolling():
if Input.is_action_just_pressed("p1roll") and not (is_rolling or is_aiming or is_shooting or is_whipping):
anim_player.play("cowboyRoll")
is_rolling = true
speed = 125
if is_rolling and direction.length() > 0:
last_direction = direction.normalized()
if anim_player.is_playing() == false and is_rolling:
is_rolling = false
speed = 75
flash()
func flash():
if sprite.flip_h:
flash_spawn.position = Vector2(6, -6)
var flash_instance = flash_scene.instantiate()
flash_instance.global_position = flash_spawn.global_position
get_parent().add_child(flash_instance)
else:
flash_spawn.position = Vector2(-7, -6)
var flash_instance = flash_scene.instantiate()
flash_instance.global_position = flash_spawn.global_position
get_parent().add_child(flash_instance)
flash_timer = Timer.new()
flash_timer.wait_time = 0.5
flash_timer.one_shot = true
flash_timer.connect("timeout", Callable(self, "_on_flash_timer_timeout"))
add_child(flash_timer)
flash_timer.start()
func attackA():
if not is_shooting and not is_whipping and Input.is_action_pressed("p1attackA"):
anim_player.play("cowboyAim")
is_aiming = true
speed = 0
can_flip = false
pivot.scale.y = 1
arm_aim = Input.get_vector("p1aimLeft", "p1aimRight", "p1aimUp", "p1aimDown").normalized()
if arm_aim.length() > 0:
if sprite.flip_h:
var angle = atan2(-arm_aim.y, -arm_aim. x)
pivot.rotation = angle
else:
var angle = atan2(arm_aim.y, arm_aim.x)
pivot.rotation = angle
if pivot.rotation > PI / 2 or pivot.rotation < -PI / 2:
pivot.scale.y = -1
else:
pivot.scale.y = 1
elif not is_shooting and not is_whipping:
pivot.rotation = 0
if Input.is_action_pressed("p1attackA") and Input.is_action_just_pressed("p1attackB") and is_shooting == false:
print("shoot")
is_shooting = true
anim_player.play("cowboyShoot")
shoot()
if Input.is_action_just_released("p1attackA"):
speed = 75
is_aiming = false
can_flip = true
func shoot():
var bullet = bullet.instantiate()
bullet.b_position = bullet_spawn.global_position
if flash_timer and flash_timer.time_left > 0:
bullet.speed = 250
if sprite.flip_h:
bullet.b_rotation = pivot.rotation + PI
bullet.direction = pivot.rotation + PI
else:
bullet.b_rotation = pivot.rotation
bullet.direction = pivot.rotation
get_parent().add_child(bullet)
func attackB():
if Input.is_action_just_pressed("p1attackB") and not (is_aiming or is_shooting):
print("whip")
is_whipping = true
can_flip = false
anim_player.play("cowboyWhipWindup")
speed = 0
whip_timer = Timer.new()
whip_timer.wait_time = 0.05
whip_timer.one_shot = true
whip_timer.connect("timeout", Callable(self, "_on_whip_timer_timeout"))
add_child(whip_timer)
whip_timer.start()
if whip_timer and whip_timer.time_left > 0:
arm_aim = Input.get_vector("p1aimLeft", "p1aimRight", "p1aimUp", "p1aimDown").normalized()
if arm_aim.length() > 0:
if sprite.flip_h:
whip_aim = atan2(-arm_aim.y, -arm_aim. x)
else:
whip_aim = atan2(arm_aim.y, arm_aim.x)
whip_aim = arm_aim.angle()
print(arm_aim, "|||", whip_aim)
if whip_timer and whip_timer.time_left == 0:
print("TIMER UP")
pivot.rotation = arm_aim.angle()
whip_timer.queue_free()
whip_timer = null
is_whipping = true
if anim_player.is_playing() == false and is_whipping:
is_whipping = false
speed = 75
func _on_animation_finished(animation_name: String):
if animation_name == "cowboyShoot":
is_shooting = false
if is_shooting == false:
print("not shooting")
elif animation_name == "cowboyWhipWindup":
is_whipping = false
speed = 75
if is_whipping == false:
print("not whipping")
can_flip = true