diff --git a/assets/projectile/loop/00001.png b/assets/projectile/loop/00001.png new file mode 100644 index 0000000..989bed5 Binary files /dev/null and b/assets/projectile/loop/00001.png differ diff --git a/assets/ship_fire/end/00001.png b/assets/ship_fire/end/00001.png deleted file mode 100644 index e8927d8..0000000 Binary files a/assets/ship_fire/end/00001.png and /dev/null differ diff --git a/assets/ship_fire/setup/00001.png b/assets/ship_fire/setup/00001.png deleted file mode 100644 index e8927d8..0000000 Binary files a/assets/ship_fire/setup/00001.png and /dev/null differ diff --git a/assets_sources/projectile/file.xcf b/assets_sources/projectile/file.xcf new file mode 100644 index 0000000..2485082 Binary files /dev/null and b/assets_sources/projectile/file.xcf differ diff --git a/assets_sources/projectile/loop.gif b/assets_sources/projectile/loop.gif new file mode 100644 index 0000000..03830c5 Binary files /dev/null and b/assets_sources/projectile/loop.gif differ diff --git a/assets_sources/ship_fire/end.gif b/assets_sources/ship_fire/end.gif deleted file mode 100644 index f499bb3..0000000 Binary files a/assets_sources/ship_fire/end.gif and /dev/null differ diff --git a/assets_sources/ship_fire/setup.gif b/assets_sources/ship_fire/setup.gif deleted file mode 100644 index f499bb3..0000000 Binary files a/assets_sources/ship_fire/setup.gif and /dev/null differ diff --git a/client.py b/client.py index 4ac2bf9..1537476 100755 --- a/client.py +++ b/client.py @@ -9,7 +9,9 @@ Created on Sun Jan 26 17:50:16 2020 import sys, pygame, time, random, socket from colorama import Fore, Style import numpy as np - +import gzip +import json +import multiprocessing def debug(*s): print("[D ] : " + str(', '.join(map(str, s))) + @@ -37,12 +39,74 @@ def error(*s): print(Fore.RED + Style.RESET_ALL + str(', '.join(map(str, s))) + Style.RESET_ALL) +level = 0 +BUFFER_SIZE = 4096 +CONTINUE = b'\x00' +END = b'\xFF' + +for i in range(level): + exec("debug info warn error".split()[i] + "= lambda *x: None") + +def lookahead(iterable): + it = iter(iterable) + last = next(it) + for val in it: + yield last, CONTINUE + last = val + yield last, END + +def chunked(size, source): + for i in range(0, len(source), size): + yield source[i:i+size] + +def handle(conn, queues): + try: + data = bytes() + while True: + in_data = conn.recv(BUFFER_SIZE) + if in_data == b"": + info("Socket closed remotely") + break + if in_data[0] == CONTINUE[0]: + data += in_data[1:] + elif in_data[0] == END[0]: + decompressed = gzip.decompress(data+in_data[1:]).decode('utf8') + queues['in'].put(json.loads(decompressed)) + else : + warn("Invalid chunk received !!") + send(conn, {'error':True, 'content':"INV_CHUNK"}) + break + finally: + info("Closing socket") + conn.close() + +def send(conn, data_obj): + data = gzip.compress(bytes(json.dumps(data_obj), encoding='utf8')) + for chunk, info in lookahead(chunked(BUFFER_SIZE - 1, data)): + conn.sendall(info + chunk.ljust(BUFFER_SIZE - 1, b'\x00')) + +class Client(object): + def __init__(self, hostname, port): + self.hostname = hostname + self.port = port + self.queues = {'in':multiprocessing.Queue(), + 'out':multiprocessing.Queue()} + + def start(self): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + info(f"Connecting to {self.hostname}:{self.port}.") + self.socket.connect((self.hostname, self.port)) + self.handler = multiprocessing.Process(target=handle, + args=(self.socket, + self.queues)) + self.handler.start() + send(self.socket, {'type':'Hello', 'content':{'player_name':"Suwako"}}) + self.handler.join() + finally: + info("Exiting.") + self.socket.close() if __name__ == "__main__": - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(("localhost", 9000)) - data = b"some data" - sock.sendall(data) - result = sock.recv(1024) - print(result) - sock.close() + client = Client("localhost", 9001) + client.start() diff --git a/mecha.py b/mecha.py index c36a48a..1fa06d1 100755 --- a/mecha.py +++ b/mecha.py @@ -7,7 +7,7 @@ Created on Mon Jan 27 16:32:02 2020 """ import numpy as np - +import visual class Mass(): def __init__(self, pos=(0, 0), speed=(0, 0), mass=1): @@ -15,9 +15,11 @@ class Mass(): self.speed = np.array(speed, dtype='float64') self.mass = mass self.G = 0.00000000001 + self.ticks=0 def tick(self): self.pos += self.speed + self.ticks+=1 def ref(self, origin=np.array((0, 0), dtype='float64'), @@ -36,6 +38,18 @@ class Mass(): u = d/norm_d norm = self.G * element.mass * (d[0]**2 + d[1]**2) self.speed += norm*u + def fire(*a): + pass + + +class Projectile(Mass): + def __init__(self, + orientation=0, + pos=(0, 0), + speed=(0, 0), + mass=0.000000001): + Mass.__init__(self, pos=pos, speed=speed, mass=mass) + self.orientation = orientation class Player(Mass): @@ -44,11 +58,13 @@ class Player(Mass): pos=(0, 0), speed=(0, 0), mass=1, - thrust=0.01): + thrust=0.01, + fire_force=1): Mass.__init__(self, pos=pos, speed=speed, mass=mass) self.orientation = orientation self.actions = {"thrust": False, "fire": False} self.thrust=thrust + self.fire_force=fire_force def action(self, **kwargs): print(kwargs) @@ -64,6 +80,20 @@ class Player(Mass): def apply_forces(self, elements): Mass.apply_forces(self, elements) self.apply_thrust() + + def fire(self, elements): + if self.actions['fire']: + projectile = visual.Projectile(orientation=self.orientation, + pos=self.pos, + speed=self.speed) + orientation = np.deg2rad(self.orientation + 90) + or_tuple=(np.cos(orientation), -np.sin(orientation)) + pnorm = self.fire_force/projectile.mecha.mass + snorm = self.fire_force/self.mass + projectile.mecha.speed += snorm * np.array(or_tuple, dtype='float64') + self.speed -= snorm * np.array(or_tuple, dtype='float64') + elements.append(projectile) + self.actions['fire'] = False if __name__ == "__main__": pass diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8af9f9f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +numpy +colorama +pygame diff --git a/server.py b/server.py index 5302c46..bcdd2df 100755 --- a/server.py +++ b/server.py @@ -11,6 +11,8 @@ if sys.platform == 'win32': import multiprocessing.reduction from colorama import Fore, Style import numpy as np +import json +import gzip def debug(*s): print("[D ] : " + @@ -40,65 +42,150 @@ def error(*s): print(Fore.RED + str(', '.join(map(str, s))) + Style.RESET_ALL) -level = 1 +level = 0 +BUFFER_SIZE = 4096 +CONTINUE = b'\x00' +END = b'\xFF' + for i in range(level): exec("debug info warn error".split()[i] + "= lambda *x: None") +def lookahead(iterable): + it = iter(iterable) + last = next(it) + for val in it: + yield last, CONTINUE + last = val + yield last, END -def handle(connection, address): +def chunked(size, source): + for i in range(0, len(source), size): + yield source[i:i+size] + +def handle(conn, address, queues): try: - info("Connected at "+ ':'.join(map(str,address))) + info("Inbound Connection at " + ':'.join(map(str,address))) + data = bytes() while True: - data = connection.recv(1024) - if data == b"": + in_data = conn.recv(BUFFER_SIZE) + if in_data == b"": info("Socket closed remotely at " + ':'.join(map(str,address))) break - debug("Received data %r" % data) - connection.sendall(data) - debug("Sent data") - except: - warn("Problem handling request") - connection.close() - raise + if in_data[0] == CONTINUE[0]: + data += in_data[1:] + elif in_data[0] == END[0]: + decompressed = gzip.decompress(data+in_data[1:]).decode('utf8') + queues['in'].put(json.loads(decompressed)) + else : + warn("Invalid chunk received !!") + send(conn, {'error':True, 'content':"INV_CHUNK"}) + break finally: - debug("Closing socket with " + ':'.join(map(str,address))) - connection.close() + info("Closing socket at " + ':'.join(map(str,address))) + conn.close() + +def send(conn, data_obj): + data = gzip.compress(bytes(json.dumps(data_obj), encoding='utf8')) + for chunk, info in lookahead(chunked(BUFFER_SIZE - 1, data)): + conn.sendall(info + chunk.ljust(BUFFER_SIZE - 1, b'\x00')) + class Server(object): def __init__(self, hostname, port): self.hostname = hostname self.port = port + self.run = False + self.connections = [] def start(self): - debug("listening") + self.run = True + info(f"Listening on {self.hostname}:{self.port}.") self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.bind((self.hostname, self.port)) - self.socket.listen(1) - - while True: - conn, address = self.socket.accept() - process = multiprocessing.Process(target=handle, - args=(conn, address)) - process.daemon = True - process.start() - + try: + self.socket.bind((self.hostname, self.port)) + self.socket.listen(1) + + while self.run: + conn, address = self.socket.accept() + queues = {'in':multiprocessing.Queue(), + 'out':multiprocessing.Queue()} + p = multiprocessing.Process(target=handle, args=(conn, + address, + queues)) + p.start() + self.connections.append({'conn':conn, 'address':address, + 'queues':queues, 'process':p}) + finally: + for process in multiprocessing.active_children(): + info("Shutting down process {process}") + process.terminate() + process.join() + self.socket.close() + + def stop(self): + info(f"Shutting down the listenner.") + self.run = False if __name__ == "__main__": - server = Server("0.0.0.0", 9000) - try: - info("Listening") - server.start() - except: - error("Unexpected exception") - for process in multiprocessing.active_children(): - info("Shutting down process %r", process) - process.terminate() - process.join() - raise - finally: - info("Shutting down") - for process in multiprocessing.active_children(): - info("Shutting down process %r", process) - process.terminate() - process.join() - info("All done") + server = Server("0.0.0.0", 9001) + server.start() + +if False : + def handle(connection, address): + try: + info("Connected at "+ ':'.join(map(str,address))) + while True: + data = connection.recv(1024) + if data == b"": + info("Socket closed remotely at " + ':'.join(map(str,address))) + break + debug("Received data %r" % data) + connection.sendall(data) + debug("Sent data") + except: + warn("Problem handling request") + connection.close() + raise + finally: + debug("Closing socket with " + ':'.join(map(str,address))) + connection.close() + + class Server(object): + def __init__(self, hostname, port): + self.hostname = hostname + self.port = port + self.connections = [] + + def start(self): + debug("listening") + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.bind((self.hostname, self.port)) + self.socket.listen(1) + + while True: + conn, address = self.socket.accept() + process = multiprocessing.Process(target=handle, + args=(conn, address)) + process.daemon = True + process.start() + + + if __name__ == "__main__": + server = Server("0.0.0.0", 9000) + try: + info("Listening") + server.start() + except: + error("Unexpected exception") + for process in multiprocessing.active_children(): + info("Shutting down process %r", process) + process.terminate() + process.join() + raise + finally: + info("Shutting down") + for process in multiprocessing.active_children(): + info("Shutting down process %r", process) + process.terminate() + process.join() + info("All done") diff --git a/visual.py b/visual.py index 7755630..da687fd 100755 --- a/visual.py +++ b/visual.py @@ -22,7 +22,7 @@ class Obj(): return np.array((self.position.width, self.position.height), dtype='float64') - def draw(self, + def draw(self, screen, scale=1, reference=np.array((0, 0), dtype='float64'), size=(0, 0)): @@ -30,6 +30,8 @@ class Obj(): scaled_pos = scale * (self.mecha.pos - reference + npsize/(2*scale)) if np.linalg.norm(scaled_pos - npsize/2) > max(size): return + if min(self.position.size)*scale < 1 : + return scaled_dimension = (scale*self.dimension()).astype(int) scaled_image = pygame.transform.scale(self.image, scaled_dimension) scaled_image = pygame.transform.rotate(scaled_image, @@ -41,7 +43,7 @@ class Obj(): class Star(Obj): def __init__(self, **keyargs): - self.mecha = mecha.Player(**keyargs) + self.mecha = mecha.Mass(**keyargs) self.image = pygame.image.load("assets/ship/loop/00001.png") self.position = self.image.get_rect() @@ -59,6 +61,11 @@ class Player(Obj): self.image = pygame.image.load("assets/ship/loop/00001.png").convert_alpha() self.position = self.image.get_rect() +class Projectile(Obj): + def __init__(self, **keyargs): + self.mecha = mecha.Projectile(**keyargs) + self.image = pygame.image.load("assets/projectile/loop/00001.png") + self.position = self.image.get_rect() if __name__ == "__main__": import time @@ -70,7 +77,7 @@ if __name__ == "__main__": tick = (time.time(), time.time(), 0) screen = pygame.display.set_mode(size, flags=pygame.RESIZABLE) - elements = [Player(speed=(5, 0), pos=(10, -200)), Player(speed=(-5, 0), pos=(10, 200), mass = 1), Planet(mass=200), Planet(mass=200, pos=(0,20), speed=(-1,0)), Planet(mass=150, pos = (0, 1000), speed = (15, 0)), Player(mass=5, pos = (0, 1010), speed = (15, 1))] + elements = [Player(speed=(5, 0), pos=(10, -200)), Player(speed=(-5, 0), pos=(10, 200), mass = 1), Planet(mass=7000), Planet(mass=200, pos=(0,20), speed=(-1,0)), Planet(mass=150, pos = (0, 1000), speed = (15, 0)), Player(mass=5, pos = (0, 1010), speed = (15, 1))] reference = 2 joy=[1, 1] while 1: @@ -95,11 +102,15 @@ if __name__ == "__main__": reference = (reference + 1)%len(elements) if event.key == (32): elements[1].mecha.action(thrust=True) + if event.key == 119: + elements[1].mecha.action(fire = True) if event.type == pygame.KEYUP: if event.key in keys: keys.remove(event.key) if event.key == (32): elements[1].mecha.action(thrust=False) + if event.key == 119: + elements[1].mecha.action(fire = False) screen.fill(black) for key in keys: if key in [275,276,273,274]: @@ -107,6 +118,16 @@ if __name__ == "__main__": elements[1].mecha.orientation=joy[0]*(-3) for element in elements: element.mecha.apply_forces([element.mecha for element in elements]) + j = 0 + while j < len(elements): + if type(elements[j]) is mecha.visual.Projectile and elements[j].mecha.ticks > 25*30: + del elements[j] + j-=1 + j+=1 + j = 0 + while j < len(elements): + elements[j].mecha.fire(elements) + j+=1 for element in elements: element.mecha.tick() ori,speed=origin=np.array(elements[0].mecha.pos), np.array(elements[0].mecha.speed) @@ -118,7 +139,7 @@ if __name__ == "__main__": while 10**(joy[1]*0.05) < 0.08 : joy[1] += 1 for element in elements: - element.draw(scale=10**(joy[1]*0.05), reference=elements[reference].mecha.pos, size=screen.get_size()) + element.draw(screen, scale=10**(joy[1]*0.05), reference=elements[reference].mecha.pos, size=screen.get_size()) pygame.display.flip() # for element in elements: # element.apply(camera=camera, origin=origin)