--- /dev/null
+#!/usr/bin/env python
+
+# An example of a vertical scrolling map with pygame
+#
+# Copyright (C) 2013 Antonio Ospite <ospite@studenti.unina.it>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Reference:
+# https://www.cs.ucsb.edu/~pconrad/cs5nm/topics/pygame/drawing/
+
+import pygame
+
+IMAGE_PATH = 'road.png'
+SCREEN_WIDTH = 800
+SCREEN_HEIGHT = 480
+
+
+class VerticalScrollingMap(pygame.Surface):
+ """
+ There are some assumptions on the scrolling image for the seamless looping
+ effect to work:
+ - The image height must be at least twice the height of the
+ screen/viewport.
+ - The image must have two identical regions, one at the top and one at
+ the bottom, of the same height as the screen/viewport.
+ """
+ def __init__(self, image, *args, **kwargs):
+ super(VerticalScrollingMap, self).__init__(*args, **kwargs)
+
+ self.viewport_width, self.viewport_height = self.get_size()
+
+ self.texture = pygame.image.load(image)
+ self.texture_widht, self.texture_height = self.texture.get_size()
+
+ self.offset = 0
+ self.y = 0
+
+ # Center along X
+ self.x = (self.viewport_width - self.texture_widht) / 2.0
+
+ def draw(self, screen):
+ self.y += self.offset
+
+ # NOTE, we assume that the texture has at least twice the height of the
+ # viewport
+ lastframe_limit = -(self.texture_height - self.viewport_height)
+
+ # Wrap around to cycle seamlessly
+ self.y %= lastframe_limit
+
+ screen.blit(self.texture, (self.x, self.y))
+
+ def set_offset(self, offset):
+ self.offset = offset
+
+ def inc_offset(self, amount=1):
+ self.offset += amount
+
+ def dec_offset(self, amount=1):
+ self.offset -= amount
+
+
+def main():
+ pygame.init()
+
+ screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT),
+ pygame.HWSURFACE | pygame.DOUBLEBUF)
+ pygame.display.set_caption('Vertical Scrolling Map')
+ pygame.mouse.set_visible(0)
+
+ screen_size = screen.get_size()
+
+ bg_color = (0, 0, 0)
+ background = pygame.Surface(screen_size)
+ background.fill(bg_color)
+
+ screen.blit(background.convert(), (0, 0))
+
+ scrolling_map = VerticalScrollingMap(IMAGE_PATH, screen_size)
+
+ # If there is a joustick connected it will take precedence
+ # to set the scrolling offset over the key presses
+ try:
+ joystick = pygame.joystick.Joystick(0)
+ joystick.init()
+ axis = 1
+ except:
+ joystick = None
+
+ clock = pygame.time.Clock()
+
+ fps = 30
+ exit = False
+ while not exit:
+ msElapsed = clock.tick(fps)
+
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ exit = True
+ break
+
+ if joystick:
+ val = joystick.get_axis(axis)
+ scrolling_map.set_offset(int(val * 50))
+
+ key = pygame.key.get_pressed()
+ if key[pygame.K_ESCAPE]:
+ exit = True
+ if key[pygame.K_UP]:
+ scrolling_map.inc_offset()
+ if key[pygame.K_DOWN]:
+ scrolling_map.dec_offset()
+
+ if exit:
+ break
+
+ screen.blit(background.convert(), (0, 0))
+ scrolling_map.draw(screen)
+
+ pygame.display.update()
+
+ pygame.quit()
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="5492.126"
+ height="56444.879"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="road.svg"
+ inkscape:export-filename="/home/ao2/WIP/pygame-experiments/road.png"
+ inkscape:export-xdpi="13.11"
+ inkscape:export-ydpi="13.11">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.01"
+ inkscape:cx="2746.063"
+ inkscape:cy="28222.441"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1152"
+ inkscape:window-height="756"
+ inkscape:window-x="0"
+ inkscape:window-y="29"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="cm" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="Background"
+ style="display:inline"
+ transform="translate(0,37311.023)"
+ sodipodi:insensitive="true">
+ <path
+ transform="translate(-164.82684,18492.735)"
+ style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.80000019;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 164.82684,-55803.758 5492.12596,0 0,56444.87909 -5492.12596,0 z"
+ id="rect4044"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ <g
+ inkscape:label="Lane"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-164.82684,55803.758)"
+ style="display:inline">
+ <path
+ style="color:#000000;fill:#555753;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 164.82698,-55803.746 0.009,56444.86691 5492.11672,0 0,-56444.86691 z"
+ id="rect3094-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#ffffff;stroke-width:354.33071899;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1062.99212598, 1062.99212598;stroke-dashoffset:2125.98365904"
+ d="m 341.9922,463.95706 -1e-5,-56090.55306"
+ id="path3971-2-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#555753;stroke:#ffffff;stroke-width:354.33071899000009353;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1062.99212598000008256, 1062.99212598000008256;stroke-dashoffset:2125.98365904000002047;display:inline"
+ d="m 5479.7875,463.95555 0,-56090.55255"
+ id="path3971-2-7-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#ffffff;stroke-width:354.33099365;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:2125.98538316;display:inline"
+ d="m 2910.8898,463.95555 c 0,0 0,-2337.10635 0,-3505.65955 0,-1172.9171 1081.0261,-2144.5229 1100,-3305.6595 21.0522,-1288.3203 -928.9006,-2428.5779 -1100,-3705.6595 -199.4852,-1488.953 83.3323,-3003.496 100,-4505.66 9.2668,-835.168 0,-1670.439 0,-2505.659 0,-735.22 7.6483,-1470.48 0,-2205.66 -16.6676,-1602.146 -369.004,-3226.169 -100,-4805.659 191.5606,-1124.771 1169.9172,-2065.089 1200,-3205.66 35.0701,-1329.66 -910.0065,-2507.533 -1200,-3805.659 -271.7431,-1216.43 -416.4789,-2462.048 -500,-3705.66 -73.8364,-1099.41 -144.3288,-2213.266 0,-3305.659 235.3611,-1781.396 1579.0946,-3417.731 1400,-5205.66 -67.0289,-669.159 -846.253,-1135.302 -900,-1805.659 -89.4577,-1115.757 974.5796,-2086.611 1000,-3205.66 29.7871,-1311.278 -1000,-2494.043 -1000,-3805.659 0,-1212.78 0,-3505.66 0,-3505.66"
+ id="path3971-2-7-7-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csaaaaaaaaaaaaasc" />
+ <rect
+ style="color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:354.33099365;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2991"
+ width="5492.126"
+ height="7.0866141"
+ x="164.82684"
+ y="-1010.0585"
+ inkscape:export-xdpi="13.11"
+ inkscape:export-ydpi="13.11" />
+ <rect
+ transform="translate(164.82684,-18492.735)"
+ style="display:inline;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:354.33099364999998215;marker:none;visibility:visible;overflow:visible;enable-background:accumulate"
+ id="rect2991-2"
+ width="5492.126"
+ height="7.0866141"
+ x="-8.2812494e-06"
+ y="-35666.93"
+ inkscape:export-xdpi="13.11"
+ inkscape:export-ydpi="13.11" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Viewport"
+ style="display:none"
+ transform="translate(0,37311.023)">
+ <path
+ transform="translate(-164.82684,18492.735)"
+ style="color:#000000;fill:#000000;fill-opacity:0.5078125;stroke:none;stroke-width:354.33071899;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 164.82684,-55803.758 5492.12596,0 0,3295.276 -5492.12596,0 z"
+ id="rect2997-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <rect
+ style="color:#000000;fill:#000000;fill-opacity:0.5078125;stroke:none;stroke-width:354.33071899;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2997"
+ width="5492.126"
+ height="3295.2756"
+ x="-2.2737368e-13"
+ y="15838.582" />
+ </g>
+</svg>