How to rotate a top down character?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By SebSharper

Hello. I am making a top down shooter game. The character should rotate towards the mouse global position. Something like this:
Character rotating

As you can see, the character changes their sprite and the gun changes its rotation according to where the mouse is pointing at. Also, if the mouse is pointing down, the gun shows in front of the player. As you can see in the GIF below:
Character with gun in front

As I have seen. The character uses 4 different sprites (one looking at the front, at the front right, the right, back right and back), and then it flips the sprite according to the mouse.
The gun could be a separate sprite that does rotate looking to the mouse.
I have tried all of this, however, it looks pretty weird, and the direction detection tends to fail sometimes and the code is too messy. What would you recommend me to achieve this in the best way? Thanks.

PS: The game in the gifs above is “Enter the Gungeon”

1 Like
:bust_in_silhouette: Reply From: 2Dfanatic

idle is the idle animation of a sprite
runf is the run forward animation of a sprite
runb is the run backward animation of a sprite
sprMinipistol is the gun sprite.

var MAX_SPEED = 100
var ACCELERATION = 2000
var motion = Vector2.ZERO
var target = Vector2()

func control(delta):
	target = get_global_mouse_position()
	$sprMinipistol.look_at(target)
	if target.x > self.position.x :
		get_node("sprMinipistol").set_flip_v(false)
	elif target.x < self.position.x :
		get_node("sprMinipistol").set_flip_v(true)
	if target.y > self.position.y :
		get_node("sprMinipistol").z_index = 0
	else :
		get_node("sprMinipistol").z_index = -1
	if Input.is_action_just_pressed("click"):
		shoot()

onready var sprite = get_node("sprPlayer")
var anim = "idle"

func _physics_process(delta):
	target = get_global_mouse_position()
	if motion.x == 0:
		anim = "idle"
	else:
		anim = "runf"
	if target.x > self.position.x :
		sprite.set_flip_h(false)
		if Input.is_action_pressed("ui_left") == true or Input.is_action_pressed("ui_down") == true:
			anim = "runb"
		elif Input.is_action_pressed("ui_right") == true or Input.is_action_pressed("ui_up") == true:
			anim = "runf" 
	elif target.x < self.position.x :
		sprite.set_flip_h(true)
		if Input.is_action_pressed("ui_left") == true or Input.is_action_pressed("ui_up") == true:
			anim = "runf" 
		elif Input.is_action_pressed("ui_right") == true or Input.is_action_pressed("ui_down") == true:
			anim = "runb"
	sprite.play(anim)
	var axis = get_input_axis()
	if axis == Vector2.ZERO:
		apply_friction(ACCELERATION * delta)
	else:
		apply_movement(axis * ACCELERATION * delta)
	motion = move_and_slide(motion)
	

func get_input_axis():
	var axis = Vector2.ZERO
	axis.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
	axis.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
	return axis.normalized()


func apply_friction(amount):
	if motion.length() > amount:
		motion -= motion.normalized() * amount
	else:
		motion = Vector2.ZERO

func apply_movement(acceleration):
	motion += acceleration
	motion = motion.clamped(MAX_SPEED)

Use Animated sprites node to add Animated sprites

2Dfanatic | 2020-06-16 09:40

Is control(delta) called in _process?

SebSharper | 2020-06-16 20:45

You can call it under fucn _physics_process(delta) aswell

2Dfanatic | 2020-06-23 13:36

1 Like