• Edited

DaveTheCoder Thanks! And no worries. I wanted this get_direction function to be more concise as it was, but I'm still learning.

How would you do the second section?

It still correctly updates the direction the character is facing when applying input, but it still only updates with diagonal directions when bouncing, again, even if the character velocity is moving in a cardinal direction as a result of the bounce.

When it bounces up it prints "Facing: (1, -1)". and if it bounces down it says (-1, 1).

So far, it still works exactly the same with this code change. I just don't know what it could be.

    NJL64 When it bounces up it prints "Facing: (1, -1)". and if it bounces down it says (-1, 1).

    What's the value of velocity when that happens, when get_direction() is called?

      • Edited

      DaveTheCoder
      From the print statements:
      When it started bouncing: (394.4125, -295.7835)
      Before it reached zero: (-0.000315, 3.000107)

      get_direction() is called in the Physics Process function, so I can't put a red dot next to it. I'm not sure how to determine what value velocity is (besides zero) when get_direction is called, because it's called every frame if I understand correctly.

      This is currently the script:

      extends CharacterBody2D
      
      # state 
      enum States {IDLE, MOVE, BLAST, BOUNCE, SPIN}
      var state = States.IDLE # default state
      
      # exportable variables (can be changed in editor)
      @export var acceleration = 1.5 # increase in speed by this much
      @export var deceleration = 0 # default
      @export var deceleration_move = 15 # deceleration when moving with input
      @export var deceleration_blast = 210 # deceleration when blasting
      @export var dir_last = Vector2(0, 1) # note: needs to be global to work
      @export var speed = 0 # default
      @export var speed_blast = 500 # speed when blast is performed
      @export var speed_move = 100 # speed when moving with input
      
      # functions
      func _physics_process(delta): # the delta variable has the value of the frame time that the engine passes to the function.
      	# local variables
      	var collision = move_and_collide(velocity * delta)
      	var dir_input = Input.get_vector("left", "right", "up", "down")
      	var facing = dir_last # see get_directon() function to see what dir_last equals
      		
      	match state:
      		
      		States.IDLE:
      			if Input.is_action_pressed("move"):
      				state = States.MOVE # change state
      			elif Input.is_action_just_released("blast"):
      				state = States.BLAST # change state
      			elif Input.is_action_pressed("spin"):
      				state = States.SPIN
      			else:
      				velocity = Vector2.ZERO # idle
      				speed = 0
      			
      		States.MOVE:
      			if ! Input.is_action_pressed("move") and velocity.is_zero_approx():
      				state = States.IDLE # change state
      			elif Input.is_action_just_released("blast"):
      				state = States.BLAST # change state
      			else:
      				velocity = dir_input * speed
      				speed = speed_move
      				move_and_slide()
      				
      		States.BLAST:
      			if Input.is_action_pressed("move"): # if input JUST pressed, not ALREADY pressed
      				state = States.MOVE 
      			elif collision:
      				state = States.BOUNCE # change state
      			else:
      				velocity = facing * speed # blast in direction facing
      				velocity = velocity.normalized() * speed # avoid going faster when diagonal
      				deceleration = deceleration_blast
      				speed = speed_blast
      				apply_deceleration(delta)
      				
      		States.BOUNCE:
      			if ! collision:
      				if velocity.is_zero_approx():
      					state = States.IDLE # change state
      				elif Input.is_action_pressed("move"):
      					state = States.MOVE # change state
      				elif Input.is_action_just_released("blast"):
      					state = States.BLAST # change state
      				elif ! Input.is_action_pressed("move"):
      					apply_deceleration(delta)
      					deceleration = deceleration_blast
      			else:
      				velocity = velocity.bounce(collision.get_normal()) # bounce (get the vector's normal)
      				# note: only faces diagonal after bouncing, even if moving cardinal
      		
      # Experimental state only when 'A' is pressed on keyboard:
      		States.SPIN:
      			if Input.is_action_pressed("spin"):
      				state = States.IDLE
      			elif Input.is_action_just_released("blast"):
      				state = States.BLAST # change state
      			elif Input.is_action_just_released("move"):
      				deceleration = deceleration_move
      				apply_deceleration(delta)
      			elif collision: # says null instance without "collision"
      				velocity = velocity.bounce(collision.get_normal())
      			else:
      				apply_acceleration(dir_input)
      				move_and_slide()
      				
      	get_direction()
      	print("State: ", state)
      	print("Facing: ", facing)
      	print("Speed: ", speed)
      	print("Velocity: ", velocity)
      	
      func apply_acceleration(dir_input):
      	velocity = velocity.move_toward(dir_input * speed_move, acceleration)
      	
      func apply_deceleration(delta):
      	velocity = velocity.move_toward(Vector2.ZERO, deceleration * delta)
      	
      func get_direction():
      	if is_zero_approx(velocity.y):
      		if velocity.x < 0:
      			dir_last = Vector2.LEFT
      			return
      		elif velocity.x > 0:
      			dir_last = Vector2.RIGHT
      			return
      	if is_zero_approx(velocity.x):
      		if velocity.y < 0:
      			dir_last = Vector2.UP
      			return
      		elif velocity.y > 0:
      			dir_last = Vector2.DOWN
      			return
      	
      	# diagonal
      	if velocity.x < 0 and velocity.y < 0:
      		dir_last = Vector2.LEFT + Vector2.UP #NW when bouncing up?
      		return
      	elif velocity.x > 0 and velocity.y < 0:
      		dir_last = Vector2.RIGHT + Vector2.UP #NE when bouncing up?
      		return
      	elif velocity.x < 0 and velocity.y > 0:
      		dir_last = Vector2.LEFT + Vector2.DOWN #SW # when bouncing down?
      		return
      	elif velocity.x > 0 and velocity.y > 0:
      		dir_last = Vector2.RIGHT + Vector2.DOWN #SE # when bouncing down?
      		return
      • xyz replied to this.

        In _physics_process, you could accumulate the values of velocity and dir_last in arrays. For example, store 100 values before and after a bounce. Then you could print and look at them after a bounce, to see what happened.

        • Best Answerset by NJL64

        NJL64 Your logic is flawed here. If the thing bounces perceptually (but not perfectly) in the cardinal direction both velocity components will be non-zero although one of them may be very small, but since you only check for a perfect cardinal bounce all non perfect ones will be registered as "diagonal".

          • Edited

          xyz I understand. That makes perfect sense. I think that's what's wrong actually. Thank you!

          Is there a way I could possibly check for directions better, so that I can check for imperfect cardinal bounces?

          I know my homemade get_direction() function isn't the best and probably only accounts for 8 perfect directions.

          • xyz replied to this.

            xyz Thank you so much! I'm gonna try that.

            • Edited

            xyz Sorry. I know you said you answered similar questions already, but I was wondering if you could help me understand a way to apply this to my function?

            Mine's not for inputs, but rather just the character moving in general.

            I just thought I'd ask ahead of time in case I have trouble. I'm researching some of this stuff right now and thinking of how to apply it to my script.

            When I get the angle of the velocity vector and snap it to 45 degrees, what should I do with it then? (I'm still brushing up on my Vector math)

            I would really appreciate it. 🙂

            • xyz replied to this.

              NJL64
              Just use your velocity vector instead of input direction vector. You can disregard the tolerance stuff as it doesn't apply to your case

                • Edited

                xyz So I wrote this function (although I admit I don't understand it myself):

                func get_dir():
                	var dir = velocity
                	var angle = posmod(rad_to_deg(dir.angle()), 360)
                	var sector = wrapi(snapped(angle, 45) / 45, 0, 8)

                But, how should I use it to update the value of "dir_last"? 🙁

                • xyz replied to this.
                  • Edited

                  NJL64 Return the value from the function and assign it to dir_last

                    xyz What's the value from the function?

                    • xyz replied to this.
                      • Edited

                      NJL64 Functions can return values. That's in fact one of their main purpose, to calculate something and then return it. Look at my code on the link again. The function there returns a direction string.

                        xyz So I tried this:

                        func get_dir():
                        	var dir = velocity
                        	var angle = posmod(rad_to_deg(dir.angle()), 360)
                        	var sector = wrapi(snapped(angle, 45) / 45, 0, 8)
                        	return ["E", "SE", "S", "SW", "W", "NW", "N", "NE"] [sector]

                        and this:

                        dir_last = get_dir()

                        and it works for input and seems to work for bouncing off of things! But if I could fix one last issue, it should work how I want it.

                        Unfortunately I can no longer say

                        velocity = dir_last * speed

                        when shooting my character in the direction facing using the "BLAST" state.

                        If you would be so, SO generous to help me with with an alternative so that I can still shoot the character in the direction they are facing, it would really help me out.

                        Thank you!

                        • xyz replied to this.

                          NJL64 Return direction vectors instead of strings.