Q:

my projectile changes direction mid-air Pygame help needed

Design: ninja who throws kunais.
Problem: the kunai if thrown to the left of the screen, she keeps consistently flipping until it leaves the screen and gets deleted.
CODE (only the projectile file aka the knife) :
import pygame

class Projectile(pygame.sprite.Sprite):

    def __init__(self,player):
        if player.face_direction == "RIGHT":
            self.direction="Right"
        else:
            self.direction="Left"
        super().__init__()
        self.player=player
        self.velocity=4
        self.image=pygame.image.load('assets/kunai.png')
        self.image=pygame.transform.scale(self.image,(80,50))
        self.rect=self.image.get_rect()
        self.rect.x=player.rect.x+20
        self.rect.y=player.rect.y+50
        self.origin_image=self.image

    
    def remove(self):
        self.player.all_projectiles.remove(self)
    
    def move(self):
        if self.direction=="Right":
            self.image=self.origin_image
            self.rect.x+=self.velocity    
        elif self.direction=="Left":
            self.image=pygame.transform.flip(self.image,True,False)  
            self.rect.x-=self.velocity

        if self.rect.x>1080 or self.rect.x<-30:
            self.remove()
            

A:

You only need to set the image to the correct facing once, in __init__. If you've done that, the move() method doesn't need to do as much work on each frame. You can do a similar thing with the velocity of the projectile, setting a negative value if you need to move to the left, greatly simplifying the logic in move():
class Projectile(pygame.sprite.Sprite):

    def __init__(self,player):
        super().__init__()

        self.player = player
        self.image = pygame.image.load('assets/kunai.png')
        self.image = pygame.transform.scale(image,(80,50))
        self.velocity = 4
        self.rect=self.image.get_rect()
        self.rect.x=player.rect.x+20 # you might want this to depend on direction
        self.rect.y=player.rect.y+50
        self.origin_image=self.image # you may not need this

        if player.face_direction == "RIGHT":
            self.direction = "Right"
        else:
            self.direction = "Left"
            self.image = pygame.transform.flip(self.image,True,False) # do the flip here
            self.velocity = -self.velocity                            # negate the velocity

    def move(self):
        self.rect.x += self.velocity                  # now this sum can be unconditional
                                                      # and no image manipulation is needed
        if self.rect.x > 1080 or self.rect.x < -30:
            self.remove()

You may not need the direction attribute any more, since move doesn't use it. And regarding remove(), you might not need this method if you're removing yourself from a PyGame Group, rather than from a list. Sprites already keep track of the groups they're in, and you can use the kill() method you've inherited to remove yourself from all groups automatically. This might mean you don't need to keep a reference to the player any more.

