示例#1
0
 def init_rendering(self):
     self.FloorColors = gen_colors(self.NFloors, (0.1, 0.1, 0.9),
                                   (0.1, 0.9, 0.1), (1.0, 1.0, 0.1))
     self.Viewer = Viewer(600, 600)
     self.Frame = self.Viewer.frame(0., 20., 0., self.NFloors)
     elevator_well = Frame()
     self.Frame.add(elevator_well, at=(3.0, 0.0))
     self.ElevatorFrame = Frame()
     self.ElevatorFrame.add(Rectangle(0.0,
                                      self.Capacity,
                                      0.0,
                                      1.0,
                                      filled=False).color(0.8, 0.8, 0.8),
                            at=(0, 0))
     elevator_well.add(self.ElevatorFrame, at=(0.0, 0))
     self.FloorFrames = []
     self.QueueFrames = []
     for f in range(self.NFloors):
         frame = Frame()
         self.Frame.add(frame, at=(0.0, f))
         self.FloorFrames.append(frame)
         frame.add(Rectangle(0.0, 2.0, 0.0,
                             1.0).color(*self.FloorColors[f]),
                   at=(0, 0))
         qf = Frame()
         frame.add(qf, at=(3.0 + self.Capacity, 0.0))
         self.QueueFrames.append(qf)
示例#2
0
 def render(self):
     if self.Viewer is None:
         self.Viewer = Viewer(800, 800)
         self.Frame = self.Viewer.frame(-0.5, self.SIZE - 0.5, -0.5,
                                        self.SIZE - 0.5)
     self.Frame.remove_all()
     self.Frame.add(
         Rectangle(-0.5, self.SIZE + 0.5, -0.5,
                   self.SIZE + 0.5).color(0, 0, 0))
     for x in range(self.SIZE):
         for y in range(self.SIZE):
             if self.Field[self.VR + x, self.VR + y] != 0:
                 r = self.Field[self.VR + x,
                                self.VR + y] / self.SPAWN_MAX * 0.45
                 o = Circle(radius=r)
                 if self.Field[self.VR + x, self.VR + y] > 0:
                     o.color(0.1, 1.0, 0.1)
                 else:
                     o.color(1.0, 0.1, 0.1)
                 self.Frame.add(o, at=(x, y))
     h = Circle(radius=0.5, filled=False).color(1.0, 1.0, 0.0)
     self.Frame.add(h, at=self.Hunter)
     s = Rectangle(-self.VR - 0.5,
                   self.VR + 0.5,
                   -self.VR - 0.5,
                   self.VR + 0.5,
                   filled=False).color(0.2, 0.4, 0.4)
     self.Frame.add(s, at=self.Hunter)
     time.sleep(0.03)
     self.Viewer.render()
示例#3
0
    def init_rendering(self):
        from draw2d import Viewer, Rectangle, Frame, Circle, Line, Polygon
        self.Viewer = Viewer(800, 800)
        self.Frame = self.Viewer.frame(self.X0, self.X1, self.Y0, self.Y1)

        class Tank(object):
            def __init__(self, parent):
                self.Frame = Frame(hidden=True)
                self.Body = Polygon([(-0.01, -0.01), (0.01, -0.005),
                                     (0.01, 0.005), (-0.01, 0.01)],
                                    filled=True)
                self.Frame.add(self.Body)
                self.FireLine = Line(
                    (0.005, 0.0),
                    (_TanksEnv.FireRange, 0.0)).color(1.0, 0.8, 0.1)
                self.FireLine.hidden = True
                self.Frame.add(self.FireLine)

            def show(self, pos, angle, fire, hit):
                self.Frame.hidden = False
                self.Frame.move_to(*pos)
                self.Frame.rotate_to(angle)
                self.FireLine.hidden = fire == 0
                #print (self.FireLine.hidden)
                if hit:
                    self.Body.color(1, 0, 0)
                else:
                    self.Body.color(0, 1, 1)

        self.Tanks = [Tank(self.Frame) for _ in range(self.NPLAYERS)]
        for t in self.Tanks:
            self.Frame.add(t.Frame)
示例#4
0
文件: clock.py 项目: imandr/draw2d
from draw2d import Viewer, Rectangle, Frame, Circle, Line

import math, time

viewer = Viewer(800, 800, clear_color=(1, 1, 1, 1))

frame = viewer.frame(-1.1, 1.1, -1.1, 1.1)

for i in range(12):
    a = math.pi / 2 - i * 2 * math.pi / 12.0
    if i % 3 == 0:
        m = Rectangle(-0.015, 0.015, -0.1, 0.05).color(0, 0, 0)
    else:
        m = Rectangle(-0.01, 0.01, -0.05, 0.05).color(0, 0, 0)
    f = Frame()
    f.add(m, at=(0.0, 1.0))
    f.rotate_by(a)
    frame.add(f)

hour_hand = Rectangle(-0.02, 0.02, -0.02, 0.5).color(0, 0, 0)
frame.add(hour_hand)
minute_hand = Rectangle(-0.01, 0.01, -0.02, 0.75).color(0, 0, 0)
frame.add(minute_hand)
second_hand = Rectangle(-0.003, 0.003, -0.1, 0.95).color(0, 0, 0)
frame.add(second_hand)

while True:
    t = time.localtime()
    s = t.tm_sec
    m = t.tm_min
    h = t.tm_hour % 12
示例#5
0
文件: text.py 项目: imandr/draw2d
from draw2d import Viewer, Text, Line, Rectangle, Frame, Point, Circle

import math, time, random

viewer = Viewer(600, 600)
W = 1.0
F = viewer.frame(0., W, 0., W)

F.add(
    Text("North", anchor_x="center", anchor_y="top",
         color=(0.2, 0.2, 1.0)).move_to(0.5, 0.9))
F.add(
    Text("South", anchor_x="center", anchor_y="bottom",
         color=(1.0, 1.0, 0.1)).move_to(0.5, 0.1))
F.add(
    Text("East", anchor_x="right", anchor_y="center",
         color=(0.2, 1.0, 1.0)).move_to(0.9, 0.5))
F.add(
    Text("West", anchor_x="left", anchor_y="center",
         color=(1.0, 0.2, 0.1)).move_to(0.1, 0.5))

fly = Frame()
fly.add(Circle(radius=0.01).color(1, 1, 1))
label = Text("").move_to(0.01, 0.01)
vlabel = Text("", rotation=0.0, anchor_x="left",
              anchor_y="center").move_to(0.02, 0.0)
fly.add(label)
fly.add(vlabel)
F.add(fly, "fly")

x, y = random.random(), random.random()
示例#6
0
import time
from draw2d import Viewer, Marker, Circle, Text

v = Viewer(600,600)
f = v.frame(-200, 200, -200, 200)
m1 = Marker(Circle(3, filled=False).color(1,1,0.5))
#f.add(m1, at=(0,0))
m1 = Marker(Circle(4).color(0.2,1,0.5))
m2 = Marker(Circle(4).color(0.2,1,0.5))
m3 = Marker(Circle(4).color(0.2,1,0.5))
f.add(m1, at=(1,3))
f.add(m2, at=(101,103))
f.add(m3, at=(197,198))

t = Text("hello")
#f.add(t, at=(-50,50))
v.render()
time.sleep(100)
示例#7
0
class _HunterEnv(object):

    SIZE = 15  # 20x20 field
    VR = 2  # visible range: [x-2, x-1, x, x+1, x+2]
    SCAN_SIZE = (VR * 2 + 1)**2 + 4
    SPAWN_MIN = 2
    SPAWN_MAX = 10
    SPAWN_ATTEMPTS = 3

    MOVES = [(0, 0), (-1, 0), (1, 0), (0, -1), (0, 1)]
    ZERO_ACTION = 0

    HISTORY_SIZE = 1

    def __init__(self):
        self.Field = np.zeros(
            (self.SIZE + self.VR * 2, self.SIZE + self.VR * 2), dtype=np.float)
        self.NextSpawn = random.random() * (self.SPAWN_MAX -
                                            self.SPAWN_MIN) + self.SPAWN_MIN
        self.Hunter = None
        self.Actions = np.arange(5)

        self.Fuel = 100.0

        self.Viewer = None

        #
        # scan, last_scan, borders, last_action
        self.ObservationDim = (self.SCAN_SIZE + 1) * self.HISTORY_SIZE
        high = np.array([np.inf] * self.ObservationDim)
        self.observation_space = spaces.Box(-high, high)
        self.action_space = spaces.Discrete(5)

        self.LastAction = self.ZERO_ACTION
        self.History = np.zeros((self.HISTORY_SIZE, self.SCAN_SIZE + 1))

    def scan(self, x, y):
        out = np.empty((self.SCAN_SIZE, ))
        out[0] = -1.0 if x <= 0 else (1.0 if x >= self.SIZE - 1 else 0.0)
        out[1] = -1.0 if y <= 0 else (1.0 if y >= self.SIZE - 1 else 0.0)
        out[2] = float(x) / float(self.SIZE)
        out[3] = float(y) / float(self.SIZE)
        frame = self.Field[x + self.VR - self.VR:x + self.VR + self.VR + 1,
                           y + self.VR - self.VR:y + self.VR + self.VR +
                           1].reshape((-1, ))
        assert len(frame) + 4 == self.SCAN_SIZE
        out[4:] = frame
        return out

    def observation(self, roll=False):
        if roll:
            x, y = self.Hunter
            self.History = np.roll(self.History, 1, axis=0)
            self.History[0, 0:self.SCAN_SIZE] = self.scan(x, y)
            #self.History[0,self.SCAN_SIZE] = self.LastAction
        return self.History.reshape((-1, ))

    def free_cell(self, n_attempts=None):
        i = 0
        while n_attempts is None or i < n_attempts:
            x = random.randint(0, self.SIZE - 1)
            y = random.randint(0, self.SIZE - 1)
            if self.Field[x + self.VR, y + self.VR] == 0:
                return x, y
            i += 1
        else:
            return None

    def spawn(self):
        location = self.free_cell(self.SPAWN_ATTEMPTS)
        if location is not None:
            x, y = location
            v = random.randint(self.SPAWN_MIN, self.SPAWN_MAX)
            if random.random() < 0.4: v = -v
            self.Field[x + self.VR, y + self.VR] = v

    def reset(self):
        self.LastAction = self.ZERO_ACTION
        self.History[...] = 0.0
        self.History[:, self.SCAN_SIZE] = self.ZERO_ACTION
        self.Field[self.VR:self.SIZE + self.VR,
                   self.VR:self.SIZE + self.VR] = 0.0
        self.spawn()
        self.NextSpawn = random.randint(self.SPAWN_MIN, self.SPAWN_MAX)
        self.Hunter = self.free_cell()
        self.Fuel = 100.0
        return self.observation(roll=False)

    def step(self, action):
        if 0.03 > random.random():
            self.spawn()
        x, y = self.Hunter
        self.LastAction = action
        dx, dy = self.MOVES[action]
        x1, y1 = x + dx, y + dy
        reward = 0.0
        if x1 < 0 or x1 > self.SIZE - 1 or y1 < 0 or y1 > self.SIZE - 1:
            reward -= 0.1
            x1, y1 = x, y
        if self.Field[x + self.VR,
                      y + self.VR] > 0.0:  # and action != self.ZERO_ACTION:
            reward += 1.0
            self.Fuel += 10.0
            self.Field[x + self.VR, y + self.VR] -= 1.0
        elif self.Field[x + self.VR, y + self.VR] < 0.0:
            reward -= 1.0
            self.Field[x + self.VR, y + self.VR] += 1.0
        self.Fuel -= 0.1
        self.Hunter = x1, y1
        done = False
        if self.Fuel <= 0.0:
            done = True
            reward -= 10.0
        return self.observation(roll=True), reward, done, {}

    def render(self):
        if self.Viewer is None:
            self.Viewer = Viewer(800, 800)
            self.Frame = self.Viewer.frame(-0.5, self.SIZE - 0.5, -0.5,
                                           self.SIZE - 0.5)
        self.Frame.remove_all()
        self.Frame.add(
            Rectangle(-0.5, self.SIZE + 0.5, -0.5,
                      self.SIZE + 0.5).color(0, 0, 0))
        for x in range(self.SIZE):
            for y in range(self.SIZE):
                if self.Field[self.VR + x, self.VR + y] != 0:
                    r = self.Field[self.VR + x,
                                   self.VR + y] / self.SPAWN_MAX * 0.45
                    o = Circle(radius=r)
                    if self.Field[self.VR + x, self.VR + y] > 0:
                        o.color(0.1, 1.0, 0.1)
                    else:
                        o.color(1.0, 0.1, 0.1)
                    self.Frame.add(o, at=(x, y))
        h = Circle(radius=0.5, filled=False).color(1.0, 1.0, 0.0)
        self.Frame.add(h, at=self.Hunter)
        s = Rectangle(-self.VR - 0.5,
                      self.VR + 0.5,
                      -self.VR - 0.5,
                      self.VR + 0.5,
                      filled=False).color(0.2, 0.4, 0.4)
        self.Frame.add(s, at=self.Hunter)
        time.sleep(0.03)
        self.Viewer.render()
示例#8
0
class _Elevator(object):

    NFloors = 8
    Capacity = 10
    ArrivalRate = 0.2

    def __init__(self):
        self.ObservationDim = self.NFloors * 4
        high = np.array([np.inf] * self.ObservationDim)
        self.observation_space = spaces.Box(-high, high)
        self.action_space = spaces.Discrete(3)
        self.Viewer = None

    def init_rendering(self):
        self.FloorColors = gen_colors(self.NFloors, (0.1, 0.1, 0.9),
                                      (0.1, 0.9, 0.1), (1.0, 1.0, 0.1))
        self.Viewer = Viewer(600, 600)
        self.Frame = self.Viewer.frame(0., 20., 0., self.NFloors)
        elevator_well = Frame()
        self.Frame.add(elevator_well, at=(3.0, 0.0))
        self.ElevatorFrame = Frame()
        self.ElevatorFrame.add(Rectangle(0.0,
                                         self.Capacity,
                                         0.0,
                                         1.0,
                                         filled=False).color(0.8, 0.8, 0.8),
                               at=(0, 0))
        elevator_well.add(self.ElevatorFrame, at=(0.0, 0))
        self.FloorFrames = []
        self.QueueFrames = []
        for f in range(self.NFloors):
            frame = Frame()
            self.Frame.add(frame, at=(0.0, f))
            self.FloorFrames.append(frame)
            frame.add(Rectangle(0.0, 2.0, 0.0,
                                1.0).color(*self.FloorColors[f]),
                      at=(0, 0))
            qf = Frame()
            frame.add(qf, at=(3.0 + self.Capacity, 0.0))
            self.QueueFrames.append(qf)

    def reset(self):
        self.Floor = 0
        self.Load = np.zeros((self.NFloors, ))
        self.Queues = [[] for _ in range(self.NFloors)]
        return self.observation()

    def exchange(self):
        #
        # unload
        #
        unloaded = self.Load[self.Floor]
        self.Load[self.Floor] = 0

        q = self.Queues[self.Floor]
        n = max(0, self.Capacity - int(sum(self.Load)))
        n = min(n, len(q))
        #print (type(n), n)
        for i in q[:n]:
            self.Load[i] += 1
        self.Queues[self.Floor] = q[n:]
        return unloaded * 10.0

    def observation(self):
        #
        # one-hot floor number
        # load
        # up buttons
        # down buttons
        #
        up_buttons = np.zeros((self.NFloors, ))
        down_buttons = np.zeros((self.NFloors, ))
        for f, q in enumerate(self.Queues):
            up = down = 0
            for d in q:
                if d > f: up = 1
                elif d < f: down = 1
            up_buttons[f] = up
            down_buttons[f] = down
        floor = np.zeros((self.NFloors, ), dtype=np.float)
        floor[self.Floor] = 1
        v = np.concatenate([floor, self.Load, up_buttons, down_buttons])
        return np.array(v, dtype=np.float)

    def step(self, action):
        reward = -0.1 * (sum(len(q) for q in self.Queues) + sum(self.Load))
        if action == 0:
            reward += self.exchange()
        elif action == 1:
            if self.Floor > 0:
                self.Floor -= 1
            else:
                reward -= 10.0
            reward -= 0.01
        elif action == 2:
            if self.Floor < self.NFloors - 1:
                self.Floor += 1
            else:
                reward -= 10.0
            reward -= 0.01

        if self.ArrivalRate > random.random():
            i = random.randint(0, self.NFloors - 1)
            if len(self.Queues[i]) < self.Capacity:
                j = random.randint(0, self.NFloors - 1)
                while j == i:
                    j = random.randint(0, self.NFloors - 1)
                self.Queues[i].append(j)

        return self.observation(), reward, False, {}

    PersonUp = [(0.0, 0.1), (0.9, 0.1), (0.45, 0.4)]
    PersonDown = [(0.0, 0.4), (0.9, 0.4), (0.45, 0.1)]
    PersonSide = [(0.0, 0.1), (0.0, 0.4), (0.9, 0.25)]

    def render(self):

        if self.Viewer is None:
            self.init_rendering()

        self.ElevatorFrame.remove_all()
        self.ElevatorFrame.move_to(0.0, self.Floor)
        self.ElevatorFrame.add(Rectangle(0.0,
                                         self.Capacity,
                                         0.0,
                                         1.0,
                                         filled=False).color(0.5, 0.5, 0.5),
                               at=(0, 0))

        x = 0
        for f, n in enumerate(self.Load):
            n = int(n)
            for _ in range(n):
                p = self.PersonUp if f > self.Floor else (
                    self.PersonDown if f < self.Floor else self.PersonSide)
                p = Polygon(p).color(*self.FloorColors[f])
                self.ElevatorFrame.add(p, at=(x, 0))
                x += 1

        for f, q in enumerate(self.Queues):
            qf = self.QueueFrames[f]
            qf.remove_all()
            x = 0
            for df in q:
                p = self.PersonUp if df > f else (
                    self.PersonDown if df < f else self.PersonSide)
                p = Polygon(p).color(*self.FloorColors[df])
                qf.add(p, at=(x, 0))
                x += 1
        self.Viewer.render()
        time.sleep(0.1)
示例#9
0
文件: test.py 项目: imandr/draw2d
from draw2d import Viewer, Circle, Polygon, Rectangle, Text, Marker
import time

viewer = Viewer(800, 800)
frame = viewer.frame(-1.0, 1.0, -1.0, 1.0)

circle = Circle(0.2).color(1,1,1)
square = Rectangle(0, 0.1, 0, 0.1).color(0,1,0)
text = Text("Hello world", color=(0.5,0.5,1.0), anchor_x="center", anchor_y="center")
marker = Marker(Polygon([(-5,0), (5,0), (0,10)]).color(1,0.5,0.5))

frame.add(circle, at=(0,0))
frame.add(square, at=(0.4,0.1))
frame.add(text, at=(-0.5,-0.3))
frame.add(marker, at=(-0.5, 0.3))

viewer.render()

while True:
    time.sleep(1.0)
示例#10
0
文件: square.py 项目: imandr/draw2d
    But if you really just want to install all Gym dependencies and not have to think about it,
    'pip install -e .[all]' or 'pip install gym[all]' will do it.
    ''')

if True:
    try:
        from pyglet.gl import *
    except ImportError as e:
        raise ImportError('''
        Error occurred while running `from pyglet.gl import *`
        HINT: make sure you have OpenGL install. On Ubuntu, you can run 'apt-get install python-opengl'.
        If you're running on a server, you may need a virtual frame buffer; something like this should work:
        'xvfb-run -s \"-screen 0 1400x900x24\" python <your_script.py>'
        ''')

viewer = Viewer(800, 800)

#frame = viewer.frame(-1.1, 1.1, -1.1, 1.1)

#r = Rectangle(100, 200, 300, 400).color(1,1,1)
#viewer.add_geom(r)
p = Point().color(1, 1, 1).move_to(30, 30)
viewer.add_geom(p)

while True:
    #viewer.render()

    viewer.window.switch_to()
    viewer.window.dispatch_events()
    viewer.window.clear()
    glClearColor(*viewer.clear_color)
示例#11
0
class _TanksEnv(object):

    FireRange = 0.4
    Speed = 0.05
    RotSpeed = math.pi * 2 / 50
    Width = 0.03

    X0 = 0.0
    X1 = 1.0
    Y0 = 0.0
    Y1 = 1.0

    IDLE = 0
    FIRE = 1
    FWD = 2
    #BACK = 3
    LEFT = 3
    RIGHT = 4
    NumActions = 5

    def __init__(self, ntanks):
        self.Viewer = None
        self.NPLAYERS = ntanks
        self.ObservationShape = (self.NPLAYERS, self.NPLAYERS * 3)
        self.ActionShape = (self.NPLAYERS, )

    def reset(self):
        self.Pos = np.random.random((self.NPLAYERS, 2))
        self.Angle = np.random.random((self.NPLAYERS, )) * 2 * math.pi
        self.Hit = np.zeros((self.NPLAYERS, ))  # for rendering only
        self.Fire = np.zeros((self.NPLAYERS, ))
        return self.observation()

    def round_angle(self, a):
        while a >= math.pi:
            a -= math.pi * 2
        while a < -math.pi:
            a += math.pi * 2
        return a

    def dist(self, i, j):
        return math.sqrt(np.sum(np.square(self.Pos[j] - self.Pos[i])))

    def bearing(self, i, j):
        d = self.Pos[j] - self.Pos[i]
        return math.atan2(d[1], d[0])

    def observation(self):
        obs = np.empty((self.NPLAYERS, self.NPLAYERS, 3))
        for i in range(self.NPLAYERS):
            obs[i, 0, :2] = self.Pos[i]
            obs[i, 0, 2] = self.Angle[i]
            others = []
            for j in range(self.NPLAYERS):
                if j != i:
                    others.append(
                        (self.dist(i, j), self.bearing(i, j), self.Angle[j]))
            others = sorted(others)
            obs[i, 1:, :] = others
        return obs.reshape((self.NPLAYERS, -1))

    def step(self, actions):

        rewards = np.zeros((self.NPLAYERS, ))
        dones = np.zeros((self.NPLAYERS, ))
        self.Hit[:] = 0
        self.Fire[:] = 0

        #
        # move first, fire second
        #
        for i, a in enumerate(actions):
            if a != self.FIRE:
                pos = self.Pos[i]
                angle = self.Angle[i]
                if a == self.LEFT:
                    angle += self.RotSpeed
                elif a == self.RIGHT:
                    angle -= self.RotSpeed
                elif a in (self.FWD, self.FWD):
                    delta = self.Speed if a == self.FWD else -self.Speed * 0.6
                    x0, y0 = pos
                    dx, dy = delta * math.cos(angle), delta * math.sin(angle)
                    x1, y1 = x0 + dx, y0 + dy
                    if x1 > self.X1 or x1 < self.X0 or y1 > self.Y1 or y1 < self.Y0:
                        x1, y1 = x0, y0
                        rewards[i] -= 1.0
                    pos = (x1, y1)
                self.Pos[i, :] = pos
                self.Angle[i] = self.round_angle(angle)

        for i, a in enumerate(actions):
            if a == self.FIRE:
                rewards[i] -= 0.1
                self.Fire[i] = 1
                posi = self.Pos[i]
                for j in range(self.NPLAYERS):
                    if j != i:
                        posj = self.Pos[j]
                        dist = self.dist(i, j)
                        if dist > 0.0 and dist < self.FireRange:
                            b = self.bearing(i, j)
                            da = abs(b - self.Angle[i])
                            if da < math.pi / 4:
                                s = math.sin(da) * dist
                                if abs(s) < self.Width:
                                    self.Hit[j] = 1
                                    #print("hit:",i,j)
                                    rewards[j] -= 10.0
                                    rewards[i] = 10.0

        return self.observation(), rewards, dones, {}

    def init_rendering(self):
        from draw2d import Viewer, Rectangle, Frame, Circle, Line, Polygon
        self.Viewer = Viewer(800, 800)
        self.Frame = self.Viewer.frame(self.X0, self.X1, self.Y0, self.Y1)

        class Tank(object):
            def __init__(self, parent):
                self.Frame = Frame(hidden=True)
                self.Body = Polygon([(-0.01, -0.01), (0.01, -0.005),
                                     (0.01, 0.005), (-0.01, 0.01)],
                                    filled=True)
                self.Frame.add(self.Body)
                self.FireLine = Line(
                    (0.005, 0.0),
                    (_TanksEnv.FireRange, 0.0)).color(1.0, 0.8, 0.1)
                self.FireLine.hidden = True
                self.Frame.add(self.FireLine)

            def show(self, pos, angle, fire, hit):
                self.Frame.hidden = False
                self.Frame.move_to(*pos)
                self.Frame.rotate_to(angle)
                self.FireLine.hidden = fire == 0
                #print (self.FireLine.hidden)
                if hit:
                    self.Body.color(1, 0, 0)
                else:
                    self.Body.color(0, 1, 1)

        self.Tanks = [Tank(self.Frame) for _ in range(self.NPLAYERS)]
        for t in self.Tanks:
            self.Frame.add(t.Frame)

    def render(self):
        if self.Viewer is None:
            self.init_rendering()

        any_hit = False
        for tank, pos, angle, fire, hit in zip(self.Tanks, self.Pos,
                                               self.Angle, self.Fire,
                                               self.Hit):
            tank.show(pos, angle, fire, hit)
            if hit: any_hit = True

        self.Viewer.render()
        if any_hit: time.sleep(0.1)