|
| 1 | +### Flame simulation on the Microbit. |
| 2 | +### Author: M. Schafer 2016 |
| 3 | +# This program has been placed into the public domain. |
| 4 | + |
| 5 | +import microbit, random |
| 6 | + |
| 7 | +# User adjustable values for range of brightness in flames. |
| 8 | +MIN_BRIGHTNESS = 1 |
| 9 | +MAX_BRIGHTNESS = 8 |
| 10 | + |
| 11 | + |
| 12 | +# fixed for the Microbit |
| 13 | +DISPLAY_WIDTH = 5 |
| 14 | +DISPLAY_HEIGHT = 5 |
| 15 | + |
| 16 | +INVERT_DISPLAY = True # flame can be oriented in either direction |
| 17 | + |
| 18 | +# MASK to create fire shape. multiplies values % |
| 19 | +MASK = [[ 88, 100, 100, 100, 88 ], |
| 20 | + [ 60, 95, 100, 95, 60 ], |
| 21 | + [ 50, 88, 90, 88, 50 ], |
| 22 | + [ 33, 75, 88, 75, 33 ], |
| 23 | + [ 10, 33, 66, 33, 10 ] ] |
| 24 | + |
| 25 | +# Generate a new bottom row of random values for the flames |
| 26 | +def generate_line(start=MIN_BRIGHTNESS, end=MAX_BRIGHTNESS): |
| 27 | + "start and end define range of dimmest to brightest 'flames'" |
| 28 | + return [start + random.randrange(end-start) for i in range(DISPLAY_WIDTH)] |
| 29 | + |
| 30 | +# shift all values in the grid up one row |
| 31 | +def shift_up(grid, newline): |
| 32 | + "Shift up lines in grid, add newline at bottom" |
| 33 | + for y in range(DISPLAY_HEIGHT-1, 0, -1): |
| 34 | + grid[y] = grid[y-1] |
| 35 | + # lowest line |
| 36 | + for x in range(DISPLAY_WIDTH): |
| 37 | + grid[0] = newline |
| 38 | + |
| 39 | + |
| 40 | +# write a frame to the screen. |
| 41 | +# Interpolate values based on percent |
| 42 | +def interpolate_frame(screen, pcnt, grid, line): |
| 43 | + """ Interpolate new values by reading from grid and |
| 44 | + writing to the screen """ |
| 45 | + # each row interpolates with the one before it |
| 46 | + for y in range(DISPLAY_HEIGHT-1, 0, -1): |
| 47 | + for x in range(DISPLAY_WIDTH): |
| 48 | + mask = MASK[y][x] |
| 49 | + newval = ((100-pcnt) * grid[y][x] + pcnt * grid[y-1][x] ) / 100.0 |
| 50 | + newval = mask * newval / 100.0 |
| 51 | + if INVERT_DISPLAY: |
| 52 | + screen.set_pixel(x, DISPLAY_HEIGHT-y-1, int(newval)) |
| 53 | + else: |
| 54 | + screen.set_pixel(x, y, int(newval)) |
| 55 | + # first row interpolates with the "next" line |
| 56 | + for x in range(DISPLAY_WIDTH): |
| 57 | + mask = MASK[y][x] |
| 58 | + newval = ((100-pcnt) * grid[0][x] + pcnt * line[x]) / 100.0 |
| 59 | + newval = mask * newval / 100.0 |
| 60 | + if INVERT_DISPLAY: |
| 61 | + screen.set_pixel(x, DISPLAY_HEIGHT-1, int(newval)) |
| 62 | + else: |
| 63 | + screen.set_pixel(x, 0, int(newval)) |
| 64 | + |
| 65 | +## Setup |
| 66 | +line = generate_line() |
| 67 | +grid = [[0 for i in range(DISPLAY_WIDTH)] for i in range(DISPLAY_HEIGHT)] |
| 68 | + |
| 69 | +SCREEN = microbit.display |
| 70 | +percent = 0 # counter to see when to re-interpolate |
| 71 | +sleeptime = 0 # delay between updates |
| 72 | +percent_increment = 25 # how fast we interpolate fire |
| 73 | + |
| 74 | + |
| 75 | +# loop forever |
| 76 | +while True: |
| 77 | + if percent > 100: |
| 78 | + # move everything up a line, insert new bottom row |
| 79 | + line = generate_line() |
| 80 | + shift_up(grid, line) |
| 81 | + percent = 0 |
| 82 | + |
| 83 | + # Check Buttons to see if changing |
| 84 | + # button_a = smoothness |
| 85 | + if microbit.button_a.was_pressed(): |
| 86 | + percent_increment += 5 |
| 87 | + if percent_increment > 50: |
| 88 | + percent_increment = 1 |
| 89 | + print("percent interpolate=", percent_increment) |
| 90 | + # button_b = delay |
| 91 | + if microbit.button_b.was_pressed(): |
| 92 | + sleeptime += 10 |
| 93 | + if sleeptime > 100: |
| 94 | + sleeptime = 0 |
| 95 | + print("sleeptime=", sleeptime) |
| 96 | + # draw frame and sleep |
| 97 | + interpolate_frame(SCREEN, percent, grid, line) |
| 98 | + microbit.sleep(sleeptime) |
| 99 | + # update main counters |
| 100 | + percent += percent_increment |
| 101 | + |
|
0 commit comments