Moving background as player moves

I am making a 2D top-down shooter game similar to Hotline Miami. I want the background to move as player moves (zoomed in). How do I do this?

As of now, I’ve coded only the player movement part without background.

Sample pic is shown below (background is bigger, it’s just the zoomed in part):

My code is:

up_pressed = False
left_pressed = False
right_pressed = False
down_pressed = False

path = os.getcwd()

img = loadImage(path + "/images/" + "shootermain.png")
img_aim = loadImage(path + "/images/" + "aim2.png")


x = 250
y = 250
speed = 5

def setup():
    size(1500, 850)

def draw():
    global x, y
    background(255)

    if up_pressed:
        y -= speed
    elif left_pressed:
        x -= speed
    elif right_pressed:
        x += speed
    elif down_pressed:
        y += speed
    
    
    with pushMatrix():
        translate(x, y)
        angle = atan2(mouseX-x, mouseY-y)
        rotate(angle*-1)
        fill(255)
        # rect(-50, -50 , 100, 100)  # player
        image(img, -50, -50, 100, 100, 300, 300, 0, 0)
        strokeWeight(0)
        fill(255, 0, 0)
        rect(0, 0, 1.5, 200)         # beam
        # image(img_aim, mouseX, mouseY)
  
        

def keyPressed():
    global up_pressed, left_pressed, right_pressed, down_pressed

    if key == 'w':
        up_pressed = True
    elif key == 'a':
        left_pressed = True
    elif key == 'd':
        right_pressed = True
    elif key == 's':
        down_pressed = True


def keyReleased():
    global up_pressed, left_pressed, right_pressed, down_pressed

    if key == 'w':
        up_pressed = False
    elif key == 'a':
        left_pressed = False
    elif key == 'd':
        right_pressed = False
    elif key == 's':
        down_pressed = False

What if you move the background image position, but keep the player in the same place (in the centre of the screen)? So, the background image is larger than the viewable area, and you pan it about. In other words, your x/y variables control the background coordinates, not the player’s.

yes that would work too!

How do I do that? I’m sorry I’m just a beginner

You need to assign your background position to be some x - some offsetx and some y - some offsety. Where offset y and offsetx is calculated when you press the arrow keys and therefore gets updated. Its the same principle as drag and drop ill post some code later

Something like –

def draw():
    ...
    # your x/y variables control the background coordinates
    image(background_image, x, y)
    
    with pushMatrix():
        # keep the player in the same place (in the centre of the screen)
        translate(width/2, height/2)
        angle = atan2(mouseX-width/2, mouseY-height/2)
        rotate(angle*-1)
        image(player_image, -50, -50, 100, 100)

    ...

However, your movement will be inverted. You’ll need to change y -= speed to y += speed, and so on.

wow works nicely! How do I add collision detection with all walls and objects? there are so many of them

Perhaps start another topic for that. There are various approaches …

You might look at AABB collision as a starting point.

Is there any way to fade the surrounding background around the player and light it up as player moves? Something like shown in sample image below?

sample.PNG

Maybe an additional tilemap-type layer – one that overlays your entire stage with tiles ranging between solid black and fully-transparent. These could include gradient ‘edge’ tiles.

I didn’t understand why the coordinates of image in your code is negative (i.e. (player_image, -50, -50, 100, 100)). Can you explain pls. It works, but I want to understand.

Also, can you tell me the best and easiest way to place enemies around (non-movable) and after 3 gunshots, kill it?

The negative x-y coordinates for player_image offset the point of rotation, so that it pivots around its centre. If you set those coordinates to (0, 0), the player image pivots on its top-left corner:

Screenshot from 2020-12-06 09-04-26

Left image: image(player_image, -50, -50, 100, 100)
Right image: image(player_image, 0, 0, 100, 100)

1 Like

It’s probably best to create a new class of enemy objects:

class Enemy(object):
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.lives = 3
    
    def display(self):
        circle(self.x, self.y, 50)

Each enemy begins with 3 lives, stored in the self.lives attribute.

You’ll want the enemy objects to pan about with your stage/background, so you adapt your code to use another pushMatrix()

...
enemy1 = Enemy(200, 300)
enemy2 = Enemy(400, 120)

...

def draw():
    ...
    # your x/y variables control the background coordinates
    with pushMatrix():
        translate(x, y)
        image(background_image, 0, 0)
        enemy1.display()
        enemy2.display()

    ...

I’m not sure what type of detection you’ll use for bullet-enemy collisions. For simplicity, I’d recommend AABB or circle-circle collision – depending which shape conforms best to your bullets and enemies. Again, I’d recommend a new class for bullet objects. Once you’ve got all that working, you can look at deducting enemy lives each time one is struck with a bullet.

can we have two pushMatrix functions together in one program?

As many as you like. You can also nest them, if that’s what you need.

but when I use pushMatrix for enemies and players both separately, the player sprite vanishes (however it still moves)

Show your code

You must use pushMatrix and popMatrix together

In Python Mode, you have two options –

# this requires no popMatrix()
with pushMatrix():
    translate(10, 10)
    square(0, 0, 50)

# this is the popMatrix() alternative
pushMatrix()
translate(10, 10)
square(0, 0, 50)
popMatrix()
2 Likes

yeah it works now! Thanks! In my game, I’m trying to implement a clock/timer. It works as of now but only problem is I need to make the frameRate to 1 but it affects the whole program’s frameRate. How do I change frameRate only for the clock function?

def clock():
    global sec, minutes, hours, col
        
    sec+=1
    if(sec == 60):
        sec = 0
        minutes+=1
    if(minutes == 60):
        minutes = 0
        hours+=1
    if(hours == 24):
        hours = 0
        minutes = 0
        sec = 0
            
    textSize(25)
    fill(255, 0, 0)
    text(floor(sec), 185, 110)
    text(floor(minutes), 135, 110)
    text(floor(hours), 85, 110)
    
    if(sec % 2 == 0):
        col = color(0)
    else:
        col = color(255, 0, 0)
    
    fill(col)
    textSize(30)
    text(":", 120, 110)
    text(":", 170, 110)


1 Like