Search code examples
pythonrandompygameinteractiveprocedural-generation

How to stop .blit() from wrapping pixels across screen, or help finding an alternative that does the same?


I am trying to generate terrain randomly, and I have made it scroll it just as a test, but when the pixels hit the end of the screen, they play back on the other side as such:brokenscroll before hitting the other side it looks like:scrolling

Here's my code:

import numpy as n
import pygame as py
import random as r
import time as t
import math as m
py.init()
left = 0
Ylev = 8
display = py.display.set_mode((512, 512))
display.fill((175, 215, 225))
def scrollX(screenSurf, offsetX):
    width, height = screenSurf.get_size()
    copySurf = screenSurf.copy()
    screenSurf.blit(copySurf, (offsetX, 0))
    if offsetX < 0:
        screenSurf.blit(copySurf, (width + offsetX, 0), (0, 0, -offsetX, height))
    else:
        screenSurf.blit(copySurf, (0, 0), (width - offsetX, 0, offsetX, height))
while True:
    num = round(r.randint(0, 5) ** 1/4)
    neg = r.randint(0, 1)
    if neg == 0:
        num = -num
    Ylev += num
    if Ylev < 0:
        Ylev = 0
    if Ylev > 16:
        Ylev = 15
    print(Ylev)
    scrollX(display, -16)
    py.draw.rect(display, (0, 100, 20), py.Rect(31 * 16, Ylev * 16, 16, 16))
    py.display.flip()
    t.sleep(0.25)

I am trying to achieve image 2, but with the ability to hit the other side of the screen and still generate new terrain. How can this be achieved, and if possible, how can I allow a player (represented by 2 pixels) to interact with this terrain, in the form of movement, but disallowing movement through the generated terrain. Can this be achieved by detecting the colour of a pixel (e.g. the terrain) and letting the player interact with it that way, or do I need a list of all the terrain pixels?

I tried to update everything but the first row, but 1. This leads to the first pixel never being displayed, and 2. This doesn't fix the problem.


Solution

  • All problem is inside if offsetX < 0: - you copy from left side to right side and this adds old pixels.

    You should rather fill() with background color.

    if offsetX < 0:
        screenSurf.fill((175, 215, 225), (width + offsetX, 0, width, height))
    else:
        screenSurf.fill((175, 215, 225), (0, 0, offsetX, height))
    

    Full working code:

    #import numpy as n
    import pygame as py
    import random as r
    #import time as t
    #import math as m
    
    # --- constants ---  # PEP8: `UPPER_CASE_NAMES`
    
    LEFT = 0
    Y_LEV = 8
    
    # --- functions ---  # PEP8: `lower_case_names`
    
    def scroll_x(screen_surf, offset_x):
    
        width, height = screen_surf.get_size()
        
        copy_surf = screen_surf.copy()
        screen_surf.blit(copy_surf, (offset_x, 0))
        
        if offset_x < 0:
            screen_surf.fill((175, 215, 225), (width+offset_x, 0, width, height))
        else:
            screen_surf.fill((175, 215, 225), (0, 0, offset_x, height))
    
    # --- main ---
            
    py.init()
    
    display = py.display.set_mode((512, 512))
    display.fill((175, 215, 225))
    
    clock = py.time.Clock()
      
    
    while True:
        for event in py.event.get():
            if event.type == py.QUIT:
                    exit()
            if event.type == py.KEYDOWN:
                if event.key == py.K_ESCAPE:
                    exit()
                    
        #num = round(r.randint(0, 5) ** 1/4)
        #neg = r.randint(0, 1)
       
        #if neg == 0:
        #    num = -num
         
        num = r.choice([-1, 0, 1])   
        #print(num)
            
        Y_LEV += num
        
        if Y_LEV < 0:
            Y_LEV = 0
        if Y_LEV > 16:
            Y_LEV = 15
    
        print(Y_LEV)
    
        offset_x = -16    
        scroll_x(display, offset_x)
        
        if offset_x < 0:
            py.draw.rect(display, (0, 100, 20), py.Rect(31 * 16, Y_LEV * 16, 16, 16))
        else:
            py.draw.rect(display, (0, 100, 20), py.Rect(0, Y_LEV * 16, 16, 16))
        
        py.display.flip()
    
        clock.tick(4)   # 4 FPS = 0.25 ms
        #t.sleep(0.25)
    

    PEP 8 -- Style Guide for Python Code