Rotating an image by direction of analogue stick?

Rotating an image by direction of analogue stick?

Postby ArrenMog » Tue Dec 03, 2013 8:01 pm

I'm essentially trying to make a game in this style: http://www.youtube.com/watch?v=ZZfTi-cq27s

I'm wondering how i can get the rotation to be done using an analogue stick (i'm using an xbox 360 controller). I've managed to get the movement working using the left analogue stick, now just trying to get the rotation done by the other. I've got an image and attached it to a rect and that's what i'm using as a character. I can get values for how much the analogue stick is being pushed in the x and y axis but i'm unsure on how to translate this into a direction, and even more unsure as to how to then rotate an image based on that. I'm pretty new python and pygame so if you need any other info or anything let me know.

Thanks for your help!
Last edited by stranac on Tue Dec 03, 2013 9:24 pm, edited 1 time in total.
Reason: First post lock.
ArrenMog
 
Posts: 5
Joined: Tue Dec 03, 2013 7:55 pm

Re: Rotating an image by direction of analogue stick?

Postby Mekire » Wed Dec 04, 2013 5:22 am

Welcome.

If you know how to get the x and y parts of the analog stick, then you can find the angle with:
Code: Select all
angle_in_radians = math.atan2(y,x)
angle = math.degrees(angle_in_radians)
You then use this angle to rotate and move your player.

I would be interested to see the code you have so far.
-Mek
User avatar
Mekire
 
Posts: 1126
Joined: Thu Feb 07, 2013 11:33 pm
Location: Asakusa, Japan

Re: Rotating an image by direction of analogue stick?

Postby ArrenMog » Wed Dec 18, 2013 12:01 am

Thanks for the help but i now have another issue, i'm trying to rotate a sprite by a given angle (10 degrees) every tick. At the moment my sprite simply judders back and forth and i'm not sure why, I just want it to rotate. A similar version of the code works for non animated sprites but i'm struggling to get it to work for this animated sprite. I'm using Python 3.3, Pygame and easypg. I have listed my code below, first the class i'm calling from easypg, then the class I am creating for my sprite that is using the sprite class from easypg as a super class, and then finally my main game section. I know there's quite a lot to take in but any help is welcome. The zip files easypg take are simply zips of images that it cycles through to produce an animated sprite, and the state selects which images to cycle through.

Thanks!

Easypg Sprite class

Code: Select all
class Sprite(pygame.sprite.Sprite):
    """A sprite consisting of (potentially) multiple images.

       It is assumed that the sprite can be in different states.  For each
       state, there can be different sets of sprite images representing
       the eight compass directions, and for each direction there can be a
       stack of images representing an animation sequence.

       The images themselves can be in a single directory or Zip archive
       and the main part of the filename (excluding the extension) should
       have the following format:

           [<state>]_[<direction>]_<num>

       <state> is optional.  If present, it consists of a short string of
       ASCII alphabetic characters.

       <direction> is also optional.  If present, it must be one of the
       following strings: 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'

       <num> is two decimal digits.  An image numbered 00 is required,
       but images numbered 01...99 are optional.

       Images are loaded into a dictionary called 'images'.  Note that this
       dictionary is not defined here.  IT MUST BE DEFINED IN A SUBCLASS,
       ideally as a class variable so that the loaded images can be shared
       by all instances of that subclass.

       Keys of this dictionary are states, with '-' representing an
       undefined state; values are themselves dictionaries, each of which
       has compass directions as keys (with '-' representing an undefined
       direction) and a corresponding list of Pygame surfaces as the
       value associated with each key.  This list of Pygame surfaces is
       used as an animation sequence for a particular state/direction.
    """

    image_regexp = re.compile('([a-zA-Z]*)_([a-zA-Z]*)_(\d\d)')

    def __init__(self, screen, path,
                 alpha=False, background=None, position=None,
                 state='-', direction='-'):
        """Creates a Sprite object for the given Pygame display surface,
           using the images at the given location.

           The required 'path' argument is either a path to a directory
           or a path to a Zip archive, containing sprite images.

           If the images have full alpha transparency, this should be
           indicated by setting the 'alpha' argument to True; otherwise,
           it is assumed that the colour of the pixel in the top-left
           corner of each sprite image is a background colour that should
           be transparent when the sprite is rendered on screen.  If some
           other specific colour represents the background, this can be
           provided as a 3-tuple using the 'background' argument.

           By default, the sprite will be positioned in the centre of the
           the display surface on which it is drawn. Other coordinates can
           be specified as a 2-tuple using the 'position' argument.

           An initial state and direction can be specified if needed;
           they default to '-', meaning 'undefined'.
        """

        super().__init__()

        self.screen = screen
        self.alpha = alpha
        self.background = background
        self.state = state
        self.direction = direction

        if not hasattr(self, 'images'):
            raise SpriteError('no image store defined')
        elif not isinstance(self.images, dict):
            raise SpriteError('image store must be a dictionary')

        if os.path.isfile(path) and path.endswith('.zip'):
            self._load_from_zip(path)
        elif os.path.isdir(path):
            self._load_from_dir(path)
        else:
            raise SpriteError('invalid image location')

        self.frame = 0
        self.counter = self.anim_delay = 3
        self.sequence = self.images[self.state][self.direction]
        self.image = self.sequence[self.frame]

        self.rect = self.image.get_rect()
        if position:
            self.rect.center = position
        else:
            w, h = self.screen.get_size()
            self.rect.center = (w // 2, h // 2)

    def _load_from_dir(self, path):
        contents = sorted(os.listdir(path))
        for (state, direction, _), name in self._find_images(contents):
            image_path = os.path.join(path, name)
            if self.alpha:
                image = pygame.image.load(image_path).convert_alpha()
            else:
                image = pygame.image.load(image_path).convert()
                self._set_background(image)
            self.images[state][direction].append(image)

    def _load_from_zip(self, path):
        archive = zipfile.ZipFile(path)
        contents = sorted(archive.namelist())
        for (state, direction, _), name in self._find_images(contents):
            data = archive.open(name).read()
            source = io.BytesIO(data)
            if self.alpha:
                image = pygame.image.load(source).convert_alpha()
            else:
                image = pygame.image.load(source).convert()
                self._set_background(image)
            self.images[state][direction].append(image)

    def _find_images(self, names):
        found = collections.OrderedDict()

        for name in names:
            match = self.image_regexp.match(name)
            if match:
                # Valid image file, so record details in dictionary

                state = match.group(1) or '-'
                direction = match.group(2) or '-'
                num = match.group(3)
                found[(state, direction, num)] = name

                # Prepare image store to hold loaded images

                if state not in self.images:
                    self.images[state] = {}
                if direction not in self.images[state]:
                    self.images[state][direction] = []

        return found.items()

    def _set_background(self, image):
        if self.background:
            image.set_colorkey(self.background)
        else:
            colour = image.get_at((0, 0))
            image.set_colorkey(colour)

    def update(self):
        """Updates this sprite.

           The implementation provided here simply invokes the check_state,
           animate, move and check_bounds methods.
        """

        self.check_state()
        self.animate()
        self.move()
        self.check_bounds()

    def check_state(self):
        """Checks this sprite's state, changing it if necessary.

           The implementation provided here is a stub that can be
           overridden in subclasses.
        """

    def animate(self):
        """Animates this sprite by changing its image at regular intervals."""

        self.counter -= 1
        if self.counter == 0:
            self.counter = self.anim_delay
            self.frame += 1
            if self.frame >= len(self.sequence):
                self.frame = 0
            self.image = self.sequence[self.frame]

    def move(self):
        """Moves this sprite.

           The implementation provided here is a stub that can be
           overridden in subclasses.
        """

    def check_bounds(self):
        """Checks whether this sprite is within bounds and modifies
           sprite properties if necessary.

           The implementation provided here is a stub that can be
           overridden in subclasses.
        """



My Player class

Code: Select all
class Player( Sprite ):

    images = {}   
   
    def __init__(self, screen, velocity=(3, 3)):
       
        super().__init__(screen, 'player.zip', state='angry')
        self.vx, self.vy = velocity
        self.sizex, self.sizey = screen.get_size()
        self.controller = pygame.joystick.Joystick(0)
        self.controller.init()
        self.angle = 0

    def move (self):

##        keys = pygame.key.get_pressed()
##        if keys[pygame.K_LEFT]:
##            self.rect.centerx -= self.vx
##        if keys[pygame.K_RIGHT]:
##            self.rect.centerx += self.vx
##        if keys[pygame.K_UP]:
##            self.rect.centery -= self.vy
##        if keys[pygame.K_DOWN]:
##            self.rect.centery += self.vy

        self.rect.centerx += int(self.vx*self.controller.get_axis(0))
        self.rect.centery += int(self.vy*self.controller.get_axis(1))       

        self.rotatedchar = pygame.transform.rotate(self.image, self.angle)
        self.rect = self.rotatedchar.get_rect(center = self.rect.center)

        self.angle += 10

        width, height = self.screen.get_size()
        if self.rect.centerx < 0:
            self.rect.centerx = width - 1
        elif self.rect.centerx >= width:
            self.rect.centerx = 0
        if self.rect.centery < 0:
            self.rect.centery = height - 1
        elif self.rect.centery >= height:
            self.rect.centery = 0


My main game code

Code: Select all
import pygame
import sprites

pygame.init()

# Configure display

size = (640, 480)
screen = pygame.display.set_mode(size)
pygame.display.set_caption('CR11 Lab 5')

# Define some colours

grey = (180, 180, 180)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)

# Create a background image and display it

background = pygame.Surface(size).convert()
background.fill(grey)
screen.blit(background, (0, 0))

# TODO: Create sprite and sprite group

char = sprites.Player( screen )
enemy0 = sprites.Monster( screen )
enemy1 = sprites.Monster( screen, velocity = (4, 2) )
enemy2 = sprites.Monster( screen, velocity = (3, 8) )

other = pygame.sprite.Group( char )
monsters = pygame.sprite.Group( enemy0, enemy1, enemy2 )

# Define variables to control the action

clock = pygame.time.Clock()
running = True

# Enter the main event loop...

while running:
    clock.tick(30)   # max 30 fps

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # TODO: Clear, update and redraw sprite group

    other.clear( screen, background )
    #monsters.clear( screen, background )
    other.update()
    #monsters.update()
    other.draw( screen )   
    #monsters.draw( screen )

    #pygame.sprite.groupcollide(other, monsters, True, False)

    pygame.display.flip()

ArrenMog
 
Posts: 5
Joined: Tue Dec 03, 2013 7:55 pm

Re: Rotating an image by direction of analogue stick?

Postby Mekire » Wed Dec 18, 2013 7:49 am

I've added an example to my sample repo showing rotation of an animated sprite.

https://github.com/Mekire/meks-pygame-samples/blob/master/rotation_animation/rotate_animate.py

The screen displays four versions of the same sprite.
  • One static
  • One rotating only
  • One animated only
  • And one animated and rotating

You will need to download the repo for it to work as it relies on an image:
Download Link

Let me know if you have any questions.

-Mek
User avatar
Mekire
 
Posts: 1126
Joined: Thu Feb 07, 2013 11:33 pm
Location: Asakusa, Japan

Re: Rotating an image by direction of analogue stick?

Postby ArrenMog » Wed Dec 18, 2013 10:43 pm

Hey man just had a quick look through all of this and thanks a lot man, about to download it all and try and get it running now but thanks man, it looks like you put a lot of time into this response so thank you!
ArrenMog
 
Posts: 5
Joined: Tue Dec 03, 2013 7:55 pm


Return to Game Development

Who is online

Users browsing this forum: No registered users and 2 guests