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.