Commits

dr0id committed 5207716

fire progress

  • Participants
  • Parent commits 1f1f04a

Comments (0)

Files changed (6)

pyweek15/gamelib/firesprite.py

+# -*- coding: utf-8 -*-
+
+
+# http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/simple-fire-effect-r222
+# http://freespace.virgin.net/hugo.elias/models/m_fire.htm
+
+import random
+
+import pygame
+from pygame import BLEND_RGBA_ADD
+from pygame import BLEND_RGBA_SUB
+from pygame import BLEND_RGBA_MULT
+from pygame import BLEND_RGBA_MIN
+
+import pyknicpygame
+
+# class FireSprite(pyknicpygame.spritesystem.Sprite):
+class FireSprite(object):
+
+    def __init__(self, size, position, scroll_speed=-1, z_layer=0, cooling_map=None):
+
+        # set up buffers
+        self.buf1 = pygame.Surface(size, pygame.SRCALPHA)
+        self.buf1.fill((0, 0, 0, 0))
+        self.buf2 = pygame.Surface(size, pygame.SRCALPHA)
+        self.buf2.fill((0, 0, 0, 0))
+    
+        # pyknicpygame.spritesystem.Sprite.__init__(self, self.buf2, position, anchor='topleft', z_layer=z_layer)
+        # self.draw_special = True
+    
+        self.mult_fill = (255//4, 255//4, 255//4, 255//4)
+        
+        self.cooling_map = cooling_map
+        if cooling_map is None:
+            self.cooling_map = self._create_cooling_map(size)
+                
+        self.cool_w, self.cool_h = self.cooling_map.get_size()
+        self.cooling_scroll_pos = 0
+        
+        self.image = self.buf2
+        self.rect = self.image.get_rect(topleft=position)
+        
+        self.heat_sources = []
+        
+        self.scroll_x = 0
+        self.scroll_y = scroll_speed
+        self.scroll_pos_y = 0
+
+    def _create_cooling_map(self, size):
+        cooling_map = pygame.Surface(size, pygame.SRCALPHA)
+        cooling_map.fill((0, 0, 0, 0))
+        for i in range(8000):
+            get_rd = lambda: random.randint(0, 1)
+            color = (get_rd(), ) * 3 +  (get_rd(), )
+            pos = (random.randint(0, cooling_map.get_size()[0]-1), random.randint(0, cooling_map.get_size()[1]-1))
+            # cooling_map.set_at(pos, color)
+            radius = random.randint(0, 10)
+            pygame.draw.circle(cooling_map, color, pos, radius)
+        temp = self.smooth(cooling_map, None)
+        for i in range(1):
+            self.smooth(temp, cooling_map)
+            temp, cooling_map = cooling_map, temp
+        return cooling_map
+        
+
+    def set_fire_scroll(self, dx=0, dy=-1):
+        self.scroll_x = dx
+        self.scroll_y = dy
+        
+    def update(self, dt):
+    
+        # step 4: convection (move the fire, here just simple scrolling up)
+        # buf1.scroll(self.scroll_x, self.scroll_y)
+        self.buf1.scroll(0, -1)
+        # dt = dt if dt < 0.02 else 0.02
+        # # print('?? ', dt, self.scroll_pos_y)
+        # self.scroll_pos_y += self.scroll_y * dt
+        # # print('???', dt, self.scroll_pos_y)
+        # while abs(self.scroll_pos_y) > 1:
+        
+        # print('!!')
+        buf1 = self.buf1
+        buf2 = self.buf2
+        buf2_blit = buf2.blit
+        
+        buf1.scroll(0, -1)
+        self.scroll_pos_y += -1 if self.scroll_pos_y > 0 else 1
+    
+        # step 1: heat source
+        self.apply_heat_source(buf1)
+        
+        # step 2: heat spread
+        # first divide by '4', then add up 
+        # buf1.blit(self.mult, (0, 0), None, BLEND_RGBA_MULT)
+        buf1.fill(self.mult_fill, None, BLEND_RGBA_MULT)
+        buf2.fill((0, 0, 0, 0))
+
+        # self.smooth(buf1, buf2)
+        buf2_blit(buf1, (-1, 0), None, BLEND_RGBA_ADD)
+        buf2_blit(buf1, ( 1, 0), None, BLEND_RGBA_ADD)
+        buf2_blit(buf1, (0, -1), None, BLEND_RGBA_ADD)
+        buf2_blit(buf1, (0,  1), None, BLEND_RGBA_ADD)
+        
+        # step 3: cooling
+        # # buf2.blit(self.cooling_map, ( 0, 0), None, BLEND_RGBA_SUB)
+
+        self.cooling_scroll_pos += 1
+        self.cooling_scroll_pos %= self.cool_h
+        buf2_blit(self.cooling_map, ( 0, 0), pygame.Rect(0, self.cooling_scroll_pos, self.cool_w, self.cool_h - 1 - self.cooling_scroll_pos), BLEND_RGBA_SUB)
+        buf2_blit(self.cooling_map, ( 0, self.cool_h - 1 - self.cooling_scroll_pos), pygame.Rect(0, 0, self.cool_w, self.cooling_scroll_pos), BLEND_RGBA_SUB)
+
+        # swap
+        self.buf2, self.buf1 = self.buf1, self.buf2
+
+        self.image = self.buf1
+        
+        # make it less transparent (like multiply alpha by two)
+        # self.image = self.buf1.copy()
+        # alpha = self.image.copy()
+        # alpha.fill((0, 0, 0, 255))
+        # alpha.blit(self.image, (0, 0), None, BLEND_RGBA_MIN)
+        # self.image.blit(alpha, (0, 0), None, BLEND_RGBA_ADD)
+
+
+    def smooth(self, source, dest=None):
+        if dest is None:
+            dest = source.copy()
+            dest.fill((0, 0, 0, 0))
+        # todo: move this to the transform.py/surface.py(?) module in pyknicpygame
+        dest.blit(source, (-1, 0), None, BLEND_RGBA_ADD)
+        dest.blit(source, ( 1, 0), None, BLEND_RGBA_ADD)
+        dest.blit(source, (0, -1), None, BLEND_RGBA_ADD)
+        dest.blit(source, (0,  1), None, BLEND_RGBA_ADD)
+        
+        return dest
+    
+    def add_heat_source(self, heat_source):
+        self.heat_sources.append(heat_source)
+        
+    def remove_heat_source(self, heat_source):
+        if heat_source in self.heat_sources:
+            self.heat_sources.remove(heat_source)
+    
+    def apply_heat_source(self, surf):
+        for hs in self.heat_sources:
+            hs.apply(surf)
+    
+    def draw(self, surf, cam, interpolation_factor=1.0):
+        screen_pos = cam.world_to_screen(self.position)
+        surf.blit(self.buf1, screen_pos.as_tuple())
+
+        
+            
+            
+class HeatSource(object):
+
+    def __init__(self, offset=0):
+        self.palette = self._create_palette()
+        self.offset_y = offset
+
+    def _create_palette(self):
+        palette = pygame.Surface((255, 1))
+        for x in range(palette.get_size()[0]):
+            i = x
+            palette.set_at((i, 0), (255, min(255, i * 2), i // 3, 255))
+            # self.palette.set_at((x, 0), (255, min(255, x * 2), x // 3, min(255, x * 5)))
+        palette.set_at((palette.get_size()[0] - 1, 0), (255, 255, 255, 255))
+        return palette
+
+        
+    def apply(self, surf):
+        w, h = surf.get_size()
+        # bottom fire
+        for x in range(0, w, 2):
+            color = self.palette.get_at((random.randint(0, self.palette.get_size()[0] - 1), 0))
+            color = (color[0], color[1], color[2], 255)
+            surf.set_at((x, h - 1 - self.offset_y), color)
+            surf.set_at((x, h - 2 - self.offset_y), color)
+            
+def main():
+
+    pygame.init()
+    pygame.display.set_mode((800, 600), 0, 32)
+    screen = pygame.display.get_surface()
+
+    fire_size = (800, 90)
+    # size, position, scroll_speed, z_layer, cooling_map=None):
+    fire_sprites = []
+    for y in range(0, 20, 20):
+        for x in range(0, 1, 1):
+            print('???', x, y)
+            fs = FireSprite(fire_size, (x,y+10),  -70)
+            fs.add_heat_source(HeatSource())
+            fs.add_heat_source(HeatSource(20))
+            fire_sprites.append(fs)
+            
+    # fire_sprite = FireSprite(fire_size, (0,10),  -70)
+    # fire_sprite.add_heat_source(HeatSource())
+    
+    # fire_sprite2 = FireSprite(fire_size, (0,30),  -70)
+    # fire_sprite2.add_heat_source(HeatSource())
+    
+    background = screen.copy()
+    background.fill((255, 0, 255, 255))
+    for i in range(0, 800, 40):
+        for j in range(0, 600, 40):
+            background.fill((255, 255, 255, 255), pygame.Rect(i, j, 20, 20))
+            background.fill((0, 0, 0, 255), pygame.Rect(i + 20, j + 20, 20, 20))
+    
+    clock = pygame.time.Clock()
+    dt = 10.0
+    frm = 0
+    simulating = True
+    pygame.event.clear()
+    while simulating:
+        # for event in [pygame.event.wait()]:
+        for event in pygame.event.get():
+            if event.type == pygame.QUIT:
+                simulating = False
+            elif event.type == pygame.KEYDOWN:
+                if event.key == pygame.K_ESCAPE:
+                    simulating = False
+                elif event.key == pygame.K_F2:
+                    print('frame:', frm, clock.get_fps())
+                
+        dt = clock.tick()
+        # dt = clock.tick(20)
+        # if dt > 50:
+            # dt = 50
+        # screen.fill((0, 0, 0, 0))
+        screen.blit(background, (0, 0))
+        
+        for fire_sprite in fire_sprites:
+            fire_sprite.update(dt / 1000.0)
+            screen.blit(fire_sprite.image, fire_sprite.rect)
+        # fire_sprite.update(dt / 1000.0)
+        # fire_sprite2.update(dt / 1000.0)
+        
+        # screen.blit(fire_sprite.image, fire_sprite.rect)
+        # screen.blit(fire_sprite.image, fire_sprite.rect)
+        # screen.blit(fire_sprite2.image, fire_sprite2.rect)
+        # screen.blit(fire_sprite2.image, fire_sprite2.rect)
+        # screen.blit(fire_sprite.image, fire_sprite.rect)
+        # screen.blit(fire_sprite.image, fire_sprite.rect)
+        # screen.blit(fire_sprite.cooling_map, (400, 300))
+        # screen.blit(pygame.transform.scale(fire_sprite.image, (800, 600)), fire_sprite.rect)
+        # pygame.transform.scale2x(fire_sprite.image, screen)
+        
+        # screen.blit(pygame.transform.scale(fire_sprite.palette, (fire_sprite.palette.get_size()[0], 20)), (0, 0))
+        
+        pygame.display.flip()
+        print('frame:', frm, clock.get_fps())
+        frm += 1
+
+
+if __name__ == '__main__':
+    main()
+        
+
+
+

pyweek15/gamelib/level01.py

 
 __version__ = '$Id: __init__.py 27 2009-05-06 21:37:20Z dr0iddr0id $'
 
+import random
+
 import pygame
 
 import pyknicpygame
 
 from pyknicpygame.pyknic.timing import Scheduler
 
+import firesprite
+
 class Player(object):
     
     def __init__(self, model):
         self.dir = Vec2(0, 0)
         self.vel = Vec2(0, 0)
         self.speed = settings.player_speed
+        self.ignition = settings.player_ignition
         self.model = model
         self.left_pressed = 0
         self.right_pressed = 0
         self.up_pressed = 0
         self.down_pressed = 0
+        self.health = 100
+        self.temp = 0
         
     def look_at(self, x, y):
         self.dir = Vec2(x, y) - self.position
         
     def update(self, dt):
         if self.flooding:
-            px, py = (self.position + self.dir).as_tuple()
+            p = self.position + self.dir
+            px, py = p.as_tuple()
             self.model.cool_down(px, py, 2, 2)
+            if self.position.get_distance(p) < 2:
+                self.temp -= 2
+                if self.temp <= 0:
+                    self.temp = 0
+            
+        if self.temp > 0:
+            self.health -= self.temp * 0.01
             
         self.position += self.vel * self.speed * dt
+        cell = self.model.cells.get((self.position.x // self.model.cell_size_x, 
+                                    self.position.y // self.model.cell_size_y), None)
+        if cell and cell.temp > self.ignition and self.temp < self.ignition:
+            self.temp = cell.temp
             
     def on_event(self, logical_event, event):
         if settings.player_move_left == logical_event:
         # print('??? palyer event', logical_event, event, self.position, self.vel)
         # print(logical_event, self.vel)
 
+class GridHeatSource(firesprite.HeatSource):
+
+    def __init__(self, model):
+        firesprite.HeatSource.__init__(self)
+        self.model = model
+        
+    def apply(self, surf):
+        # todo
+
+        rw = rh = 10
+        rect = pygame.Rect(0, 0, rw, rh)
+        for cy in range(self.model.cells_count_y):
+            for cx in range(self.model.cells_count_x):
+                cell = self.model.cells[(cx, cy)]
+                if cell.has_fire():
+                    ratio = 2 * cell.temp / self.model.max_temp
+                    for i in range(rw):
+                        sx = cx * rw + i
+                        sy = cy * rh - rh//2
+                        
+                        # color = (max(0, min(255, int(self.model.cells[(x, y)].temp * 10))), )*3
+                        color = self.palette.get_at((random.randint(0, self.palette.get_size()[0] - 1), 0))
+                        alpha = int(255 * ratio)
+                        color = (color[0], color[1], color[2], alpha if alpha <= 255 else 255)
+                        surf.set_at((sx, sy + random.randint(-rh//2, rh//2)), color)
+                
+
+        
+        
+
+        
 class Level01(pyknicpygame.pyknic.context.Context):
 
 
         self._load_level(levels.level04)
         self.player.set_flooding(False)
         
+        self.win_cond_id = self.scheduler.schedule(self.check_win_condition, 1.0)
+        
+        self.firesprite = firesprite.FireSprite(settings.resolution, (0, 0))
+        self.firesprite.add_heat_source(GridHeatSource(self.model))
+        
+    def check_win_condition(self):
+        print('checking win conditions:')
+        print('     health: ', self.player.health)
+        print('player temp: ', self.player.temp)
+        print('     fires : ', len(self.model.fires))
+        if self.player.health <= 0:
+            print('LOOOSEEE!!')
+        if len(self.model.fires) == 0:
+            print('WWIIIIIINN!')
+        return 1.0
+        
     def _load_level(self, level):
         self.model.load_level(levels.level04)
         px, py = levels.level04["player_pos"]
 
     def exit(self):
         """Called when this context is popped off the stack."""
-        pass
+        # self.scheduler.remove(self.win_cond_id)
+        self.scheduler.clear()
+        
     def suspend(self):
         """Called when another context is pushed on top of this one."""
         pass
         self.player.update(delta_time)
         self.player_spr.position.copy_values(self.player.position)
         self.water_spr.position.copy_values(self.player.position + self.player.dir)
+        self.process_events()
+        self.firesprite.update(delta_time)
+        
+    def process_events(self):
         for event in pygame.event.get():
             logical_event = None
             # if pygame.MOUSEBUTTONDOWN == event.type:
                 # s +=  "{0}, ".format(str(self.model.cells[(x, y)].temp))
             # print(s)
         screen.fill((0, 0, 0))
-        rw = rh = 10
-        rect = pygame.Rect(0, 0, rw, rh)
-        for y in range(self.model.cells_count_y):
-            for x in range(self.model.cells_count_x):
-                rect.topleft = (x*rw, y*rh)
-                color = (max(0, min(255, int(self.model.cells[(x, y)].temp * 10))), )*3
-                screen.fill(color, rect)
+        # rw = rh = 10
+        # rect = pygame.Rect(0, 0, rw, rh)
+        # for y in range(self.model.cells_count_y):
+            # for x in range(self.model.cells_count_x):
+                # rect.topleft = (x*rw, y*rh)
+                # color = (max(0, min(255, int(self.model.cells[(x, y)].temp * 10))), )*3
+                # screen.fill(color, rect)
         self.renderer.draw(screen, self.cam)
+        screen.blit(self.firesprite.image, self.firesprite.rect)
         pygame.display.flip()

pyweek15/gamelib/levels.py

             "cell_size_y"    : 10,
             "cells_count_x" : 20,
             "cells_count_y" : 20,
-            "max_temp"      : 100,
+            "max_temp"      : 10,
             "player_pos"    : (10, 200),
             "temp"          : [
 

pyweek15/gamelib/main.py

         dt = clock.tick() / 1000.0 # convert to seconds
         context_top().draw(screen)
         alpha = lock_stepper.update(dt, timestep_seconds=settings.sim_time_step)
-        # if __debug__:
-            # print('fps: ', str(clock.get_fps()), alpha)
+        if __debug__:
+            print('fps: ', str(clock.get_fps()), alpha)
         
     pygame.quit()
     

pyweek15/gamelib/model.py

         self.max_temp = 100
         self.cell_size_x = 0
         self.cell_size_y = 0
+        self.fires = []
         
 
     def update(self, dt):
     def remove_fire(self, cell):
         if cell.has_fire():
             self.scheduler.remove(cell.fire.id)
+            self.fires.remove(cell.fire)
             cell.fire = None
 
     def create_fire(self, x, y, size, max_size, burn_rate, update_interval):
         fire.id = self.scheduler.schedule(self._update_fire, update_interval, random.random() * update_interval, fire)
         cell = self.cells.get((x, y), Cell())
         cell.fire = fire
+        self.fires.append(fire)
 
     def _update_fire(self, fire):
         # update grid

pyweek15/gamelib/settings.py

 sim_time_step = 0.025
 
 player_speed = 20
+player_ignition = 4
 
-player_move_left = 1000
-player_move_right = 1001
-player_move_up = 1002
-player_move_down = 1003
-player_stop_left = 1004
-player_stop_right = 1005
-player_stop_up = 1006
-player_stop_down = 1007
-player_dir = 1008
-player_start_flooding = 1009
-player_stop_flooding = 1010
+
+# 1<<30  == 1073741824  <- biggest non 'L' int
+player_move_left        = 1000
+player_move_right       = 1001
+player_move_up          = 1002
+player_move_down        = 1003
+player_stop_left        = 1004
+player_stop_right       = 1005
+player_stop_up          = 1006
+player_stop_down        = 1007
+player_dir              = 1008
+player_start_flooding   = 1009
+player_stop_flooding    = 1010
 
 key_map = {
             (pygame.KEYDOWN, pygame.K_a) : player_move_left,