Commits

schlangen committed 1cd2256

- implemented mileage for ship
- added replay test

Comments (0)

Files changed (7)

data/ui/fuel.png

Added
New image
                 
         # "menu" or "game" or "editor"
         self.state = "menu"
-        self.fade_to(self.menu)
-#        self.start_game("testlevel")
+#        self.fade_to(self.menu)
+        self.start_game("testlevel")
 #        self.start_editor()
         self.photo_sound = load_sound("photo.wav")
         self.c = 0
+import pygame
+
+try:
+    from cjson import dump, loads
+except ImportError:
+    from json import dump, loads
+    
+class Recorder(object):
+    def __init__(self, path, filter=None, events=[], autostart=False):
+        """
+        """
+        if filter == "only":
+            self.filter = 1
+        elif filter == "deny":
+            self.filter = 2
+        else:
+            self.filter = 0
+        self._events = events
+        
+        self.f = file(path, "w+")
+        self._started = False
+        
+        self.tick_buffer = 0
+        self.autostart = autostart
+        
+    def start(self):
+        self.clock = pygame.time.Clock()
+        self._started = True
+        
+    def stop(self):
+        self._started = False
+        
+    def quit(self):
+        self.f.close()
+        
+    def update(self, events):
+        if not self._started:
+            if self.autostart:
+                self.start()
+            else:
+                return
+        event_part = []
+        _events = self._events
+        filter = self.filter
+        for event in events:
+            if filter:
+                if filter == 1 and event.type not in _events:
+                    continue
+                elif filter == 2 and event.type in _events:
+                    continue
+            event_part.append((event.type, event.dict))
+        if event_part:
+            block = (self.clock.tick()+self.tick_buffer, event_part)
+            self.tick_buffer = 0
+            dump(block, self.f)
+            self.f.write("\n")
+        else:
+            self.tick_buffer += self.clock.tick()
+        
+        
+class Player(object):
+    def __init__(self, path, autostart=False):
+        self.f = file(path, "r")
+        self.clock = pygame.time.Clock()
+        self.ticks = 0
+        self._started = False
+        
+        self.event_block = None
+        self.block_time = 0
+        
+        self.autostart = autostart
+        
+    def start(self):
+        self._started = True
+        self.next_block()
+
+    def stop(self):
+        self._started = False
+        
+    def quit(self):
+        self.f.close()
+        
+    def next_block(self):
+        line = self.f.readline().strip()
+        if line:
+            self.block_time, self.event_block = loads(line)
+        else:
+            self.stop()
+                
+    def get_events(self):
+        if not self._started:
+            if self.autostart:
+                self.start()
+            else:
+                return []
+        self.ticks += self.clock.tick()
+        events = []
+        while self.ticks > self.block_time:
+            self.ticks -= self.block_time
+            for ev_type, ev_args in self.event_block:
+                events.append(pygame.event.Event(ev_type, ev_args))
+                
+            self.next_block()
+        return events
+            
+    def post_events(self):
+        for event in self.get_events():
+            pygame.event.post(event)

gallox/settings.py

 settings_path = os.path.abspath(os.path.join(os.path.dirname(__file__),"..", "controls.cfg"))
 CONTROLS = ControlDict(settings_path)
 
+CAMERA_SIZE = (400,400)
 
 # variables
 TURN_STEP = 0.01
 
 
+# total number of minutes with boost on with 100% fuel
+BOOST_DURATION = 0.1
+# percentage points per minute
+MILEAGE = 100 / BOOST_DURATION
+
+
 # world settings
 AIR_DRAG = 0.1
 
 
 ALLOWED_LANDING_ANGLE = 45
 
+# paths
 PROJECT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
 DATA_PATH = os.path.join(PROJECT_DIR, "data")
 

gallox/sprites/player.py

         # yet unused
         self.munition = 100
         self.fuel = 100
+        self.health = 100
         
         # indicators to replace key.set_repeat
         self.boost_on = False
         if self.plattform:
             for event in events:
                 if (event.type == pygame.KEYDOWN and 
-                    event.key == CONTROLS["boost"]):
+                    event.key == CONTROLS["boost"] and self.fuel > 0):
                     self.plattform.undock()
                     self.plattform = None
             if self.plattform:
                     self.turn = -1
                 elif event.key == CONTROLS["turn_right"]:
                     self.turn = 1
-                elif event.key == CONTROLS["boost"]:
+                elif event.key == CONTROLS["boost"] and self.fuel > 0:
                     self.boost_on = True
                     self.orig_image = self.orig_image_boost
                     update = True
             f = self.power * 1000. / FPS * ticks
             self.direction[0] += math.cos(math.radians(270-rot)) * f
             self.direction[1] += math.sin(math.radians(270-rot)) * f
+            self.fuel -= MILEAGE * (ticks/ (1000. * 60.))
+            if self.fuel <= 0:
+                self.boost_on = False
+                self.orig_image = self.orig_image_normal
+                update = True
+                self.fuel = 0
+        # needs update after rotation or sth else (eg. boost on/off)
         if rot != self.rot or update:
             self.rot %= 360
             img = self.image = pygame.transform.rotate(self.orig_image, self.rot)
             self.rect = self.image.get_rect(center=self.rect.center)
+            #! remove since normal image and boost image have the same mask
             if self.boost_on:
                 img = pygame.transform.rotate(self.orig_image_normal, self.rot)
                 rect = img.get_rect(center=self.rect.center)
             # always use normal image for mask
             self.mask = pygame.mask.from_surface(img)
             
-            
+            #! ???
             if self.map.collides(self):
                 self.rot = rot 
                 self.image = pygame.transform.rotate(self.orig_image, self.rot)

gallox/ui/game.py

+# game ui
+import os
+import math
+
+import pygame
+
+from gallox.utils import load_image
+from gallox.settings import *
+
+def draw_line(surf, color, start, stop, width):
+    x1, y1 = start
+    x2, y2 = stop
+    w = width / 2.
+    if x1 == x2:
+        points = [(x1-w, y1), (x1+w, y1), (x1+w, y2), (x1-w, y2)]
+    elif y1 == y2:
+        points = [(x1, y1-w), (x1, y1+w), (x2, y1+w), (x2, y1-w)]
+    else:
+        orig_m = float(y2-y1) / float(x2-x1)
+        m = - 1. / orig_m
+        l = math.sqrt(1+m*m)
+        n = width/ (2.*l)
+        points = [(x+n*i, y+n*m*i) for (x, y), i in (((x1, y1), 1), 
+                  ((x2, y2), 1), ((x2, y2), -1), ((x1, y1), -1))]
+        
+    return pygame.draw.polygon(surf, color, points)
+
+class StatusOverlay(object):
+    def __init__(self, pos, size, world):
+        self.world = world
+        self.player = world.map.ship
+        self.rect = pygame.Rect((0,0), size)
+        self.bg = pygame.Surface(size, pygame.SRCALPHA)
+        self.bg.fill((0,0,0,0)) 
+        fuel,r = load_image(os.path.join(PROJECT_DIR, "data", "ui", "fuel.png"),
+                          alpha=True)
+        self.bg.blit(fuel, fuel.get_rect(bottomright=self.rect.bottomright))
+        
+        
+        self.rect.topleft = pos
+        
+    def update(self, events):
+        return events
+    
+    def draw(self, screen):
+        screen.blit(self.bg, self.rect)
+        
+        # draw fuel gauge
+        fuel_angle = math.radians(90 * self.player.fuel / 100.)
+        start = self.rect.right - 4, self.rect.bottom - 4
+        r = 30
+        stop1 = (start[0] - math.cos(fuel_angle) * r,
+                start[1] - math.sin(fuel_angle) * r)
+        r += 10
+        stop2 = (start[0] - math.cos(fuel_angle) * r,
+                start[1] - math.sin(fuel_angle) * r)
+        # get missing points for the arrow head
+        x1,y1 = start
+        x2,y2 = stop1
+        # avoid zero division errors
+        if x1==x2:
+            x2 -= 0.0001
+        if y1==y2:
+            y2 -= 0.0001
+        width = 5
+        orig_m = float(y2-y1) / float(x2-x1)
+        m = - 1. / orig_m
+        l = math.sqrt(1+m*m)
+        n = width/ (2.*l)
+
+        p1,p2 = [(x+n*i, y+n*m*i) for (x, y), i in (((x2, y2), 1), ((x2, y2), -1))]
+        # draw the line
+        pygame.draw.aaline(screen, (0,0,0), start, stop1, 1)
+        # draw the arrow head
+        for a,b in ((p1,p2), (p2,stop2), (stop2,p1)):
+            pygame.draw.aaline(screen, (0,0,0), a, b, 1)
 
+import time
 
 import pygame
 
 from gallox.map import Map
 from gallox.camera import Camera
+from gallox.ui.game import StatusOverlay
+from gallox.replay import Recorder, Player
 from gallox.sprites import *
 from gallox.settings import *
 
 
 class World(object):
-    def __init__(self, name):
+    def __init__(self, name, replay=None):
+#    def __init__(self, name, replay="testlevel_19-04-10.rpl"):
         # ...
-
         self.clock = pygame.time.Clock()
         self.map = Map(name, self)
-        self.cam = Camera(self.map, self.map.ship, (400,400), (20,20))
-        
+        CAMERA_POS = (20,20)
+        self.cam = Camera(self.map, self.map.ship, CAMERA_SIZE, CAMERA_POS)
+        self.ui = StatusOverlay(CAMERA_POS, CAMERA_SIZE, self)
+        # normal game, record events
+        if not replay:
+            #! make_unique(path)
+#            path = os.path.join(PROJECT_DIR, "replays", 
+#                                    time.strftime("%s_%%d-%%m-%%y.rpl" % os.path.split(name)[1]))
+#            print "record to", path
+#            print "components", PROJECT_DIR, "replays", time.strftime("%s_%%d-%%m-%%y.rpl" % name)
+#            self.recorder = Recorder(path, filter="only",
+#                                     events=[pygame.KEYDOWN, pygame.KEYUP],
+#                                     autostart=True)
+            self.replay = False
+        else:
+            path = os.path.join(PROJECT_DIR, "replays", replay)
+            self.player = Player(path, autostart=True)
+            self.replay = True
         
     def update(self, events):
         ticks = self.clock.tick()
-        events, drects = self.map.update(events, ticks)
+        if not self.replay:
+#            self.recorder.update(events)
+            events, drects = self.map.update(events, ticks)
+        else:
+            ev, drects = self.map.update(self.player.get_events(), ticks)
         events = self.cam.update(events, ticks)
         return events, drects
 
     def blit(self, screen):
         self.cam.draw(screen)
+        self.ui.draw(screen)