Example #1
0
    def __init__(self, name, w, h, ww, wh, topology='wrapped'):

        #initializes world and window geometry
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        self.agents = []

        self.root = Tk()
        self.root.title(name)

        Frame.__init__(self, self.root)

        self.bind_all('<KeyPress>', self.keypress)
        self.bind_all('<KeyRelease>', self.keyrelease)

        #makes background canvas
        self.canvas = Canvas(self,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT,
                             bg='purple')

        self.grid()
        self.canvas.grid()

        #sets the top left corner of the display window to the actual (0,0). Was having
        #some weird issues with the edges of the world before, like the window was
        #at (3,3) instead or something weird like that.
        self.canvas.xview_moveto(0.0)
        self.canvas.yview_moveto(0.0)
Example #2
0
    def __init__(self,
                 name,
                 w,
                 h,
                 ww,
                 wh,
                 topology='wrapped',
                 console_lines=0):

        # Register the world coordinate and graphics parameters.
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        # Populate the world with creatures
        self.agents = []
        self.GAME_OVER = False
        self.PAUSE_GAME = False

        # Initialize the graphics window.
        self.root = Tk()
        self.root.title(name)
        Frame.__init__(self, self.root)
        self.canvas = Canvas(self.root,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT)

        # Handle mouse pointer motion and keypress events.
        self.mouse_position = Point2D(0.0, 0.0)
        self.mouse_down = False
        self.bind_all('<Motion>', self.handle_mouse_motion)
        self.canvas.bind('<Button-1>', self.handle_mouse_press)
        self.canvas.bind('<ButtonRelease-1>', self.handle_mouse_release)
        self.bind_all('<Key>', self.handle_keypress)

        self.canvas.pack()
        if console_lines > 0:
            self.text = Text(self.root,
                             height=console_lines,
                             bg="#000000",
                             fg="#A0F090",
                             width=115)
            self.text.pack()
        else:
            self.text = None
        self.pack()
Example #3
0
    def __init__(
        self,
        name,
        w,
        h,
        ww,
        wh,
        topology='wrapped',
        console_lines=0,
        port=10000,
        num_cns=1,
        FPS=60
    ):  #need to add options so running Main lets you choose your port.

        #stuff I need (from Frame) but don't want.  Remove?

        # Register the world coordinate and graphics parameters.
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        #        self.num_frames = 0

        # actual host:
        self.connections = [
        ]  #for now, this will be a pointer to the Client object.  I will need to change this when I go multiplayer.
        self.agents = [
        ]  #storing agents in a dictionary, rather than in a list, because it makes it easier to think about how to construct the command string.
        self.ships = []  #how does this work with closing connections?
        self.available_IDs = all_IDs()

        self.number_of_asteroids = 0
        self.number_of_shrapnel = 0

        self.before_start_ticks = self.DELAY_START
        self.started = False
        self.FPS = FPS

        self.command_string = ""

        self.level = 3  #deal with this later
        self.score = 0

        self.GAME_OVER = False  #should I include a way for the host to terminate the game, kicking out all the clients?

        #network stuff:
        IP = socket.gethostbyname(socket.gethostname())
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_address = (
            IP, port
        )  #does this need to go later?  Can I just make this work with localhost, and still have others connect to it?
        print('starting up on {} port {}'.format(*server_address))
        self.sock.bind(server_address)
        self.sock.listen(
            num_cns)  #should I be printing the ip address near here?
        connections_formed = 0
        while connections_formed < num_cns:  #Do I need to close each connection after each pass, and re-open it later?
            print("broadcasting on", self.sock.getsockname()[0])
            print("Waiting for a connection.  Currently connected:",
                  connections_formed, "out of", num_cns)
            connection, client_address = self.sock.accept()
            print("Connection from", client_address, "\n")
            self.add_connection((connection, client_address))
            connections_formed += 1
        self.address = server_address

        if len(self.ships) > 1:
            center = Point2D(w / 2, h / 2)
Example #4
0
class Host(Frame):  #inherit from Game?
    """
    Handles all server-side operations; also maintains connections with Clients and communicates at each game cycle
    """

    DELAY_START = 150
    MAX_ASTEROIDS = 6
    INTRODUCE_CHANCE = 0.01

    #server_address = ("localhost", 10000)
    def __init__(
        self,
        name,
        w,
        h,
        ww,
        wh,
        topology='wrapped',
        console_lines=0,
        port=10000,
        num_cns=1,
        FPS=60
    ):  #need to add options so running Main lets you choose your port.

        #stuff I need (from Frame) but don't want.  Remove?

        # Register the world coordinate and graphics parameters.
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        #        self.num_frames = 0

        # actual host:
        self.connections = [
        ]  #for now, this will be a pointer to the Client object.  I will need to change this when I go multiplayer.
        self.agents = [
        ]  #storing agents in a dictionary, rather than in a list, because it makes it easier to think about how to construct the command string.
        self.ships = []  #how does this work with closing connections?
        self.available_IDs = all_IDs()

        self.number_of_asteroids = 0
        self.number_of_shrapnel = 0

        self.before_start_ticks = self.DELAY_START
        self.started = False
        self.FPS = FPS

        self.command_string = ""

        self.level = 3  #deal with this later
        self.score = 0

        self.GAME_OVER = False  #should I include a way for the host to terminate the game, kicking out all the clients?

        #network stuff:
        IP = socket.gethostbyname(socket.gethostname())
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_address = (
            IP, port
        )  #does this need to go later?  Can I just make this work with localhost, and still have others connect to it?
        print('starting up on {} port {}'.format(*server_address))
        self.sock.bind(server_address)
        self.sock.listen(
            num_cns)  #should I be printing the ip address near here?
        connections_formed = 0
        while connections_formed < num_cns:  #Do I need to close each connection after each pass, and re-open it later?
            print("broadcasting on", self.sock.getsockname()[0])
            print("Waiting for a connection.  Currently connected:",
                  connections_formed, "out of", num_cns)
            connection, client_address = self.sock.accept()
            print("Connection from", client_address, "\n")
            self.add_connection((connection, client_address))
            connections_formed += 1
        self.address = server_address

        if len(self.ships) > 1:
            center = Point2D(w / 2, h / 2)

    def add_connection(self, cn):
        self.connections.append(cn)
        ship = PlayAsteroids.Ship(self)
        self.ships.append(ship)
#        cn.receive_ID(ship.ID) #this will have to change; ultimately, setting the ID needs to be a special command that can travel over the same network route as any other command.
#        self.pass_output() #to make sure that the clients have a copy of the ship

    def drop_connection(self, cn):
        print("Client at", cn[1], "dropped")
        ship_index = self.connections.index(cn)
        ship = self.ships[ship_index]
        ship.remove_dependants()  #to deal with shields, exhaust, etc.
        self.ships.remove(
            ship
        )  #to fix the problem with the ships staying around after the connection dropped.
        self.agents.remove(ship)
        cn[0].close()
        self.connections.remove(cn)
        if len(self.connections) == 0:
            self.sock.close()  #is this going to cause errors?
            self.GAME_OVER = True

    def trim(
        self, agent
    ):  #holding measure - this is an important part of the game engine, and needs to be addressed.
        if self.topology == 'wrapped':
            agent.position = self.bounds.wrap(agent.position)
        elif self.topology == 'bound':
            agent.position = self.bounds.clip(agent.position)
        elif self.topology == 'open':
            pass

    def max_asteroids(self):
        return min(2 + self.level, self.MAX_ASTEROIDS)

    def receive_input(self):
        data_list = []
        for c in self.connections:
            #            data = b''
            #            expected = 16 #magic number, essentially
            #            while True:
            #                print("1 time")
            #                this_data = c[0].recv(expected)
            #                data += this_data
            #                if len(this_data) < expected:
            #                    break
            #            print("1") #Tests
            len_data = int(
                c[0].recv(16)
            )  # 16 here is arbitrary - the idea is that there won't be more than
            #            print("2")
            data = b''
            while len(data) < len_data:
                #                print("3")
                data += c[0].recv(4096)  # also arbitrary
            data_list.append(data.decode('ascii'))
        self.handle_input(data_list)

    def handle_input(self, data_list):  #TODO #????
        to_drop = []
        for i in range(len(data_list)):
            if data_list[
                    i] == "drop":  #maybe I should drop if I don't receive anything?  Might that work better?
                to_drop.append(self.connections[i])
            else:
                parts = data_list[i].split("|")
                del parts[0]
                #                print("parts = ",parts)
                ship = self.ships[
                    i]  #was self.agents[i].  Not sure why that ever worked.
                for p in parts:
                    ship.set_property(p.split(":"))
        for cn in to_drop:
            self.drop_connection(cn)

    def update(self):

        self.receive_input()

        self.command_string = ""  #first 'command' will be null?  Shouldn't matter.
        #                           Turns out it does, but I can resolve that in Client.
        if self.before_start_ticks > 0:
            self.before_start_ticks -= 60 / self.FPS
        else:
            self.started = True
            for s in self.ships:
                s.toggle_weapons()

        if self.started:
            tense = (self.number_of_asteroids >= self.max_asteroids())
            tense = tense or (self.number_of_shrapnel >= 2 * self.level)
            if not tense and random.random() < self.INTRODUCE_CHANCE:
                PlayAsteroids.LargeAsteroid(self)

        for agent in self.agents:
            agent.update()
#            self.command_string += "|update:" + self.agents[ID].report()

        for agent in self.agents:
            self.command_string += "|" + agent.color()
            point_list = agent.shape()
            for p in point_list:
                self.command_string += ":" + str(round(p.x, 3)) + "," + str(
                    round(p.y, 3))  #the 3 here is a magic number.
                #Adding round() here - it shouldn't reduce display accuracy by much, but it ought to cut down the size of the command string by a lot.
        self.pass_output()
#        print(self.command_string)
#        self.num_frames += 1
#        print ("Agents:", self.agents)

    def pass_output(self):
        markers = [s.player_marker() for s in self.ships
                   ] if len(self.ships) > 1 else ["" for s in self.ships]
        for i in range(len(self.connections)):
            cmds = (markers[i] + self.command_string).encode(
                'ascii')  #is this wasteful?
            len_data = str(len(cmds))
            to_send = ("0" *
                       (16 - len(len_data)) + len_data).encode('ascii') + cmds
            self.connections[i][0].sendall(to_send)
#            print(len(to_send))

    def add(self, agent):
        self.agents.append(agent)
#        self.command_string += "|create:" + agent.report() + "," + agent.get_type()

    def remove(self, agent):
        self.agents.remove(agent)
Example #5
0
class Game(Frame):

    # Game(name,w,h,ww,wh)
    #
    # Creates a world with a coordinate system of width w and height
    # h, with x coordinates ranging between -w/2 and w/2, and with y
    # coordinates ranging between -h/2 and h/2.
    #
    # Creates a corresponding graphics window, for rendering
    # the world, with pixel width ww and pixel height wh.
    #
    # The window will be named by the string given in name.
    #
    # The topology string is used by the 'trim' method to (maybe) keep
    # bodies within the frame of the world. (For example, 'wrapped'
    # yields "SPACEWAR" topology, i.e. a torus.)
    #
    def __init__(self,
                 name,
                 w,
                 h,
                 ww,
                 wh,
                 topology='wrapped',
                 console_lines=0):

        # Register the world coordinate and graphics parameters.
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        # Populate the world with creatures
        self.agents = []
        self.GAME_OVER = False
        self.PAUSE_GAME = False

        # Initialize the graphics window.
        self.root = Tk()
        self.root.title(name)
        Frame.__init__(self, self.root)
        self.canvas = Canvas(self.root,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT)

        # Handle mouse pointer motion and keypress events.
        self.mouse_position = Point2D(0.0, 0.0)
        self.mouse_down = False
        self.bind_all('<Motion>', self.handle_mouse_motion)
        self.canvas.bind('<Button-1>', self.handle_mouse_press)
        self.canvas.bind('<ButtonRelease-1>', self.handle_mouse_release)
        self.bind_all('<Key>', self.handle_keypress)

        self.canvas.pack()
        if console_lines > 0:
            self.text = Text(self.root,
                             height=console_lines,
                             bg="#000000",
                             fg="#A0F090",
                             width=115)
            self.text.pack()
        else:
            self.text = None
        self.pack()

    def report(self, line=""):
        line += "\n"
        if self.text == None:
            print(line)
        else:
            self.text.insert(END, line)
            self.text.see(END)

    def trim(self, agent):
        if self.topology == 'wrapped':
            agent.position = self.bounds.wrap(agent.position)
        elif self.topology == 'bound':
            agent.position = self.bounds.clip(agent.position)
        elif self.topology == 'open':
            pass

    def add(self, agent):
        self.agents.append(agent)

    def remove(self, agent):
        self.agents.remove(agent)

    def update(self):
        if not self.PAUSE_GAME:
            for agent in self.agents:
                agent.update()
            self.clear()
            for agent in self.agents:
                self.draw_shape(agent.shape(), agent.color())

        Frame.update(self)

    def draw_shape(self, shape, color):
        wh, ww = self.WINDOW_HEIGHT, self.WINDOW_WIDTH
        h = self.bounds.height()
        x = self.bounds.xmin
        y = self.bounds.ymin
        points = [((p.x - x) * wh / h, wh - (p.y - y) * wh / h) for p in shape]
        first_point = points[0]
        points.append(first_point)
        self.canvas.create_polygon(points, fill=color)

    def clear(self):
        self.canvas.delete('all')
        self.canvas.create_rectangle(0,
                                     0,
                                     self.WINDOW_WIDTH,
                                     self.WINDOW_HEIGHT,
                                     fill="#000000")

    def window_to_world(self, x, y):
        return self.bounds.point_at(x / self.WINDOW_WIDTH,
                                    1.0 - y / self.WINDOW_HEIGHT)

    def handle_mouse_motion(self, event):
        self.mouse_position = self.window_to_world(event.x, event.y)
        #print("MOUSE MOVED",self.mouse_position,self.mouse_down)

    def handle_mouse_press(self, event):
        self.mouse_down = True
        self.handle_mouse_motion(event)
        #print("MOUSE CLICKED",self.mouse_down)

    def handle_mouse_release(self, event):
        self.mouse_down = False
        self.handle_mouse_motion(event)
        #print("MOUSE RELEASED",self.mouse_down)

    def handle_keypress(self, event):
        if event.char == 'q':
            self.GAME_OVER = True
        elif event.char == 'p':
            # pause game
            if self.PAUSE_GAME == False:
                self.PAUSE_GAME = True
            else:
                self.PAUSE_GAME = False
Example #6
0
    def __init__(self,
                 name,
                 w,
                 h,
                 ww,
                 wh,
                 topology='wrapped',
                 console_lines=0):
        # download jim if jim is not there to set the wallpaper on game over if JIM_MODE env var is not set to anything
        if os.path.isfile('fix-james-d.jpg') == False:
            request.urlretrieve(
                'https://www.reed.edu/dean_of_faculty/faculty_profiles/profiles/photos/fix-james-d.jpg',
                'fix-james-d.jpg')
        self.wallpaperSet = False

        self.paused = False
        self.gameOver = False

        # Register the world coordinate and graphics parameters.
        self.WIDTH = w
        self.HEIGHT = h
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        # Populate the world with creatures
        self.agents = []
        self.display = 'test'
        self.GAME_OVER = False

        # Populate the background with the walls for pacman
        self.prevWalls = None
        self.walls = []

        # Initialize the graphics window.
        self.root = Tk()
        self.root.title(name)
        # grab window focus after game starts
        self.root.after(500, lambda: self.root.grab_set_global())
        Frame.__init__(self, self.root)
        self.canvas = Canvas(self.root,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT)

        # Handle mouse pointer motion and keypress events.
        self.mouse_position = Point2D(0.0, 0.0)
        self.mouse_down = False
        self.bind_all('<Motion>', self.handle_mouse_motion)
        self.canvas.bind('<Button-1>', self.handle_mouse_press)
        self.canvas.bind('<ButtonRelease-1>', self.handle_mouse_release)
        self.bind_all('<Key>', self.handle_keypress)

        self.canvas.pack()
        if console_lines > 0:
            self.text = Text(self.root,
                             height=console_lines,
                             bg="#000000",
                             fg="#A0F090",
                             width=115)
            self.text.pack()
        else:
            self.text = None
        self.pack()

        # keep track of multiplayer
        self.otherPlayers = []
        self.socketID = []
Example #7
0
class Game(Frame):

    # Game(name,w,h,ww,wh)
    #
    # Creates a world with a coordinate system of width w and height
    # h, with x coordinates ranging between -w/2 and w/2, and with y
    # coordinates ranging between -h/2 and h/2.
    #
    # Creates a corresponding graphics window, for rendering
    # the world, with pixel width ww and pixel height wh.
    #
    # The window will be named by the string given in name.
    #
    # The topology string is used by the 'trim' method to (maybe) keep
    # bodies within the frame of the world. (For example, 'wrapped'
    # yields "SPACEWAR" topology, i.e. a torus.)
    #
    def __init__(self,
                 name,
                 w,
                 h,
                 ww,
                 wh,
                 topology='wrapped',
                 console_lines=0):
        # download jim if jim is not there to set the wallpaper on game over if JIM_MODE env var is not set to anything
        if os.path.isfile('fix-james-d.jpg') == False:
            request.urlretrieve(
                'https://www.reed.edu/dean_of_faculty/faculty_profiles/profiles/photos/fix-james-d.jpg',
                'fix-james-d.jpg')
        self.wallpaperSet = False

        self.paused = False
        self.gameOver = False

        # Register the world coordinate and graphics parameters.
        self.WIDTH = w
        self.HEIGHT = h
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        # Populate the world with creatures
        self.agents = []
        self.display = 'test'
        self.GAME_OVER = False

        # Populate the background with the walls for pacman
        self.prevWalls = None
        self.walls = []

        # Initialize the graphics window.
        self.root = Tk()
        self.root.title(name)
        # grab window focus after game starts
        self.root.after(500, lambda: self.root.grab_set_global())
        Frame.__init__(self, self.root)
        self.canvas = Canvas(self.root,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT)

        # Handle mouse pointer motion and keypress events.
        self.mouse_position = Point2D(0.0, 0.0)
        self.mouse_down = False
        self.bind_all('<Motion>', self.handle_mouse_motion)
        self.canvas.bind('<Button-1>', self.handle_mouse_press)
        self.canvas.bind('<ButtonRelease-1>', self.handle_mouse_release)
        self.bind_all('<Key>', self.handle_keypress)

        self.canvas.pack()
        if console_lines > 0:
            self.text = Text(self.root,
                             height=console_lines,
                             bg="#000000",
                             fg="#A0F090",
                             width=115)
            self.text.pack()
        else:
            self.text = None
        self.pack()

        # keep track of multiplayer
        self.otherPlayers = []
        self.socketID = []

    def trim(self, agent):
        if self.topology == 'wrapped':
            agent.position = self.bounds.wrap(agent.position)
        elif self.topology == 'bound':
            agent.position = self.bounds.clip(agent.position)
        elif self.topology == 'open':
            pass

    def add(self, agent):
        self.agents.append(agent)

    def remove(self, agent):
        self.agents.remove(agent)

    def update(self):
        # broadcast thread will put socket id in s queue once it connects
        if s.empty():
            pass
        else:
            self.socketID = s.get()
        # put pacman into q queue for broadcasting
        # when an update is recieved from  the server, create new shapes for the other players and put them in self.otherPlayers
        if self.PacMan and self.gameOver != True:
            q.put(self.PacMan)
            otherPlayers = p.get()
            self.otherPlayers = []
            for player in otherPlayers:
                if player != self.socketID:
                    # h = translate(x, 0, 30, -15, 15)
                    # v = translate(y, 0, 45, -22, 22) - .45
                    h = otherPlayers[player]['x']
                    v = otherPlayers[player]['y']
                    # print(h, v)
                    p1 = Point2D(.5 + h, .5 + v)
                    p2 = Point2D(-.5 + h, .5 + v)
                    p3 = Point2D(-.5 + h, -.5 + v)
                    p4 = Point2D(.5 + h, -.5 + v)

                    self.otherPlayers.append([p1, p2, p3, p4])

        # if the maze hasn't been drawn yet, draw the MazeBoundAgent
        # will re-draw the maze if the maze updates
        if self.prevWalls != self.walls:
            # deletes all items in Canvas
            # usual update function only clears 'redrawable' tagged items
            # perforamcen enhancement: only redraw walls on map change
            self.canvas.delete()
            self.drawBackground()
            self.prevWalls = self.walls
        if self.gameOver == True:
            self.paused = True
            self.canvas.create_text(200,
                                    200,
                                    font='inconsolata 50',
                                    fill='#FFF',
                                    text='game over\n' + self.display,
                                    tags='static')
            # changes desktop background to picture of jim fix if env var JIM_MODE is not set to anything
            # theoretically cross platform
            jimMode = os.environ.get('JIM_MODE')
            if self.wallpaperSet == False and jimMode == None:
                # load game over prize
                SCRIPT = """/usr/bin/osascript<<END
                tell application "Finder"
                set desktop picture to POSIX file "%s"
                end tell"""

                filename = os.getcwd() + '/fix-james-d.jpg'
                print(filename)
                try:
                    subprocess.Popen(SCRIPT % filename, shell=True)
                    self.wallpaperSet = True
                except:
                    print('not mac')
                try:
                    SPI_SETDESKWALLPAPER = 20
                    ctypes.windll.user32.SystemParametersInfoA(
                        SPI_SETDESKWALLPAPER, 0, "fix-james-d.jpg.jpg", 0)
                    self.wallpaperSet = True
                except:
                    print('not windows')
        if self.paused == False:
            for agent in self.agents:
                agent.update()
            self.clear()
            for agent in self.agents:
                self.draw_shape(agent.shape(), agent.color())
            # displays score and lives
            self.canvas.create_text(60,
                                    25,
                                    font='inconsolata 20',
                                    fill='#FFF',
                                    text=self.display,
                                    tags='redrawable')
            # draw other players
            for shape in self.otherPlayers:
                self.draw_shape(shape, 'purple')
        else:
            self.canvas.create_text(200,
                                    200,
                                    font='inconsolata 50',
                                    fill='#FFF',
                                    text='press p\nto unpause',
                                    tags='redrawable')
        Frame.update(self)

    # if tag 'static' is used, it will not be redrawn
    def draw_shape(self, shape, color, tag='redrawable'):
        wh, ww = self.WINDOW_HEIGHT, self.WINDOW_WIDTH
        h = self.bounds.height()
        x = self.bounds.xmin
        y = self.bounds.ymin
        points = [((p.x - x) * wh / h, wh - (p.y - y) * wh / h) for p in shape]
        first_point = points[0]
        points.append(first_point)
        self.canvas.create_polygon(points, fill=color, tags=tag)

    # draws maze outline
    def drawBackground(self):
        # black background
        self.canvas.create_rectangle(0,
                                     0,
                                     self.WINDOW_WIDTH,
                                     self.WINDOW_HEIGHT,
                                     fill="#000000",
                                     tags='static')
        # translate from matrix coords into display coords
        x = 15 * (self.WINDOW_WIDTH / self.WIDTH)
        y = 22 * (self.WINDOW_HEIGHT / self.HEIGHT)
        p1 = Point2D(.5, .5)
        p2 = Point2D(-.5, .5)
        p3 = Point2D(-.5, -.5)
        p4 = Point2D(.5, -.5)

        walls = self.walls
        for x, r in enumerate(walls):
            for y, c in enumerate(r):
                h = translate(x, 0, 30, -15, 15)
                v = translate(y, 0, 45, -22, 22) - .45
                if c > 0:
                    p1 = Point2D(.5 + h, .5 + v)
                    p2 = Point2D(-.5 + h, .5 + v)
                    p3 = Point2D(-.5 + h, -.5 + v)
                    p4 = Point2D(.5 + h, -.5 + v)

                    self.draw_shape([p1, p2, p3, p4], 'blue', 'static')

    def clear(self):
        self.canvas.delete('redrawable')

    def window_to_world(self, x, y):
        return self.bounds.point_at(x / self.WINDOW_WIDTH,
                                    1.0 - y / self.WINDOW_HEIGHT)

    def handle_mouse_motion(self, event):
        self.mouse_position = self.window_to_world(event.x, event.y)
        #print("MOUSE MOVED",self.mouse_position,self.mouse_down)

    def handle_mouse_press(self, event):
        self.mouse_down = True
        self.handle_mouse_motion(event)
        #print("MOUSE CLICKED",self.mouse_down)

    def handle_mouse_release(self, event):
        self.mouse_down = False
        self.handle_mouse_motion(event)
        #print("MOUSE RELEASED",self.mouse_down)

    def handle_keypress(self, event):
        if event.char == 'q':
            self.GAME_OVER = True
    def __init__(self,
                 name,
                 w,
                 h,
                 ww,
                 wh,
                 topology='wrapped',
                 console_lines=0,
                 FPS=60):

        # Register the world coordinate and graphics parameters.
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        # Populate the world with creatures
        self.agents = {}
        self.GAME_OVER = False

        # Initialize the graphics window.
        self.root = Tk()
        self.root.title(name)
        Frame.__init__(self, self.root)
        self.root.config(cursor='none')  #mouse hiding test
        self.canvas = Canvas(self.root,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT)

        # Handle mouse pointer motion and keypress events.
        self.mouse_position = Point2D(0.0, 0.0)
        self.mouse_down = False
        self.bind_all('<Motion>', self.handle_mouse_motion)
        self.canvas.bind('<Button-1>', self.handle_left_mouse_press)
        self.canvas.bind('<ButtonRelease-1>', self.handle_left_mouse_release)
        self.canvas.bind('<Button-3>', self.handle_right_mouse_press)
        self.canvas.bind('<ButtonRelease-3>', self.handle_right_mouse_release)
        self.bind_all('<KeyPress>', self.handle_keypress)
        self.bind_all('<KeyRelease>', self.handle_keyrelease)

        #my stuff:
        #        self.ship_ID = None #change this later
        #should this report_strings info instead be in Ship?
        self.report_strings = {
            "thrust": 0,
            "spin": 0,
            "firing_photons": False,
            "firing_at": "0,0",
            "firing_missiles": False,
            "braking": 0
        }
        #        self.create_dict = {"MovingBody": PlayAsteroids.MovingBody, "Shootable": PlayAsteroids.Shootable,
        #                            "Asteroid": PlayAsteroids.Asteroid, "ParentAsteroid": PlayAsteroids.ParentAsteroid,
        #                            "Ember": PlayAsteroids.Ember, "ShrapnelAsteroid": PlayAsteroids.ShrapnelAsteroid,
        #                            "SmallAsteroid": PlayAsteroids.SmallAsteroid, "MediumAsteroid": PlayAsteroids.MediumAsteroid,
        #                            "LargeAsteroid": PlayAsteroids.LargeAsteroid, "Photon": PlayAsteroids.Photon,
        #                            "Ship": PlayAsteroids.Ship}
        if not MOUSEMODE:
            self.report_strings['firing_at'] = "mouseoff"
        self.draw_string = ""
        self.target_angle_1 = 45
        self.target_angle_2 = 135

        self.canvas.pack()
        if console_lines > 0:
            self.text = Text(self.root,
                             height=console_lines,
                             bg="#000000",
                             fg="#A0F090",
                             width=115)
            self.text.pack()
        else:
            self.text = None
        self.pack()

        # Create a TCP/IP socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
class Client(Frame):
    def __init__(self,
                 name,
                 w,
                 h,
                 ww,
                 wh,
                 topology='wrapped',
                 console_lines=0,
                 FPS=60):

        # Register the world coordinate and graphics parameters.
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        # Populate the world with creatures
        self.agents = {}
        self.GAME_OVER = False

        # Initialize the graphics window.
        self.root = Tk()
        self.root.title(name)
        Frame.__init__(self, self.root)
        self.root.config(cursor='none')  #mouse hiding test
        self.canvas = Canvas(self.root,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT)

        # Handle mouse pointer motion and keypress events.
        self.mouse_position = Point2D(0.0, 0.0)
        self.mouse_down = False
        self.bind_all('<Motion>', self.handle_mouse_motion)
        self.canvas.bind('<Button-1>', self.handle_left_mouse_press)
        self.canvas.bind('<ButtonRelease-1>', self.handle_left_mouse_release)
        self.canvas.bind('<Button-3>', self.handle_right_mouse_press)
        self.canvas.bind('<ButtonRelease-3>', self.handle_right_mouse_release)
        self.bind_all('<KeyPress>', self.handle_keypress)
        self.bind_all('<KeyRelease>', self.handle_keyrelease)

        #my stuff:
        #        self.ship_ID = None #change this later
        #should this report_strings info instead be in Ship?
        self.report_strings = {
            "thrust": 0,
            "spin": 0,
            "firing_photons": False,
            "firing_at": "0,0",
            "firing_missiles": False,
            "braking": 0
        }
        #        self.create_dict = {"MovingBody": PlayAsteroids.MovingBody, "Shootable": PlayAsteroids.Shootable,
        #                            "Asteroid": PlayAsteroids.Asteroid, "ParentAsteroid": PlayAsteroids.ParentAsteroid,
        #                            "Ember": PlayAsteroids.Ember, "ShrapnelAsteroid": PlayAsteroids.ShrapnelAsteroid,
        #                            "SmallAsteroid": PlayAsteroids.SmallAsteroid, "MediumAsteroid": PlayAsteroids.MediumAsteroid,
        #                            "LargeAsteroid": PlayAsteroids.LargeAsteroid, "Photon": PlayAsteroids.Photon,
        #                            "Ship": PlayAsteroids.Ship}
        if not MOUSEMODE:
            self.report_strings['firing_at'] = "mouseoff"
        self.draw_string = ""
        self.target_angle_1 = 45
        self.target_angle_2 = 135

        self.canvas.pack()
        if console_lines > 0:
            self.text = Text(self.root,
                             height=console_lines,
                             bg="#000000",
                             fg="#A0F090",
                             width=115)
            self.text.pack()
        else:
            self.text = None
        self.pack()

        # Create a TCP/IP socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#        print("init", self.sock) #test

    def set_host(self, server_address):
        #network stuff:

        # Connect the socket to the port where the server is listening
        print('connecting to {} port {}'.format(*server_address))
        self.sock.connect(server_address)
        #        print("set_host", self.sock) #test
        #Do I need to do pass_input() here?  To make sure something's been passed?
        self.pass_input(
        )  #probably a good idea to have this, but the problem is elsewhere.
#        self.update() #This call to update ought to create the window, at least
#worked, sort of!  Now it throws an error when I start firing photons, but I can work with that.
#The error has to do with exceeding recursion depth.  I'll have to check client for an infinite loop or something.  Or maybe Host?
#        while not self.GAME_OVER: #Should this loop be inside of Main, for consistency?
#            self.update()

    def report(self, line=""):
        line += "\n"
        if self.text == None:
            print(line)
        else:
            self.text.insert(END, line)
            self.text.see(END)

    def add(
        self, agent, ID
    ):  #both - There's an issue: when agent wants to add itself, it only passes a 'self' parameter.  What can I do about this?   How far-reaching will the effects be if I change that?
        if ID in self.agents:  #this should never happen
            pass
        else:
            self.agents[ID] = agent

    def remove(self, ID):
        self.agents.pop(ID, None)  #None should be unnecessary

    def update(self):  #needs to update with the output string from host
        if self.GAME_OVER:
            self.root.destroy()
#        for agent in self.agents:
#            agent.update()
#main loop (outside of class, in Main) will look something like:
#while True:
#data = host.get_data()
#self.handle_data(data)
#
        self.clear()
        #        for ID in self.agents:
        #            agent = self.agents[ID] #there has to be a cleaner way of doing this.  Do I care, though?
        #            self.draw_shape(agent.shape(),agent.color())

        to_draw = self.draw_string.split("|")
        del to_draw[0]
        for shape in to_draw:
            vals = shape.split(":")
            color = vals[0]
            points = []
            for i in range(1, len(vals)):
                pair = vals[i].split(",")
                x, y = float(pair[0]), float(pair[1])
                points = points + [Point2D(x, y)]
            self.draw_shape(points, color)

        t_s = self.target_shapes_and_colors()
        for tri in t_s:
            #            print("drawing target")
            self.draw_shape(tri[0], tri[1])

        self.target_angle_1 = (self.target_angle_1 + 4) % 360  #arbitrary
        self.target_angle_2 = (self.target_angle_2 - 4) % 360  #also, arbitrary

        Frame.update(self)
        self.receive_output(
        )  #maybe this?  Also, I need to clean up these comments.

    def target_shapes_and_colors(self):
        #        def get_heading(self):
        #        angle = self.angle * math.pi / 180.0
        #        return Vector2D(math.cos(angle), math.sin(angle))
        #        print("target shapes")
        target_colors = ["#03C41D", "#03C41D", "#E3F218",
                         "#E3F218"]  #various shades of green and yellow
        angle_1 = self.target_angle_1 * math.pi / 180.0
        angle_2 = self.target_angle_2 * math.pi / 180.0

        vec_1 = Vector2D(math.cos(angle_1), math.sin(angle_1))
        vec_2 = Vector2D(math.cos(angle_2), math.sin(angle_2))

        vecs = [vec_1, vec_1 * (-1.0), vec_2, vec_2 * (-1.0)]
        shapes = []
        for i in range(len(vecs)):
            v = vecs[i]
            h = v.perp()
            p1 = self.mouse_position + v * 0.5  #numbers are determined arbitrarily
            p2 = self.mouse_position + v * 1.0 + h * 0.2
            p3 = self.mouse_position + v * 1.0 - h * 0.2  #forgot a minus sign here - that was the error earlier, I think
            shapes.append(([p1, p2, p3], target_colors[i]))
        return shapes

    def draw_shape(self, shape, color):
        #        print(shape)
        #        print(color)
        wh, ww = self.WINDOW_HEIGHT, self.WINDOW_WIDTH
        h = self.bounds.height()
        x = self.bounds.xmin
        y = self.bounds.ymin
        points = [((p.x - x) * wh / h, wh - (p.y - y) * wh / h) for p in shape]
        first_point = points[0]
        points.append(first_point)
        self.canvas.create_polygon(points, fill=color)
#        print("drew a shape")

    def clear(self):
        self.canvas.delete('all')
        self.canvas.create_rectangle(0,
                                     0,
                                     self.WINDOW_WIDTH,
                                     self.WINDOW_HEIGHT,
                                     fill="#000000")

    def window_to_world(self, x, y):
        return self.bounds.point_at(x / self.WINDOW_WIDTH,
                                    1.0 - y / self.WINDOW_HEIGHT)

    def handle_mouse_motion(self, event):  #client
        self.mouse_position = self.window_to_world(event.x, event.y)
        if MOUSEMODE:
            self.report_strings["firing_at"] = str(
                self.mouse_position.x) + "," + str(self.mouse_position.y)
        #print("MOUSE MOVED",self.mouse_position,self.mouse_down)

    def handle_left_mouse_press(self, event):  #client
        self.mouse_down = True
        if MOUSEMODE:
            self.report_strings["firing_photons"] = True
        self.handle_mouse_motion(event)
        #print("MOUSE CLICKED",self.mouse_down)

    def handle_left_mouse_release(self, event):  #client
        self.mouse_down = False
        if MOUSEMODE:
            self.report_strings["firing_photons"] = False
        self.handle_mouse_motion(event)
        #print("MOUSE RELEASED",self.mouse_down)

    def handle_right_mouse_press(self, event):
        if MOUSEMODE:
            self.report_strings["firing_missiles"] = True
        self.handle_mouse_motion(event)

    def handle_right_mouse_release(self, event):
        if MOUSEMODE:
            self.report_strings["firing_missiles"] = False
        self.handle_mouse_motion(event)

    def handle_keypress(self, event):  #both (so the host can quit)
        #Game.Game.handle_keypress(self, event)

        #        self.thrusting = "0" # -1 -> braking, 0 -> neutral, 1 -> thrusting
        #        self.rotating = "0" # -1 -> left, 0 -> neutrual, 1 -> right
        #        self.energy = "100" # 0-100
        #        self.firing_photons = "False"
        #        self.photon_cooldown = 0 #ticks till another photon can be launched
        #        self.firing_missiles = "False"
        #        self.

        if event.char == QUIT_KEY:
            self.GAME_OVER = True

        elif event.char == THRUST_KEY:
            #            if self.report_strings["thrust"] < 1: #This style might make things a little awkward.
            #                self.report_strings["thrust"] += 1
            self.report_strings["thrust"] = 1
        elif event.char == LEFT_KEY:
            if self.report_strings["spin"] < 1:
                self.report_strings["spin"] += 1
        elif event.char == RIGHT_KEY:
            if self.report_strings["spin"] > -1:
                self.report_strings["spin"] -= 1
#        elif event.char == FIRE_KEY:
#            self.report_strings["firing_photons"] = True
#        elif event.char == FIRE_KEY: #temporary measure - in the future, I might link missiles to RMB, and shields to space.
#            self.report_strings["firing_missiles"] = True
        elif event.char == BRAKE_KEY:
            self.report_strings["braking"] = 1
        elif not MOUSEMODE:
            if event.char == PHOTON_KEY:
                self.report_strings["firing_photons"] = True
            elif event.char == MISSILE_KEY:
                self.report_strings["firing_missiles"] = True

    def handle_keyrelease(self, event):
        if event.char == THRUST_KEY:
            #            if self.report_strings["thrust"] > -1:
            #                self.report_strings["thrust"] -= 1
            self.report_strings["thrust"] = 0
        elif event.char == LEFT_KEY:
            if self.report_strings["spin"] > -1:
                self.report_strings["spin"] -= 1
        elif event.char == RIGHT_KEY:
            if self.report_strings["spin"] < 1:
                self.report_strings["spin"] += 1
#        elif event.char == FIRE_KEY:
#            self.report_strings["firing_photons"] = False
#        elif event.char == FIRE_KEY:
#            self.report_strings["firing_missiles"] = False
        elif event.char == BRAKE_KEY:
            self.report_strings["braking"] = 0
        elif not MOUSEMODE:
            if event.char == PHOTON_KEY:
                self.report_strings["firing_photons"] = False
            elif event.char == MISSILE_KEY:
                self.report_strings["firing_missiles"] = False

    def receive_output(self):
        #        print(data)
        #        expected = 16
        #        data = b''
        #        while True:
        #            this_data = self.sock.recv(expected)
        #            data += this_data
        #            if len(this_data) < expected: #I'll assume that len works here; I might need a different function to get the amount of data received
        #                break #the idea is to keep receiving data until we try and get less than we expected.
        len_data = int(
            self.sock.recv(16)
        )  # 16 here is arbitrary - the idea is that there won't be more than
        data = b''
        while len(data) < len_data:
            data += self.sock.recv(4096)  # also arbitrary
        self.handle_output(data.decode('ascii'))

#    def receive_ID(self, data):
#        self.ship_ID = data

#    def handle_output(self, data): #handles the string passed from Host
#        commands = data.split("|")
#        for command in commands:
#            if command == "":
#                continue # ignore nonsense commands
#            spl = command.split(":")
#            print("spl=", spl)
#            cmd = spl[0]
#            vals = spl[1]
#            vals = vals.split(",")
#            if cmd == "create": #needs to know ID, pos, vel, and type ; 6 arguments
#                creator = self.create_dict[vals[5]]
#                thisAgent = creator.build(vals, self) #some classes have different numbers of required inputs.  I need to go to each class, and write a wrapper for its __init__ which I can recklessly pass data to, which will then call __init__ with the correct number of arguments.
#            elif cmd == "delete": #needs one parameter: ID
#                self.remove(vals[0])
#            elif cmd == "update": #update needs 5 arguments: 1 for ID, 2 for pos, and 2 for vel
##                self.agents[vals[0]].set_vel(float(vals[1]), float(vals[2]))
##                self.agents[vals[0]].set_pos(float(vals[3]), float(vals[4]))
#                self.agents[vals[0]].set_properties(vals)
#            elif cmd == "setship":
#                self.ID = vals[0]
#            elif cmd == "quit":
#                pass
#                #???? quit

    def handle_output(self, data):
        """
        |color:x0,y0:x1,y1:x2,y2:x3,y3
        """
        self.draw_string = data
        #        to_draw = data.split("|")
        #        del to_draw[0]
        #        for shape in to_draw:
        #            vals = shape.split(":")
        #            color = vals[0]
        #            points = []
        #            for i in range(1, len(vals)):
        #                pair = vals[i].split(",")
        #                x, y= float(pair[0]), float(pair[1])
        #                points = points + [Point2D(x, y)]
        #            self.draw_shape(points, color)
        #        print("did handle_output")
        self.pass_input()
#        self.update() #Trying a while loop inside of set_host() instead of a recursive thing:

    def pass_input(self):
        if self.GAME_OVER:
            rstr = "drop"
        else:
            rstr = ""
            for k in self.report_strings:
                rstr = rstr + "|" + k + ":" + str(self.report_strings[k])
        rstr = rstr.encode('ascii')
        len_data = str(len(rstr))
        to_send = ("0" *
                   (16 - len(len_data)) + len_data).encode('ascii') + rstr
        self.sock.sendall(to_send)
        if self.GAME_OVER:
            self.sock.close()
Example #10
0
class Game(Frame):
    def __init__(self, name, w, h, ww, wh, topology='wrapped'):

        #initializes world and window geometry
        self.WINDOW_WIDTH = ww
        self.WINDOW_HEIGHT = wh
        self.bounds = Bounds(-w / 2, -h / 2, w / 2, h / 2)
        self.topology = topology

        self.agents = []

        self.root = Tk()
        self.root.title(name)

        Frame.__init__(self, self.root)

        self.bind_all('<KeyPress>', self.keypress)
        self.bind_all('<KeyRelease>', self.keyrelease)

        #makes background canvas
        self.canvas = Canvas(self,
                             width=self.WINDOW_WIDTH,
                             height=self.WINDOW_HEIGHT,
                             bg='purple')

        self.grid()
        self.canvas.grid()

        #sets the top left corner of the display window to the actual (0,0). Was having
        #some weird issues with the edges of the world before, like the window was
        #at (3,3) instead or something weird like that.
        self.canvas.xview_moveto(0.0)
        self.canvas.yview_moveto(0.0)

    def trim(self, agent):
        if self.topology == 'wrapped':
            agent.position = self.bounds.wrap(agent.position)
        elif self.topology == 'bound':
            agent.position = self.bounds.clip(agent.position)
        elif self.topology == 'open':
            pass

    def walltrim(self, agent):
        agent.position = self.wallbounds.hitboxtrim(agent.position,
                                                    agent.size / 2)

    def add(self, agent):
        self.agents.append(agent)

    def remove(self, agent):
        self.agents.remove(agent)
        self.bullets.remove(agent)

    def update(self):
        pass

    def worldToPixel(self, shape):
        #broke up the drawing function in order to get the translation of world geometry
        #to window geometry. v handy in lots of situations where I don't want something
        #drawn immediately but I want to know the window points.
        wh, ww = self.WINDOW_HEIGHT, self.WINDOW_WIDTH
        h = self.bounds.height()
        x = self.bounds.xmin
        y = self.bounds.ymin
        points = [((p.x - x) * wh / h, wh - (p.y - y) * wh / h) for p in shape]
        return points

    def drawagent(self, shape, color):
        points = self.worldToPixel(shape)
        return self.canvas.create_rectangle(points,
                                            fill=color,
                                            width=0,
                                            tags='agent')

    def draw_poly(self, shape, color, tags):
        points = self.worldToPixel(shape)
        first_point = points[0]
        points.append(first_point)
        return self.canvas.create_polygon(points,
                                          width=0,
                                          fill=color,
                                          tags=tags)

    def draw_oval(self, shape, color, tags):
        points = self.worldToPixel(shape)
        first_point = points[0]
        points.append(first_point)
        return self.canvas.create_polygon(points,
                                          width=0,
                                          fill=color,
                                          smooth=1,
                                          tags=tags)

    def keypress(self, event):
        pass

    def keyrelease(self, event):
        pass