Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflavio <fdanesse@gmail.com>2011-11-26 23:51:04 (GMT)
committer flavio <fdanesse@gmail.com>2011-11-26 23:51:04 (GMT)
commitd2bdd86293f62663389894d9d6100c829ddd68fc (patch)
treef38821aa03564673e229d7883449b2af5022f570
Aprendiendo gitHEADmaster
-rw-r--r--Enlace_Red_JAMtank.py179
-rw-r--r--Graficos_JAMtank.py299
-rw-r--r--Imagenes/JAMtank.pngbin0 -> 399222 bytes
-rw-r--r--Imagenes/Tanque.bmpbin0 -> 6778 bytes
-rw-r--r--Imagenes/Tanque_Enemigo.bmpbin0 -> 6778 bytes
-rw-r--r--Imagenes/Teclado.pngbin0 -> 32239 bytes
-rw-r--r--Imagenes/bala.bmpbin0 -> 374 bytes
-rw-r--r--Imagenes/explosion.pngbin0 -> 1255 bytes
-rw-r--r--Imagenes/fondo.pngbin0 -> 153544 bytes
-rw-r--r--Imagenes/tank1.pngbin0 -> 864 bytes
-rw-r--r--Imagenes/tank2.pngbin0 -> 938 bytes
-rw-r--r--JAMtank.py98
-rw-r--r--Jugador_JAMtank.py225
-rw-r--r--Manejador_de_Eventos.py96
-rw-r--r--Sonidos/Juego.oggbin0 -> 87134 bytes
-rw-r--r--Sonidos/Menu.oggbin0 -> 90525 bytes
-rw-r--r--Sonidos/Tanque-M60.oggbin0 -> 17352 bytes
-rw-r--r--Sonidos/explosion.oggbin0 -> 22121 bytes
-rw-r--r--Sonidos/motor.oggbin0 -> 13787 bytes
-rw-r--r--TCP_Server_thread_Stream.py234
-rw-r--r--Variables.py84
-rw-r--r--activity/JAMtank.svg141
-rw-r--r--activity/activity.info7
-rw-r--r--gtk_JAMtank_Ventana.py335
-rw-r--r--setup.py3
25 files changed, 1701 insertions, 0 deletions
diff --git a/Enlace_Red_JAMtank.py b/Enlace_Red_JAMtank.py
new file mode 100644
index 0000000..e905c75
--- /dev/null
+++ b/Enlace_Red_JAMtank.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Enlace_Red_JAMtank.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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 gc
+gc.enable()
+
+import socket, time
+import os
+import sys
+
+from Jugador_JAMtank import Jugador_JAMtank
+
+TERMINATOR = "\r\n\r\n"
+
+class Enlace_Red_JAMtank():
+ def __init__(self, ip="localhost", PUERTO=5000, protagonista=None, objetos_graficos=None, nombre=None):
+ # El socket con el server
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ # La direccion de escucha del server
+ self.direccion_servidor = (ip, PUERTO)
+ self.socket.connect(self.direccion_servidor)
+ self.socket.setblocking(0)
+
+ # Datos del Jugador Local
+ self.nombre = nombre # identifica al jugador local en el server
+ self.protagonista = protagonista # es el jugador local
+
+ # Debe informarse de los cambios a los objetos gráficos
+ self.objetos_graficos = objetos_graficos
+
+ # Diccionario de jugadores en el juego
+ self.jugadores = {} # Diccionario=> key=nombre:value=Jugador_JAMtank(pygame.sprite.Sprite)
+
+ # Datos entrantes y salientes
+ self.buffer_de_salida = None
+
+ # Latencia en la red
+ self.TIEMPO_ENVIO = 0.0
+ self.TIEMPO_RECIBO = 0.0
+ self.LATENCIA = 0.0
+
+ def desconectarse (self):
+ # cierra el socket, el server debe hacer finish
+ print "Desconectandose de la Red . . ."
+ self.socket.close()
+ time.sleep(0.2)
+
+ def enviar_datos(self):
+ # Envia datos al server, el buffer es llenado desde JAMtank
+ #print "Enviando Datos en Enlace_Red_JAMtank: ", self.buffer_de_salida
+ # calculo de latencia
+ self.TIEMPO_ENVIO = time.time()
+ try:
+ self.socket.send(self.buffer_de_salida)
+ except socket.error, e:
+ #print "Error en Cliente al Enviar Datos: ", self.buffer_de_salida, "Error %s" % (e)
+ return
+
+ self.buffer_de_salida = ""
+
+ def get_jugadores_puntos(self):
+ # devuelve una lista puntos-nombre para armar un ranking
+ lista = []
+ for jugador in self.jugadores.values():
+ puntaje, nombre = jugador.puntaje, jugador.nombre
+ lista.append( (puntaje, nombre) )
+ return lista
+
+ def recibir_datos(self):
+ # recibe los datos del server (incluyendo los propios)
+ buffer_de_entrada = None
+ mensajes = None
+ try:
+ buffer_de_entrada = self.socket.recv(512)
+ mensajes = list(buffer_de_entrada.split(TERMINATOR))
+ self.procesar_datos(mensajes)
+ except socket.error, e:
+ #print "Error en Cliente al Recibir Datos: ", buffer_de_entrada, "Error %s" % (e)
+ return
+
+ '''
+ # calculo de latencia
+ self.TIEMPO_RECIBO = time.time()
+ tiempo = self.TIEMPO_RECIBO-self.TIEMPO_ENVIO
+ if tiempo > self.LATENCIA:
+ self.LATENCIA = tiempo
+ print self.LATENCIA '''
+
+ def procesar_datos(self, lista_mesajes):
+ # Se recibe una lista de mensajes y se procesan según su tipo
+
+ for mensaje in lista_mesajes: # para todos los mensajes
+
+ valores = mensaje.split() # separar los datos
+
+ if "T" in valores:
+ # Recibe los datos de posición de un tanque
+ try:
+ nombre, angulo, x, y = int(valores[0]), int(valores[2]), int(valores[3]), int(valores[4])
+ except:
+ return
+
+ if nombre not in self.jugadores.keys():
+ # Si es un nuevo jugador, lo agrega al diccionario
+ if nombre == self.nombre:
+ # Si es el jugador local es el protagonista
+ self.jugadores[nombre] = self.protagonista
+ else:
+ # Si no es el jugador local
+ img = self.objetos_graficos.directorio_de_imagenes+"Tanque_Enemigo.bmp"
+ self.jugadores[nombre] = Jugador_JAMtank(imagen=img,nombre=nombre, angulo=angulo, x=x, y=y,resolucion_monitor=self.objetos_graficos.resolucion_monitor,
+ directorio_de_imagenes=self.objetos_graficos.directorio_de_imagenes)
+ self.jugadores[nombre].setup()
+
+ self.objetos_graficos.tanques.add(self.jugadores[nombre])
+ self.objetos_graficos.set_play_motor()
+
+ # Ranking
+ #self.objetos_graficos.set_menu_jugadores(self.get_jugadores_puntos())
+
+ # Actualiza la posicion del tanque
+ if nombre != self.nombre:
+ self.jugadores[nombre].set_posicion(angulo=angulo, x=x, y=y) # actualiza la posición
+
+
+ elif "DES" in valores:
+ # un jugador se ha desconectado
+ nombre = int(valores[1])
+ self.jugadores[nombre].kill()
+ del self.jugadores[nombre]
+
+ elif "B" in valores:
+ # Recibe los datos de una bala
+ try:
+ nombre, angulo, x, y = int(valores[0]), int(valores[2]), int(valores[3]), int(valores[4])
+ except:
+ return
+ self.jugadores[nombre].crear_disparo(nombre, angulo, (x,y))
+ self.objetos_graficos.todas_las_balas.add(self.jugadores[nombre].bala)
+ self.objetos_graficos.set_play_bala()
+
+ if nombre == self.nombre:
+ # si la bala es propia, se informa de que se recibió, cuando la bala desaparezca, se pondrá en None
+ self.protagonista.estado_bala = "recibida"
+
+ elif "D" in valores:
+ # Recibe el puntaje de un jugador
+ # self.puntos = "%s %s %s %s%s" % (self.nombre, "D", energia, puntaje, TERMINATOR)
+ try:
+ nombre, energia, puntaje = int(valores[0]), int(valores[2]), int(valores[3])
+ except:
+ return
+ self.jugadores[nombre].set_puntaje(energia, puntaje)
+
+ elif "P" in valores:
+ pass
+ else:
+ if valores:
+ print "recibiendo cosas raras en el cliente:", valores
+ pass
diff --git a/Graficos_JAMtank.py b/Graficos_JAMtank.py
new file mode 100644
index 0000000..b338133
--- /dev/null
+++ b/Graficos_JAMtank.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Graficos_JAMtank.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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 gc
+gc.enable()
+
+BLANCO = pygame.Color ("white")#(255, 255, 255, 1)
+AMARILLO = pygame.Color ("yellow")#(255, 255, 0, 1)
+ROJO = pygame.Color ("red")#(255, 0, 0, 1)
+
+# para las balas
+MAGENTA = (255, 0, 255)
+VELOCIDAD = 8
+from math import sin, cos, radians
+from pygame.sprite import Sprite
+
+class Graficos_JAMtank():
+ ''' Maneja todos los objetos gráficos y de audio del juego. '''
+
+ def __init__(self, resolucion_monitor, directorio_de_imagenes, directorio_de_sonidos):
+ # Monitor
+ self.resolucion_monitor = resolucion_monitor
+
+ # Ventana y Escenario
+ self.directorio_de_imagenes = directorio_de_imagenes
+ self.fondo = None
+ self.ventana = None
+
+ # Sonido
+ self.directorio_de_sonidos = directorio_de_sonidos
+ self.sonido_disparo = None
+ self.sonido_motor = None
+ self.sonido_juego = None
+
+ # sprites y grupos de sprits
+ self.tanques = pygame.sprite.RenderUpdates() # todos los tanques en el juego
+ self.todas_las_balas = pygame.sprite.RenderUpdates() # todas las balas en el juego
+ self.textos = pygame.sprite.RenderUpdates() # información en pantalla para puntaje y energia de tanques
+ self.protagonista = None
+ self.explosiones = pygame.sprite.RenderUpdates()
+
+ # Fuente y textos del menú energía y puntaje
+ self.fuente_menu = None
+ self.img_puntaje = pygame.sprite.Sprite()
+ self.img_energia = pygame.sprite.Sprite()
+ self.textos_jugadores = pygame.sprite.RenderUpdates()
+
+ def set_menu_puntaje(self):
+ # Crea el menu de energía y puntaje del jugador local
+ puntos = 1000
+ energia = 100
+
+ titulo_puntaje = pygame.sprite.Sprite()
+ titulo_energia = pygame.sprite.Sprite()
+
+ x = 5
+ titulo_puntaje.image = self.fuente_menu.render("Puntos:", 1, (BLANCO))
+ titulo_puntaje.rect = titulo_puntaje.image.get_rect()
+ titulo_puntaje.rect.x = x
+ titulo_puntaje.rect.y = 0
+ self.textos.add(titulo_puntaje)
+
+ x += int(titulo_puntaje.rect.width + 10)
+ self.img_puntaje.image = self.fuente_menu.render(str(puntos), 1, (AMARILLO))
+ self.img_puntaje.rect = self.img_puntaje.image.get_rect()
+ self.img_puntaje.rect.x = x
+ self.img_puntaje.rect.y = 0
+ self.textos.add(self.img_puntaje)
+
+ x += int(self.img_puntaje.rect.width + 10)
+ titulo_energia.image = self.fuente_menu.render("Energia:", 1, (BLANCO))
+ titulo_energia.rect = titulo_energia.image.get_rect()
+ titulo_energia.rect.x = x
+ titulo_energia.rect.y = 0
+ self.textos.add(titulo_energia)
+
+ x += int(titulo_energia.rect.width + 10)
+ self.img_energia.image = self.fuente_menu.render(str(energia), 1, (AMARILLO))
+ self.img_energia.rect = self.img_energia.image.get_rect()
+ self.img_energia.rect.x = x
+ self.img_energia.rect.y = 0
+ self.textos.add(self.img_energia)
+
+ def set_menu_jugadores(self, lista):
+ # Crea el menu de energía y puntaje del jugador local
+ for texto in self.textos_jugadores:
+ texto.kill()
+
+ #lista.sort()
+ ancho_pantalla = self.resolucion_monitor[0]
+ distancia = 10
+ y = 0
+ for elemento in lista:
+ puntos, nombre = elemento
+
+ img_nombre = pygame.sprite.Sprite()
+ img_puntaje = pygame.sprite.Sprite()
+
+ img_puntaje.image = self.fuente_menu.render(str(puntos), 1, (AMARILLO))
+ img_puntaje.rect = img_puntaje.image.get_rect()
+ img_nombre.image = self.fuente_menu.render(str(nombre), 1, (AMARILLO))
+ img_nombre.rect = img_nombre.image.get_rect()
+
+ img_puntaje.rect.x = ancho_pantalla - img_puntaje.rect.w - distancia - img_nombre.rect.w
+ img_puntaje.rect.y = y
+
+ img_nombre.rect.x = ancho_pantalla - img_nombre.rect.w
+ img_nombre.rect.y = y
+
+ self.textos_jugadores.add(img_nombre)
+ self.textos_jugadores.add(img_puntaje)
+
+ y += 20
+
+ def set_menu_ip_server(self, ip):
+ # Para mostrar la ip del servidor del juego
+ texto = "IP del Servidor: %s" %(ip)
+
+ img_texto = pygame.sprite.Sprite()
+ img_texto.image = self.fuente_menu.render(str(texto), 1, (BLANCO))
+ img_texto.rect = img_texto.image.get_rect()
+
+ img_texto.rect.x = 0
+ img_texto.rect.y = 860
+
+ self.textos.add(img_texto)
+
+ def actualiza_puntaje(self, puntos=0, energia=100):
+ # Actualiza en pantalla el puntaje y la energia del jugador local
+ self.img_puntaje.image = self.fuente_menu.render(str(puntos), 1, (AMARILLO))
+ color = AMARILLO
+ if energia < 50: color = ROJO
+ self.img_energia.image = self.fuente_menu.render(str(energia), 1, (color))
+
+ def actualizar(self):
+ # dibuja los sprites y el fondo
+
+ # Actualiza la imagen de los tanques
+ self.tanques.clear(self.ventana, self.fondo)
+ cambios = self.tanques.draw(self.ventana)
+
+ # Actualiza la imagen del menú
+ self.textos.clear(self.ventana, self.fondo)
+ cambios.extend( self.textos.draw(self.ventana) )
+
+ # Actualiza las balas en pantalla
+ if self.todas_las_balas:
+ self.todas_las_balas.clear(self.ventana, self.fondo)
+ for bala in self.todas_las_balas:
+ x, y = bala.Actualizar()
+ if x < 0 or x > self.resolucion_monitor[0] or y < 0 or y > self.resolucion_monitor[1]:
+ # Si se sale de la pantalla se elimina
+
+ for tanque in self.tanques:
+ # buscar entre los tanques al que tenga el mismo nombre y poner bala en None
+ if tanque.nombre == bala.autor:
+ tanque.bala = None
+ bala.kill()
+ else:
+ # si no se sale de la pantalla ver si le pega a alguien
+ self.detectar_colisiones(bala)
+ cambios.extend( self.todas_las_balas.draw(self.ventana) )
+
+ # Actualiza las explosiones
+ if self.explosiones:
+ self.explosiones.clear(self.ventana, self.fondo)
+ for explosion in self.explosiones:
+ explosion.Actualizar()
+ cambios.extend( self.explosiones.draw(self.ventana) )
+
+ # Actualiza la imagen del ranking
+ self.textos_jugadores.clear(self.ventana, self.fondo)
+ cambios.extend( self.textos_jugadores.draw(self.ventana) )
+
+ pygame.display.update(cambios) # dibuja el personaje y las balas
+
+ '''# efecto sello
+ self.tanques.draw(self.ventana)
+ pygame.display.update()'''
+
+ def detectar_colisiones(self, bala):
+ # Detecta las colisiones entre balas y tanques.
+ for tanque in self.tanques:
+ if bala.autor != tanque.nombre:
+ # si la bala no pertenece al tanque que está tocando.
+ if bala.rect.colliderect(tanque.rect):
+ # Si la bala toca al tanque
+
+ if tanque == self.protagonista:
+ # Si me pegan a mi, pierdo energia
+ self.protagonista.energia -= 10
+ self.protagonista.nuevos_datos_puntos = True
+
+ elif bala.autor == self.protagonista.nombre:
+ # si yo le pego a otro, cobro punto
+ tanque.energia -= 10
+ if tanque.energia < 1:
+ tanque.energia = 100
+ self.protagonista.puntaje += 1
+ self.protagonista.nuevos_datos_puntos = True
+ else:
+ # si se pegan entre ellos
+ pass
+
+ # dibujar explosión
+ angulo, x, y = bala.get_posicion()
+ bala.kill()
+ self.explosiones.add(Explosion(x=x, y=y, image_explosion=self.image_explosion, sonido_explosion=self.sonido_explosion))
+
+ for tanque1 in self.tanques:
+ # buscar entre los tanques al que tenga el mismo nombre y poner bala en None
+ if tanque1.nombre == bala.autor:
+ tanque1.bala = None
+ else:
+ # si la bala pertenece a este tanque no hacer nada.
+ pass
+
+ def set_play_motor(self):
+ self.sonido_motor.play(-1)
+
+ def set_play_bala(self):
+ self.sonido_disparo.play()
+
+ def iniciar_escenario(self):
+ # levanta el Escenario
+ print "Iniciando el Escenario de JAMtank"
+ self.ventana.blit(self.fondo, (0,0))
+ pygame.display.update()
+
+ def setup(self, Jugador_JAMtank=None):
+ # Configurar objetos gráficos y de sonido para el juego
+ print "Seteando Modo Gráfico, Sonidos y Fuentes para JAMtank"
+ pygame.init()
+ self.protagonista=Jugador_JAMtank
+ # Monitor y Ventana
+ pygame.display.set_mode(self.resolucion_monitor, 0, 0)
+ pygame.display.set_caption("JAMtank - fdanesse@hotmail.com - CeibalJAM! - Uruguay")
+ # Ventana y Escenario
+ self.fondo = pygame.transform.scale(pygame.image.load(self.directorio_de_imagenes+"fondo.png"), self.resolucion_monitor).convert_alpha()
+ self.ventana = pygame.display.get_surface() # la ventana del juego
+ # Mouse
+ pygame.mouse.set_visible(False)
+ # Sonido
+ pygame.mixer.init(44100, -16, 2, 2048)
+ pygame.mixer.music.set_volume(1.0)
+ self.sonido_disparo = pygame.mixer.Sound(self.directorio_de_sonidos+"Tanque-M60.ogg")
+ self.sonido_motor = pygame.mixer.Sound(self.directorio_de_sonidos+"motor.ogg")
+ self.sonido_juego = pygame.mixer.Sound(self.directorio_de_sonidos+"Juego.ogg")
+ self.sonido_juego.play(-1)
+ # Explosiones
+ self.sonido_explosion = pygame.mixer.Sound(self.directorio_de_sonidos+"explosion.ogg")
+ self.image_explosion = pygame.image.load(self.directorio_de_imagenes+"explosion.png").convert_alpha()
+ # Fuentes
+ pygame.font.init()
+ self.fuente_menu = pygame.font.Font(pygame.font.match_font('Purisa', True, False), 25)
+
+ # http://efectos-de-sonido.anuncios-radio.com/gratis/
+ # http://www.tuwebdeinformatica.com/Crearjuegos/massprites3.html
+
+class Explosion(pygame.sprite.Sprite):
+# Las Balas del tanque.
+ def __init__(self, x=0, y=0, image_explosion=None, sonido_explosion=None):
+
+ pygame.sprite.Sprite.__init__(self)
+
+ self.image = image_explosion
+ self.rect = self.image.get_rect()
+ self.rect.center = (x, y)
+ self.contador = 0
+ self.sonido_explosion = sonido_explosion
+ self.sonido_explosion.play()
+ self.Actualizar()
+
+ def Actualizar(self):
+ self.contador += 1
+ if self.contador == 5:
+ self.kill()
+
diff --git a/Imagenes/JAMtank.png b/Imagenes/JAMtank.png
new file mode 100644
index 0000000..ff5690d
--- /dev/null
+++ b/Imagenes/JAMtank.png
Binary files differ
diff --git a/Imagenes/Tanque.bmp b/Imagenes/Tanque.bmp
new file mode 100644
index 0000000..45168b9
--- /dev/null
+++ b/Imagenes/Tanque.bmp
Binary files differ
diff --git a/Imagenes/Tanque_Enemigo.bmp b/Imagenes/Tanque_Enemigo.bmp
new file mode 100644
index 0000000..ece7165
--- /dev/null
+++ b/Imagenes/Tanque_Enemigo.bmp
Binary files differ
diff --git a/Imagenes/Teclado.png b/Imagenes/Teclado.png
new file mode 100644
index 0000000..ae56fec
--- /dev/null
+++ b/Imagenes/Teclado.png
Binary files differ
diff --git a/Imagenes/bala.bmp b/Imagenes/bala.bmp
new file mode 100644
index 0000000..f6f0248
--- /dev/null
+++ b/Imagenes/bala.bmp
Binary files differ
diff --git a/Imagenes/explosion.png b/Imagenes/explosion.png
new file mode 100644
index 0000000..9d87bfd
--- /dev/null
+++ b/Imagenes/explosion.png
Binary files differ
diff --git a/Imagenes/fondo.png b/Imagenes/fondo.png
new file mode 100644
index 0000000..b655013
--- /dev/null
+++ b/Imagenes/fondo.png
Binary files differ
diff --git a/Imagenes/tank1.png b/Imagenes/tank1.png
new file mode 100644
index 0000000..ea012a0
--- /dev/null
+++ b/Imagenes/tank1.png
Binary files differ
diff --git a/Imagenes/tank2.png b/Imagenes/tank2.png
new file mode 100644
index 0000000..e0c38a2
--- /dev/null
+++ b/Imagenes/tank2.png
Binary files differ
diff --git a/JAMtank.py b/JAMtank.py
new file mode 100644
index 0000000..a957c5a
--- /dev/null
+++ b/JAMtank.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# JAMtank.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# CeibalJAM! - Uruguay
+#
+# 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 gc
+gc.enable()
+
+import os
+
+# Constantes para todo el Juego
+RESOLUCIONMONITOR = (1200,900)
+DIRECTORIODEIMAGENES = os.getcwd()+"/Imagenes/"
+DIRECTORIODESONIDOS = os.getcwd()+"/Sonidos/"
+MINOMBRE = os.getpid() # me identifica en el servidor
+
+# importación de clases para objetos del juego en el cliente
+from Graficos_JAMtank import Graficos_JAMtank
+from Manejador_de_Eventos import Manejador_de_Eventos
+from Jugador_JAMtank import Jugador_JAMtank
+from Enlace_Red_JAMtank import Enlace_Red_JAMtank
+
+class JAMtank():
+ ''' Motor del Juego. Máquina de estados. '''
+ def __init__(self, ip="localhost", PUERTO=5000):
+ # Todo lo que deba ser dibujado se hace en esta clase
+ self.objetos_graficos = Graficos_JAMtank(RESOLUCIONMONITOR, DIRECTORIODEIMAGENES, DIRECTORIODESONIDOS)
+ # Todos los eventos se manejan en esta clase
+ self.objetos_de_eventos = Manejador_de_Eventos()
+ # El Jugador Local
+ self.protagonista = Jugador_JAMtank(imagen=DIRECTORIODEIMAGENES+"Tanque.bmp", nombre=MINOMBRE,
+ angulo=0, x=0, y=0, resolucion_monitor=RESOLUCIONMONITOR,
+ directorio_de_imagenes=DIRECTORIODEIMAGENES) # recordar que es un tanque sprite
+
+ # Enlace con el servidor en la red
+ self.enlace_red = Enlace_Red_JAMtank(ip=ip, PUERTO=PUERTO, protagonista=self.protagonista, objetos_graficos=self.objetos_graficos, nombre=MINOMBRE)
+ self.reloj = pygame.time.Clock()
+
+ self.Run() # ejecuta el juego.
+
+ def Run(self):
+ # ----------------------- Comienza el juego ---------------------------
+
+ self.objetos_graficos.setup(Jugador_JAMtank=self.protagonista) # Iniciando pygame
+ self.objetos_graficos.iniciar_escenario() # Levantando Escenario y Fondo
+ self.objetos_graficos.set_menu_puntaje() # Levantando Menús para Puntajes
+
+ self.objetos_de_eventos.setup(Jugador_JAMtank=self.protagonista, Enlace_Red=self.enlace_red) # Configurando Eventos para el Jugador Local
+ self.protagonista.setup() # Configurando al jugador protagónico (el local)
+ self.objetos_graficos.set_menu_ip_server(self.enlace_red.direccion_servidor[0])
+ pygame.time.wait(3)
+ self.estado = "En Juego"
+
+ #contar = 0
+ while self.estado == "En Juego":
+ self.reloj.tick(35)
+
+ # Detectar eventos y calcular en consecuencia
+ self.objetos_de_eventos.detectar()
+
+ # recolectar datos para enviar, recordar que los objetos se actualizan cuando los datos vuelven del server
+ self.enlace_red.buffer_de_salida = self.protagonista.get_datos_para_la_red()
+
+ self.enlace_red.enviar_datos()# enviar datos
+ self.enlace_red.recibir_datos()# recibir datos
+
+ # Actualiza los datos de puntaje y energia del jugador local en pantalla
+ self.objetos_graficos.actualiza_puntaje(puntos=self.protagonista.puntaje, energia=self.protagonista.energia)
+
+ # ranking
+ self.objetos_graficos.set_menu_jugadores(self.enlace_red.get_jugadores_puntos())
+
+ # Dibuja los cambios en pantalla
+ self.objetos_graficos.actualizar()
+ pygame.time.wait(1)
+
+if __name__ == "__main__":
+ JAMtank("localhost")
+
diff --git a/Jugador_JAMtank.py b/Jugador_JAMtank.py
new file mode 100644
index 0000000..4f81aa2
--- /dev/null
+++ b/Jugador_JAMtank.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Jugador_JAMtank.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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
diff --git a/Manejador_de_Eventos.py b/Manejador_de_Eventos.py
new file mode 100644
index 0000000..5e1b510
--- /dev/null
+++ b/Manejador_de_Eventos.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Manejador_de_Eventos.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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 gc
+gc.enable()
+
+class Manejador_de_Eventos():
+ ''' Maneja todos los eventos del juego. '''
+ def __init__(self):
+ pass
+
+ def setup(self, Jugador_JAMtank=None, Enlace_Red=None):
+ # Configurar objetos de eventos para el juego y asociarlos al jugador local
+
+ self.red = Enlace_Red
+ print "Seteando Eventos de Usuario para JAMtank"
+ self.protagonista = Jugador_JAMtank
+ pygame.event.set_blocked([MOUSEMOTION, MOUSEBUTTONUP, MOUSEBUTTONDOWN, JOYAXISMOTION, JOYBALLMOTION, JOYHATMOTION, JOYBUTTONUP, JOYBUTTONDOWN,
+ KEYUP, VIDEORESIZE, VIDEOEXPOSE, USEREVENT, QUIT, ACTIVEEVENT]) # bloqueados
+ pygame.event.set_allowed([KEYDOWN]) # permitidos
+ pygame.key.set_repeat(15, 15) # repetición de teclas
+
+ def detectar(self):
+ # detecta si hay eventos
+ hayTeclas = False
+ for event in pygame.event.get():
+ if event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
+ hayTeclas = True
+ if hayTeclas:
+ self.Manejar_Eventos()
+ pygame.event.clear()
+
+ def Manejar_Eventos(self):
+ # Maneja los eventos del usuario
+ teclas = pygame.key.get_pressed()
+
+ # girar en movimiento
+ if teclas[pygame.K_UP] and teclas[pygame.K_RIGHT]:# adelante - derecha
+ self.protagonista.evento(pygame.K_UP)
+ self.protagonista.evento(pygame.K_RIGHT)
+ elif teclas[pygame.K_UP] and teclas[pygame.K_LEFT]:# adelante - izquierda
+ self.protagonista.evento(pygame.K_UP)
+ self.protagonista.evento(pygame.K_LEFT)
+ elif teclas[pygame.K_DOWN] and teclas[pygame.K_RIGHT]:# atras - derecha
+ self.protagonista.evento(pygame.K_DOWN)
+ self.protagonista.evento(pygame.K_LEFT)
+ elif teclas[pygame.K_DOWN] and teclas[pygame.K_LEFT]:# atras - izquierda
+ self.protagonista.evento(pygame.K_DOWN)
+ self.protagonista.evento(pygame.K_RIGHT)
+
+ # moverse sin girar
+ elif teclas[pygame.K_UP] and not teclas[pygame.K_DOWN]:# adelante
+ self.protagonista.evento(pygame.K_UP)
+ elif teclas[pygame.K_DOWN] and not teclas[pygame.K_UP]:# atras
+ self.protagonista.evento(pygame.K_DOWN)
+
+ # girar sin moverse
+ elif teclas[pygame.K_RIGHT] and not teclas[pygame.K_LEFT]:# derecha
+ self.protagonista.evento(pygame.K_RIGHT)
+ elif teclas[pygame.K_LEFT] and not teclas[pygame.K_RIGHT]:# izquierda
+ self.protagonista.evento(pygame.K_LEFT)
+
+ # Disparar.
+ if teclas[pygame.K_LCTRL]:
+ self.protagonista.evento(pygame.K_LCTRL)
+ # salir
+ elif teclas[pygame.K_ESCAPE]:
+ print "*** Cerrando pygame y Saliendo del Juego ***"
+ self.red.desconectarse()
+ pygame.quit()
+ import sys
+ sys.exit()
+ else:
+ pass
+
diff --git a/Sonidos/Juego.ogg b/Sonidos/Juego.ogg
new file mode 100644
index 0000000..6d3a054
--- /dev/null
+++ b/Sonidos/Juego.ogg
Binary files differ
diff --git a/Sonidos/Menu.ogg b/Sonidos/Menu.ogg
new file mode 100644
index 0000000..d4fa3b3
--- /dev/null
+++ b/Sonidos/Menu.ogg
Binary files differ
diff --git a/Sonidos/Tanque-M60.ogg b/Sonidos/Tanque-M60.ogg
new file mode 100644
index 0000000..741528e
--- /dev/null
+++ b/Sonidos/Tanque-M60.ogg
Binary files differ
diff --git a/Sonidos/explosion.ogg b/Sonidos/explosion.ogg
new file mode 100644
index 0000000..bf6e6a1
--- /dev/null
+++ b/Sonidos/explosion.ogg
Binary files differ
diff --git a/Sonidos/motor.ogg b/Sonidos/motor.ogg
new file mode 100644
index 0000000..66f3e0b
--- /dev/null
+++ b/Sonidos/motor.ogg
Binary files differ
diff --git a/TCP_Server_thread_Stream.py b/TCP_Server_thread_Stream.py
new file mode 100644
index 0000000..93cf2ee
--- /dev/null
+++ b/TCP_Server_thread_Stream.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# TCP_Server_thread_Stream.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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 time
+import socket
+import threading
+import SocketServer
+
+import time
+from SocketServer import StreamRequestHandler
+from SocketServer import ThreadingTCPServer
+
+import Variables as ESPEJO
+
+class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.ThreadingTCPServer):
+ ''' Servidor Multihilo para conexiones simultáneas. '''
+ pass
+ '''
+ __init__(self, server_address, RequestHandlerClass) from TCPServer
+ fileno(self) from TCPServer
+ finish_request(self, request, client_address) from TCPServer
+ get_request(self) from TCPServer
+ handle_error(self, request, client_address) from TCPServer
+ handle_request(self) from TCPServer
+ process_request(self, request, client_address) from ThreadingMixIn
+ serve_forever(self) from TCPServer
+ server_activate(self) from TCPServer
+ server_bind(self) from TCPServer
+ verify_request(self, request, client_address) from TCPServer
+ '''
+ '''
+ def __init__(self, server_address, handler_class=None):
+ SocketServer.TCPServer.__init__(self, server_address, handler_class)
+ return
+
+ def server_activate(self):
+ SocketServer.TCPServer.server_activate(self)
+ return
+
+ def serve_forever(self):
+ while True:
+ self.handle_request()
+ return
+
+ def handle_request(self):
+ return SocketServer.TCPServer.handle_request(self)
+
+ def verify_request(self, request, client_address):
+ return SocketServer.TCPServer.verify_request(self, request, client_address)
+
+ def process_request(self, request, client_address):
+ return SocketServer.TCPServer.process_request(self, request, client_address)
+
+ def server_close(self):
+ return SocketServer.TCPServer.server_close(self)
+
+ def finish_request(self, request, client_address):
+ return SocketServer.TCPServer.finish_request(self, request, client_address)
+
+ def close_request(self, request_address):
+ return SocketServer.TCPServer.close_request(self, request_address) '''
+
+class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler):
+ ''' Atiende y procesa todas las conexiones entrantes
+ __del__(self) from BaseRequestHandler
+ __init__(self, request, client_address, server) from BaseRequestHandler
+ finish(self)
+ handle(self) from BaseRequestHandler
+ setup(self)
+ def __init__(self, request, client_address, server):
+ SocketServer.StreamRequestHandler.__init__(self, request, client_address, server)
+ return '''
+
+ def handle(self):
+ # Acepta la conexión de un jugador
+ while 1:
+ try:
+ datos = self.request.recv(200)
+ self.recibir_datos(datos)
+ self.enviar_datos()
+
+ except socket.error, e:
+ print "Error en Handle del Server: ", "Error %s" % (e)
+ self.request.close()
+ return
+
+ def recibir_datos(self, datos):
+ # Recibe los datos del jugador conectado
+ mensajes = str(datos).split(ESPEJO.TERMINATOR)
+ #print "Datos Recibidos en Servidor: ", mensajes
+
+ for mensaje in mensajes:
+ valores = mensaje.split()
+ if "T" in valores:
+ # Se recibe un tanque
+ try:
+ # para evitar que falle si no vienen todos los datos
+ nombre, angulo, x, y = int(valores[0]), int(valores[2]), int(valores[3]), int(valores[4])
+ self.procesar_datos_tanques(nombre=nombre, angulo=angulo, x=x, y=y)
+ except:
+ return
+
+ elif "B" in valores:
+ # Se recibe una bala
+ try:
+ angulo, x, y = int(valores[2]), int(valores[3]), int(valores[4])
+ self.procesar_datos_balas(angulo=angulo, x=x, y=y)
+ except:
+ return
+
+ elif "D" in valores:
+ # self.procesar_datos_puntos(mensaje)
+ # mensaje_puntos = "%s %s %s%s" % ("D", self.energia, self.puntaje, TERMINATOR)
+ energia, puntaje = int(valores[1]), int(valores[2])
+ self.procesar_datos_puntos(energia=energia, puntaje=puntaje)
+
+ elif "P" in valores:
+ # simple presencia en la red
+ pass
+
+ else:
+ #print "Recibiendo Otras Cosas: ", mensaje, "***"
+ pass
+
+ # ---------------------inicio PERSISTENCIA DE DATOS -----------------------------------
+ def procesar_datos_puntos(self, energia=100, puntaje=0):
+ # hay cambios de puntaje o energía
+ ESPEJO.Tanques[self.client_address[0]].set_puntos(energia=energia, puntaje=puntaje)
+ ESPEJO.Tanques[self.client_address[0]].set_jugadores_por_informar_puntaje(ESPEJO.Tanques.keys())
+
+ def procesar_datos_balas(self, angulo=0, x=0, y=0):
+ # ha llegado una bala
+ ESPEJO.Tanques[self.client_address[0]].set_bala(angulo=angulo, x=x, y=y) # crea la bala
+ ESPEJO.Tanques[self.client_address[0]].set_jugadores_por_informar_disparo(ESPEJO.Tanques.keys())
+ # pasa la lista de todos los jugadores para informar del disparo, a medida que se informa, se eliminan de la lista
+
+ def procesar_datos_tanques(self, nombre=None, angulo=0, x=0, y=0):
+ # Actualiza los datos del tanque de este jugador. Si el Jugador no existe, lo agrega.
+ if nombre == None:
+ # si no hay nombre no puede procesarse
+ return
+
+ if not self.client_address[0] in ESPEJO.Tanques.keys():
+ # Si no existe, se agrega
+ ESPEJO.Tanques[self.client_address[0]] = ESPEJO.Tanque(nombre)
+ ESPEJO.Tanques[self.client_address[0]].set_datos_tanque(nombre=nombre, angulo=angulo, x=x, y=y)
+ else:
+ # Si existe se actualiza
+ ESPEJO.Tanques[self.client_address[0]].set_datos_tanque(nombre=nombre, angulo=angulo, x=x, y=y)
+ # ---------------------fin PERSISTENCIA DE DATOS -----------------------------------
+
+ def enviar_datos(self):
+ # A quien se conectó se le envían los datos de todos, también los suyos.
+
+ mensaje = ""
+ for jugador in ESPEJO.Tanques.values(): # para todos los jugadores.
+ mensaje += jugador.get_datos_tanque() # obtener las posiciones de tanques.
+
+ bala = jugador.get_bala()
+ if bala != None and self.client_address[0] in jugador.jugadores_por_informar_disparo:
+ # Si hay una bala en juego de este jugador y el que se ha conectado no ha sido informado:
+ mensaje += bala
+ jugador.jugadores_por_informar_disparo.remove(self.client_address[0]) # borrar de la lista, ya se le informó
+ if not jugador.jugadores_por_informar_disparo: jugador.bala = None
+
+ if jugador.jugadores_por_informar_puntaje:
+ if self.client_address[0] in jugador.jugadores_por_informar_puntaje:
+ # Si hay cambios de puntaje y el que se ha conectado no ha sido informado:
+ mensaje += jugador.get_puntos()
+ jugador.jugadores_por_informar_puntaje.remove(self.client_address[0]) # borrar de la lista, ya se le informó
+
+ if self.client_address[0] in ESPEJO.Tanques.keys():
+ # evitar error de escaner de red de los clientes
+ if ESPEJO.Tanques[self.client_address[0]].desconectados:
+ # si hay información de desconexión de algún jugador
+ mensaje += ESPEJO.Tanques[self.client_address[0]].desconectados
+ ESPEJO.Tanques[self.client_address[0]].desconectados = ""
+
+ if len(mensaje) > ESPEJO.CARGA:
+ ESPEJO.CARGA = len(mensaje)
+ print "Carga en la red: ", ESPEJO.CARGA
+ self.request.send(mensaje)
+
+ def setup(self):
+ # Llamado antes de la handle() para realizar acciones de inicialización necesaria. La implementación predeterminada no hace nada.
+ #print "Server Setup"
+ #return SocketServer.BaseRequestHandler.setup(self)
+ pass
+
+ def finish(self):
+ # Llamado despues de la handle() para realizar cualquier método de limpieza. La implementación predeterminada no hace nada.
+ if self.client_address[0] in ESPEJO.Tanques.keys():
+ # si está en la lista, porque da error cuando los clientes escanean la red en busca de servers, pero no están en el juego aun.
+ print "Server Finish"
+ for jugador in ESPEJO.Tanques.values():
+ # para informar a todos los jugadores sobre la desconexión de otro jugador
+ jugador.desconectados += "DES %s%s" % (ESPEJO.Tanques[self.client_address[0]].nombre, ESPEJO.TERMINATOR)
+ del ESPEJO.Tanques[self.client_address[0]]
+ #return SocketServer.BaseRequestHandler.finish(self)
+ return
+
+
+
+if __name__ == "__main__":
+ server = ThreadedTCPServer(("localhost", 5000), ThreadedTCPRequestHandler)
+ server.serve_forever()
+
+ '''
+ import SocketServer
+ class MyHandler(SocketServer.BaseRequestHandler):
+ def handle(self):
+ while 1:
+ dataReceived = self.request.recv(1024)
+ self.request.send(dataReceived)
+ myServer = SocketServer.ThreadingTCPServer(('',8881), MyHandler)
+ myServer.serve_forever( )'''
diff --git a/Variables.py b/Variables.py
new file mode 100644
index 0000000..7858e6f
--- /dev/null
+++ b/Variables.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Variables.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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
+
+TERMINATOR = "\r\n\r\n"
+Tanques={}
+CARGA = 0
+
+class Tanque():
+ def __init__(self, nombre):
+
+ # Datos del Tanque
+ self.nombre = nombre
+ self.angulo, self.x, self.y = 0, 0, 0
+ self.ultimo_angulo, self.ultima_x, self.ultima_y = 0, 0, 0
+
+ # persistencia balas
+ self.jugadores_por_informar_disparo = None
+ self.bala = None
+
+ # persistencia puntos y energía
+ self.puntos = None
+ self.jugadores_por_informar_puntaje = None
+
+ # Cuando un jugador se desconecta, se debe avisar a todos
+ self.desconectados = ""
+
+# ---------------- inicio DATOS POSICION TANQUE ---------------------------
+ def get_datos_tanque(self):
+ # devuelve los datos de posición del tanque. (Se llama desde enviar_datos() en class UDPServer_thread)
+ self.angulo, self.x, self.y = self.ultimo_angulo, self.ultima_x, self.ultima_y
+ mensaje_posicion = "%s %s %s %s %s%s" % (self.nombre, "T", self.angulo, self.x, self.y, TERMINATOR)
+ return mensaje_posicion
+
+ def set_datos_tanque(self, nombre=None, angulo=0, x=0, y=0):
+ # guarda los datos de posición del tanque. (Se llama desde recibir_datos() en class UDPServer_thread)
+ self.ultimo_angulo, self.ultima_x, self.ultima_y = int(angulo), int(x), int(y)
+# ---------------- fin DATOS POSICION TANQUE ------------------------------
+
+ def set_puntos(self, energia=100, puntaje=0):
+ # establece los datos iniciales de la bala
+ self.puntos = "%s %s %s %s%s" % (self.nombre, "D", energia, puntaje, TERMINATOR)
+ #print "Nuevo puntaje en Espejo: ", self.puntos
+
+ def get_puntos(self):
+ # devuelve los datos de la bala
+ return self.puntos
+
+ def set_jugadores_por_informar_puntaje(self, jugadores_por_informar_puntaje):
+ # Lista de jugadores a los que hay que informar sobre un disparo
+ self.jugadores_por_informar_puntaje = jugadores_por_informar_puntaje
+
+# ---------------- inicio DATOS BALAS -------------------------------------
+ def set_bala(self, angulo=0, x=0, y=0):
+ # establece los datos iniciales de la bala
+ self.bala = "%s %s %s %s %s%s" % (self.nombre, "B", angulo, x, y, TERMINATOR)
+
+ def get_bala(self):
+ # devuelve los datos de la bala
+ return self.bala
+
+ def set_jugadores_por_informar_disparo(self, jugadores_por_informar_disparo):
+ # Lista de jugadores a los que hay que informar sobre un disparo
+ self.jugadores_por_informar_disparo = jugadores_por_informar_disparo
+
+# ---------------- FIN DATOS BALAS -------------------------------------
+
diff --git a/activity/JAMtank.svg b/activity/JAMtank.svg
new file mode 100644
index 0000000..618d8b9
--- /dev/null
+++ b/activity/JAMtank.svg
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ enable-background="new 0 0 50.878 48.833"
+ height="48.833"
+ id="Icon"
+ inkscape:version="0.47pre4 r22446"
+ overflow="visible"
+ sodipodi:docname="JAMtank.svg"
+ version="1.1"
+ viewBox="0 0 50.878 48.833"
+ width="50.878"
+ xml:space="preserve"><metadata
+ id="metadata17"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs15"><inkscape:perspective
+ id="perspective19"
+ inkscape:persp3d-origin="25.438999 : 16.277667 : 1"
+ inkscape:vp_x="0 : 24.4165 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="50.877998 : 24.4165 : 1"
+ sodipodi:type="inkscape:persp3d" /><inkscape:perspective
+ id="perspective2841"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_x="0 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="1 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" /></defs><sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="1"
+ gridtolerance="10"
+ guidetolerance="10"
+ id="namedview13"
+ inkscape:current-layer="Icon"
+ inkscape:cx="-21.770898"
+ inkscape:cy="25.160153"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-height="690"
+ inkscape:window-maximized="1"
+ inkscape:window-width="1366"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:zoom="6.8346077"
+ objecttolerance="10"
+ pagecolor="#ffffff"
+ showgrid="false" />
+
+
+
+
+
+<rect
+ height="7.1541862"
+ id="rect3805"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:0.92739450999999995;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="23.516075"
+ x="13.826815"
+ y="23.801159" /><rect
+ height="6.9323936"
+ id="rect3690"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:1.02922772999999990;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="14.801596"
+ x="18.184059"
+ y="13.943574" /><path
+ d="M 20.713446,19.939156 2.9140599,24.061119 48.255655,24.248482 29.51946,19.751793 20.713446,19.939156 z"
+ id="path3688"
+ style="fill:#ffffff;stroke:#004980;stroke-width:1.02922772999999990;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /><g
+ id="g3807"
+ style="fill:#ffffff;stroke:#004980;stroke-opacity:1"
+ transform="matrix(0.18547891,0,0,0.18547891,-69.705397,-46.721509)"><g
+ id="g3769"
+ style="fill:#ffffff;stroke:#004980;stroke-opacity:1"><rect
+ height="16.120926"
+ id="rect3692-84"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="57.578693"
+ x="577.28711"
+ y="384.96368" /><rect
+ height="16.120926"
+ id="rect3692-8-8"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="57.578693"
+ x="577.28711"
+ y="402.25772" /><rect
+ height="16.120926"
+ id="rect3692-6-9"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="57.578693"
+ x="577.28711"
+ y="419.01105" /></g><g
+ id="g3769-8"
+ style="fill:#ffffff;stroke:#004980;stroke-opacity:1"
+ transform="translate(-184.64788,-1.6142185)"><rect
+ height="16.120926"
+ id="rect3692-84-9"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="57.578693"
+ x="577.28711"
+ y="384.96368" /><rect
+ height="16.120926"
+ id="rect3692-8-8-8"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="57.578693"
+ x="577.28711"
+ y="402.25772" /><rect
+ height="16.120926"
+ id="rect3692-6-9-9"
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ width="57.578693"
+ x="577.28711"
+ y="419.01105" /></g></g>
+<rect
+ style="fill:#ffffff;fill-opacity:1;stroke:#004980;stroke-width:1.02922785000000006;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3600"
+ width="10.115947"
+ height="3.9398949"
+ x="20.473646"
+ y="16.112465" /><path
+ d="m 21.672004,27.386792 1.961038,-8.023013 c 0.04585,-1.964554 3.743612,-2.0258 3.914271,-0.12471 l 1.414286,8.399268 -7.289595,-0.251545 z"
+ id="path3817"
+ sodipodi:nodetypes="ccccc"
+ style="fill:#ffffff;stroke:#004980;stroke-width:1.05081022000000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /><path
+ d="m 528.30977,368.48892 a 26.263966,26.263966 0 1 1 -52.52793,0 26.263966,26.263966 0 1 1 52.52793,0 z"
+ id="path3686"
+ sodipodi:cx="502.04581"
+ sodipodi:cy="368.48892"
+ sodipodi:rx="26.263966"
+ sodipodi:ry="26.263966"
+ sodipodi:type="arc"
+ style="fill:#ffffff;stroke:#004980;stroke-width:11.30000019000000044;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ transform="matrix(0.13541442,0,0,0.13237365,-42.71265,-20.225608)" /></svg> \ No newline at end of file
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..e2e721f
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,7 @@
+[Activity]
+name = JAMtank
+activity_version = 1
+service_name = org.laptop.JAMtank
+icon = JAMtank
+show_launcher = yes
+class = gtk_JAMtank_Ventana.GTK_JAMtank
diff --git a/gtk_JAMtank_Ventana.py b/gtk_JAMtank_Ventana.py
new file mode 100644
index 0000000..f8947ca
--- /dev/null
+++ b/gtk_JAMtank_Ventana.py
@@ -0,0 +1,335 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# gtk_JAMtank_Ventana.py por:
+# Flavio Danesse <fdanesse@gmail.com>
+# 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 gc
+gc.enable()
+
+import socket
+import SocketServer
+import gobject
+import threading
+
+import gtk
+import pygtk
+pygtk.require("2.0")
+
+from sugar.activity import activity
+
+import time
+import string
+import sys
+import dbus
+import os
+import commands
+import threading
+
+from JAMtank import JAMtank
+from TCP_Server_thread_Stream import ThreadedTCPServer, ThreadedTCPRequestHandler
+
+DIRECTORIODEIMAGENES = os.getcwd()+"/Imagenes/"
+DIRECTORIODESONIDOS = os.getcwd()+"/Sonidos/"
+PUERTO = 5000
+
+# ------ Inicio de Funciones de Presencia ----------
+OLPC_SESSION_BUS = "/tmp/olpc-session-bus"
+PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
+PRESENCE_PATH = "/org/laptop/Sugar/Presence"
+PRESENCE_IFACE = "org.laptop.Sugar.Presence"
+BUDDY_IFACE = "org.laptop.Sugar.Presence.Buddy"
+
+def get_bus():
+# sugar presence
+ if os.path.exists(OLPC_SESSION_BUS):
+ address = "unix:path=%s" % OLPC_SESSION_BUS
+ return dbus.bus.BusConnection(address_or_type=address)
+ else:
+ if len(sys.argv) != 2:
+ sys.exit(1)
+
+ if 'DBUS_SESSION_BUS_ADDRESS' in os.environ:
+ del os.environ['DBUS_SESSION_BUS_ADDRESS']
+
+ display = sys.argv[1]
+ os.environ['DISPLAY'] = display
+ return dbus.bus.BusConnection()
+def get_Xos():
+# devuelve la ip y el nombre de todas las xo en la red
+# En realidad devuelve el nick de todas las xo, la ip local y las ip en la mesh de las demás xo
+ bus = get_bus()
+ ps = bus.get_object(PRESENCE_SERVICE, PRESENCE_PATH)
+ ps_iface = dbus.Interface(ps, PRESENCE_IFACE)
+ buddies = map(lambda b: bus.get_object(PRESENCE_SERVICE, b), ps_iface.GetBuddies())
+
+ xos = []
+ for buddy in buddies:
+ buddy_iface = dbus.Interface(buddy, BUDDY_IFACE)
+ try:
+ props = buddy_iface.GetProperties()
+ ip = "%s" % (props['ip4-address'].encode('utf-8'))
+ nick = "%s" % (props['nick'].encode('utf-8'))
+ xo = (ip, nick)
+ xos.append(xo)
+
+ except dbus.DBusException:
+ pass
+ return xos
+# ------ Fin de Funciones de Presencia ----------
+
+
+class GTK_JAMtank(activity.Activity):
+# Interface gtk
+ def __init__(self, handle):
+
+ activity.Activity.__init__(self, handle, False)
+
+ self.set_title("-.JAMtank (versión 1).- -. CeibalJAM! 2010.-")
+
+ pygame.mixer.init(44100, -16, 2, 2048)
+ pygame.mixer.music.set_volume(1.0)
+ self.sonido = pygame.mixer.Sound(DIRECTORIODESONIDOS+"Menu.ogg")
+
+ self.jamtank = None
+ self.servidor = None
+ self.modo = None
+ self.estado = "Presentacion"
+ self.nick = None
+ self.lista_servidores = None
+ self.ip = None # ip local
+ self.ip_server = None # ip servidor
+
+ # Canvas
+ self.contenedor_principal = gtk.VBox()
+
+ # imagen Creditos
+ imagen = gtk.Image()
+ imagen.set_from_file(DIRECTORIODEIMAGENES + "JAMtank.png")
+ self.contenedor_principal.pack_start(imagen, False, False, 0)
+
+ # Lista de Servidores Activos
+ # self.contenedor_principal.pack_start(gtk.Label("Servidores JAMtank Actualmente Activos en la Red"), False, False, 0)
+
+ # Lista de Servidores Activos
+ self.caja_servers = gtk.VBox()
+ viewport = gtk.ScrolledWindow()
+ viewport.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ viewport.add_with_viewport(self.caja_servers)
+
+ frame = gtk.Frame()
+ frame.add(viewport)
+
+ # busca servidores JAMtank en la red
+ self.actualiza_servers(None)
+
+ # Botones servidor local, actualizar lista de servidores y salir
+ caja_botones = gtk.VBox()
+
+ boton_servidor = gtk.Button("Crear Nuevo Juego en Red")
+ boton_servidor.connect("clicked", self.set_Estado, "servidor", self.ip)
+ boton_servidor.connect_object("clicked", gtk.Widget.destroy, self)
+
+ boton_scan = gtk.Button("Actualizar Lista de Juegos en la Red")
+ boton_scan.connect("clicked", self.actualiza_servers)
+
+ boton_salir = gtk.Button("Salir de JAMtank")
+ boton_salir.connect_object("clicked", self.salir, None)
+
+ caja_botones.pack_start(boton_servidor, True, True, 5)
+ caja_botones.pack_start(boton_scan, True, True, 5)
+ caja_botones.pack_end(boton_salir, True, True, 5)
+
+ # imagen Teclado
+ imagen1 = gtk.Image()
+ imagen1.set_from_file(DIRECTORIODEIMAGENES + "Teclado.png")
+
+ caja_secundaria = gtk.HBox()
+ caja_secundaria.pack_start(imagen1, False, False, 0)
+ caja_secundaria.pack_start(frame, True, True, 5)
+ caja_secundaria.pack_end(caja_botones, False, False, 5)
+
+ self.contenedor_principal.pack_start(caja_secundaria, True, True, 0)
+
+ # para introducir una IP conocida
+ #caja = gtk.HBox()
+ #etiqueta = gtk.Label("IP: ")
+ self.entrada = None
+ #conectar = gtk.Button("Conectarse a Esta IP")
+ #conectar.connect("clicked", self.get_connect_ip_conocida)
+ #caja.pack_start (etiqueta, False, False, 5)
+ #caja.pack_start (self.entrada, False, False, 5)
+ #caja.pack_start (conectar, False, False, 5)
+ #self.contenedor_principal.pack_start(caja, False, False, 5)
+
+ self.set_canvas(self.contenedor_principal)
+
+ self.show_all()
+
+ self.sonido.play(loops=-1)
+
+ # switch gtk pygame
+ reloj = gobject.timeout_add(500, self.get_Juego)
+
+ def set_entrada_ip_conocida(self):
+ # objetos para agregar ip de servidor conocido
+ caja = gtk.HBox()
+ etiqueta = gtk.Label("Conectarse a (IP): ")
+ self.entrada = gtk.Entry()
+ conectar = gtk.Button("Jugar")
+ conectar.connect("clicked", self.get_connect_ip_conocida)
+ caja.pack_start (etiqueta, True, True, 5)
+ caja.pack_start (self.entrada, True, True, 5)
+ caja.pack_end (conectar, True, True, 5)
+ caja.show_all()
+ self.caja_servers.pack_start(caja, False, False, 5)
+
+ def get_connect_ip_conocida(self, widget):
+ # Conecta a la ip ingresada
+ ip = self.entrada.get_text()
+ if ip:
+ self.set_Estado(None, "cliente", ip)
+ gtk.Widget.destroy(self)
+
+ def actualiza_servers(self, widget):
+ # Verifica tener conexión a una red
+
+ self.lista_servidores = []
+
+ # obtiene el nombre de la xo
+ XOs = get_Xos()
+ self.ip, self.nick = XOs[0]
+
+ while not self.ip or self.ip == "localhost":
+ # obtiene el nombre de la xo
+ XOs = get_Xos()
+ self.ip, self.nick = XOs[0]
+ self.get_avisar_no_hay_ip()
+
+ red = self.ip.split(".")
+ for x in range(2, 254):
+ ip = "%s.%s.%s.%s" % (red[0],red[1],red[2],x)
+ thread = threading.Thread( target=self.scan_red, args=( ip, PUERTO) )
+ thread.start()
+ time.sleep(0.02)
+
+ self.get_lista_xos()
+
+ def scan_red (self, ip, puerto):
+ # escanea la red en busca del puerto abierto para JAMtant
+ conexion = socket.socket()
+ try:
+ conexion.connect( (ip, puerto) )
+ self.lista_servidores.append(ip)
+ except:
+ pass
+ conexion.close()
+
+ def get_lista_xos(self):
+ # arma la lista de xo en la red con server JAMtank corriendo
+
+ for child in self.caja_servers:
+ self.caja_servers.remove(child)
+
+ self.set_entrada_ip_conocida()
+
+ for ip in self.lista_servidores:
+ caja = gtk.HBox()
+ lab_ip = gtk.Label(ip)
+ conectar = gtk.Button("Jugar")
+
+ conectar.connect("clicked", self.set_Estado, "cliente", ip)
+ conectar.connect_object("clicked", gtk.Widget.destroy, self)
+
+ caja.pack_start(lab_ip, True, True, 5)
+ caja.pack_end(conectar, True, True, 5)
+ caja.show_all()
+ self.caja_servers.pack_start(caja, False, False, 5)
+
+ def get_avisar_no_hay_ip(self):
+ # Crea un cuadro de dialogo para avisar que no está conectado a ninguna red.
+
+ dialog = gtk.Dialog("Atención !!!", None, gtk.DIALOG_MODAL, None)
+
+ etiqueta0 = gtk.Label("No estás conectado a ninguna Red.")
+ dialog.vbox.pack_start(etiqueta0, True, True, 5)
+
+ etiqueta1 = gtk.Label("JAMtank es un juego en red, debes conectarte a una Red")
+ dialog.vbox.pack_start(etiqueta1, True, True, 5)
+
+ dialog.add_button("OK", 1)
+ dialog.add_button("Cancelar", 2)
+
+ dialog.show_all()
+
+ if dialog.run() == 1:
+ pass
+ elif dialog.run() == 2:
+ # sale automaticamente
+ sys.exit()
+
+ dialog.destroy()
+
+ def delete_event(self, widget, event, data=None):
+ # Cierra la ventana gtk
+ return gtk.FALSE
+
+ def salir(self, widget):
+ sys.exit()
+
+ def set_Estado(self, widget, modo, ip):
+ # para poder llamar al juego luego de que se cierre la ventana gtk
+ self.sonido.stop()
+ pygame.quit()
+ self.ip_server = ip
+ self.modo = modo # Servidor o Cliente
+ self.estado = "Juego"
+
+ #----------------------Juego pygame-------------------------------------------------------------
+ def get_Juego(self):
+ # Se llama al juego pygame
+ if self.estado == "Juego":
+ if self.modo == "servidor":
+ server = ThreadedTCPServer((self.ip, PUERTO), ThreadedTCPRequestHandler)
+ server.allow_reuse_address = True
+ server.socket.setblocking(0)
+
+ server_thread = threading.Thread(target=server.serve_forever)
+ server_thread.setDaemon(True)
+ server_thread.start()
+
+ self.jamtank = JAMtank(ip=self.ip, PUERTO=PUERTO)
+
+ elif self.modo == "cliente":
+ self.jamtank = JAMtank(ip=self.ip_server, PUERTO=PUERTO)
+
+ return False # no volver por acá
+ else:
+ pass
+
+ return True # seguir viniendo por acá
+ #----------------------Juego pygame-------------------------------------------------------------
+
+
+if __name__ == "__main__":
+ GTK_JAMtank()
+
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..6ea61a6
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,3 @@
+#!/usr/bin/python
+from sugar.activity import bundlebuilder
+bundlebuilder.start()