TILEBASED WORLDS SCROLLING Lecture 2 OVERVIEW Basically A
TILE-BASED WORLDS + SCROLLING Lecture 2
OVERVIEW • Basically: • A palette of "chunks" • stitch together to make worlds • Old-school • Mega-man • Legend of Zelda • (anything SNES / GB / etc. ) • New-school • Harder to spot…and it's 3 d • Unity "Prefab" / Unreal "Blueprint"
REFRESHER ON PYGAME BLITTING • blit = copy (part of) one surface to another 250 screen = pygame. display. set_mode((800, 600)) fimg = pygame. image. load("fallout. bmp") zimg = pygame. image. load("zelda. png") screen. blit(zimg, (50, 100)) # Blit all screen. blit(fimg, (400, 100), (200, 130, 250, 212)) # Blit some fimg (200, 130) 212 500 (400, 100) (50, 100) 700 zimg 600 400 800 screen 200
PYTHON DICTIONARIES • The “normal” python sequences (we’ve seen): • Strings: a collection of characters (immutable) • Tuples: a collection of arbitrary objects / values (immutable) • Lists: a collection of arbitrary objects / values (mutable) • How Dictionaries are different: • An unordered set of key-value pairs • …because of this, no “normal” (positional) indexing
PYTHON DICTIONARIES D = {} # Going to be a string => integer dictionary D[“bob”] = 10 # Makes a new key (“bob”) / value (10) pair print(D[“bob”]) # 10 D[“sue”] = 11 D[“bob”] = 13 # Modifies the value associated with “bob” del D[“sue”] print(len(D)) # 1 D 2 = {5 : 3. 27, 23 : -19. 1} print(D 2[5]) # 3. 27 print(len(D 2)) # 2 for key in D 2: print(key) # 5 on one line, then 23 on another print(tuple(D 2. keys())) # (5, 23) (perhaps not in that order) print(tuple(D 2. values()) # (3. 27, -19. 1)
OVERVIEW • Large world, smaller visible section (screen) • All objects (enemies, tiles, power-ups, etc. ) are in world-coordinates • Camera is the bridge • Position expressed in world-coordinates • We use it to convert any world-coordinate to screen • I usually picture it in the upper-left corner of the screen Camera position
CAMERA / SCREEN CONNECTION • World => Screen conversions • screenx = worldx – camerax; screeny = worldy – cameray; • Screen => World conversion • worldx = screenx + camerax; • Negative / huge values • Clipping! worldy = screey + cameray;
SCROLLING: NAÏVE APPROACH • Store world in a large surface. • Use the more-powerful blit command: • screen. blit(background, (0, 0), (camerax, cameray, screenwidth, screenheight)) • Problem with our tile-renderer: • Normally, 3 bytes per pixel (1 byte each for red, green, blue) • Say our world is 200 tiles wide, 200 high (32 x 32 tiles) • 200 x 32 x 3 • = about 120 MB…for a *tiny* map! • 2000 x 2000 tile world = 11. 4 GB! • Digression: virtual memory
SMARTER APPROACH • Just render the things that are (partially) on-screen • We use a bit more CPU power, but use much less RAM. • It’s worth it! • Modifications to our tile-rendering • Find which tile to start with • This is where the upper-left corner of the screen (i. e. …) is located in the world. • Render enough tiles to fill the screen. • Challenge: the first tile usually isn’t at (0, 0) on the screen… • [Develop an algorithm using the “worksheet” on the next slide]
10 px . . 51 52 53 54 55 56 57 58 59 60 61 28 29 30 31 32 33 34 35 36 37 39 63 64 65 66 SMARTER APPROACH, CONT. 27 38 62 120 px 67 68 …
DO WE EVEN NEED TILES? • Maybe • Alternative: • A list of shapes (images, primitives, etc. ) • Still expressed in world units. • Brute-force rendering: • Loop through all shapes, render if (partially) on-screen • Better alternative: • Organize shapes – only draw those that we need to • Ideas: • Spatial Hashing • Quadtrees • …
- Slides: 11