How do I make my player image bigger on collision while keeping its proportions?

Viewed 112

I am making a game in pygame where you now swim around and eat small squares, with an animation to the jellyfish. I've made it so you get bigger when eating, but when adding a number between 1-9 to the scale the image sort of gets wider than I want it to become. When I have the scale go up by 10 or more when eating this problem does not occur as badly.

enter image description here

enter image description here

This is the code for the jellyfish/player:

import pygame, math, time

pt = time.time()
speed = 40
pygame.display.set_mode((800, 500))
img0 = pygame.transform.scale(pygame.image.load("assets/glow0.png"), (30,30)).convert_alpha()
img1 = pygame.transform.scale(pygame.image.load("assets/glow1.png"), (30,30)).convert_alpha()
img2 = pygame.transform.scale(pygame.image.load("assets/glow2.png"), (30,30)).convert_alpha()
img3 = pygame.transform.scale(pygame.image.load("assets/glow3.png"), (30,30)).convert_alpha()
img4 = pygame.transform.scale(pygame.image.load("assets/glow4.png"), (30,30)).convert_alpha()
img5 = pygame.transform.scale(pygame.image.load("assets/glow5.png"), (30,30)).convert_alpha()
img6 = pygame.transform.scale(pygame.image.load("assets/glow6.png"), (30,30)).convert_alpha()
img7 = pygame.transform.scale(pygame.image.load("assets/glow7.png"), (30,30)).convert_alpha()
img8 = pygame.transform.scale(pygame.image.load("assets/glow8.png"), (30,30)).convert_alpha()

class Glow():
    rot = 0
    rotp = 1
    xsp = 0
    ysp = 0
    
    def __init__(self, x, y, scale):
        self.x, self.y = x, y
        self.scale = scale
        self.list = [img0, img1, img2, img3, img4, img5, img6, img7, img8]
        self.current = 0
        self.image = self.list[int(self.current)]
        self.rect = self.image.get_rect(center = (x, y))
        self.colRect = pygame.rect.Rect((0, 0), (self.rect.width/3, self.rect.height/3))
        self.colRect.center = self.rect.center

    def update(self, x, y, accex):
        global pt, speed
        now = time.time()
        dt = now - pt
        pt = now
        
        self.rect = self.image.get_rect(center = (x, y))
        if pygame.key.get_pressed()[pygame.K_UP] or accex:
            # animation
            self.current += dt*5
            if self.current >= len(self.list):
                self.current = 0
            self.image = pygame.transform.rotate(self.list[int(self.current)], self.rot)
            self.rect = self.image.get_rect(center = (x, y))
            self.colRect.center = self.rect.center

            # go in direction of rotation
            self.rotr = math.radians(self.rot) 
            self.ysp = math.cos(self.rotr)
            self.xsp = math.sin(self.rotr)
            self.x -= self.xsp*dt*speed
            self.y -= self.ysp*dt*speed
            if not accex:
                if pygame.key.get_pressed()[pygame.K_LEFT]:
                    self.rot += math.pi*dt*7

                if pygame.key.get_pressed()[pygame.K_RIGHT]:
                    self.rot -= math.pi*dt*7

        if accex:
            speed += dt*10

    def scaleup(self):
        self.scale += 2
        i = 0
        for img in self.list:
            self.list.remove(img)
            img = pygame.transform.scale(img, (self.scale, self.scale))
            self.list.insert(i, img)
            i += 1

This is the main code in the game loop that has to do with this:

W, H = 800, 500
sc = pygame.display.set_mode((W, H))
score = 0
score_x, score_y = 10, 10
font = pygame.font.SysFont("calibri", 30)
score_text = font.render("0", True, (255,255,255))
score _rect = score_text.get_rect(topleft = (score_x, score_y))
if lvl0:
        glow.update(glow.x, glow.y, accex)
        sc.fill((0,0,0))
        for food in Food.food_list:
            sc.blit(food.image, (food.x, food.y))
            if pygame.Rect.colliderect(glow.colRect, food.rect):
                Food.food_list.remove(food)
                glow.scaleup()
                score += 3
                score_text = font.render(str(score), True, (255,255,255))
                score_rect = score_text.get_rect(topleft = (score_x, score_y))

        sc.blit(glow.image, glow.rect)
        sc.blit(label, label_rect)
        pygame.display.update()
2 Answers

Pygame behaves weird when using the transformed image repetitively as in case of rotation...

I even have faced crashes due to it

So try using the the same image which is initially loaded as img0,img1,etc. and scale it to the desired size. As of now you were using the same scaled image again and again . This might help

I know there is an already accepted answer, but here is how I do it:

class Wabbit:
    # this store the main, unaltered image loaded from disk
    _main_image = None
    def __init__(self, pos, scale=1):
        # if the class._main_image variable is not set
        # we do this so we only have to load the image once
        # when the first instance is created
        if not self._main_image:
            # load the image from disk
            self._main_image = pygame.image.load('wabbit_alpha.png')
        
        self.pos = Vector2(pos)
        self.vel = Vector2()
        self.scale = scale
        
        # some variables to store the "previous" values
        self._scale = None
        self._image = None
    
    @property
    def size(self):
        # returns the size of our image, as a Vector2
        return Vector2(self.image.get_size())
    
    @property
    def image(self):
        # this is where we look at our current scale
        # compare it to our previous _scale
        # and update our _image if the two arent the same
        if self.scale != self._scale:
            # update the previous _scale value
            self._scale = self.scale
            # get the size of the original image and scale it
            # according to our scale value
            size = Vector2(self._main_image.get_size()).elementwise() * self.scale
            # set our _image to be the scaled version of the main, original image
            self._image = pygame.transform.scale(self._main_image, size)
        # return our scaled image
        return self._image
    
    def update(self, dt):
        self.pos += self.vel * dt

    def draw(self, surface):
        surface.blit(self.image, self.pos-self.size/2)

Bouncing and scaling wabbit

Related