#!/usr/bin/env python # -*- coding: utf-8 -*- # Jugador_JAMtank.py por: # Flavio Danesse # CeibalJAM! - Uruguay - Plan Ceibal # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import pygame from pygame.locals import * import os from math import sin, cos, radians VELOCIDAD = 10 INDICE_ROTACION = 5 TERMINATOR = "\r\n\r\n" # para las balas MAGENTA = (255, 0, 255) from math import sin, cos, radians from pygame.sprite import Sprite class Jugador_JAMtank(pygame.sprite.Sprite): ''' Clase Jugador, tanto para datos como objetos gráficos. En esta clase no se dibuja, se calcula y guarda los datos del jugador y del sprite que lo representa''' def __init__(self, imagen=None, nombre=None, angulo=0, x=0, y=0, resolucion_monitor=(1200,900), directorio_de_imagenes=None): pygame.sprite.Sprite.__init__(self) self.directorio_de_imagenes = directorio_de_imagenes # monitor y ventana self.ancho_monitor, self.alto_monitor = resolucion_monitor self.imagen = imagen self.imagen_original = None # Atributos del sprite self.image = None self.rect = None # datos para gráficos self.angulo = 0 self.x = self.ancho_monitor / 2 self.y = self.alto_monitor / 2 self.dx, self.dy = self.get_vector(self.angulo) # distancia en x,y # Datos no gráficos, puntajes del jugador self.energia = 100 self.puntaje = 0 self.nuevos_datos_puntos = False # Balas de jugador local en juego. self.estado_bala = None self.bala = None self.nuevo_mensaje_bala = None # Datos para la Red self.nombre = nombre # self.nick self.nuevo_mensaje_posicion = None # para comparar con el ultimo mensaje y si hay cambios enviar. self.ultimo_mensaje_posicion = None def setup(self): # Levanta los objetos gráficos del jugador. (Solo se ejecuta al principio del juego) print "Seteando Jugador para JAMtank\n" self.imagen_original = pygame.transform.scale(pygame.image.load(self.imagen), (50,50)).convert_alpha() # Atributos del sprite self.image = self.imagen_original.copy() self.rect = self.image.get_rect() self.nuevo_mensaje_posicion = "%s %s %s %s %s%s" % (self.nombre, "T", self.angulo, self.rect.x, self.rect.y, TERMINATOR) # sólo lo usa el local def set_posicion(self, angulo=0, x=0, y=0): # Se reciben los datos desde el server, se actualiza la posición del tanque, se guardan los datos en ultimo mensaje self.angulo = angulo self.rect.x = x self.rect.y = y self.image = pygame.transform.rotate(self.imagen_original, -self.angulo) def get_datos_para_la_red(self): # devuelve los nuevos datos formateados para ser enviados buffer_de_salida = "" if self.nuevo_mensaje_posicion != self.ultimo_mensaje_posicion: # Si ha cambiado la posición o el angulo self.ultimo_mensaje_posicion = self.nuevo_mensaje_posicion buffer_de_salida += self.nuevo_mensaje_posicion if self.nuevo_mensaje_bala and self.estado_bala == "disparada": # Si se ha disparado una bala buffer_de_salida += self.nuevo_mensaje_bala self.estado_bala = "enviada" if self.nuevos_datos_puntos: # pasar puntaje y energía mensaje_puntos = "%s %s %s%s" % ("D", self.energia, self.puntaje, TERMINATOR) buffer_de_salida += mensaje_puntos self.nuevos_datos_puntos = False if buffer_de_salida: # Si hay datos return buffer_de_salida else: return "%s%s" % ("P", TERMINATOR) def set_puntaje(self, energia, puntaje): # actualiza puntaje y energía self.energia, self.puntaje = energia, puntaje if self.energia < 1: self.energia = 100 self.set_posicion(angulo=0, x=0, y=0) self.nuevo_mensaje_posicion = "%s %s %s %s %s%s" % (self.nombre, "T", self.angulo, self.rect.x, self.rect.y, TERMINATOR) # ------------------- Inicio de Cálculos en Función de los Eventos Recibidos (esto no actualiza el sprite ----------------------- def evento(self, tecla): # El tanque local responde a la captura de teclas # mandar girar, se suma o resta grados if tecla == K_RIGHT: self.angulo += int(0.7 * INDICE_ROTACION) self.image = pygame.transform.rotate(self.imagen_original, -self.angulo) elif tecla == K_LEFT: self.angulo -= int(0.7 * INDICE_ROTACION) self.image = pygame.transform.rotate(self.imagen_original, -self.angulo) # mandar mover, se calcula x e y segun la direccion de movimiento. if tecla == K_UP: self.dx, self.dy = self.get_vector(self.angulo) self.actualizar_posicion() elif tecla == K_DOWN: x, y = self.get_vector(self.angulo) self.dx = x * -1 self.dy = y * -1 self.actualizar_posicion() # Si hay eventos de posición, hay cambios y debe informarse self.nuevo_mensaje_posicion = "%s %s %s %s %s%s" % (self.nombre, "T", self.angulo, self.rect.x, self.rect.y, TERMINATOR) # Disparar if tecla == K_LCTRL: if not self.bala and self.estado_bala == "recibida": self.estado_bala = None if not self.bala and self.estado_bala == None: (x, y) = self.rect.center self.nuevo_mensaje_bala = "%s %s %s %s %s%s" % (self.nombre, "B", self.angulo, x, y, TERMINATOR) self.estado_bala = "disparada" #print "Bala", self.estado_bala, self.nuevo_mensaje_bala def get_vector(self, angulo): # Recibe un ángulo que da orientación al tanque # Devuelve el incremento de puntos x,y en su desplazamiento x = int(cos(radians(angulo)) * VELOCIDAD) y = int(sin(radians(angulo)) * VELOCIDAD) return x,y def actualizar_posicion(self): # cambia la posicion del rectangulo # Solo se ejecuta si el tanque se mueve hacia adelante o hacia atras # no se ejecuta cuando está girando en un mismo lugar x = self.x + self.dx y = self.y + self.dy if x > 0 and x < self.ancho_monitor and y > 0 and y < self.alto_monitor: self.x += self.dx self.y += self.dy self.rect.x = int(self.x) - self.rect.w / 2 self.rect.y = int(self.y) - self.rect.h / 2 # ------------------- Fin de Cálculos en Función de los Eventos Recibidos ---------------------------- def crear_disparo(self, autor, angulo, origen_disparo): # Genera un disparo self.bala = Bala(autor=autor, angulo=angulo, origen_disparo=origen_disparo, directorio_de_imagenes=self.directorio_de_imagenes) #print "crear disparo: ", autor, angulo, origen_disparo VELOCIDADBALA = 18 class Bala(pygame.sprite.Sprite): # Las Balas del tanque. def __init__(self, autor=None, angulo=0, origen_disparo=(0,0), directorio_de_imagenes=None): pygame.sprite.Sprite.__init__(self) self.directorio_de_imagenes = directorio_de_imagenes self.autor = autor self.imagen_original = pygame.image.load(self.directorio_de_imagenes+"bala.bmp") self.image = self.imagen_original.copy() self.image.set_colorkey(MAGENTA) self.rect = self.image.get_rect() self.angulo = angulo (self.rect.x, self.rect.y) = origen_disparo self.dx, self.dy = self.get_vector(angulo) self.Actualizar() def get_posicion(self): # devuelve la posicion actual return self.angulo, self.rect.x, self.rect.y def get_vector(self, angulo): # Recibe un ángulo que da orientación al disparo # Devuelve el incremento de puntos x,y self.angulo = angulo x = int(cos(radians(angulo)) * VELOCIDADBALA) y = int(sin(radians(angulo)) * VELOCIDADBALA) return x,y def Actualizar(self): self.rect.x += self.dx self.rect.y += self.dy return self.rect.x, self.rect.y