So i have a problem where my character is drawn at the first frame and i am able to move and collect "ammo" with it but my character is invisible and i have no idea why it is happening.
Also tried to change something from Vector to rect but it does not works.
import pygame
from sys import exit
from pygame.math import Vector2
import random
pygame.init()
win = pygame.display.set_mode((800,600))
pygame.display.set_caption("Rectshooter")
clock = pygame.time.Clock()
game_active = True
class Player :
width = height = 50
def __init__(self,color=(255,0,0)):
self.body = Vector2(500,200)
self.color = color
self.direction = Vector2(0,0)
self.player_rect = pygame.Rect(self.body.x,self.body.y,self.width,self.height)
def draw(self):
#pygame.draw.rect(win,self.color,(self.body.x,self.body.y,self.width,self.height))
pygame.draw.rect(win, self.color, self.player_rect)
def move(self):
self.body += self.direction
class Player2 :
width = height = 50
def __init__(self,color=(255,0,0)):
self.body = Vector2(300,200)
self.color = color
self.direction = Vector2(0,0)
def draw(self):
pygame.draw.rect(win,self.color,(self.body.x,self.body.y,self.width,self.height))
def move(self):
self.body += self.direction
class Ammo:
width = height = 30
def __init__(self,x1,x2):
self.x = random.randint(x1,x2)
self.y = random.randint(50,550)
self.pos = Vector2(self.x,self.y)
self.ammo_rect = pygame.Rect(self.x,self.y,self.width,self.height)
def draw_ammo(self):
pygame.draw.ellipse(win,(255,100,00),self.ammo_rect)
player1 = Player()
player2 = Player2()
speed = 15 #player speed
ammo1 = Ammo(50,300)
ammo2 = Ammo(450,750)
print(ammo2.pos.x)
print(player1.body.x)
There is another problem with colliding, i wrote a long if statement for it and it works fine,but i want to make it with simple "player1.player_rect.colliderect(ammo2.ammo_rect)" if statement,but this only triggers when the ammo(random spawn) spwans at the location of the player,i mean the original location of the player that spawns at the first frame not the current location.
I am so confused,and i need a little help with it.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
#player1 key pressing movement
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player1.direction = Vector2(0,-speed)
if event.key == pygame.K_DOWN:
player1.direction = Vector2(0,speed)
if event.key == pygame.K_LEFT:
player1.direction = Vector2(-speed,0)
if event.key == pygame.K_RIGHT:
player1.direction = Vector2(speed,0)
#player2 key pressing movement
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player2.direction = Vector2(0,-speed)
if event.key == pygame.K_s:
player2.direction = Vector2(0,speed)
if event.key == pygame.K_a:
player2.direction = Vector2(-speed,0)
if event.key == pygame.K_d:
player2.direction = Vector2(speed,0)
if game_active:
#player1 preventing from going out of the screen and the middle line
if player1.body.y < 0:#up
player1.body.y = 0
player1.direction = Vector2(0,0)
if player1.body.x < 410:#left
player1.body.x = 410
player1.direction = Vector2(0,0)
if player1.body.y > 550:#down
player1.body.y = 550
player1.direction = Vector2(0,0)
if player1.body.x > 750:#right
player1.body.x = 750
player1.direction = Vector2(0,0)
#player2 preventing from going out of the screen and the middle line
if player2.body.y < 0:#up
player2.body.y = 0
player2.direction = Vector2(0,0)
if player2.body.x < 0:#left
player2.body.x = 0
player2.direction = Vector2(0,0)
if player2.body.y > 550:#down
player2.body.y = 550
player2.direction = Vector2(0,0)
if player2.body.x > 341:#right
player2.body.x = 341
player2.direction = Vector2(0,0)
#collide p1 with ammo1
if ammo2.pos.x + 20 > player1.body.x - 20 and ammo2.pos.x - 20 < player1.body.x + 20 and ammo2.pos.y + 20 > player1.body.y - 20 and ammo2.pos.y - 20 < player1.body.y + 20:
ammo2 = Ammo(450,750)
ammo2.draw_ammo()
print("collide")
if player1.player_rect.colliderect(ammo2.ammo_rect):
print("collide with start position")
#print(player1.body.x)
#print(player1.body.y)
win.fill((0, 0, 0))
pygame.draw.line(win, (255, 255, 255), (400, 600), (400, 0), 20)
#p1
player1.draw()
player1.move()
#p2
player2.draw()
player2.move()
#ammo
ammo1.draw_ammo()
ammo2.draw_ammo()
pygame.display.update()
clock.tick(60)
The player is drawn at the position stored in the player_rect attribute. When you change the body attribute, the position of the rectangle does not magically change. You need to update the position of the rectangle:
class Player :
width = height = 50
def __init__(self,color = (255,0,0)):
self.body = Vector2(500, 200)
self.color = color
self.direction = Vector2(0, 0)
self.player_rect = pygame.Rect(self.body.x, self.body.y, self.width, self.height)
def draw(self):
pygame.draw.rect(win, self.color, self.player_rect)
def move(self):
self.body += self.direction
# update player_rect
self.player_rect.x = round(self.body.x)
self.player_rect.y = round(self.body.y)
Related
This question already has an answer here:
Replace a rectangle with an Image in Pygame
(1 answer)
Closed last year.
So I don't know how to turn the rectangle representing the player into an image (spaceship). I know it must be simple, but after a few hours with this I'm a little frustrated, so I'm looking for help :(
bg_color = pygame.Color('black')
text_color = pygame.Color('darkgrey')
obstacles_color = pygame.Color('darkred')
player_color = pygame.Color('yellow')
fps = 60
window_height = 1200
window_width = 1200
player_speed = 4
player_size = 8
player_max_up = 125
obstacle_spawn_rate = 1
obstacle_min_size = 3
obstacle_max_size = 6
obstacle_min_speed = 2
obstacle_max_speed = 2
class Player:
def __init__(self):
self.size = player_size
self.speed = player_speed
self.color = player_color
self.position = (window_width / 2, (window_height - (window_height / 10)))
def draw(self, surface):
r = self.get_rect()
pygame.draw.rect(surface, self.color, r)
def move(self, x, y):
newX = self.position[0] + x
newY = self.position[1] + y
if newX < 0 or newX > window_width - player_size:
newX = self.position[0]
if newY < window_height - player_max_up or newY > window_height - player_size:
newY = self.position[0]
self.position = (newX, newY)
def collision_detection(self, rect):
r = self.get_rect()
return r.colliderect(rect)
def get_rect(self):
return pygame.Rect(self.position, (self.size, self.size))
class Obstacles:
def __init__(self):
self.size = random.randint(obstacle_min_size, obstacle_max_size)
self.speed = random.randint(obstacle_min_speed, obstacle_max_speed)
self.color = obstacles_color
self.position = (random.randint(0, window_width - self.size), 0 - self.size)
def draw(self, surface):
r = self.get_rect()
pygame.draw.rect(surface, self.color, r)
def move(self):
self.position = (self.position[0], self.position[1] + self.speed)
def is_off_window(self):
return self.position[1] > window_height
def get_rect(self):
return pygame.Rect(self.position, (self.size, self.size))
class World:
def __init__(self):
self.reset()
def reset(self):
self.player = Player()
self.obstacles = []
self.gameOver = False
self.score = 0
self.obstacles_counter = 0
self.moveUp = False
self.moveDown = False
self.moveLeft = False
self.moveRight = False
def is_game_over(self):
return self.gameOver
def update(self):
self.score += 1
if self.moveUp:
self.player.move(0, - player_speed)
if self.moveUp:
self.player.move(0, player_speed)
if self.moveLeft:
self.player.move(-player_speed, 0)
if self.moveRight:
self.player.move(player_speed, 0)
for each in self.obstacles:
each.move()
if self.player.collision_detection(each.get_rect()):
self.gameOver = True
if each.is_off_window():
self.obstacles.remove(each)
self.obstacles_counter += 1
if self.obstacles_counter > obstacle_spawn_rate:
self.obstacles_counter = 0
self.obstacles.append(Obstacles())
def draw(self, surface):
self.player.draw(surface)
for each in self.obstacles:
each.draw(surface)
def movement_keys(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.moveUp = True
if event.key == pygame.K_DOWN:
self.moveDown = True
if event.key == pygame.K_LEFT:
self.moveLeft = True
if event.key == pygame.K_RIGHT:
self.moveRight = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
self.moveUp = False
if event.key == pygame.K_DOWN:
self.moveDown = False
if event.key == pygame.K_LEFT:
self.moveLeft = False
if event.key == pygame.K_RIGHT:
self.moveRight = False
def run():
pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode((window_height, window_width))
pygame.display.set_caption("Avoid Obstacles")
surface = pygame.Surface(window.get_size())
surface = surface.convert()
world = World()
font = pygame.font.SysFont("Times", 35, "bold")
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key == ord("r"):
world.reset()
else:
world.movement_keys(event)
if not world.is_game_over():
world.update()
window.fill(bg_color)
clock.tick(fps)
world.draw(window)
surface.blit(surface, (0, 0))
text = font.render("Score {0}".format(world.score), 1, text_color)
window.blit(text, (1, 1))
if world.is_game_over():
end = font.render("The end of your journey", 1, text_color)
window.blit(end, (window_width / 2 - 220, window_height / 2))
restart = font.render("Hit R to reset", 1, text_color)
window.blit(restart, (window_width / 2 - 120, window_height / 2 + 45))
pygame.display.update()
if __name__ == '__main__':
run()
pygame.quit()
I tried changing the draw function in the Player class, but still couldn't figure out how to do it correctly. I'm drawing an image of the spaceship on the screen/window, but I can't get it to move to the player rectangle.
I don't know what you've tried, but here's how to do this with a call to blit:
myimage = pygame.image.load("bar.png")
...
def draw(self, surface):
r = self.get_rect()
surface.blit(myimage, r)
The key point here is that you're giving blit the same coordinates that you were using to draw the rectangle. When I tried this, I got the correct/natural size of the image even though the r rectangle is of different dimensions. If that turns out to cause a problem, you could adjust the dimensions of the rectangle to be the same as the image. You also might want to adjust the coordinates of r such that the image is drawn centered on the location at which you wish to draw it.
The 'draw' family of functions are convenience functions that create Surface objects and then paint pixels on it that correspond to basic shapes (like circles, rectangles etc, filled or otherwise).
Instead, you need to create a Surface where the pixels have been initialised via an image. For this, you need the "image" family of functions (see https://www.pygame.org/docs/ref/image.html for image functions).
Other than that, everything in pygame is a surface, and you're manipulating and updating surfaces on the display, so your code should not change, whether your surfaces were initialised via 'draw' or 'image'.
This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Simple drag physics, acting differently when moving left or right [duplicate]
(1 answer)
Closed 2 years ago.
Basically I am working on a simple platformer and I have all of the basics like the gravity, acceleration, and platforms, but for some reason the character will decelerate going right, but when it goes left it will continue moving slowly instead of stopping. I even printed the value of my variable "changeX" to see what was going on, and it showed me the values I that should be happening rather than what was displayed. Sorry my comments are very limited in their helpfulness. The code regarding variables rect.x , changeX, and accelX are likely the most relevant.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
COLOR = BLUE
#Top Speed
tSpeedX = 7
tSpeedY = 20
#gravity constant
gConstant = 1
#acceleration X variable
accelX = 0
#acceleration Y variable
accelY = 0
#whether you can jump or not
jumpB = True
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
#iniatilized values for rect
self.image = pygame.Surface([50, 50])
self.image.fill(COLOR)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.changeX = 0
self.changeY = 0
self.walls = None
#the velocity function. X and Y values are assigned based on the accelX
#and Y constants and added to the points of the rectangle
def velocity(self,x,y):
#change in speed
self.changeX += x
self.changeY += y
if abs(self.changeX) >= tSpeedX:
self.changeX = self.changeX/abs(self.changeX) * tSpeedX
if abs(self.changeY) >= tSpeedY:
self.changeY = self.changeY/abs(self.changeY) * tSpeedY
#standard update function. Will update rectangles position and deaccelerate it if no key held
def jump(self,y):
self.changeY = y
def update(self):
if accelX == 0:
self.changeX *= 0.92
if accelY == 0:
self.changeY *= .95
self.rect.x += self.changeX
print(self.changeX)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeX > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.changeY + (9*gConstant)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeY >= -5:
global jumpB
jumpB = True
COLOR = WHITE
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class wall(pygame.sprite.Sprite):
def __init__(self, sx, sy,px,py):
super().__init__()
#iniatilized values for walls
collision = False
self.image = pygame.Surface([sx, sy])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
self.rect.x = px
self.rect.y = py
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
spriteList = pygame.sprite.Group()
wallList = pygame.sprite.Group()
Player = player(100,100)
spriteList.add(Player)
Wall1 = wall(1000, 30, 0, 400)
Wall2 = wall(100, 30, 150, 350)
wallList.add(Wall2)
spriteList.add(Wall2)
wallList.add(Wall1)
spriteList.add(Wall1)
Player.walls = wallList
clock = pygame.time.Clock()
#Allows program to exit
quit = False
while not quit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True
#Sets accel values
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
accelX = -.25
if event.key == pygame.K_RIGHT:
accelX = .25
if event.key == pygame.K_UP and jumpB == True:
Player.jump(-20)
jumpB = False
COLOR = BLUE
if event.key == pygame.K_DOWN:
accelY = .25
#reverses accel values to allow for deaccleration
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
accelX = 0
if event.key == pygame.K_RIGHT:
accelX = 0
if event.key == pygame.K_UP:
accelY = 0
if event.key == pygame.K_DOWN:
accelY = 0
#calls function to move rectangle
Player.velocity(accelX, accelY)
spriteList.update()
screen.fill(BLACK)
spriteList.draw(screen)
pygame.display.flip()
clock.tick(60)
When I run my code the program says to me:
Traceback (most recent call last):
File "C:\Users\User\Documents\projects\two_player_gun_game.py", line 192, in <module>
if player_one_bullet.is_collided_with(player_two):
NameError: name 'player_one_bullet' is not defined
I do not understand why this reason comes up I have created a function in one of the classes which is is_collided_with but. it still seems not to work can. I have put at the bottom an if statement which checks for collisions. colllisions are meant to be happening for player 1 and 2's bullets.
Here is my code to help:
import pygame
import random
import sys
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock() # A clock to limit the frame rate.
pygame.display.set_caption("this game")
class Background:
picture = pygame.image.load("C:/images/space.jpg").convert()
picture = pygame.transform.scale(picture, (1280, 720))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
class player_first:
picture = pygame.image.load("C:/aliens/ezgif.com-crop.gif")
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
self.speed_x = 0
self.speed_y = 0
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
self.ypos += self.speed_y
def draw(self): #left right
#screen.blit(pygame.transform.flip(self.picture, True, False), self.rect)
screen.blit(self.picture, (self.xpos, self.ypos))
class player_second:
picture = pygame.image.load("C:/aliens/Giantmechanicalcrab2 - Copy.gif")
picture = pygame.transform.scale(picture, (300, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
self.speed_x = 0
self.speed_y = 0
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
self.ypos += self.speed_y
def draw(self): #left right
#screen.blit(pygame.transform.flip(self.picture, True, False), self.rect)
screen.blit(self.picture, (self.xpos, self.ypos))
class player_one_Bullet(pygame.sprite.Sprite):
picture = pygame.image.load("C:/aliens/giphy.gif").convert_alpha()
picture = pygame.transform.scale(picture, (100, 100))
def __init__(self):
self.xpos = 360
self.ypos = 360
self.speed_x = 0
super().__init__()
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
#self.screen.blit(pygame.transform.flip(self.picture, False, True), self.rect)
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
class player_two_Bullet(pygame.sprite.Sprite):
picture = pygame.image.load("C:/aliens/MajesticLavishBackswimmer-size_restricted.gif").convert_alpha()
picture = pygame.transform.scale(picture, (100, 100))
picture = pygame.transform.rotate(picture, 180)
def __init__(self):
self.xpos = 360
self.ypos = 360
self.speed_x = 0
super().__init__()
self.rect = self.picture.get_rect()
def update(self):
self.xpos -= self.speed_x
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
#self.screen.blit(pygame.transform.flip(self.picture, False, True), self.rect)
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
player_one = player_first(0, 0)
player_two = player_second(1000, 0)
cliff = Background(0, 0)
player_one_bullet_list = pygame.sprite.Group()
player_two_bullet_list = pygame.sprite.Group()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player_one.speed_y = -5
elif event.key == pygame.K_s:
player_one.speed_y = 5
elif event.key == pygame.K_UP:
player_two.speed_y = -5
elif event.key == pygame.K_DOWN:
player_two.speed_y = 5
elif event.key == pygame.K_SPACE:
player_one_bullet = player_one_Bullet()
player_one_bullet.ypos = player_one.ypos
player_one_bullet.xpos = player_one.xpos
player_one_bullet.speed_x = 14
player_one_bullet_list.add(player_one_bullet)
elif event.key == pygame.K_KP0:
player_two_bullet = player_two_Bullet()
player_two_bullet.ypos = player_two.ypos
player_two_bullet.xpos = player_two.xpos
player_two_bullet.speed_x = 14
player_two_bullet_list.add(player_two_bullet)
elif event.type == pygame.KEYUP:
# Stop moving when the keys are released.
if event.key == pygame.K_s and player_one.speed_y > 0:
player_one.speed_y = 0
elif event.key == pygame.K_w and player_one.speed_y < 0:
player_one.speed_y = 0
if event.key == pygame.K_DOWN and player_two.speed_y > 0:
player_two.speed_y = 0
elif event.key == pygame.K_UP and player_two.speed_y < 0:
player_two.speed_y = 0
if player_one_bullet.is_collided_with(player_two):
player_one_bullet.kill()
if player_two_bullet.is_collided_with(player_one):
player_two_bullet.kill()
player_one.update()
player_two.update()
cliff.draw()
player_one.draw()
player_two.draw()
player_one_bullet_list.update()
player_two_bullet_list.update()
for player_one_bullet in player_one_bullet_list:
player_one_bullet.draw()
for player_two_bullet in player_two_bullet_list:
player_two_bullet.draw()
pygame.display.flip()
clock.tick(60)
#IGNORE THIS
#player_one_bullet_list = pygame.sprite.Group()
#elif event.key == pygame.K_SPACE:
# player_one_bullet = player_one_Bullet()
#
# player_one_bullet.ypos = player_one.ypos
# player_one.xpos = player_one.xpos
#
# player_one_bullet.speed_x = 14
#
# player_one_bullet_list.add(player_one_bullet)
#
#
#player_one_bullet_list.update()
#
# for player_one_bullet in player_one_bullet_list:
# player_one_bullet.draw()
#if hammerhood.rect.colliderect(crab): #.rect.top
# hammerhood.speed_y = 0
When python complains about something not being defined, it typically means you are trying to use something which is not there or has not yet been made.
This is the only time you define 'player_one_bullet':
elif event.key == pygame.K_SPACE:
player_one_bullet = player_one_Bullet()`
So long as you do not press space, there are no bullets and 'player_one_bullet' remains undefined.
That is the reason why this piece of code gives an error:
if player_one_bullet.is_collided_with(player_two):
You cannot use something which does not exist!
Additionally only the last bullet fired from each player will check if it is hitting the other player, the other bullets will ignore everything!
Fortunately there is an easy way to fix it; instead of doing this:
if player_one_bullet.is_collided_with(player_two):
player_one_bullet.kill()
if player_two_bullet.is_collided_with(player_one):
player_two_bullet.kill()
You can use player_one_bullet_list and player_two_bullet_list to check if bullets exist and whether they are colliding!
for bullet in player_one_bullet_list.sprites():
if bullet.is_collided_with(player_two):
player_one_bullet.kill()
for bullet in player_two_bullet_list.sprites():
if bullet.is_collided_with(player_one):
player_two_bullet.kill()
Now you have a for loop that iterates through the list of bullets and if any exist only then it checks whether there is a collision.
Hope this helps you out!
new to pygame and game programming in general, just wondered how I could get a camera to follow a car (nothing fancy) in a top down car game - think Micro Machines! I'm using Python 3.6, and have got a bike rotating, and moving around. I've kept the code here shorter but I do have a static image for reference if the camera worked!
Here's what I have:
import pygame, math, sys, random
from pygame.locals import *
display_width = 1280
display_height = 800
# Sets size of screen
screen = pygame.display.set_mode((display_width, display_height))
# Initialises clock
clock = pygame.time.Clock()
# Colours
white = (255,255,255)
black = (0,0,0)
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
# Creates a vehicle class
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
# Creates object instance off
pygame.sprite.Sprite.__init__(self)
self.src_image = pygame.image.load(image)
self.position = position
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += (self.k_up +self.k_down)
if self.speed > self.MAX_FORWARD_SPEED:
self.speed = self.MAX_FORWARD_SPEED
if self.speed < -self.MAX_REVERSE_SPEED:
self.speed = -self.MAX_REVERSE_SPEED
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
x, y = self.position
rad = self.direction * math.pi / 180
x += -self.speed*math.sin(rad)
y += -self.speed*math.cos(rad)
self.position = (x, y)
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect()
self.rect.center = self.position
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
rect = screen.get_rect()
# Background
BackGround = Background('/home/pi/gametuts/images/backgrounds/bkg_img.png', [0, 0])
# Bike image load
bike = VehicleSprite('/home/pi/gametuts/images/BikePixelBig.png', rect.center)
bike_group = pygame.sprite.RenderPlain(bike)
# Ball image load
ball = VehicleSprite('/home/pi/gametuts/images/ironball.png', rect.center)
ball_group = pygame.sprite.RenderPlain(ball)
# Main game loop
def game_loop():
while 1:
#USER INPUT
# Sets frame rate
time = clock.tick(60)
for event in pygame.event.get():
if not hasattr(event, 'key'): continue
down = event.type == KEYDOWN
# Bike Input (Player 1)
if event.key == K_d: bike.k_right = down * -5
elif event.key == K_a: bike.k_left = down * 5
elif event.key == K_w: bike.k_up = down * 2
elif event.key == K_s: bike.k_down = down * -2
# Quit
elif event.key == K_ESCAPE: sys.exit(0)
#RENDERING
# Game background
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
# Bike render
bike_group.update(time)
bike_group.draw(screen)
ball_group.update(time)
ball_group.draw(screen)
pygame.display.flip()
game_loop()
pygame.quit()
quit()
Thanks in advance!
The simplest way to implement a camera is to use a pygame.math.Vector2 as the camera, subtract the player velocity from it each frame and add it to the position of all game elements during the blitting.
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, walls, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('dodgerblue'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.walls = walls
self.camera = Vector2(0, 0)
def update(self):
self.camera -= self.vel # Change the camera pos if we're moving.
# Horizontal movement.
self.pos.x += self.vel.x
self.rect.centerx = self.pos.x
# Change the rect and self.pos coords if we touched a wall.
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.x > 0:
self.rect.right = wall.rect.left
elif self.vel.x < 0:
self.rect.left = wall.rect.right
self.pos.x = self.rect.centerx
self.camera.x += self.vel.x # Also move the camera back.
# Vertical movement.
self.pos.y += self.vel.y
self.rect.centery = self.pos.y
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.y > 0:
self.rect.bottom = wall.rect.top
elif self.vel.y < 0:
self.rect.top = wall.rect.bottom
self.pos.y = self.rect.centery
self.camera.y += self.vel.y
class Wall(pg.sprite.Sprite):
def __init__(self, x, y, w, h, *groups):
super().__init__(*groups)
self.image = pg.Surface((w, h))
self.image.fill(pg.Color('sienna2'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
walls = pg.sprite.Group()
for rect in ((100, 170, 90, 20), (200, 100, 20, 140),
(400, 60, 150, 100), (300, 470, 150, 100)):
walls.add(Wall(*rect))
all_sprites.add(walls)
player = Player((320, 240), walls, all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_a:
player.vel.x = -5
elif event.key == pg.K_w:
player.vel.y = -5
elif event.key == pg.K_s:
player.vel.y = 5
elif event.type == pg.KEYUP:
if event.key == pg.K_d and player.vel.x > 0:
player.vel.x = 0
elif event.key == pg.K_a and player.vel.x < 0:
player.vel.x = 0
elif event.key == pg.K_w and player.vel.y < 0:
player.vel.y = 0
elif event.key == pg.K_s and player.vel.y > 0:
player.vel.y = 0
all_sprites.update()
screen.fill((30, 30, 30))
for sprite in all_sprites:
# Add the player's camera offset to the coords of all sprites.
screen.blit(sprite.image, sprite.rect.topleft+player.camera)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Edit: Here's your code example with a camera. I've also tried to improve a few more things, for example the max(min(...)) trick to clamp the speed value. I'm not sure if the movement works as you want, but you can of course adjust it yourself. (I'd probably make even more modifications to the update method.)
import math
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 800))
rect = screen.get_rect()
clock = pygame.time.Clock()
WHITE = pygame.Color('white')
# Load images globally and reuse them in your program.
# Also use the `.convert()` or `.convert_alpha()` methods after
# loading the images to improve the performance.
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((30, 30, 30))
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
self.src_image = image
self.image = image
self.rect = self.image.get_rect(center=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += self.k_up + self.k_down
# To clamp the speed.
self.speed = max(-self.MAX_REVERSE_SPEED,
min(self.speed, self.MAX_FORWARD_SPEED))
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
rad = math.radians(self.direction)
self.velocity.x = -self.speed*math.sin(rad)
self.velocity.y = -self.speed*math.cos(rad)
self.position += self.velocity
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect(center=self.position)
class Background(pygame.sprite.Sprite):
def __init__(self, image, location):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect(topleft=location)
def game_loop():
background = Background(BACKGROUND, [0, 0])
bike = VehicleSprite(VEHICLE1, rect.center)
ball = VehicleSprite(VEHICLE2, rect.center)
bike_group = pygame.sprite.Group(bike)
ball_group = pygame.sprite.Group(ball)
all_sprites = pygame.sprite.Group(bike_group, ball_group)
camera = pygame.math.Vector2(0, 0)
done = False
while not done:
time = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Bike Input (Player 1)
if event.key == pygame.K_d:
bike.k_right = -5
elif event.key == pygame.K_a:
bike.k_left = 5
elif event.key == pygame.K_w:
bike.k_up = 2
elif event.key == pygame.K_s:
bike.k_down = -2
elif event.key == pygame.K_ESCAPE:
done = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
bike.k_right = 0
elif event.key == pygame.K_a:
bike.k_left = 0
elif event.key == pygame.K_w:
bike.k_up = 0
elif event.key == pygame.K_s:
bike.k_down = 0
camera -= bike.velocity
all_sprites.update(time)
screen.fill(WHITE)
screen.blit(background.image, background.rect)
for sprite in all_sprites:
screen.blit(sprite.image, sprite.rect.topleft+camera)
pygame.display.flip()
game_loop()
pygame.quit()
I am trying to make my Sprite move on the screen, I have created function that should make it happen but it does not work> the problem lies in move_ip function, but I don't know how to fix it. These are my first attempts with classes so any suggestions are welcome.
import pygame
pygame.init()
finish = False
white = ( 255, 255, 255)
black = (0, 0, 0)
grey = (211, 211, 211)
font = pygame.font.Font("C:/Windows/Fonts/BRITANIC.TTF", 20)
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Game")
class Sprite(object):
def __init__(self, name):
self.health = 3
self.name = name
self.points = 0
self.x = 25
self.y = 25
def printName(self):
print (self.name)
class Dog(Sprite):
def __init__(self, name):
super(Dog, self).__init__(name)
self.dog_img = pygame.image.load("dog_left.png")
self.dog_rect = self.dog_img.get_rect()
def drawDog(self, screen):
screen.blit(self.dog_img, (self.x, self.y))
def takeBone(self, sp1, sp2):
takebone = pygame.sprite.collide_rect(sp1, sp2)
if takebone == True:
self.points += 1
def moving(self):
self.player_move_x = 0
self.player_move_y = 0
self.move = self.dog_img.move_ip(player_move_x, player_move_y)
class Bone(Sprite):
def __init__(self, name):
super(Bone, self).__init__(name)
self.neme = "Bone"
self.bone = pygame.image.load("bone.png")
self.bone_rect = self.bone.get_rect()
self.x = 250
self.y = 250
def drawBone(self, screen):
screen.blit(self.bone, (self.x, self.y))
end_pos = 170
player_x = 10
player_y = 10
background = pygame.image.load("grass.png")
background_rect = background.get_rect()
size = background.get_size()
screen2 = pygame.display.set_mode(size)
player = Dog("Tom")
bone = Bone("Bone")
timer = pygame.time.Clock()
while finish == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_move_x = -5
if event.key == pygame.K_RIGHT:
player_move_x = 5
if event.key == pygame.K_UP:
player_move_y = -5
if event.key == pygame.K_DOWN:
player_move_y = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player_move_x = 0
if event.key == pygame.K_RIGHT:
player_move_x = 0
if event.key == pygame.K_UP:
player_move_y = 0
if event.key == pygame.K_DOWN:
player_move_y = 0
screen.blit(background, background_rect)
player.drawDog(screen)
bone.drawBone(screen)
pygame.display.flip()
timer.tick(25)
pygame.quit()
I have made changes to my code:
import pygame
pygame.init()
finish = False
white = ( 255, 255, 255)
black = (0, 0, 0)
grey = (211, 211, 211)
font = pygame.font.Font("C:/Windows/Fonts/BRITANIC.TTF", 20)
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Game")
class Sprite(object):
def __init__(self, name):
self.health = 3
self.name = name
self.points = 0
self.x = 25
self.y = 25
def printName(self):
print (self.name)
class Dog(Sprite):
def __init__(self, name):
super(Dog, self).__init__(name)
self.dog_img = pygame.image.load("dog_left.png")
self.dog_rect = self.dog_img.get_rect()
def drawDog(self, screen):
screen.blit(self.dog_img, (self.x, self.y))
def takeBone(self, sp1, sp2):
takebone = pygame.sprite.collide_rect(sp1, sp2)
if takebone == True:
self.points += 1
def moving(self):
self.player_move_x = 0
self.player_move_y = 0
self.move = self.dog_rect.move_ip(self.player_move_x, self.player_move_y)
class Bone(Sprite):
def __init__(self, name):
super(Bone, self).__init__(name)
self.neme = "Bone"
self.bone = pygame.image.load("bone.png")
self.bone_rect = self.bone.get_rect()
self.x = 250
self.y = 250
def drawBone(self, screen):
screen.blit(self.bone, (self.x, self.y))
background = pygame.image.load("grass.png")
background_rect = background.get_rect()
size = background.get_size()
screen2 = pygame.display.set_mode(size)
player = Dog("Tom")
bone = Bone("Bone")
timer = pygame.time.Clock()
while finish == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.player_move_x = -5
if event.key == pygame.K_RIGHT:
self.player_move_x = 5
if event.key == pygame.K_UP:
player.dog_rect.move_ip(-5, 0)
player_move_y = -5
if event.key == pygame.K_DOWN:
self.player_move_y = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
self.player_move_x = 0
if event.key == pygame.K_RIGHT:
self.player_move_x = 0
if event.key == pygame.K_UP:
player.dog_rect.move_ip(0, 0)
player_move_y = 0
if event.key == pygame.K_DOWN:
self.player_move_y = 0
screen.blit(background, background_rect)
player.drawDog(screen)
player.moving()
bone.drawBone(screen)
pygame.display.flip()
timer.tick(25)
pygame.quit()
First of all, you shouldn't name your class Sprite, since the name collides with the Sprite class of pygame.
Also, if you want to work with the Rect class, your classes don't need a x and y field to store its position, since you can use the Rect for that.
Let's look at the moving function:
self.player_move_x = 0
self.player_move_y = 0
self.move = self.dog_rect.move_ip(self.player_move_x, self.player_move_y)
Here you set player_move_x and player_move_y to 0, then you want to move dog_rect with these values. Beside the fact that you never actually use dog_rect for blitting the image at the right position, moving a Rect by 0, 0 doesn't do anything.
There are some more errors in both code sample you've given, but your code should probably look like this (I added some comments for explanation):
import pygame
pygame.init()
background = pygame.image.load("grass.png")
background_rect = background.get_rect()
size = background.get_size()
# only call set_mode once
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Game")
# no need for three different classes
class MySprite(pygame.sprite.Sprite):
def __init__(self, name, img_path, pos):
super(MySprite, self).__init__()
self.name = name
self.image = pygame.image.load(img_path)
self.rect = self.image.get_rect(topleft=pos)
# use rect for drawing
def draw(self, screen):
screen.blit(self.image, self.rect)
# use rect for moving
def move(self, dir):
self.rect.move_ip(dir)
player = MySprite("Tom", "dog_left.png", (10, 10))
bone = MySprite("Bone", "bone.png", (250, 250))
timer = pygame.time.Clock()
def main():
points = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return points
# get all pressed keys
pressed = pygame.key.get_pressed()
# pressed[some_key] is 1 if the key some_key is pressed
l, r, u, d = [pressed[k] for k in pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s]
# create a tuple describing the direction of movement
# TODO: normalizing/different speed
player.move((-l + r, -u + d))
if pygame.sprite.collide_rect(player, bone):
points += 1
screen.blit(background, background_rect)
player.draw(screen)
bone.draw(screen)
pygame.display.flip()
timer.tick(25)
if __name__ == '__main__':
print main()
You don't seem to have any calls to moving from your main loop. This probably is the issue.