132b44af9914cf5d584f6487cff80013a911cccb
[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
25 IMAGE_PATH = 'road.png'
26 SCREEN_WIDTH = 800
27 SCREEN_HEIGHT = 480
28
29
30 class VerticalScrollingMap(pygame.Surface):
31     """
32     There are some assumptions on the scrolling image for the seamless looping
33     effect to work:
34       - The image height must be at least twice the height of the
35         screen/viewport.
36       - The image must have two identical regions, one at the top and one at
37         the bottom, of the same height as the screen/viewport.
38     """
39     def __init__(self, image, *args, **kwargs):
40         super(VerticalScrollingMap, self).__init__(*args, **kwargs)
41
42         self.viewport_width, self.viewport_height = self.get_size()
43
44         self.texture = pygame.image.load(image)
45         self.texture_widht, self.texture_height = self.texture.get_size()
46
47         self.offset = 0
48         self.y = 0
49
50         # Center along X
51         self.x = (self.viewport_width - self.texture_widht) / 2.0
52
53     def draw(self, screen):
54         self.y += self.offset
55
56         # NOTE, we assume that the texture has at least twice the height of the
57         # viewport
58         lastframe_limit = -(self.texture_height - self.viewport_height)
59
60         # Wrap around to cycle seamlessly
61         self.y %= lastframe_limit
62
63         screen.blit(self.texture, (self.x, self.y))
64
65     def set_offset(self, offset):
66         self.offset = offset
67
68     def inc_offset(self, amount=1):
69         self.offset += amount
70
71     def dec_offset(self, amount=1):
72         self.offset -= amount
73
74
75 def main():
76     pygame.init()
77
78     screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT),
79             pygame.HWSURFACE | pygame.DOUBLEBUF)
80     pygame.display.set_caption('Vertical Scrolling Map')
81     pygame.mouse.set_visible(0)
82
83     screen_size = screen.get_size()
84
85     bg_color = (0, 0, 0)
86     background = pygame.Surface(screen_size)
87     background.fill(bg_color)
88
89     screen.blit(background.convert(), (0, 0))
90
91     scrolling_map = VerticalScrollingMap(IMAGE_PATH, screen_size)
92
93     # If there is a joustick connected it will take precedence
94     # to set the scrolling offset over the key presses
95     try:
96         joystick = pygame.joystick.Joystick(0)
97         joystick.init()
98         axis = 1
99     except:
100         joystick = None
101
102     clock = pygame.time.Clock()
103
104     fps = 30
105     exit = False
106     while not exit:
107         msElapsed = clock.tick(fps)
108
109         for event in pygame.event.get():
110             if event.type == pygame.QUIT:
111                 exit = True
112                 break
113
114         if joystick:
115             val = joystick.get_axis(axis)
116             scrolling_map.set_offset(int(val * 50))
117
118         key = pygame.key.get_pressed()
119         if key[pygame.K_ESCAPE]:
120             exit = True
121         if key[pygame.K_UP]:
122             scrolling_map.inc_offset()
123         if key[pygame.K_DOWN]:
124             scrolling_map.dec_offset()
125
126         if exit:
127             break
128
129         screen.blit(background.convert(), (0, 0))
130         scrolling_map.draw(screen)
131
132         pygame.display.update()
133
134     pygame.quit()
135
136 if __name__ == '__main__':
137     main()