#RPG-ENGINE #RPG Engine #Cristobal Troncoso, 2010 import pygame, sys, os import random from pygame.locals import * #Iniciar Pygame pygame.init() #Dirty rect dirty_rect = [] # Constantes SCREEN_WIDTH = 640 SCREEN_HEIGHT = 480 MOVER_STEP = 1 RETROCEDER_STEP = 2 LADO_WIDTH = 1 ## # This comment provides documentation for the following # function. def function(argument): pass #Funciones genericas de pygame def inicia_ventana(width, height, caption): '''Inicia la ventana principal de PyGame en donde se despliega el juego''' window = pygame.display.set_mode((width,height)) pygame.display.set_caption(caption) screen = pygame.display.get_surface() return window, screen def carga_imagen(folder,picture, ckey="00pixel"): image_filename = os.path.join(folder,picture) image = pygame.image.load(image_filename).convert() if ckey == "00pixel": image.set_colorkey(image.get_at((0,0)), RLEACCEL) return image def load_sound(name): class NoneSound: def play(self): pass if not pygame.mixer: return NoneSound() fullname = os.path.join(name) sound = pygame.mixer.Sound(fullname) return sound #Funciones del engine RPG class Actor(object): def __init__(self, imagen): self.imagen = imagen self.rect = imagen.get_rect() def dibuja(self, screen): screen.blit(self.imagen, self.rect) dirty_rect.append(self.rect) def borra(self, screen, background): screen.blit(background, self.rect, self.rect) dirty_rect.append(self.rect) def mover(self, n_xd, n_yd): self.xd = n_xd self.yd = n_yd self.borra(pantalla, img_fondo) self.rect = self.rect.move([self.xd, self.yd]) self.dibuja(pantalla) class Bloque(Actor): def __init__(self, tipo, (B_x, B_y)): img_bloque = carga_imagen("Data\\tiles", ""+str(tipo)+".jpg", 1) self.imagen = img_bloque self.rect = img_bloque.get_rect() self.x = B_x self.y = B_y self.rect.top = self.y self.rect.left = self.x class Item(Actor): def __init__(self, tipo, (I_x, I_y)): img_item = carga_imagen("Data\\items", ""+str(tipo)+".png", "00pixel") self.imagen = img_item self.rect = img_item.get_rect() self.x = I_x self.y = I_y self.rect.top = self.y self.rect.left = self.x class Nivel(object): actual = 1 salidas = [] bloque_list = [] items = [] items_ubicacion = [] portales = [] portales_ubicacion = [] def __init__ (self): self.actualizar(self.actual) def detectar_borde(self, jugador): if jugador.rect.top > 480: #Si el jugador se sale por abajo jugador.rect.top = -30 #Actualice el nivel para la salida SUR (1) self.actualizar(self.salidas[1]) elif jugador.rect.top < -40: #Si el jugador se sale por arriba jugador.rect.top = 470 #Actualice el nivel para la salida NORTE (0) self.actualizar(self.salidas[0]) elif jugador.rect.left < -40: #Si el jugador se sale por la izquierda jugador.rect.left = 630 #Actualize el nivel para la salida OESTE (3) self.actualizar(self.salidas[3]) elif jugador.rect.left > 640: #Si el jugador se sale por la derecha jugador.rect.left = -30 #Actualize el nivel para la salida ESTE (2) self.actualizar(self.salidas[2]) #detectar salidas de portales colision = jugador.rect.collidelist(self.portales_ubicacion) if colision !=-1: self.actualizar(self.portales[colision]) def leer_nivel(self, num_nivel): #leer salidas a=0 self.salidas = [] file = open("Data/niveles/" + str(num_nivel) + "/salidas.txt", "rU") for line in file: if '\n' in line: line = line[:-1] a = a + 1 if a <= 4: self.salidas.append(line) #leer imagen de fondo self.fondo = carga_imagen("Data\\niveles\\"+str(num_nivel), "fondo.jpg", 1) #leer objetos escenario a=0 level = [] self.bloque_list=[] file = open("Data/niveles/" + str(self.actual) + "/escenario.txt") for line in file: if '\n' in line: line = line[:-1] a=a+1 if a<=20: level.append(line) #b=0 for j in range(20): for i in range(20): if level[j][i].isdigit(): tipo = int(level[j][i]) self.bloque_list.append(Bloque(tipo, ((i*32), ((j*24))))) #leer portales level = [] self.portales=[] self.portales_ubicacion=[] file = open("Data/niveles/" + str(self.actual) + "/portales.txt") for line in file: if '\n' in line: line = line[:-1] if line!="#": level.append(line) #level.remove(level[-1]) for linea in level: linea = linea.split() #Guarde en portales el nombre del portal a ir self.portales.append(linea[2]) #Guarde en portales_ubicacion los rects de los portales self.portales_ubicacion.append(pygame.Rect(int(linea[0]),int(linea[1]),5,5)) #Queda entonces #portales_ubicacion -> [ rect(100, 200) , ...] #portales -> [ 'CASA_ABAJO' , ...] #leer items level = [] self.items=[] self.items_ubicacion=[] file = open("Data/niveles/" + str(self.actual) + "/items.txt") for line in file: if '\n' in line: line = line[:-1] if line!="#": level.append(line) for linea in level: linea = linea.split() #Guarde en items_ubicacion los rects de los portales self.items_ubicacion.append(pygame.Rect(int(linea[0]),int(linea[1]),64,48)) #Queda entonces #portales_ubicacion -> [ rect(100, 200) , ...] #portales -> [ 'CASA_ABAJO' , ...] self.items.append(Item(str(linea[2]),(int(linea[0]),int(linea[1])))) def actualizar(self, nivel): self.actual=nivel self.leer_nivel(self.actual) pantalla.blit(self.fondo,(0,0)) pygame.display.flip() #Dibujar escenario for block in self.bloque_list: block.dibuja(pantalla) #Dibujar items for item in self.items: item.dibuja(pantalla) def game_over(): gameover.play() pygame.time.wait(1500) sys.exit() pygame.quit() class Avatar(Actor): def __init__(self): self.imagen = carga_imagen("Data\\avatar", "avatar.bmp", 1) self.imagen_frente = carga_imagen("Data\\avatar", "avatar.bmp", 1) self.imagen_back = carga_imagen("Data\\avatar", "avatar_espalda.bmp", 1) self.imagen_izq = carga_imagen("Data\\avatar", "avatar_izq.bmp", 1) self.imagen_der = carga_imagen("Data\\avatar", "avatar_der.bmp", 1) self.rect = self.imagen.get_rect() self.rect.top = 400 self.rect.left = 200 self.dibuja(pantalla) self.sonido_paso = load_sound("Data/sonidos/pasos.wav") self.sonido_paso.set_volume(0.5) def get_lado_hit(self): self.r_left = pygame.Rect(self.rect.left, (self.rect.top + LADO_WIDTH), LADO_WIDTH, (self.rect.height - 2*LADO_WIDTH)) self.r_right = pygame.Rect((self.rect.right - LADO_WIDTH) , (self.rect.top + LADO_WIDTH), LADO_WIDTH, (self.rect.height - 2*LADO_WIDTH)) self.r_top = pygame.Rect((self.rect.left + LADO_WIDTH), self.rect.top, (self.rect.width - (2*LADO_WIDTH)), LADO_WIDTH) self.r_bottom = pygame.Rect((self.rect.left + LADO_WIDTH), (self.rect.bottom - LADO_WIDTH), (self.rect.width - (2*LADO_WIDTH)), LADO_WIDTH) self.lista_lados = [self.r_left, self.r_right, self.r_top, self.r_bottom] def colisiones(self, lista_rect): self.get_lado_hit() bloque_chocado = self.rect.collidelist(lista_rect) if bloque_chocado !=-1: #colision entrega el lado del personaje que choca con un bloque dado #0 = lado izquierdo, 1 = lado derecho, 2 = lado superior, 3 = lado inferior colision = lista_rect[bloque_chocado].rect.collidelist(self.lista_lados) if colision==0: personaje.mover(RETROCEDER_STEP,0) elif colision==1: personaje.mover(-RETROCEDER_STEP,0) elif colision==2: personaje.mover(0,RETROCEDER_STEP) elif colision==3: personaje.mover(0,-RETROCEDER_STEP) #Redibuje el bloque chocado lista_rect[bloque_chocado].dibuja(pantalla) def control(self): key = pygame.key.get_pressed() if key[K_RIGHT]: personaje.mover(MOVER_STEP,0) self.imagen = self.imagen_der self.sonido_paso.play() elif key[K_LEFT]: personaje.mover(-MOVER_STEP,0) self.imagen = self.imagen_izq self.sonido_paso.play() elif key[K_UP]: personaje.mover(0,-MOVER_STEP) self.imagen = self.imagen_back self.sonido_paso.play() elif key[K_DOWN]: personaje.mover(0,MOVER_STEP) self.imagen = self.imagen_frente self.sonido_paso.play() #Inicia ventana y pantalla ventana, pantalla = inicia_ventana(SCREEN_WIDTH, SCREEN_HEIGHT, "RPG ENGINE") #Inicio de reloj clock = pygame.time.Clock() #Inicia manejador de niveles NivelHandler = Nivel() #Crea objetos iniciales personaje = Avatar() #Carga musica music = pygame.mixer.music.load('Data/sonidos/musica.mp3') pygame.mixer.music.play(50) #Ciclo principal del juego while 1: clock.tick(300) for evento in pygame.event.get(): if evento.type == QUIT: sys.exit() pygame.quit() #Actualiza fondo. Solo actualiza cuando cambia. img_fondo = NivelHandler.fondo #Detectar si el personaje se sale del borde del nivel, #o si entra en un portal NivelHandler.detectar_borde(personaje) #Colisiones de personaje y escenario personaje.colisiones(NivelHandler.bloque_list) #Controlar al personaje personaje.control() pygame.display.update(dirty_rect) dirty_rect = []