diff --git a/chat.py b/chat.py new file mode 100644 index 0000000..6b09431 --- /dev/null +++ b/chat.py @@ -0,0 +1,14 @@ +import network, sys, time + +sock = network.Sock() +port = 33077 + +if sys.argv[1] == "s": + sock.listen(["0.0.0.0", port]) + while True: + for d, a in sock.get(): + print(a, d) + time.sleep(0.1) +elif sys.argv[1] == "c": + while True: + sock.send(input(), ["192.168.0.255", port]) diff --git a/demo.py b/demo.py index 4c79817..ec3615d 100644 --- a/demo.py +++ b/demo.py @@ -12,5 +12,5 @@ if sys.argv[1] == "s": time.sleep(0.1) elif sys.argv[1] == "c": while True: - sock.send(str(time.time()), (sys.argv[3], port)) + sock.send(time.time(), (sys.argv[3], port)) time.sleep(1) diff --git a/demo1.py b/demo1.py new file mode 100644 index 0000000..d2754de --- /dev/null +++ b/demo1.py @@ -0,0 +1,8 @@ +import network, sys, time + +sock = network.Sock() +destination = ["192.168.0.255", 33077] + +while True: + message = input("envoyer: ") + sock.send(message, destination) diff --git a/demo2.py b/demo2.py new file mode 100644 index 0000000..f226594 --- /dev/null +++ b/demo2.py @@ -0,0 +1,10 @@ +import network, sys, time + +sock = network.Sock() +address = ("0.0.0.0", 33077) + +sock.listen(address) +while True: + for d, a in sock.get(): + print(a, d) + time.sleep(0.1) diff --git a/game.py b/game.py index ac244ba..202232b 100644 --- a/game.py +++ b/game.py @@ -1,4 +1,4 @@ -import network, sys, json, pygame, random, xlog +import network, sys, pygame, random, xlog, time, colorsys pygame.init() @@ -7,26 +7,37 @@ w, h = 640, 480 size = [w, h] black = [0, 0, 0] +def random_color(): + return [int(i*255) for i in colorsys.hsv_to_rgb(random.random(), 0.8, 1)] + +def normalize(n): + if n > 0: + return 1 + if n < 0: + return -1 + return 0 + def new_oid(): return random.randint(0,2147483648) class Obj: def __init__(self, oid): self.oid = oid - def damage(self, dmg): pass + def damage(self, dmg, author=None): pass def update(self): pass def draw(self, surface): pass def print_debug(self, lines): pass class Player(Obj): - def __init__(self, oid, address, pos, color): + def __init__(self, oid, address, pos, color, life=100, score=0): Obj.__init__(self, oid) self.address = address self.pos = pos self.color = color + self.score = score self.speed = [0, 0] - self.life = 100 - self.direction = [1, 0] + self.life = life + self.direction = [0, 1] def throw_energy_ball(self): oid = new_oid() @@ -34,7 +45,7 @@ class Player(Obj): pos[0] += self.direction[0] * 16 pos[1] += self.direction[1] * 16 speed = [self.speed[0]+self.direction[0]*4, self.speed[1]+self.direction[1]*4] - objects[oid] = EnergyBall(oid, pos, speed) + objects[oid] = EnergyBall(oid, pos, speed, self.oid) def stab(self): for oid in players: @@ -42,30 +53,37 @@ class Player(Obj): continue player = players[oid] if abs(player.pos[0]-self.pos[0]) < 32 and abs(player.pos[1]-self.pos[1]) < 32: - player.damage(10) + player.damage(10, self.oid) - def damage(self, dmg): + def damage(self, dmg, author=None): self.life -= dmg if self.life <= 0: - print("die!") + self.speed = [0, 0] + self.pos = [16, 16] + self.life = 100 + if author in players: + players[author].score += 1 def update(self): + if self.speed[0] != 0 or self.speed[1] != 0: + self.direction = [normalize(self.speed[0]), normalize(self.speed[1])] self.pos[0] += self.speed[0] self.pos[1] += self.speed[1] def draw(self, surface): pygame.draw.rect(surface, self.color, (self.pos[0]-8, self.pos[1]-8, 16, 16)) - lifebar = int(32*self.life/100) - pygame.draw.rect(surface, (64,255,64), (self.pos[0]-lifebar//2+8, self.pos[1]+6, lifebar, 4)) + lifebar = int(16*self.life/100) + pygame.draw.rect(surface, (64,255,64), (self.pos[0]-8, self.pos[1]-16, lifebar, 4)) def print_debug(self, lines): - lines.append("Player {}: {}".format(self.oid, obj.address)) + lines.append("Player {}: {} / score {}".format(self.oid, obj.address, obj.score)) class EnergyBall(Obj): - def __init__(self, oid, pos, speed): + def __init__(self, oid, pos, speed, thrower): Obj.__init__(self, oid) self.pos = pos self.speed = speed + self.thrower = thrower def update(self): self.pos[0] += self.speed[0] @@ -75,14 +93,14 @@ class EnergyBall(Obj): continue obj = objects[oid] if abs(self.pos[0]-obj.pos[0])<8 and abs(self.pos[1]-obj.pos[1])<8: - obj.damage(10) + obj.damage(10, self.thrower) removable.append(self.oid) return def draw(self, surface): pygame.draw.rect(surface, (128,255,255), (self.pos[0]-2, self.pos[1]-2, 4, 4)) - def damage(self, dmg): + def damage(self, dmg, author=None): if dmg > 0: removable.append(self.oid) @@ -95,15 +113,29 @@ clock = pygame.time.Clock() sock = network.Sock() sock.listen(address) -me = Player(new_oid(), address, [10, 10], [255, 0, 0]) +me = Player(new_oid(), address, [random.randint(16, w-16), random.randint(16, h-16)], random_color()) objects = {me.oid: me} players = {me.oid: me} removable = [] def send_all(msg): - msg = json.dumps(msg) for oid in players: - sock.send(msg, objects[oid].address) + if oid != me.oid: + sock.send(msg, objects[oid].address) + +def make_recap(): + pl = [] + for oid in players: + player = players[oid] + pl.append({ + "oid": oid, + "pos": player.pos, + "color": player.color, + "address": player.address, + "life": player.life, + "score": player.score + }) + return {"type":"recap", "players":pl, "oid":me.oid} def remove_objects(): for oid in removable: @@ -113,8 +145,11 @@ def remove_objects(): players.pop(oid) removable.clear() -sock.send(json.dumps({"type":"join","pos":me.pos,"color":me.color,"port":address[1],"oid":me.oid}), ["192.168.0.255", 33033]) -sock.send(json.dumps({"type":"join","pos":me.pos,"color":me.color,"port":address[1],"oid":me.oid}), ["127.0.0.1", 33033]) +sock.send({"type":"join","pos":me.pos,"color":me.color,"port":address[1],"oid":me.oid}, ["192.168.0.255", 33033]) +sock.send({"type":"join","pos":me.pos,"color":me.color,"port":address[1],"oid":me.oid}, ["192.168.0.255", 33033]) +sock.send({"type":"join","pos":me.pos,"color":me.color,"port":address[1],"oid":me.oid}, ["127.0.0.1", 33033]) + +last_recap = 0 while True: for event in pygame.event.get(): @@ -125,19 +160,15 @@ while True: send_all({"type":"quit", "oid":me.oid}) sys.exit() if event.key == pygame.K_RIGHT: - me.direction = [1, 0] me.speed[0] = 2 send_all({"type":"move", "oid":me.oid, "speed":me.speed}) elif event.key == pygame.K_LEFT: - me.direction = [-1, 0] me.speed[0] = -2 send_all({"type":"move", "oid":me.oid, "speed":me.speed}) elif event.key == pygame.K_DOWN: - me.direction = [0, 1] me.speed[1] = 2 send_all({"type":"move", "oid":me.oid, "speed":me.speed}) elif event.key == pygame.K_UP: - me.direction = [0, -1] me.speed[1] = -2 send_all({"type":"move", "oid":me.oid, "speed":me.speed}) elif event.key == pygame.K_SPACE: @@ -160,16 +191,14 @@ while True: me.speed[1] = 0 send_all({"type":"move", "oid":me.oid, "speed":me.speed}) for (r, c) in sock.get(): - r = json.loads(r.decode()) if r["oid"] == me.oid: continue if r["type"] == "join": - pl = [] - for oid in players: - player = players[oid] - pl.append({"oid":oid, "pos":player.pos, "color":player.color, "address":player.address}) - sock.send(json.dumps({"type":"recap", "players":pl, "oid":me.oid}), [c[0], r["port"]]) - players[r["oid"]] = Player(r["oid"], [c[0], r["port"]], r["pos"], r["color"]) + sock.send(make_recap(), [c[0], r["port"]]) + sock.send(make_recap(), [c[0], r["port"]]) + new_player = Player(r["oid"], [c[0], r["port"]], r["pos"], r["color"]) + players[r["oid"]] = new_player + objects[r["oid"]] = new_player elif r["type"] == "move": players[r["oid"]].speed = r["speed"] elif r["type"] == "recap": @@ -178,12 +207,21 @@ while True: address = player["address"] if address[0] == "0.0.0.0": address = [c[0], c[1]] - objects[player["oid"]] = Player(player["oid"], address, player["pos"], player["color"]) - players[player["oid"]] = objects[player["oid"]] + new_player = Player(player["oid"], address, player["pos"], player["color"], + life=player["life"], + score=player["score"] + ) + objects[player["oid"]] = new_player + players[player["oid"]] = new_player + elif c[0] == player["address"][0]: + players[player["oid"]].pos = player["pos"] + players[player["oid"]].speed = player["speed"] elif r["type"] == "quit": removable.append(r["oid"]) elif r["type"] == "stab": objects[r["oid"]].stab() + elif r["type"] == "throw": + objects[r["oid"]].throw_energy_ball() remove_objects() @@ -200,5 +238,9 @@ while True: xlog.display(screen, lines) + if time.time() > last_recap + 5: + send_all(make_recap()) + last_recap = time.time() + 5 + pygame.display.flip() clock.tick(30) diff --git a/network.py b/network.py index f62af0c..01aea39 100644 --- a/network.py +++ b/network.py @@ -1,4 +1,4 @@ -import socket, os, sys +import socket, os, sys, json from threading import Thread, Lock NETTRACE = str(os.environ.get("NETTRACE", "0")) == "1" @@ -12,25 +12,44 @@ class Sock: self.queue_lock = Lock() self.sock_thread = None - def send(self, message, address): + def send_raw(self, message, address): if type(message) == str: message = message.encode() if NETTRACE: print("Send to", tuple(address), ":", message, file=sys.stderr) self.sock.sendto(message, tuple(address)) + def send(self, message, address): + message = json.dumps(message) + if NETTRACE: + print("Send to", tuple(address), ":", message, file=sys.stderr) + self.sock.sendto(message.encode(), tuple(address)) + def listen(self, address, length=65535): self.sock_thread = SockThread(self, tuple(address), length) self.sock_thread.setDaemon(True) self.sock_thread.start() - def get(self): + def get_raw(self): if len(self.queue) == 0: return [] with self.queue_lock: queue = self.queue self.queue = [] return queue + + def get(self): + if len(self.queue) == 0: + return [] + queue = [] + with self.queue_lock: + for r in self.queue: + try: + queue.append([json.loads(r[0].decode()), r[1]]) + except: + pass + self.queue.clear() + return queue class SockThread(Thread): def __init__(self, sock, address, length): diff --git a/template.py b/template.py new file mode 100644 index 0000000..1c94ded --- /dev/null +++ b/template.py @@ -0,0 +1,108 @@ +import network, sys, pygame, random, xlog, time, colorsys + +pygame.init() + +w, h = 640, 480 # Taille de la fenêtre +size = [w, h] +black = [0, 0, 0] # Couleur noire + +# Créer une couleur aléatoire +def random_color(): + return [int(i*255) for i in colorsys.hsv_to_rgb(random.random(), 0.8, 1)] + +# Créer un identifiant d'objet aléatoire +def new_oid(): + return random.randint(0,2147483648) + +# Définit les méthodes par défaut d'un objet +class Obj: + def __init__(self, oid): + self.oid = oid + def update(self): pass + def draw(self, surface): pass + def print_debug(self, lines): pass + +# Définit un joueur +class Player(Obj): + def __init__(self, oid, pos, color): + Obj.__init__(self, oid) + self.pos = pos + self.speed = [0, 0] + self.color = color + + # Mise à jour de l'état du joueur + def update(self): + self.pos[0] += self.speed[0] + self.pos[1] += self.speed[1] + + # Dessiner le joueur + def draw(self, surface): + pygame.draw.rect(surface, self.color, (self.pos[0]-8, self.pos[1]-8, 16, 16)) + + # Afficher le texte d'information + def print_debug(self, lines): + lines.append("Player {}".format(self.oid)) + +screen = pygame.display.set_mode(size) # définir la taille de la fenêtre +clock = pygame.time.Clock() + +# Créer notre propre joueur +me = Player(new_oid(), [random.randint(16, w-16), random.randint(16, h-16)], random_color()) +objects = {me.oid: me} # dictionnaire de tous les objets +players = {me.oid: me} # dictionnaire de tous les joueurs (qui sont aussi des objets) +removable = [] # identifiants des objets à supprimer + +# Supprimer les objets à supprimer +def remove_objects(): + for oid in removable: + if oid in objects: + objects.pop(oid) + if oid in players: + players.pop(oid) + removable.clear() + +# Boucle principale +while True: + # Lecture des événements + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + sys.exit() + if event.key == pygame.K_RIGHT: + me.speed[0] = 2 + elif event.key == pygame.K_LEFT: + me.speed[0] = -2 + elif event.key == pygame.K_DOWN: + me.speed[1] = 2 + elif event.key == pygame.K_UP: + me.speed[1] = -2 + elif event.type == pygame.KEYUP: + if event.key == pygame.K_RIGHT: + me.speed[0] = 0 + elif event.key == pygame.K_LEFT: + me.speed[0] = 0 + elif event.key == pygame.K_DOWN: + me.speed[1] = 0 + elif event.key == pygame.K_UP: + me.speed[1] = 0 + + remove_objects() + + screen.fill(black) # colorier le fond en noir + + # Mettre à jour tous les objets + lines = [] + for oid in objects: + obj = objects[oid] + obj.update() + obj.draw(screen) + obj.print_debug(lines) + + remove_objects() + + xlog.display(screen, lines) # afficher le texte d'information + + pygame.display.flip() # mettre à jour l'écran + clock.tick(30) # attendre un peu