0
votes

I am making a roguelike in pygame and for a few day I can't handle problem with map scrolling.

On the left is how it looks at the begning and on the right after two steps down enter image description here As you can see some of the titles on the top vanished and rest haven't moved anyway. I tried to implemet algorithm from roguebasin but it doesn't help. This problem took me few days from life and I have no idea what's wrong. I post here two functions I have problem with.

def world_gen():
camera_x = scrolling_map(hero.x, 5, 10, map_width)
camera_y = scrolling_map(hero.y, 5, 10, map_height)
for x in range(camera_x, camera_x+11):
    for y in range(camera_y, camera_y+11):
        if world[y][x] != 0:
            display_surf.blit(find_title(world[y][x]).image, (64 * x, 64 * y))
            display_surf.blit(hero.image, (64 * 5, 64 * 5))

def scrolling_map(p, hs, s, m):
"""
    Get the position of the camera in a scrolling map:

     - p is the position of the player.
     - hs is half of the screen size, and s is the full screen size.
     - m is the size of the map.
    """

if p < hs:
    return 0
elif p >= m - hs:
    return m - s
else:
    return p - hs

and here is all code. Id' be realy greatful if someone colud help me with that because I can't sleep becouse od this.

1
Problem can be in (64 * x, 64 * y). You can't use the same x, y to get value from world and to draw it on screen. Now when you move ie. 3 steps down then you start drawing in (64 * 3, 64 * 0) but you have always start drawing in (64 * 0, 64 * 0) - furas

1 Answers

1
votes

I didn't check this but I think problem is (64 * x, 64 * y) because you move camera but you also move where it will be drawn. But you have always start at (64 * 0, 64 * 0)

You have to move it back

if world[y][x] != 0:
    a = x - camera_x
    b = y - camera_y
    display_surf.blit(find_title(world[y][x]).image, (64 * a, 64 * b))

EDIT: tested - it works

import sys
import random
import pygame
#from pygame.locals import * # don't need it

# --- constants --- (UPPER_CASE names)

FPS = 30
WINDOW_WIDTH = 704
WINDOW_HEIGHT = 704
MAP_WIDTH = 30
MAP_HEIGHT = 14 # not 15

GREEN = (100, 255, 0)

# --- classes --- (CamelCase names)

class Object:
    # this is a generic object: the player, a monster, an item, the stairs...
    # it's always represented by a character on screen.

    def __init__(self, x, y, image):
        self.x = x
        self.y = y

        self.image = pygame.image.load(image)

        # use pygame.Rect() to keep object position and size -
        # it use by other Pygame function
        # ie. pygame.sprite.Sprite() and "colision detection"
        # or pygame.sprite.Group()

        self.rect = self.image.get_rect()
        self.rect.x = 64 * 5 
        self.rect.y = 64 * 5

    def move(self, dx, dy):
        if self.y+dx < len(world) and self.y+dy < len(world[0]):
            if find_title(world[self.y+dy][self.x+dx]).solid is False:  #this line checks if move is possible
                self.x += dx
                self.y += dy

    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def event_handler(self, event):
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if self.x - 1 >= 0:
                    self.move(-1, 0)
            elif event.key == pygame.K_RIGHT:
                if self.x + 1 < MAP_WIDTH:
                    self.move(1, 0)
            elif event.key == pygame.K_UP:
                if self.y - 1 >= 0:
                    self.move(0, -1)
            elif event.key == pygame.K_DOWN:
                if self.y + 1 < MAP_HEIGHT:
                    self.move(0, 1)


class Title:
    # this is a class for titles like grass, road and so on

    def __init__(self, title_number, solid, image):
        self.title_number = title_number
        self.solid = solid
        self.image = pygame.image.load(image)

# --- functions --- (lower_case names)

def find_title(n):
    tiles = [nothing, grass, fance]

    if n < len(tiles):
        return tiles[n]

#    if n == 0:
#        return nothing
#    if n == 1:
#        return grass
#    if n == 2:
#        return fance

def world_draw(screen): # could be split in "move_camera" and "draw_world" 

    for x in range(camera_x, camera_x+11):
        for y in range(camera_y, camera_y+11):
            if y < len(world) and x < len(world[0]): # control map size
                if world[y][x] != 0:
                    a = x - camera_x
                    b = y - camera_y
                    screen.blit(find_title(world[y][x]).image, (64 * a, 64 * b))

def scrolling_map(position, half_size, screen_size, map_size): # use readable names
    """
        Get the position of the camera in a scrolling map:

         - p is the position of the player.
         - hs is half of the screen size, and s is the full screen size.
         - m is the size of the map.
        """

    if position < half_size:
        return 0
    elif position >= map_size - half_size:
        return map_size - screen_size
    else:
        return position - half_size

# --- main ---

world = [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]


# - init -

pygame.init()
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0, 32)
screen_rect = screen.get_rect()
pygame.display.set_caption("Rl")

# - objects -

hero = Object(5, 5, "hero.png")
grass = Title(1, False, "grass.png")
fance = Title(2, True, "fance.png")
nothing = Title(0, False, "road.png")

# - mainloop -

fps_clock = pygame.time.Clock()

while True:

    # - events -

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        hero.event_handler(event)

    # - updates (without draw) -

    camera_x = scrolling_map(hero.x, 5, 10, MAP_WIDTH)
    camera_y = scrolling_map(hero.y, 5, 10, MAP_HEIGHT)

    # - draws (without updates) -

    screen.fill(GREEN)

    world_draw(screen)

    hero.draw(screen)

    pygame.display.update()

    # - FPS - control speed -
    # pygame.time.delay(50) # you don't need it - you have `fps_clock.tick` for this

    fps_clock.tick(FPS)