0

I am currently working on a small project. I am looking to create a basic RPG to get used to classes in Python 2.7.1. I am using Pygame. I currently coded a movement system which is click based and centred on the player sprite (fixed at the centre of the display). Looking to mimic the Diablo II system.

All the files to run the program can be found at this WeTransfer link: Program Files

Movement Basics: At each iteration of the main loop I run the get_offset(character,event) function below, if the MOUSEBUTTONDOWN event is detected, then and only then does it provides me with a x and y offset and a number of "steps" needed to reach the destination (area of the map under the mouse position at the time of click).

The x and y offsets are repeated at each loop until the player clicks again or that the number of "steps" fall to 0, in which case the offsets are set to 0 (player stops).

The get_offset function is below:

def get_offset(character,event):
    if event.type == MOUSEBUTTONDOWN:
        print 'reset'
        m_pos = pygame.mouse.get_pos() #mouse position tracker
        variables.player_dest_pos = m_pos
        speed = character.speed #player's speed

        xp = (variables.screenWIDTH/2)
        yp = (variables.screenHEIGHT/2)
        #print xp,yp
        xm = m_pos[0]-10 #adds offset to center player
        ym = m_pos[1]-5

        dx= xm-xp
        dy= float(ym-yp) 

        dist = (dx**2+dy**2)**0.5 #get lenght to travel

        #sets number of steps/loops needed to reach destination
        steps = dist/speed #float
        steps = int(dist)/speed #int        

        #calculates angle and sets quadrant
        if dx == 0 or dy == 0:
            angle_rad = 0
            if dx == 0 and ym > yp:
                xoffset = 0
                yoffset = -speed
            elif dx == 0 and ym < yp:
                xoffset = 0
                yoffset = speed
            elif dy == 0 and xm > xp:
                xoffset = 0
                yoffset = -speed
            elif dy == 0 and xm < xp:
                xoffset = 0
                yoffset = speed
            else:
                xoffset, yoffset = 0,0
        elif xm > xp and ym > yp:
            angle_rad = np.arctan((abs(dy)/abs(dx)))
            xoffset = -np.cos(angle_rad)*speed
            yoffset = -np.sin(angle_rad)*speed
        elif xm < xp and ym > yp:
            angle_rad = np.arctan((abs(dx)/abs(dy)))
            xoffset = -np.cos(angle_rad)*speed
            yoffset = -np.sin(angle_rad)*speed
        elif xm < xp and ym < yp:
            angle_rad = np.arctan((abs(dy)/abs(dx)))
            xoffset = np.cos(angle_rad)*speed
            yoffset = np.sin(angle_rad)*speed
        else:# xm > xp and ym < yp:
            angle_rad = np.arctan((abs(dx)/abs(dy)))
            xoffset = -np.sin(angle_rad)*speed
            yoffset =  np.cos(angle_rad)*speed

        #sets the values to global accessible in the 'variables' module       
        variables.xoffset = xoffset
        variables.yoffset = yoffset

        variables.offset_time = steps

I then create a enemy sprite which has the following move method:

 def move(self,event):#,mouse_pos, screen, background
    if event.type == MOUSEBUTTONDOWN:
        self.dest = (random.randint(0,600),random.randint(0,480))
    if self.dest[0] > self.rect[0]:
        variables.screen.blit(variables.background, self.rect, self.rect) #erases players by bliting bg 
        variables.move_speed = self.speed
        self.move_EW() #moves player
        variables.screen.blit(self.image, self.rect) #draws player
    if self.dest[0] < self.rect[0]:
        variables.screen.blit(variables.background, self.rect, self.rect) #erases players by bliting bg 
        variables.move_speed = -self.speed
        self.move_EW() #moves player
        variables.screen.blit(self.image, self.rect) #draws player  
    if self.dest[1] < self.rect[1]:
        variables.screen.blit(variables.background, self.rect, self.rect) #erases players by bliting bg 
        variables.move_speed = -self.speed
        self.move_NS() #moves player
        variables.screen.blit(self.image, self.rect) #draws player
    if self.dest[1] > self.rect[1]:
        variables.screen.blit(variables.background, self.rect, self.rect) #erases players by bliting bg 
        variables.move_speed = self.speed
        self.move_NS() #moves player
        variables.screen.blit(self.image, self.rect) #draws player 

def move_NS(self):
    self.rect = self.rect.move(0, variables.move_speed)
    if self.rect.top < 0:
        self.rect.bottom = 480
    if self.rect.bottom > 480:
        self.rect.top = 0
    # Check for Collisions
    for obstacle in variables.building_list:
        if pygame.sprite.collide_rect(self, obstacle):
            #print 'collide'
            self.rect = self.rect.move(0, -(variables.move_speed))


def move_EW(self):
    self.rect = self.rect.move(variables.move_speed , 0)
    if self.rect.right > 600:
        self.rect.left = 0
    if self.rect.left < 0:
        self.rect.left = 600
    # Check for Collisions
    for obstacle in variables.building_list:
        if pygame.sprite.collide_rect(self, obstacle):
            #print 'collide'
            self.rect = self.rect.move(-(variables.move_speed) , 0)

The movement of this sprite is basically independent of anything else at the moment.

I then coded in a group_offset(group,character) function which is able to add the get_offset offsets to any sprite in a group, in order to make any sprite in the game "move" relatively to the player (this therefore applies also to static objects.) It also checks if any elements of the group collide with the player using a local variable test_rect, if collision occurs then the offset is set to 0 in both direction. If no collision occurs, then the sprite is moved by the offset value.

def group_offset(group,character):
    for sprite in group: #checks if sprite collide with character using test_rect
        test_rect = Rect(sprite.rect)
        if variables.offset_time  > 0:
            test_rect = test_rect.move(variables.xoffset,variables.yoffset)
            if test_rect.colliderect(character.rect):
                variables.xoffset, variables.yoffset = 0,0
    #if no collision occurs moves the sprites in the group            
    if variables.xoffset != 0 and variables.yoffset != 0:
        for sprite in group:
            if variables.offset_time  > 0:
                sprite.rect = sprite.rect.move(variables.xoffset,variables.yoffset)

My problem occurs when I use the group offset function twice, once for my buildings and once for my enemies. When I do that my hero stops moving after what looks like only one "step" has been taken.

After the first call all is fine and the hero moves until it reaches it's destination.

When I call it again with group_offset(variables.ennemi_list,hero). Then my player stops after one step.

I initially thought that my enemy sprites where checking collision against my buildings instead of my player, but as you can see the call is made with the player(hero) so it should only detect a collision and stop the movement either when my player hit's a building (from the first call) or an enemy...

Any help would be helpful as I really don't know why this bug is occurring. I've tried commenting out many things and it really seems like the problem comes from this line of code: group_offset(variables.ennemi_list,hero).

This is my main.py script with the game loop:

import pygame, sys, variables from pygame.locals import * from classes import * from instances import * from functions import *

#game loop    
while True:
    variables.screen.fill((0,0,0)) #make background black for map edges
    for event in pygame.event.get(): #setting up quit
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    get_offset(hero,event) # sets the movement offset for the iteration

    for o in variables.char_list: 
        if isinstance(o, Character): #moves characters
            o.move(event)
        if isinstance(o, Ennemi): #performs attack when enemmi is clicked and in contact
            if pygame.sprite.collide_rect(o,hero) == True:
                hero.attack(sword,o)

    group_offset(variables.building_list,hero) #new building position using offset
    scroll_map.offset() #offsets grass background map

    variables.screen.blit(scroll_map.image, scroll_map.rect) # blits the grass map to new pos
    variables.building_list.draw(variables.screen) #blits the buildings to new pos
    variables.screen.blit(hero.image, hero.rect) #blits hero to screen center

    #group_offset(variables.ennemi_list,hero)
    for o in variables.ennemi_list:
        variables.screen.blit(o.image, o.rect)
    pygame.display.update()
    pygame.time.delay(10)
    variables.offset_time -= 1 #removes on step from the offset counter to keep track of when
    #offset needs to be reset to 0, i.e. position is reached
Sorade
  • 865
  • 13
  • 27
  • import pygame, sys, variables ImportError: No module named variables. What is variables. I tried to run your code and this is what I got. – emorphus Apr 28 '16 at 12:40
  • Sorry about that, I didn't want to clutter the question with all my code. But you are right, I will but a wetransfer link in the question so people can run the code. here is the link: [WeTransfer link](https://www.wetransfer.com/downloads/cc2113da6a8650b5d37887cc12d4480420160428131312/894c850cfcfc9e004c22549d9828c90320160428131312/42ec8c) – Sorade Apr 28 '16 at 13:16

0 Answers0