Add support for saving the raw output to a file
[experiments/pygame.git] / pygame-vertical-scrolling-map.py
1 #!/usr/bin/env python
2
3 # An example of a vertical scrolling map with pygame
4 #
5 # Copyright (C) 2013  Antonio Ospite <ospite@studenti.unina.it>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 # Reference:
21 # https://www.cs.ucsb.edu/~pconrad/cs5nm/topics/pygame/drawing/
22
23 import pygame
24 import sys
25 import os
26
27 IMAGE_PATH = 'road.png'
28 SCREEN_WIDTH = 800
29 SCREEN_HEIGHT = 480
30
31
32 class VerticalScrollingMap(pygame.Surface):
33     """
34     There are some assumptions on the scrolling image for the seamless looping
35     effect to work:
36       - The image height must be at least twice the height of the
37         screen/viewport.
38       - The image must have two identical regions, one at the top and one at
39         the bottom, of the same height as the screen/viewport.
40     """
41     def __init__(self, image, *args, **kwargs):
42         super(VerticalScrollingMap, self).__init__(*args, **kwargs)
43
44         self.viewport_width, self.viewport_height = self.get_size()
45
46         self.texture = pygame.image.load(image)
47         self.texture_widht, self.texture_height = self.texture.get_size()
48
49         self.offset = 0
50         self.y = 0
51
52         # Center along X
53         self.x = (self.viewport_width - self.texture_widht) / 2.0
54
55         # NOTE, we assume that the texture has at least twice the height of the
56         # viewport
57         self.lastframe_limit = -(self.texture_height - self.viewport_height)
58
59     def draw(self, screen):
60         self.y += self.offset
61
62         # Wrap around to cycle seamlessly
63         self.y %= self.lastframe_limit
64
65         screen.blit(self.texture, (self.x, self.y))
66
67     def set_offset(self, offset):
68         self.offset = offset
69
70     def inc_offset(self, amount=1):
71         self.offset += amount
72
73     def dec_offset(self, amount=1):
74         self.offset -= amount
75
76
77 def main():
78     pygame.init()
79
80     screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT),
81             pygame.HWSURFACE | pygame.DOUBLEBUF)
82     pygame.display.set_caption('Vertical Scrolling Map')
83     pygame.mouse.set_visible(0)
84
85     screen_size = screen.get_size()
86
87     bg_color = (0, 0, 0)
88     background = pygame.Surface(screen_size)
89     background.fill(bg_color)
90
91     screen.blit(background.convert(), (0, 0))
92
93     scrolling_map = VerticalScrollingMap(IMAGE_PATH, screen_size)
94
95     # If there is a joustick connected it will take precedence
96     # to set the scrolling offset over the key presses
97     try:
98         joystick = pygame.joystick.Joystick(0)
99         joystick.init()
100         axis = 1
101     except:
102         joystick = None
103
104     if len(sys.argv) > 1:
105         if sys.argv[1] == '-':
106             outputfile = sys.stdout.fileno()
107         else:
108             outputfile = os.open(sys.argv[1], os.O_WRONLY)
109     else:
110         outputfile = None
111
112     clock = pygame.time.Clock()
113
114     fps = 30
115     exit = False
116     while not exit:
117         msElapsed = clock.tick(fps)
118
119         for event in pygame.event.get():
120             if event.type == pygame.QUIT:
121                 exit = True
122                 break
123
124         if joystick:
125             val = joystick.get_axis(axis)
126             scrolling_map.set_offset(int(val * 50))
127
128         key = pygame.key.get_pressed()
129         if key[pygame.K_ESCAPE]:
130             exit = True
131         if key[pygame.K_UP]:
132             scrolling_map.inc_offset()
133         if key[pygame.K_DOWN]:
134             scrolling_map.dec_offset()
135
136         if exit:
137             break
138
139         screen.blit(background.convert(), (0, 0))
140         scrolling_map.draw(screen)
141
142         if outputfile:
143             buf = pygame.image.tostring(pygame.display.get_surface(), "RGB", False)
144             os.write(outputfile, buf)
145
146         pygame.display.update()
147
148     pygame.quit()
149
150 if __name__ == '__main__':
151     main()