This question already has answers here:
Add scrolling to a platformer in pygame
(4 answers)
Closed last month.
I am using pygame framework to implement my game in Python. Below is my code.
I do not know how to properly ask questions at StackOverflow, so I have included the whole program so that you can see all the details.
I would like to have a camera that would follow my player, but I do not know how to do that.
Could you, please, help me?
import pygame
pygame.init()
class Oyun():
def __init__(self):
self.x = 20
pygame.display.set_caption("Cabbar_Oyunda_Vol01")
self.uzunluk = 1280
self.genişlik = 800
self.pencere = pygame.display.set_mode((self.uzunluk, self.genişlik))
self.area = self.uzunluk * self.genişlik
self.clock = pygame.time.Clock()
self.adam = pygame.image.load("R8E.png")
self.bg = pygame.image.load("mountains.png").convert()
self.bgWidth, self.bgHeight = self.bg.get_rect().size
self.stageWidth = self.bgWidth * 2
self.stagePosX=0
self.startScrollingPosX=self.uzunluk/2
self.circleRadius=25
self.circlePosX=self.circleRadius
self.playerPosX = self.circleRadius
self.playerPosY = 685
self.playerVelocityX = 0
self.right = False
self.left = False
self.walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load("L3.png"), pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'), pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
self.walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'), pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'), pygame.image.load('R7.png'), pygame.image.load('R8.png'),pygame.image.load('R9.png')]
self.walkCount=0
self.canavar_left=[pygame.image.load("L1E.png"),pygame.image.load("L2E.png"),pygame.image.load("L3E.png"),pygame.image.load("L4E.png"),pygame.image.load("L5E.png"),pygame.image.load("L6E.png"),pygame.image.load("L7E.png"),pygame.image.load("L8E.png"),pygame.image.load("L9E.png")]
self.canavar_right = [pygame.image.load("R1E.png"), pygame.image.load("R2E.png"), pygame.image.load("R3E.png"),pygame.image.load("R4E.png"), pygame.image.load("R5E.png"), pygame.image.load("R6E.png"),pygame.image.load("R7E.png"), pygame.image.load("R8E.png"), pygame.image.load("R9E.png")]
self.c_walkount=0
self.isJump = False
self.jumpCount = 10
self.sayac=0
self.yorgunluk_x=70
self.font=pygame.font.SysFont("Arial",17)
self.mermi=pygame.image.load("bullet.png")
self.mermi_x=0
self.mermi_y=0
self.mermi_stage="ready"
self.deneme=pygame.image.load("bg.jpg")
self.a = self.stagePosX + 1300
self.canavar=False
pygame.mixer.music.load("background.wav")
pygame.mixer.music.play(-1)
self.yon=1
self.scroll=[0,0]
def move(self):
self.clock.tick(40)
if self.walkCount + 1 >= 27:
self.walkCount = 0
if self.right:
self.pencere.blit(self.walkRight[self.walkCount // 3], (self.circlePosX, self.playerPosY))
self.walkCount += 1
elif self.left:
self.pencere.blit(self.walkLeft[self.walkCount // 3], (self.circlePosX, self.playerPosY))
self.walkCount += 1
else:
self.pencere.blit(self.walkRight[0], (self.circlePosX, self.playerPosY))
if self.canavar:
if self.a>1400 or self.a<1200:
self.yon*=-1
self.a += 2 * self.yon
def fire_bullet(self,circlePosX,playerPosY):
self.mermi_stage="fire"
self.pencere.blit(self.mermi,(circlePosX+40,playerPosY+20))
def kontrol(self):
keys=pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
if self.mermi_stage is "ready":
self.mermi_x=self.circlePosX
self.mermi_y=self.playerPosY
self.fire_bullet(self.mermi_x,self.mermi_y)
self.mermi_ses = pygame.mixer.Sound("laser.wav")
self.mermi_ses.play()
if self.mermi_stage is "fire":
self.fire_bullet(self.mermi_x,self.mermi_y)
self.mermi_x+=18
if self.mermi_x>=1280:
self.mermi_x=self.circlePosX
self.mermi_stage="ready"
self.pencere.blit(self.adam, (self.a, 685))
def Game(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
return "son"
self.pencere.blit(self.bg, (0, 0))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.left = False
self.right = True
self.circlePosX += 5
elif keys[pygame.K_LEFT]:
self.left = True
self.right = False
self.circlePosX=-5
if not (self.isJump):
if keys[pygame.K_UP]:
self.isJump = True
self.left = False
self.right = True
self.walkCount = 0
self.sayac += 1
else:
if self.jumpCount >= -10:
self.playerPosY -= (self.jumpCount * abs(self.jumpCount)) * 0.5
self.jumpCount -= 1
else:
self.jumpCount = 10
self.isJump = False
self.canavar=True
self.move()
self.kontrol()
pygame.display.update()
Game = Oyun()
while True:
Durum = Game.Game()
if Durum == "son":
break
A simple(but not most efficient) way to do this would be to move the background and all other assets, while keeping the player stationary.
# insert code in each object in background/assets
if right:
OBJECT.right() # code to change location
if left:
OBJECT.left() #code to change location
Also, off-topic, but it is easier to have a single direction variable with -1 for left, 0 for stationary, and 1 for right. You can also easily add speed to this, too, so keep this in mind and implement it if you can.
Related
This question already has answers here:
How to implement barriers to stop the player moving through walls
(1 answer)
Collision for Pygame Game Map
(2 answers)
Adding collision to maze walls
(1 answer)
How do I prevent the player from moving through the walls in a maze?
(3 answers)
Closed 7 months ago.
I'm trying to make a maze platformer game in pygame, but my player keeps jumping through the floor. I didn't find any good answers or tutorials to that problem. I hope to get an answer from here soon. I didn't add the player code, because StackOverflow thought my question was mostly code and the movements are not made by the player sprite, either. My previous question got deleted, but the "similar question" did not solve my problem at all. Here's my code...
Main code:
import pygame
from levels import Level
from misc import Background
from player import Player
from pygame.locals import (
RLEACCEL,
K_UP,
K_DOWN,
K_LEFT,
K_RIGHT,
K_ESCAPE,
KEYDOWN,
QUIT,
)
screen = pygame.display.set_mode((800,600))
clock = pygame.time.Clock()
player = Player()
background = pygame.Surface(screen.get_size())
bg = Background()
level = Level()
running = True
while running:
screen.blit(background, (0, 0))
bg.walling()
pressed_keys = pygame.key.get_pressed()
level.render()
level.move(pressed_keys)
player.update(pressed_keys)
screen.blit(player.surf, player.rect)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
pygame.display.flip()
clock.tick(100)
pygame.quit()
Map code:
import pygame
from pygame.locals import (
RLEACCEL,
K_UP,
K_DOWN,
K_LEFT,
K_RIGHT,
K_ESCAPE,
KEYDOWN,
QUIT,
)
from player import Player
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
player = Player()
class Level(pygame.sprite.Sprite):
def __init__(self):
super(Level, self).__init__()
self.level = 0
self.map1 = pygame.image.load("../misc/maps/level1.png").convert_alpha()
self.map1 = pygame.transform.scale(self.map1, (4000, 3000))
self.surf = pygame.Surface((4000, 3000))
self.rect = self.surf.get_rect(center=(500,1700))
self.map = self.map1
self.jumping = False
self.v = 10
self.m = 1
def render(self):
screen.blit(self.map, self.rect)
self.floorcolor = screen.get_at((400,402))
self.leftcolor = screen.get_at((380, 372))
self.rightcolor = screen.get_at((420,372))
self.upcolor = screen.get_at((400, 342))
def jump(self):
if self.jumping == False:
self.jumping = True
if self.jumping:
F = (1 / 2) * self.m * (self.v ** 2)
self.rect.move_ip(0,F)
self.v = self.v - 1
if self.v < 0:
self.m = -1
if self.v == -9:
self.jumping = False
self.v = 10
self.m = 1
def move(self, pressed_keys):
if pressed_keys[K_UP]:
self.jump()
if self.floorcolor != (88,88,88) and self.floorcolor != (64,64,64):
self.rect.move_ip(0, -4)
if self.leftcolor == (88,88,88) or self.leftcolor == (64,64,64):
self.rect.move_ip(-4,0)
if self.rightcolor == (88,88,88) or self.rightcolor == (64,64,64):
self.rect.move_ip(4,0)
if self.upcolor == (88,88,88) or self.upcolor == (64,64,64):
self.rect.move_ip(0,-4)
if pressed_keys[K_LEFT]:
self.rect.move_ip(4, 0)
if pressed_keys[K_RIGHT]:
self.rect.move_ip(-4, 0)
I am still a newbie to Python and I am following a tutorial on Youtube about Pygame. I came across an error while running Pygame. I tried looking up the solution here but it seems that my error is a bit different. Hoping for some insights from you guys on how to fix this.
# Character Class
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.velocity = 5
self.isJump = False
self.jumpCount = 10
self.left = False
self.right = False
self.walkCount = 0
self.standing = True
def draw(self, window):
# Draw Image
if self.walkCount + 1 >= 27:
self.walkCount = 0
if not (self.standing):
if self.left:
window.blit(walkLeft[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
elif self.right:
window.blit(walkRight[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
else:
if self.right:
window.blit(walkRight[0], (self.x, self.y))
else:
window.blit(walkLeft[0], (self.x, self.y))
# Projectile Class
def projectile(object):
def __init__(self, x, y, radius, color, facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.velocity = 8 * facing
def draw(self, window):
pygame.draw.circle(window, self.color, (self.x, self.y), self.radius)
# Game Function
def redrawGameWindow():
window.blit(background, (0, 0))
hero.draw(window)
for bullet in bullets:
bullet.draw(window)
pygame.display.update()
# Main Loop
hero = player(300, 410, 64, 64)
bullets = []
run = True
while run:
clock.tick(27)
# Check for events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# Bullets
for bullet in bullets:
if bullet.x < 500 and bullet.x > 0:
bullet.x += bullet.velocity
else:
bullets.pop(bullets.index(bullet))
# Movements
keys = pygame.key.get_pressed()
# Shoot Bullets
if keys[pygame.K_SPACE]:
if hero.left:
facing = -1
else:
facing = 1
if len(bullets) < 5:
bullets.append(projectile(round(hero.x + hero.width //2), round(hero.y + hero.height //2), 6, (0,0,0), facing))
The error that I receive was this:
bullets.append(projectile(round(hero.x + hero.width //2), round(hero.y + hero.height //2), 6, (0,0,0), facing))
TypeError: projectile() takes 1 positional argument but 5 were given
The code is defining a function projectile(), with a local-function __init__() - not a class.
# Projectile Class
def projectile(object): # <-- HERE
def __init__(self, x, y, radius, color, facing):
self.x = x
...
It just needs a minor syntax change:
# Projectile Class
class projectile(object): # <-- HERE
def __init__(self, x, y, radius, color, facing):
self.x = x
...
This probably should be a comment, not an answer, but it took me a few minutes to work it out myself, so I figured maybe it's worth a full answer.
I'm trying to get my character to change images once it reaches a certain distance from another character. Basically, if the character is 50 or more units away, she is set to walking mode, but if she is less than 50 units away, she is set to attack mode, which have their corresponding images/powersets.
I've tried while loops and adding other conditions
if sif.x - cap.x > 50 and sif.collideCount == 0:
sif.moveLeft() #cap is the other character
elif cap.x - sif.x > 50 and sif.collideCount == 0:
sif.moveRight()
elif cap.x - sif.x <= 50 and sif.collideCount == 0:
sif.punch = True
sif.right = True
sif.punchRight()
if sif.rect.colliderect(cap.rect):
sif.collideCount = 1
sif.collided = True
if sif.collided:
sif.moveLeft()
if sif.x < 30:
sif.moveRight()
sif.collideCount = 0
sif.collided = False
punch function
def punchRight(self):
self.img = pygame.image.load('sifpunch.png')
self.punch = True
self.right = True
self.left = False
self.x += self.vel
self.rect.x = self.x
screen.blit(self.img, (self.x,self.y))
draw function that contains the updated image:
def draw(self, screen):
elif self.punch and self.right:
self.img = pygame.image.load('sifpunch.png')
screen.blit(self.img, (self.x,self.y))
Pygame never ends up setting sif.punch to True, so Sif continues walking to the left and right instead of switching to attack mode.
i figured it out - I changed the boundary from 50 to 200. A 50 unit range was too small for the clip to show up in time.
I have tried to make a snake game using python's pygame. What I did was create 2 segments in the start at a particular distance this will be my snake and as it eats more objects it will grow. But I want my game to end when the snakes head collides with any other segment. I used sprite collide method to detect collision between snakes head(here snake_segment[0]) and the segment group.Here's the code which is relevant to my problem
class Segment(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([segment_width,segment_height])
self.image.fill(black)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# we create the apple object here
class Apple(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.transform.scale(apple1,(25,25))
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(30,screen_width-30)
self.rect.y = random.randrange(30,screen_height-30)
# we create the function for sprites so that we can manage all the sprites
all_sprites = pygame.sprite.Group()
segment_group = pygame.sprite.Group()
snake_segment = [] # we create this list to store all thhe segments
for i in range(0,2):
x = 250 - (segment_width+ segement_margin)*i
y= 30
segments =Segment(x,y)
snake_segment.append(segments)
all_sprites.add(segments)
segment_group.add(segments)
apple_group = pygame.sprite.Group()
apple =Apple()
apple_group.add(apple)
all_sprites.add(apple)
running = True
while running:
# we tweak the fps here
clock.tick(fps)
# we keep track of all the events here
for event in pygame.event.get():
# if the user wishes to quit
if event.type == pygame.QUIT:
running = False
# we set the movement of the segments
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
y_change = (segment_height + segement_margin)*-1
x_change=0
if event.key == pygame.K_DOWN:
y_change = (segment_height + segement_margin)
x_change= 0
if event.key == pygame.K_LEFT:
x_change = (segment_width + segement_margin)*-1
y_change = 0
if event.key == pygame.K_RIGHT:
x_change = (segment_width + segement_margin)
y_change = 0
# we remove the last element of the snake segment
old_segment = snake_segment.pop()
all_sprites.remove(old_segment)
# we add the new element on the top of the snake
x = snake_segment[0].rect.x + x_change
y = snake_segment[0].rect.y + y_change
segment = Segment(x,y)
snake_segment.insert(0,segment)
all_sprites.add(segment)
# here we detect collison between apple group and snake sprite and make changes
eat_coll = pygame.sprite.spritecollide(snake_segment[0],apple_group,True)
if eat_coll:
x = snake_segment[-1].rect.x - x_change
y = snake_segment[-1].rect.y - y_change
segment = Segment(x,y)
snake_segment.insert(-1,segment)
segment_group.add(segment)
apple = Apple()
apple_group.add(apple)
all_sprites.add(apple)
bite_sound.play()
snake_coll = pygame.sprite.spritecollide(snake_segment[0],segment_group,False)
if snake_coll:
running = False
# update each sprite
all_sprites.add(segment)
# here we fill the background
screen.blit(background_image,background_rect)
all_sprites.draw(screen)
# we will update the screen
pygame.display.update()
Just check if the snakes head is inside the snakes body.
def self_collision(self):
"""
Return True if head is inside the body
"""
return self.snake_segnment[0] in self.snake_segment[1:]
Im converting my small physics test code in pygame from using pairs of variables to describe position, velocity and acceleration into math.Vector2()'s. The reason being is obvious since there are a whole lot of methods relating to the Vector2 that make it easy to find the length, normalize, cross product so on and so forth.
In the pygame docs it also has a whole bunch of numerical operations it supports like vec*number, vec*=vec etc. However my issue has arisen when I start to use the vec+=vec or vec*=vec. I am getting this kind of error...
"malloc: * error for object 0x7fb4a1ec31a0: pointer being freed was not allocated"
If I comment out all those operations the code runs fine without animation of course. Is there a bug with Vector2() or am I just utilising it wrong?
import pygame, math, random
pygame.init()
class Circle(pygame.sprite.Sprite):
def __init__(self, screen):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.position = pygame.math.Vector2(random.randrange(20,self.screen.get_width()), self.screen.get_height()/3)
self.velocity = pygame.math.Vector2(0.0, 0.0)
self.acceleration = pygame.math.Vector2(0.0, 0.1)
self.netForce = pygame.math.Vector2(0.0, 0.0)
self.x = random.randrange(20,self.screen.get_width())
self.y = self.screen.get_height()/2
self.radius = random.randrange(5,30)
self.image = pygame.Surface((self.radius*2,self.radius*2))
self.image.set_colorkey((0,0,0))
self.image.set_alpha(120)
self.mass = self.radius/15.0
pygame.draw.circle(self.image, (175,255,0), (self.radius,self.radius), self.radius)
self.image = self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.center = self.position
def update(self):
self.calcPos()
self.checkBounds()
self.rect.center = self.position
self.netForce *= 0.0
def calcPos(self):
self.acceleration = self.netForce
self.velocity += self.acceleration
self.position += self.velocity
def applyForce(self, force):
force /self.mass
self.netForce += force
def checkBounds(self):
if self.position[1] > self.screen.get_height():
self.acceleration[1] *= -1.0
self.position[1] = self.screen.get_height()
if self.position[0] > self.screen.get_width():
self.acceleration[0] *= -1.0
self.position[0] = self.screen.get_width()
if self.position[1] < 0:
self.acceleration[1] *= -1.0
if self.position[0] < 0:
self.acceleration[0] *= -1.0
def main():
screen = pygame.display.set_mode((600,400))
background = pygame.Surface((screen.get_size()))
background.fill((150,150,150))
background = background.convert()
circleGRP = pygame.sprite.Group() #Add balls
for x in range(10):
circleGRP.add(Circle(screen))
wind = pygame.math.Vector2(1.0, 0)
gravity = pygame.math.Vector2(0, 1.0)
clock = pygame.time.Clock()
mainLoop = True
while mainLoop:
clock.tick(30) #Clock
for event in pygame.event.get(): #Key events
if event.type == pygame.QUIT:
mainLoop = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
mainLoop = False
elif event.type == pygame.MOUSEBUTTONDOWN: #Add wind
if pygame.mouse.get_pressed()[0]:
for circle in circleGRP:
circle.applyForce(wind)
#----------------------------------------------------------------------------
for circle in circleGRP: #Add gravity
gravity = gravity * circle.mass
circle.applyForce(gravity)
#pass
#circleX = circle.dx * -1 #Add drag
#circleY = circle.dy * -1
#drag = (circleX/80* circle.mass* (circle.radius/5), circleY/80* circle.mass* (circle.radius/5))
#circle.applyForce(drag)
#----------------------------------------------------------------------------
circleGRP.update()
screen.blit(background, (0,0))
circleGRP.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
Alternatively, you can use the Vec2d class that is given here.
It has operator overloading (can use with tuples or lists), uses slots for perforance, is picklable, implements list interface (so it's compatible with pygame functions), has a fair bit of high level vector operators (for performance and readability) and has unit tests built in.
I have worked with it in simulations and physics testings, and it provides all that you need.