diff options
| author | Raymond Hogenson <rayhogenson@openmailbox.org> | 2016-10-15 10:06:20 -0400 |
|---|---|---|
| committer | Raymond Hogenson <rayhogenson@openmailbox.org> | 2016-10-15 10:06:20 -0400 |
| commit | c4999bbbfdbca65986e876ac78863041e85cfbe4 (patch) | |
| tree | b3f300c16fb369061ea7139c3e3684e7eac8a924 | |
| parent | 2dd0795104b14fbb7aeee95f9f6bcf349f119960 (diff) | |
| parent | ad2fbe28d4e345c9b100f47eef2da0b8f76ff9a5 (diff) | |
| download | bridge-c4999bbbfdbca65986e876ac78863041e85cfbe4.tar.zst | |
Merge branch 'master' of github.com:rayhogenson/bridge
| -rw-r--r-- | ShowRunner.py | 17 | ||||
| -rwxr-xr-x | bridge.py | 8 | ||||
| -rw-r--r-- | fish_show.py | 91 | ||||
| -rw-r--r-- | show.py | 18 | ||||
| -rw-r--r-- | sunrise.py | 138 | ||||
| -rw-r--r-- | webapp/app/__init__.py | 5 | ||||
| -rw-r--r-- | webapp/app/static/carousel.css | 144 | ||||
| -rw-r--r-- | webapp/app/templates/index.html | 206 | ||||
| -rw-r--r-- | webapp/app/views.py | 29 | ||||
| -rwxr-xr-x | webapp/run.py | 10 |
10 files changed, 536 insertions, 130 deletions
diff --git a/ShowRunner.py b/ShowRunner.py new file mode 100644 index 0000000..05877ed --- /dev/null +++ b/ShowRunner.py @@ -0,0 +1,17 @@ +from bridge import Bridge +from fish_show import FishShow +from sunrise import SunriseShow +from constants import * + +import sys +sys.path.append('webapp') +from run import server_thread, send_queue, recv_queue + +def run_show(): + server_thread.start() + bridge = Bridge() + SunriseShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) + FishShow(bridge, send_queue=recv_queue, recv_queue=send_queue).run(framerate=FRAME_RATE) + print "done!" + +run_show()
\ No newline at end of file @@ -35,11 +35,13 @@ class Bridge(object): for x in xrange(1, self.WIDTH+1)] - def main(): + """Just for testing. Use ShowRunner when running the show for real.""" + import Queue bridge = Bridge() - show = FishShow(bridge) + show = FishShow(bridge, send_queue=Queue.Queue(), recv_queue=Queue.Queue()) #show = SunriseShow(bridge) show.run(framerate=FRAME_RATE) -main() +if __name__ == '__main__': + main() diff --git a/fish_show.py b/fish_show.py index 7cd8300..6677ddd 100644 --- a/fish_show.py +++ b/fish_show.py @@ -7,6 +7,8 @@ from constants import * import math from show import Show + + class Fish(object): """Object displayed on the bridge, probably a fish.""" def __init__(self, x, y, width, height, color, step): @@ -31,6 +33,9 @@ class Fish(object): def update(self): """Swim gently to the other side of the bridge.""" + if self.x > constants.BRIDGE_WIDTH or self.x < -self.width: + return False + self.speed += self.drag * self.speed if abs(self.speed) < self.tailThreshold: self.tailMoving = True @@ -44,15 +49,8 @@ class Fish(object): self.tailMoveCount += 1 self.x += self.speed.components[0] self.y += self.speed.components[1] - # - # THIS NEEDS TO CHANGE - # - if self.x > constants.BRIDGE_WIDTH: - self.x = -self.width - if self.x < -self.width: - self.x = constants.BRIDGE_WIDTH - print(self.x, self.y) + return True def fix_direction(self): min_theta = -0.32 @@ -65,7 +63,29 @@ class Fish(object): #theta = rand_in_range(min_theta, max_theta) theta = random.gauss((max_theta+min_theta)/2, (max_theta - min_theta)/12) self.tailAcceleration = Vector(self.tailAccelMag, 0).rot2d(theta) - + + @classmethod + def by_type(cls, fish_type): + if (fish_type == 'jellyfish'): + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'dolphin': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'boat': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'dory': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'nemo': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'whale': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'stingray': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'eel': + return cls(0, 0.5, 23, 1.5, color.black, 1) + if fish_type == 'shark': + return cls(0, 0.5, 23, 1.5, color.black, 1) + + class Light(object): """Represent a bridge light and its state.""" @@ -78,23 +98,21 @@ class Light(object): self.x = x self.y = y - def update(self, fish): + def update(self, depth, fishes): """Change color depending on where the fish is.""" if abs(self.transitioning_to - self.color) <= self.step: - self.transitioning_to = pick_HSV().to_RGB() + self.transitioning_to = pick_HSV(depth).to_RGB() self.step = (random_change() * abs(self.color - self.transitioning_to)) new_background = transition( self.color, self.transitioning_to, self.step ) - coverage = compute_coverage(fish, self.x, self.y) - #coverage *= coverage - new_color = coverage * fish.color + (1 - coverage) * new_background - #new_color = new_background + self.color = new_background - if self.x == 30 and self.y == 0: - pass - #print(self.color.r(), self.color.g(), self.color.b()) + new_color = new_background + for fish in fishes: + coverage = compute_coverage(fish, self.x, self.y) + new_color = coverage * fish.color + (1 - coverage) * new_color self.light.setRGBRaw( *map(lambda x: clamp(0, x, 1), new_color.components) ) @@ -113,10 +131,12 @@ def compute_coverage(fish, x, y): return coverage * scale -def pick_HSV(): +def pick_HSV(depth): """Return a random color in an appropriate interval.""" - hue = random.random() * (constants.MAX_HUE - constants.MIN_HUE) + constants.MIN_HUE - saturation = random.random() * (MAX_SATURATION - MIN_SATURATION) + MIN_SATURATION + min_hue = constants.MIN_HUE + (10/360)*depth + min_saturation = constants.MIN_SATURATION + 0.05*depth + hue = random.random() * (constants.MAX_HUE - min_hue) + min_hue + saturation = random.random() * (MAX_SATURATION - min_saturation) + min_saturation value = random.random() * (MAX_VALUE - MIN_VALUE) + MIN_VALUE return color.HSV(hue, saturation, value) @@ -143,17 +163,38 @@ def clamp(low, x, high): return max(low, min(x, high)) class FishShow(Show): + # 1 minute show + TICKS_PER_DEPTH = FRAME_RATE * 10 + MAX_DEPTH = 6 + def init(self): self.lights = [Light(x, y, self.bridge.get_light(x, y)) for y in xrange(self.bridge.HEIGHT) for x in xrange(self.bridge.WIDTH)] - self.fish = Fish(0, 0.5, 23, 1.5, color.black, 1) - + self.fishes = set() + self.tick_count = 0 + self.depth = 0 def update(self): - self.fish.update() + event = self.recv_event() + if event and event[0] == 'spawn': + new_fish = Fish.by_type(event[1]['type']) + self.fishes.add(new_fish) + + for fish in list(self.fishes): + if not fish.update(): + self.fishes.remove(fish) for light in self.lights: - light.update(self.fish) + light.update(self.depth, self.fishes) + + self.tick_count += 1 + if self.tick_count % self.TICKS_PER_DEPTH == 0: + self.depth += 1 + print("DEPTH: ", self.depth) + + if self.depth > self.MAX_DEPTH: + self.stop() + def rand_in_range(low, high): return random.random() * (high - low) + low @@ -1,5 +1,6 @@ from __future__ import division, print_function import time +import Queue class Clock(object): def __init__(self): @@ -18,10 +19,12 @@ class Clock(object): class Show(object): - def __init__(self, bridge): + def __init__(self, bridge, send_queue, recv_queue): self.bridge = bridge self.clock = Clock() self.running = True + self.send_queue = send_queue + self.recv_queue = recv_queue self.init() def run(self, framerate=40): @@ -30,6 +33,19 @@ class Show(object): self.bridge.update() self.clock.tick(framerate) + def stop(self): + self.running = False + + def send_event(self, event_name, data=None): + self.send_queue.put((event_name, data)) + + def recv_event(self): + try: + msg = self.recv_queue.get_nowait() + return msg + except Queue.Empty: + return None + def init(self): """Override me""" raise NotImplementedError @@ -9,38 +9,46 @@ from show import Show class Sun(object): """Object displayed on the bridge, probably a fish.""" - def __init__(self, x, y, width, height, c, step): + def __init__(self): """Create fish with default parameters.""" - self.x = x - self.y = y - self.x = 75 - self.y = -2 - self.width = width - self.width = 75 - self.height = height + self.x = 25 + self.y = 0 - 1 + self.width = 150 self.height = 2 - self.color = c - self.color = color.RGB(1, 0.5, 0) - self.speed = step - self.step = step - self.wait = 0 + self.base_color = color.HSV(27/360, 1, 0.5) + self.end_color = color.HSV(53/360, 1, 1) + self.color = self.base_color.to_RGB() def update(self): """Swim gently to the other side of the bridge.""" - #self.x += self.step - #if self.x > 200: - # self.x = 0 - #self.y = 0.25 + 0.25 * math.sin(math.pi * self.x / 10) - #theta = random.random() * math.pi / 2 - math.pi / 4 - #self.y += 0.01 * math.sin(theta) - #print(self.y) self.y += 0.005 - if self.y >= 1: - self.y = 1 - self.wait += 1 - if self.wait >= 200: - self.wait = 0 - self.y = -2 + if self.y + self.height >= 3: + self.y = 3 - self.height + elif self.y + self.height > 1: + self.width += 0.2 + self.x -= 0.1 + color_range = (self.end_color - self.base_color).unit() + self.color = (self.y + self.height - 1) / 3 * color_range + self.base_color + self.color = self.color.to_RGB() + + #print(self.y) + + #def color_at(self, x, y): + #ball_width = 15 + #if abs(x - self.center_x) < ball_width: + #return color.RGB(1, 1, 1) + #distance = abs(self.center_x - x) + #start_hue = 58 / 360 + #end_hue = 41 / 360 + #start_sat = 0 + #end_sat = 0.92 + #sat = scale_with_clamp(distance, ball_width, 60, start_sat, end_sat) + #hue = scale_with_clamp(distance, ball_width, 100, start_hue, end_hue) + #return color.HSV(hue, sat, 1).to_RGB() + + +def scale_with_clamp(inp, min_inp, max_inp, min_out, max_out): + return (clamp(min_inp, inp, max_inp) - min_inp) / (max_inp - min_inp) * (max_out - min_out) + min_out class Light(object): @@ -53,18 +61,36 @@ class Light(object): self.step = 0 self.x = x self.y = y + self.fade_step = 0 - def update(self, fish): + def update(self, sky_brightness, sun): """Change color depending on where the fish is.""" - if self.y == 1: - new_color = color.RGB(0.5, 0.5, 0.5) + if self.y == 0: + if abs(self.transitioning_to - self.color) <= self.step: + self.transitioning_to = pick_ocean_HSV(sky_brightness).to_RGB() + self.step = (random_change() + * abs(self.color - self.transitioning_to)) + self.color = transition( + self.color, self.transitioning_to, self.step + ) + self.light.setRGBRaw( + *map(lambda x: clamp(0, x, 1), self.color.components) + ) else: - new_color = color.RGB(0.5, 0.5, 0) - coverage = compute_coverage(fish, self.x, self.y) - ccolor = new_color * (1 - coverage) + fish.color * coverage - self.light.setRGBRaw( - *map(lambda x: clamp(0, x, 1), ccolor.components) - ) + sky_color = color.HSV(250/360, 0.25, sky_brightness).to_RGB() + coverage = compute_coverage(sun, self.x, self.y) + self.color = coverage * sun.color + (1 - coverage) * sky_color + self.light.setRGBRaw( + *map(lambda x: clamp(0, x, 1), self.color.components) + ) + + def fade_to_black(self, steps): + hue = self.color.to_HSV().h() + sat = self.color.to_HSV().s() + value = self.color.to_HSV().v() + new_color = color.HSV(hue, sat, value - value / steps * self.fade_step).to_RGB() + self.fade_step += 1 + self.light.setRGBRaw(*map(lambda x: clamp(0, x, 1), new_color.components)) class SunriseShow(Show): @@ -72,13 +98,30 @@ class SunriseShow(Show): self.lights = [Light(x, y, self.bridge.get_light(x, y)) for y in xrange(self.bridge.HEIGHT) for x in xrange(self.bridge.WIDTH)] - self.sun = Sun(0, 0, 23, 1.5, color.black, 1) + self.sun = Sun() + self.sky_brightness = 0 + self.tick_count = 0 def update(self): - self.sun.update() - for light in self.lights: - light.update(self.sun) + if self.tick_count > 1000: + fade_time = 3 # sec + if self.tick_count > 1000 + fade_time * FRAME_RATE: + self.stop() + return + for light in self.lights: + light.fade_to_black(fade_time * FRAME_RATE) + else: + if self.sky_brightness >= 1: + self.sun.update() + for light in self.lights: + light.update(self.sky_brightness, self.sun) + + if self.sky_brightness < 1: + self.sky_brightness += 0.05 / FRAME_RATE + + self.tick_count += 1 + print self.tick_count def compute_coverage(fish, x, y): @@ -95,12 +138,15 @@ def compute_coverage(fish, x, y): return coverage * scale -def pick_HSV(): +def pick_ocean_HSV(sky_brightness): """Return a random color in an appropriate interval.""" - hue = random.random() * (constants.MAX_HUE - constants.MIN_HUE) + constants.MIN_HUE - saturation = random.random() * (MAX_SATURATION - MIN_SATURATION) + MIN_SATURATION - value = random.random() * (MAX_VALUE - MIN_VALUE) + MIN_VALUE - return color.HSV(hue, saturation, value) + min_hue = 236 / 360 + max_hue = 250 / 360 + min_sat = 0.25 + max_sat = 0.6 + hue = random.random() * (max_hue - min_hue) + min_hue + saturation = random.random() * (max_sat - min_sat) + min_sat + return color.HSV(hue, saturation, sky_brightness) def transition(start, end, step): @@ -115,8 +161,8 @@ def transition(start, end, step): def random_change(): """Return a random amount that a light should change each frame.""" - min_time = int(constants.MIN_TIME * FRAME_RATE) - max_time = int(MAX_TIME * FRAME_RATE) + min_time = int(2 * FRAME_RATE) + max_time = int(6 * FRAME_RATE) return 1 / random.randint(min_time, max_time) diff --git a/webapp/app/__init__.py b/webapp/app/__init__.py index 29cd22b..3e188ec 100644 --- a/webapp/app/__init__.py +++ b/webapp/app/__init__.py @@ -1,6 +1,11 @@ from flask import Flask import socketio +import Queue + +recv_queue = Queue.Queue() +send_queue = Queue.Queue() + sio = socketio.Server(async_mode='threading') app = Flask(__name__) app.wsgi_app = socketio.Middleware(sio, app.wsgi_app) diff --git a/webapp/app/static/carousel.css b/webapp/app/static/carousel.css new file mode 100644 index 0000000..4e49305 --- /dev/null +++ b/webapp/app/static/carousel.css @@ -0,0 +1,144 @@ +/* GLOBAL STYLES +-------------------------------------------------- */ +/* Padding below the footer and lighter body text */ + +body { + padding-bottom: 40px; + color: #5a5a5a; + /*background: lighten(#000, 93.5%);*/ +} + + +/* CUSTOMIZE THE NAVBAR +-------------------------------------------------- */ + +/* Special class on .container surrounding .navbar, used for positioning it into place. */ +.navbar-wrapper { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 20; +} + +/* Flip around the padding for proper display in narrow viewports */ +.navbar-wrapper > .container { + padding-right: 0; + padding-left: 0; +} +.navbar-wrapper .navbar { + padding-right: 15px; + padding-left: 15px; +} +.navbar-wrapper .navbar .container { + width: auto; +} + + +/* CUSTOMIZE THE CAROUSEL +-------------------------------------------------- */ + +/* Carousel base class */ +.carousel { + height: 500px; + margin-bottom: 60px; +} +/* Since positioning the image, we need to help out the caption */ +.carousel-caption { + z-index: 10; +} + +/* Declare heights because of positioning of img element */ +.carousel .item { + height: 500px; + background-color: #777; +} +.carousel-inner > .item > img { + position: absolute; + top: 0; + left: 0; + min-width: 100%; + height: 500px; +} + + +/* MARKETING CONTENT +-------------------------------------------------- */ + +/* Center align the text within the three columns below the carousel */ +.marketing .col-lg-4 { + margin-bottom: 20px; + text-align: center; +} +.marketing h2 { + font-weight: normal; +} +.marketing .col-lg-4 p { + margin-right: 10px; + margin-left: 10px; +} + + +/* Featurettes +------------------------- */ + +.featurette-divider { + margin: 80px 0; /* Space out the Bootstrap <hr> more */ +} + +/* Thin out the marketing headings */ +.featurette-heading { + font-weight: 300; + line-height: 1; + letter-spacing: -1px; +} + +img.img-disable { + -webkit-filter: grayscale(100%); + -moz-filter: grayscale(100%); + -o-filter: grayscale(100%); + -ms-filter: grayscale(100%); + filter: grayscale(100%); + opacity: 0.5; +} + +/* RESPONSIVE CSS +-------------------------------------------------- */ + +@media (min-width: 768px) { + /* Navbar positioning foo */ + .navbar-wrapper { + margin-top: 20px; + } + .navbar-wrapper .container { + padding-right: 15px; + padding-left: 15px; + } + .navbar-wrapper .navbar { + padding-right: 0; + padding-left: 0; + } + + /* The navbar becomes detached from the top, so we round the corners */ + .navbar-wrapper .navbar { + border-radius: 4px; + } + + /* Bump up size of carousel content */ + .carousel-caption p { + margin-bottom: 20px; + font-size: 21px; + line-height: 1.4; + } + + .featurette-heading { + font-size: 50px; + } +} + +@media (min-width: 992px) { + .featurette-heading { + margin-top: 120px; + } + +} diff --git a/webapp/app/templates/index.html b/webapp/app/templates/index.html index b0d9bb3..4dadb7b 100644 --- a/webapp/app/templates/index.html +++ b/webapp/app/templates/index.html @@ -1,55 +1,171 @@ -<html> - <head> - <script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script> - <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script> - - <script> - var SPAWN_URL = "/spawn"; +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> + <!--<meta name="description" content=""> + <meta name="author" content=""> + <link rel="icon" href="../../favicon.ico">--> + + <!-- Bootstrap core CSS --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> + + <!-- Custom styles for this template --> + <link href="static/carousel.css" rel="stylesheet"> + + </head> + +<div class = "page-header"> +<center> + <h1> + Welcome to the Underwater World <br> + <small>Select your favorite sea creature and relax!</small> + </h1> +</center> + +</div> + + + <!-- Marketing messaging and featurettes + ================================================== --> + <!-- Wrap the rest of the page in another container to center all the content. --> + + <div class="container marketing"> + + <!-- Three columns of text below the carousel --> + <div class="row"> + <div class="col-lg-4"> + <img id="jellyfish" onClick="clickImg(this)" class="img-circle" src="http://animalia-life.com/data_images/jellyfish/jellyfish7.jpg" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + <div class="col-lg-4"> + <img id="dolphin" onClick="clickImg(this)" class="img-circle" src="http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Mammals/A-G/bottlenose-dolphin-jumping.jpg.adapt.945.1.jpg" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + <div class="col-lg-4"> + <img id="boat" onClick="clickImg(this)" class="img-circle" src="http://yachtpals.com/files/groupimages/woodduck.jpg" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + </div><!-- /.row --> +<br> + <div class="row"> + <div class="col-lg-4"> + <img id="dory" onClick="clickImg(this)" class="img-circle" src="https://www.sciencenewsforstudents.org/sites/default/files/2016/06/main/articles/wt_blue_tang_dory_free.jpg" alt="Generic placeholder image" width="150" height="150"> + </div><!-- /.col-lg-4 --> + <div class="col-lg-4"> + <img id="nemo" onClick="clickImg(this)" class="img-circle" src="http://img.wallpaperfolder.com/f/63DCF495B5BC/clown-fish-75948.jpg" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + <div class="col-lg-4"> + <img id="whale" onClick="clickImg(this)" class="img-circle" src="http://media-channel.nationalgeographic.com/media/uploads/photos/content/photo/2013/01/30/KillerWhale_01_BuiltForTheKillV.jpg" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + </div><!-- /.row --> +<br> + <div class="row"> + <div class="col-lg-4"> + <img id="stingray" onClick="clickImg(this)" class="img-circle" src="http://3.bp.blogspot.com/-enlwcfp2skQ/Tlxxws9FRlI/AAAAAAAAAmg/0-TEWn8Sokw/s1600/stingray_5.JPG" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + <div class="col-lg-4"> + <img id="eel" onClick="clickImg(this)" class="img-circle" src="http://blogs.courierpostonline.com/fishhead/files/2012/11/eel.jpg" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + <div class="col-lg-4"> + <img id="shark" onClick="clickImg(this)" class="img-circle" src="http://www.livescience.com/images/i/000/083/926/original/shark-attacks-increased-in-2015.jpg?interpolation=lanczos-none&downsize=*:1000" alt="Generic placeholder image" width="140" height="140"> + </div><!-- /.col-lg-4 --> + </div><!-- /.row --> + + </div><!-- /.container --> - function creature(name, socket) { - var self = this; - self.name = name; - self.socket = socket; - - self.render = function($parent) { - var $a = $('<a>'); - $a.text(self.name); - $a.click(self.click.bind(self)); - var $li = $('<li>'); - $li.append($a); - $parent.append($li); - }; + <!-- Bootstrap core JavaScript + ================================================== --> + <!-- Placed at the end of the document so the pages load faster --> + <script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script> + <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> - self.click = function() { - self.socket.emit('spawn', {name:self.name}); - } + <script> + var SPAWN_URL = "/spawn"; + + function creature(name, socket) { + var self = this; + self.name = name; + self.socket = socket; + + self.render = function($parent) { + var $a = $('<a>'); + $a.text(self.name); + $a.click(self.click.bind(self)); + + var $li = $('<li>'); + $li.append($a); + $parent.append($li); + }; + + self.click = function() { + self.socket.emit('spawn', {type:self.name}); } + } - $(document).ready(function() { - var namespace = '/spawn'; - var socket = io.connect('http://' + document.domain + ':' + location.port + namespace); - - socket.on('connect', function() { - console.log('connected!'); - }); - socket.on('new creature', function(msg) { - console.log('new!'); - var c = new creature(msg.name, socket); - c.render($('#creatures')); - }); + $(document).ready(function() { + var namespace = '/spawn'; + socket = io.connect('http://' + document.domain + ':' + location.port + namespace); + + socket.on('connect', function() { + console.log('connected!'); + }); + + socket.on('new creature', function(msg) { + console.log('new!'); + var c = new creature(msg.name, socket); + c.render($('#creatures')); + }); + + socket.on('enable image', function(msg) { + console.log('enable image'); + // to be tested + var name = msg.name; + var myImgElement = $("#" + name); + myImgElement.removeClass('img-disable'); + + }); + + socket.on('disable image', function(msg) { + console.log('disable image'); + // to be tested + var name = msg.name; + var myImgElement = $("#" + name); + myImgElement.addClass('img-disable'); + }); - socket.on('disconnect', function() { - console.log('disconnected'); - }); + socket.on('disconnect', function() { + console.log('disconnected'); }); - </script> - <title>{{ title }}</title> - </head> - <body> - <h1>Ocean Fun Times</h1> - <ul id="creatures"></ul> - </body> + socket.emit('ready'); + }); + + function clickImg(element) { + console.log(element.id); + + //-----Testing------------------ + //var name = element.id; + //var myImgElement = $("#" + name); + //myImgElement.addClass('img-disable'); + // ----------------------------- + + var c = new creature(element.id, socket); + c.click() + } + + </script> + <!-- Just to make our placeholder images work. Don't actually copy the next line! --> + <!--<script src="../../assets/js/vendor/holder.min.js"></script>--> + <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> + <!--<script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>--> + </body> </html> diff --git a/webapp/app/views.py b/webapp/app/views.py index 4aa2c05..b03f6ab 100644 --- a/webapp/app/views.py +++ b/webapp/app/views.py @@ -1,17 +1,19 @@ -from flask import render_template, request -from app import app, sio +from flask import render_template, request, send_from_directory +from app import app, sio, send_queue, recv_queue import time import threading -thread = None - @app.route('/') @app.route('/index') def index(): return render_template('index.html', title='F16 Group1') +@app.route('/static/<path:path>') +def send_static(path): + return send_from_directory('static', path) + connections = set() @sio.on('connect', namespace='/spawn') @@ -22,6 +24,14 @@ def connect(sid, environ): @sio.on('spawn', namespace='/spawn') def message(sid, data): print("message ", data) + send_queue.put(('spawn', data)) + +@sio.on('ready', namespace='/spawn') +def ready(sid): + print("got ready message from ", sid) + for event in received_events: + print "sending missed event", event + sio.emit(event[0], event[1], room=sid, namespace='/spawn') @sio.on('disconnect', namespace='/spawn') def disconnect(sid): @@ -29,9 +39,12 @@ def disconnect(sid): connections.remove(sid) +received_events = [] +def recv_events(): + while True: + event = recv_queue.get() + sio.emit(event[0], event[1], namespace='/spawn') + received_events.append(event) -def add_creature(): - time.sleep(5) - sio.emit('new creature', {'name': 'fish1'}, namespace='/spawn') -thread = sio.start_background_task(add_creature) +thread = sio.start_background_task(recv_events) diff --git a/webapp/run.py b/webapp/run.py index b5c8c6f..2290f41 100755 --- a/webapp/run.py +++ b/webapp/run.py @@ -3,5 +3,11 @@ import sys sys.path.append('packages') -from app import app -app.run(threaded=True, host='', port=8000) +import threading + +from app import app, send_queue, recv_queue + +def run_server(): + app.run(threaded=True, host='', port=8000) + +server_thread = threading.Thread(target=run_server) |
