how can i check (easily) if two sprites are near each other - pygame

how can i check (easily) if two sprites are near each other like they have a 100 pixels difference between them and i need it to be something that doesn't require a lot of if's. the only thing i got to is doing a lot of if's and for my game (hexagon) i need it to be with not so many if's
def is_near(myPearl,bPearl):
if (abs(myPearl.rect.x - bPearl.rect.x) == 100 and abs(myPearl.rect.y - bPearl.rect.y) == 100) or abs(myPearl.rect.y - bPearl.rect.y) == 100 or myPearl.rect.x == bPearl.rect.x:
return 1 # 1 means that the pearl is near it and this pearl is next to the pushed pearl
if abs(myPearl.rect.x - bPearl.rect.x) == 200 or abs(myPearl.rect.y - bPearl.rect.y) == 200 or myPearl.rect.x == bPearl.rect.x:
return 2 # 2 means that the pearl is near it and this pearl is two slots near the pushed pearl

I'd check if the center of a sprite is within the radius of another sprite. You can use pg.math.Vectors and their distance_to method to get the distance and then look if it's less than the radius. In the following example I do this in the circle_collision function which is passed as a callback to pg.sprite.groupcollide. I needed the if left != right: test, so that sprites don't collide with themselves.
import sys
import pygame as pg
from pygame.math import Vector2
from pygame.color import THECOLORS
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((50, 30))
self.image.fill(THECOLORS['sienna1'])
self.rect = self.image.get_rect(center=pos)
self.radius = 100
def circle_collision(left, right):
if left != right:
distance = Vector2(left.rect.center).distance_to(right.rect.center)
return distance < left.radius
else:
return False
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
sprite_group = pg.sprite.Group()
player1 = Player((100, 300), sprite_group)
player2 = Player((400, 300), sprite_group)
player3 = Player((100, 100), sprite_group)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEMOTION:
player1.rect.center = event.pos
sprite_group.update()
collided_sprites = pg.sprite.groupcollide(
sprite_group, sprite_group, False, False,
collided=circle_collision)
# Draw everything.
screen.fill(THECOLORS['lemonchiffon4'])
sprite_group.draw(screen)
for collided_sprite in collided_sprites:
pg.draw.circle(screen, THECOLORS['lightcyan1'],
collided_sprite.rect.center,
collided_sprite.radius, 2)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
You could also give the sprites a second, larger rect and look if it collides with the rect of the other sprite. The code is pretty much the same, but pygame.rect.colliderect is used instead of the distance < radius check.
import sys
import pygame as pg
from pygame.color import THECOLORS
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((50, 30))
self.image.fill(THECOLORS['sienna1'])
self.rect = self.image.get_rect(center=pos)
self.vicinity_rect = self.rect.inflate(200, 200)
self.vicinity_rect.center = self.rect.center
def update(self):
self.vicinity_rect.center = self.rect.center
def vicinity_collision(left, right):
if left != right:
return left.vicinity_rect.colliderect(right.rect)
else:
return False
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
sprite_group = pg.sprite.Group()
player1 = Player((100, 300), sprite_group)
player2 = Player((400, 300), sprite_group)
player3 = Player((100, 100), sprite_group)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEMOTION:
player1.rect.center = event.pos
sprite_group.update()
collided_sprites = pg.sprite.groupcollide(
sprite_group, sprite_group, False, False,
collided=vicinity_collision)
# Draw everything.
screen.fill(THECOLORS['lemonchiffon4'])
sprite_group.draw(screen)
for collided_sprite in collided_sprites:
pg.draw.rect(screen, THECOLORS['lightcyan1'],
collided_sprite.vicinity_rect, 2)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

Related

Order class objects are displayed on the screen

I am very new to Python and Pygame, if anyone can help point me in the right direction I would really appreciate it :)
From what I understand, the order these are displayed determines how they will appear.
I need the "ticker" to appear in front of the other class object, "tickerchart" but I can't seem to figure out why it isn't working.
self.ticker_movement() is first on the list.
Can anyone tell me why the ticker is not showing up on top of the "tickerchart" image when it moves to the same space on the screen?
class Ticker:
def __init__(self, main_ticker_screen):
self.main_ticker_screen = main_ticker_screen
TICKER_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\ticker.png').convert_alpha()
self.TICKER = pygame.transform.scale(TICKER_IMAGE, (6, 95))
self.TICKER_x = 1277.5
self.TICKER_y = 841
self.TICKER_direction = 'none'
def move_right(self):
self.TICKER_direction = 'right'
def move_left(self):
self.TICKER_direction = 'left'
def stopmoving(self):
self.TICKER_direction = 'none'
def drawticker(self):
self.main_ticker_screen.fill(BLACK)
self.main_ticker_screen.blit(self.TICKER, (self.TICKER_x, self.TICKER_y))
pygame.display.flip()
def movement(self):
if self.TICKER_direction == 'right':
self.TICKER_x += 22
if self.TICKER_direction == 'left':
self.TICKER_x -= 22
if self.TICKER_direction == 'none':
self.TICKER_x = self.TICKER_x
self.drawticker()
class TickerChart:
def __init__(self, ticker_screen):
self.ticker_screen = ticker_screen
FORTY_ONE_LEFT_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\41.png').convert_alpha()
self.FORTY_ONE = pygame.transform.scale(FORTY_ONE_IMAGE, (6, 120))
def draw_tickerchart(self):
#greytickers #left - 40s
self.ticker_screen.blit(self.FORTY_ONE, (1079.5, 816))
pygame.display.flip()
class Game:
def __init__(self):
pygame.init()
self.surface = pygame.display.set_mode((2555, 1005))
pygame.display.set_caption("PBF SCORE")
self.surface.fill(BLACK)
SCOREBOARD_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\score_board.png').convert_alpha()
self.SCOREBOARD = pygame.transform.scale(SCOREBOARD_IMAGE, (1236, 700))
self.surface.blit(self.SCOREBOARD, (650, 0))
self.ticker = Ticker(self.surface)
self.ticker.drawticker()
self.tickerchart = TickerChart(self.surface)
self.tickerchart.draw_tickerchart()
def run(self):
running = True
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
if event.key == K_q:
self.ticker.move_right()
if event.key == K_o:
self.ticker.move_left()
if event.key == K_p:
self.ticker.stopmoving()
elif event.type == QUIT:
running = False
self.ticker.movement()
self.surface.blit(self.SCOREBOARD, (650, 0))
self.tickerchart.draw_tickerchart()
time.sleep(0.65)
if __name__ == "__main__":
game = Game()
game.run()
A possible problem might be that you arent calling for Ticket to be drawn every frame, only them the Game() class is initialized.
Put this in the run loop:
class Game:
def __init__(self):
pygame.init()
self.surface = pygame.display.set_mode((2555, 1005))
pygame.display.set_caption("PBF SCORE")
self.surface.fill(BLACK)
SCOREBOARD_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\score_board.png').convert_alpha()
self.SCOREBOARD = pygame.transform.scale(SCOREBOARD_IMAGE, (1236, 700))
self.surface.blit(self.SCOREBOARD, (650, 0))
self.ticker = Ticker(self.surface)
self.ticker.drawticker()
self.tickerchart = TickerChart(self.surface)
self.tickerchart.draw_tickerchart()
def run(self):
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_q:
self.ticker.move_right()
if event.key == pygame.K_o:
self.ticker.move_left()
if event.key == pygame.K_p:
self.ticker.stopmoving()
elif event.type == pygame.QUIT:
running = False
self.ticker.movement()
self.surface.blit(self.SCOREBOARD, (650, 0))
self.tickerchart.draw_tickerchart() # just add this line!!
time.sleep(0.65)
if __name__ == "__main__":
game = Game()
game.run()
I ran this and it seemed to work fine, the ticker (the moving object i presume) does apear and it does move around.
You just need to change ONE line of code in the Game class.

How to make my sprite shoot fireballs (bullets) in pygame?

This is my Sprite1.py program which I import to my main.py program. It contains all the classes I use in my main.py. I tried to create bullets based on a program I saw online but it doesn't work for me. Could anyone help me figure out how to successfully make it work? I don't know how to add the Bullet class from my Sprite.py program to the main.py one.
import pygame
import sys
import os
import time
import random
from pygame import mixer
from pygame.locals import *
def showStartScreen(surface):
show = True
while show == True:
startbg = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
surface.blit(startbg, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
show = False
pygame.init()
class Player(pygame.sprite.Sprite):
'''
Spawn a player
'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
super().__init__()
self.movex = 0
self.movey = 0
self.frame = 0
self.images = []
self.imagesleft = []
self.imagesright = []
self.alpha = (0,0,0)
self.ani = 4 # animation cycles
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
#self.rect = self.image.get_rect(center=pos)
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.bullets = bullets
self.bullet_timer = .1
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
#self.rect = self.image.get_rect(center=pos)
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.bullets = bullets
self.bullet_timer = .1
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey -= y
self.bullets
def update(self, dt):
'''
Update sprite position
'''
self.rect.center = pg.mouse.get_pos()
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
mouse_pressed = pg.mouse.get_pressed()
self.bullet_timer -= dt # Subtract the time since the last tick.
if self.bullet_timer <= 0:
self.bullet_timer = 0 # Bullet ready.
if mouse_pressed[0]: # Left mouse button.
# Create a new bullet instance and add it to the groups.
Bullet(pygame.mouse.get_pos(), self.all_sprites, self.bullets)
self.bullet_timer = .1 # Reset the timer.
class Bullet(pygame.sprite.Sprite):
def __init__(self, pos, *sprite_groups):
super().__init__(*sprite_groups)
BULLET_IMG = pygame.image.load(os.path.join('images','fireball.png')).convert_alpha()
self.image = BULLET_IMG
self.rect = self.image.get_rect(center=pos)
self.pos = pygame.math.Vector2(pos)
self.vel = pygame.math.Vector2(0, -450)
self.damage = 10
def update(self, dt):
# Add the velocity to the position vector to move the sprite.
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if self.rect.bottom <= 0:
self.kill()
This is my main.py program
import pygame
import os
import time
from pygame import mixer
from pygame.locals import *
import Sprite1
width = 960
height = 720
fps = 40 # frame rate
#ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISLAYSURF = pygame.display.set_mode((width,height))
surface = pygame.display.set_mode([width,height])
pygame.display.set_caption('B.S.G.!!!')
background = pygame.image.load(os.path.join('images','Bg.png')).convert()
backdropbox = surface.get_rect()
pygame.mixer.music.load('.\\sounds\\Fairy.mp3')
pygame.mixer.music.play(-1, 0.0)
player = Sprite1.Player() # spawn player
fire = Sprite1.Bullet()
player.rect.x = 50
player.rect.y = 500
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
Sprite.showStartScreen(surface)
while main == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
main = False
#if event.type == pygame.MOUSEBUTTONDOWN:
#if Bullet.bullet_timer <= 0:
#Bullet.bullet_timer = 0 # Bullet ready.
#if mouse_pressed[0]: # Left mouse button.
## Create a new bullet instance and add it to the groups.
#Bullet(pg.mouse.get_pos(), self.all_sprites, self.bullets)
#Bullet.bullet_timer = .1 # Reset the timer.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.control(-steps,0)
if event.key == pygame.K_RIGHT:
player.control(steps,0)
if event.key == pygame.K_UP:
player.rect.y -= 100
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.control(steps,0)
if event.key == pygame.K_RIGHT:
player.control(-steps,0)
if event.key == pygame.K_UP:
player.rect.y += 100
if event.key == ord('q'):
pygame.quit()
sys.exit()
main = False
surface.blit(background, (0, 0))
player.update()
player_list.draw(surface) #refresh player position
pygame.display.flip()
clock.tick(fps)
You already import the sprite file in your main.py on line 6:
import Sprite1
So now your code can call functions from this file:
Sprite1.showStartScreen( window )
Alternatively, instead on line 6 you could use:
from Sprite1 import *
And then your code can reference everything in Sprite1.py as if it was defined in the main.py itself.
The import section of the Python Documentation makes for fairly dry reading, but might just be worth a quick look if you get stuck.
Your bullet sprite code looks mostly OK now, and should work. It seems to be adding the newly created sprite to a bullets - which should be a SpriteGroup, but the supplied code does not show a definition of this.
Typically to move the bullet sprites, the code would call bullets.update() inside the main loop every frame. I can see the code calling player.update() in the last few lines of the main loop. Maybe it just needs a similar call to update() for the bullets group.

How do i make the player look like in the back of the tree? [duplicate]

This question already has answers here:
Pygame image transparency confusion
(1 answer)
How can I make an Image with a transparent Backround in Pygame?
(2 answers)
Closed last year.
i have this python with pygame please don't mind the comment with ignore. every things work fine but i need to know how to make the player lower than the tree. I already tried to display character first and then the tree but the problem is when i import another TILED TMX it has a blackbackground i don't see the setting of being transparent.
brief information: LoadFileMap is where tmx opened and then it display the map here:
makemaps = LoadFileMap.make_map(scroll[0],scroll[1])
display.blit(makemaps,(0,0))
Example
my Main code:
import pygame, sys, os, random, math
clock = pygame.time.Clock()
from pygame.locals import *
import data.engine as e
import data.Mapload as Map
import data.Makemap as M
#Setting of the Windows
pygame.init()
pygame.display.set_caption("Pineapple")
WINDOWS_SIZE = (800, 608)
screen = pygame.display.set_mode(WINDOWS_SIZE,0,32)
display=pygame.Surface((304,256))
# pygame.mouse.set_visible(False)
#Loading the Animations & Particles
e.load_animations('data/images/Entities/')\
#Create random map
# LoadFileMap = Map.createfileworld("data/Map") Ignore
LoadFileMap = M.TilledMap('data/untitled.tmx')
tile_rects=[]
#Variables for the character
'''Player Status'''
for tile_object in LoadFileMap.tmxdata.objects:
if tile_object.name == 'Player':
player = e.entity(tile_object.x,tile_object.y,14,26,'player')
if tile_object.name == 'Tree':
tile_rects.append(pygame.Rect(tile_object.x,tile_object.y,tile_object.width,tile_object.height))
'''Camera'''
true_scroll = [player.x-304/2,player.y-256/2]
'''Character Movement'''
moving_right = False
moving_left = False
moving_up = False
moving_down =False
while True:
display.fill((146,244,255))
#Scroll Camera movement
true_scroll[0] += ((player.get_center()[0]-304/2)-true_scroll[0])/10
true_scroll[1] += ((player.get_center()[1]-256/2)-true_scroll[1])/10
if true_scroll[0] < 0:
true_scroll[0] = 0
if true_scroll[0] > 496:
true_scroll[0] = 496
if true_scroll[1] > 544:
true_scroll[1] = 544
if true_scroll[1] < 0:
true_scroll[1] = 0
scroll = true_scroll.copy()
scroll[0] = int(scroll[0])
scroll[1] = int(scroll[1])
#Rendering the map and rects
makemaps = LoadFileMap.make_map(scroll[0],scroll[1])
display.blit(makemaps,(0,0))
#Character Movement
player_movement = [0,0]
if moving_up == True:
player_movement[1] -= 2
if moving_down == True:
player_movement[1] += 2
if moving_right == True:
player_movement[0] += 2
if moving_left == True:
player_movement[0] -= 2
collision_types= player.move(player_movement,tile_rects)
player.display(display,scroll)
#Buttons
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_d:
moving_right = True
if event.key == K_a:
moving_left = True
if event.key == K_w:
moving_up = True
if event.key == K_s:
moving_down =True
if event.type == KEYUP:
if event.key == K_d:
moving_right = False
if event.key == K_a:
moving_left = False
if event.key == K_w:
moving_up = False
if event.key == K_s:
moving_down =False
screen.blit(pygame.transform.scale(display,WINDOWS_SIZE),(0,0))
pygame.display.update()
clock.tick(60)
this is the file where it renders the map (Makemaps.py)
import pygame, sys, os
from pygame.locals import *
import pytmx
class TilledMap:
def __init__(self, filename):
tm = pytmx.load_pygame(filename, pixelalpha=True)
self.width= tm.width*tm.tilewidth
self.height= tm.height*tm.tileheight
self.tmxdata = tm
def render(self,Surface,scrollx,scrolly):
ti = self.tmxdata.get_tile_image_by_gid
for layer in self.tmxdata.visible_layers:
test = str(layer)
if isinstance(layer,pytmx.TiledTileLayer):
for x, y, gid, in layer:
tile = ti(gid)
if tile:
Surface.blit(tile,(x*self.tmxdata.tilewidth-scrollx,y*self.tmxdata.tileheight-scrolly))
def make_map(self,scrollx,scrolly):
temp_surface = pygame.Surface((self.width,self.height))
self.render(temp_surface,scrollx,scrolly)
return temp_surface
class obstacle:
def __init__(game,x,y,w,h):
self.group = game.Tree
# pygame.sprite.Sprite.__init__(self.groups)
self.game = game
self.rect = pygame(x,y,w,h)
self.x = x
self.y = y
self.rect.x=x
self.rect.y=y

Pygame character face mouse

I am creating a basic 2d overhead view game, and am currently working to make the character "face" the mouse as I move it.
Here is my code so far:
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super(Player,self).__init__()
self.image=player_image
self.original_image=self.image
self.rect=self.image.get_rect(center=(x,y))
self.change_x=0
self.change_y=0
self.speed=7.5
self.inventory={'wood':0}
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self,rect):
player.rotate()
self.rect.x+=self.change_x
self.rect.y+=self.change_y
screen.blit(self.image,(rect.x,rect.y))
def check(self):
global tick
if pygame.mouse.get_pressed()[0]:
for tree in resources:
tree_rect=tree.rect
if self.rect.colliderect(tree_rect) and tick>=9:
self.inventory['wood']+=1
tick=0
def rotate(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - self.rect.x, mouse_y -self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = pygame.transform.rotate(self.original_image, int(angle))
self.rect = self.image.get_rect(center=(self.rect.x,self.rect.y))
To do this, I followed this answer. It supposedly calculated the vector between the mouse and the player, and turned the character around toward the mouse each step, but for me the sprite wobbled around when the mouse moved, and turned invisible.
Full code:
import pygame
from pygame.locals import *
import sys
import math
import pygame.gfxdraw
import random
pygame.init()
black=(0,0,0)
white=(255,255,255)
forest=(34,139,34)
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
light_green=(0,120,0)
dark_green=(0,90,0)
skin=(255,224,189)
yellow=(255,255,0)
wood_image=pygame.image.load('./assets/images/wood.png')
stone_image=pygame.image.load('./assets/images/stone.png')
player_image=pygame.image.load('./assets/images/player.png')
tick=0
def terminate():
pygame.quit()
sys.exit()
def drawTextcenter(text,font,screen,x,y,color):
textobj=font.render(text,True,color)
textrect=textobj.get_rect(center=(x,y))
screen.blit(textobj,textrect)
def drawText(text, font, surface, x, y,color):
textobj=font.render(text, 1, color)
textrect=textobj.get_rect()
textrect.topleft=(x, y)
surface.blit(textobj, textrect)
class Button(object):
global screen_width,screen_height,screen
def __init__(self,x,y,width,height,text_color,background_color,text):
self.rect=pygame.Rect(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.text=text
self.text_color=text_color
self.background_color=background_color
self.angle=0
def check(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def draw(self):
pygame.draw.rect(screen, self.background_color,(self.rect),0)
drawTextcenter(self.text,font,screen,self.x+self.width/2,self.y+self.height/2,self.text_color)
pygame.draw.rect(screen,self.text_color,self.rect,3)
class Bar(object):
def __init__(self,x,y,length,color):
self.rect=pygame.Rect(x,y,length,17.5)
self.image=pygame.draw.rect(screen,white,(self.rect),)
self.x=x
self.y=y
self.width=100
self.height=17.5
self.color=color
self.multiplier=length/100
def draw(self,num):
rect=pygame.Rect(self.x,self.y,num*self.multiplier,self.height)
pygame.draw.rect(screen,self.color,self.rect,3)
pygame.draw.rect(screen,self.color,rect,0)
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super(Player,self).__init__()
self.image=player_image
self.original_image=self.image
self.rect=self.image.get_rect(center=(x,y))
self.change_x=0
self.change_y=0
self.speed=7.5
self.inventory={'wood':0}
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self,rect):
self.rotate(camera)
self.rect.x += self.change_x
self.rect.y += self.change_y
rect = camera.apply(self)
screen.blit(self.image, rect)
def check(self):
global tick
if pygame.mouse.get_pressed()[0]:
for tree in resources:
tree_rect=tree.rect
if self.rect.colliderect(tree_rect) and tick>=9:
self.inventory['wood']+=1
tick=0
def rotate(self,camera):
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_x -= camera.state.x
mouse_y -= camera.state.y
rel_x, rel_y = mouse_x - self.rect.centerx, mouse_y -self.rect.centery
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Tree(pygame.sprite.Sprite):
def __init__(self,x,y):
super(Tree,self).__init__()
self.rect=pygame.Rect(x,y,100,100)
self.rect.x=x
self.rect.y=y
def update(self,rect):
pygame.gfxdraw.filled_circle(screen,rect.x,rect.y,80,light_green)
pygame.gfxdraw.aacircle(screen,rect.x,rect.y,80,light_green)
class Rock(pygame.sprite.Sprite):
def __init__(self):
pass
class Camera(object):
def __init__(self,camera_func,width,height):
self.camera_func=camera_func
self.state=pygame.Rect(0,0,width,height)
def apply(self,target):
return target.rect.move(self.state.topleft)
def update(self,target):
self.state=self.camera_func(self.state,target.rect)
def complex_camera(camera, target_rect):
l, t = target_rect.center
_,_,w,h = camera
l,t,_,_ = -l+screen_width/2, -t+screen_height/2, w, h
l = min(0, l)
l = max(-(camera.width-screen_width), l)
t = max(-(camera.height-screen_height), t)
t = min(0, t)
return pygame.Rect(l, t, w, h)
clock=pygame.time.Clock()
font=pygame.font.SysFont(None,40)
screen_width=1440
screen_height=800
screen=pygame.display.set_mode([screen_width,screen_height])
pygame.display.set_caption('Survival')
total_level_width=screen_width*5
total_level_height=screen_height*5
camera = Camera(complex_camera, total_level_width, total_level_height)
player=Player(random.randint(100,7900),random.randint(100,5900))
friendlies=pygame.sprite.Group()
friendlies.add(player)
player_health_bar=Bar(125,15,200,green)
player_health=100
player_food_bar=Bar(437.5,15,200,red)
player_food=100
player_thirst_bar=Bar(750,15,200,blue)
player_thirst=100
player_energy_bar=Bar(1100,15,200,yellow)
player_energy=100
resources=pygame.sprite.Group()
wood=False
inventory={}
for i in range(1000):
tree=Tree(random.randint(100,7900),random.randint(100,5900))
resources.add(tree)
done1=False
while not done1:
screen.fill(black)
font=pygame.font.SysFont(None, 90)
text_width,text_height=font.size('Survival')
drawText('Survival', font, screen, (screen_width/2-text_width/2), (screen_height / 2-375),white)
font=pygame.font.SysFont(None, 40)
start_button=Button(screen_width/2-125,650,250,50,white,black,'Start')
start_button.draw()
back_button=Button(screen_width/2-125,725,250,50,white,black,'Back')
back_button.draw()
pygame.display.flip()
done2=False
while not done2:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if start_button.check()==True:
done3=False
pause_back=False
while not done3:
tick+=1
for event in pygame.event.get():
if event.type==pygame.QUIT:
terminate()
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_a:
player.changespeed(-(player.speed), 0)
elif event.key==pygame.K_d:
player.changespeed(player.speed, 0)
elif event.key==pygame.K_w:
player.changespeed(0, -(player.speed))
elif event.key==pygame.K_s:
player.changespeed(0, player.speed)
elif event.key==pygame.K_p:
font=pygame.font.SysFont(None, 90)
text_width,text_height=font.size('Paused')
drawText('Paused', font, screen, (screen_width / 2-(text_width/2)), (screen_height / 2-375),white)
resume_button=Button(screen_width/2-125,650,250,50,white,black,'Resume')
resume_button.draw()
back_button.draw()
pygame.display.flip()
back=False
while not back:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if resume_button.check()==True:
back=True
elif back_button.check()==True:
done3=True
done2=True
pause_back=True
back=True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.changespeed(player.speed, 0)
elif event.key == pygame.K_d:
player.changespeed(-(player.speed), 0)
elif event.key == pygame.K_w:
player.changespeed(0, player.speed)
elif event.key == pygame.K_s:
player.changespeed(0, -(player.speed))
camera.update(player)
if player.rect.x<0:
player.rect.x=0
if player.rect.right>total_level_width:
player.rect.right=total_level_width
if player.rect.y<0:
player.rect.y=0
if player.rect.bottom>total_level_height:
player.rect.bottom=total_level_height
screen.fill(dark_green)
player.update(camera)
for resource in resources:
resource.update(camera.apply(resource))
player_health_bar.draw(player_health)
player_food_bar.draw(player_food)
player_thirst_bar.draw(player_thirst)
#player_endergy_bar.draw(player_energy)
font=pygame.font.SysFont(None, 40)
drawText('Health:',font,screen,20,10,green)
drawText('Food:',font,screen,350,10,red)
drawText('Thirst:',font,screen,650,10,blue)
#drawText('Energy:', font, screen, 975, 10, yellow)
pygame.draw.rect(screen,forest,(50,675,100,100))
pygame.draw.rect(screen,forest,(175,675,100,100))
pygame.draw.rect(screen,forest,(300,675,100,100))
#player.check()
for item in player.inventory:
if item=='wood' and player.inventory['wood']>0:
wood=True
if wood:
screen.blit(wood_image,(62.5,687.5))
drawTextcenter(str(player.inventory['wood']),font,screen,100,735,black)
pygame.display.flip()
clock.tick(100)
if pause_back==True:
break
if pause_back==True:
break
screen.fill(black)
font=pygame.font.SysFont(None, 90)
text_width,text_height=font.size("Game Over")
drawText('Game Over', font, screen, (screen_width/2-text_width/2), (screen_height / 2-200),white)
font=pygame.font.SysFont(None, 40)
retry_button=Button(screen_width/2-125,650,250,50,white,black,'Retry')
retry_button.draw()
back_button.draw()
pygame.display.flip()
back=False
while not back:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if retry_button.check()==True:
back=True
if back_button.check()==True:
back=True
done2=True
done3=True
elif back_button.check()==True:
done2=True
done1=True
I haven't checked out your complete program because it's too much code, but I can see a mistake in the Player class. You're assigning the (self.rect.x,self.rect.y) (the top left) coordinates to the center of the new rect in the rotate method, but you have to assign the center coords of the previous rect.
self.rect = self.image.get_rect(center=(self.rect.x,self.rect.y))
Change the line above to:
self.rect = self.image.get_rect(center=self.rect.center)
Here's a minimal, complete example:
import math
import pygame as pg
class Player(pg.sprite.Sprite):
def __init__(self, pos):
super(Player,self).__init__()
x, y = pos
self.image = pg.Surface((50, 30), pg.SRCALPHA)
pg.draw.polygon(
self.image,
pg.Color('dodgerblue1'),
((1, 1), (49, 15), (1, 29)))
self.original_image = self.image
self.rect=self.image.get_rect(center=(x,y))
self.change_x=0
self.change_y=0
self.speed=7.5
self.inventory={'wood':0}
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self):
self.rotate()
self.rect.x+=self.change_x
self.rect.y+=self.change_y
def rotate(self):
mouse_x, mouse_y = pg.mouse.get_pos()
rel_x, rel_y = mouse_x - self.rect.x, mouse_y -self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = pg.transform.rotate(self.original_image, angle)
# rect.x and .y are the topleft coords, but you need the to
# pass the center coordinates of the previous rect to the new one.
self.rect = self.image.get_rect(center=self.rect.center)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
player = Player((300, 200))
all_sprites.add(player)
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.change_x = 4
elif event.key == pg.K_a:
player.change_x = -4
elif event.type == pg.KEYUP:
if event.key == pg.K_d:
player.change_x = 0
elif event.key == pg.K_a:
player.change_x = 0
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
The problem is caused by the camera. You have to apply the camera offset to the mouse position as well.
Here's a simple solution. First, pass the camera instead of the rect to the player.update method.
player.update(camera)
Pass it to the rotate method as well.
def update(self, camera):
self.rotate(camera)
self.rect.x += self.change_x
self.rect.y += self.change_y
rect = camera.apply(self)
screen.blit(self.image, rect)
In the rotate method you have to subtract the camera position from the mouse position to get the world coordinates.
def rotate(self, camera):
mouse_x, mouse_y = pygame.mouse.get_pos()
# Subtract the camera offset from the mouse position.
mouse_x -= camera.state.x
mouse_y -= camera.state.y
# Use the center coordinates of the rect.
rel_x, rel_y = mouse_x - self.rect.centerx, mouse_y -self.rect.centery
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.original_image, angle)
# Set the new center to the previous center coords.
self.rect = self.image.get_rect(center=self.rect.center)
I also had to modify the complex_camera function, because it should work with the center coordinates.
def complex_camera(camera, target_rect):
# The camera works with the center instead of
# the topleft coordinates now.
l, t = target_rect.center
_,_,w,h = camera
l,t,_,_ = -l+screen_width/2, -t+screen_height/2, w, h
l = min(0, l)
l = max(-(camera.width-screen_width), l)
t = max(-(camera.height-screen_height), t)
t = min(0, t)
return pygame.Rect(l, t, w, h)

Pygame, why does my rectangle not move

I don't get why the rectangle is not changing it's y position when i press the up key. I don't get any errors and everything is showing up.
import pygame
from pygame.locals import *
class SnekHead(object):
def __init__(self, screensize):
self.screensize = screensize
self.center_x = int(screensize[0]*0.5)
self.center_y = int(screensize[1]*0.5)
self.width = 50
self.height = 50
self.rect = pygame.Rect(self.center_x-25, self.center_y-50, self.width, self.height)
self.color = (100, 255, 100)
self.speed = 10
self.direction = 0
def update(self):
self.center_y += self.direction*self.speed
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect, 0)
def run_game():
pygame.init()
screensize = (640, 480)
background_image = pygame.image.load('Sky_back_layer.png')
screen = pygame.display.set_mode(screensize)
clock = pygame.time.Clock()
snake = SnekHead(screensize)
running = True
while running:
clock.tick(64)
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.key == K_UP:
snake.direction = -1
snake.update()
screen.blit(background_image, (0, 0))
snake.render(screen)
pygame.display.flip()
pygame.quit()
run_game()
Ask yourself this question. What is the value of self.rect after the key is pressed? (You decrement snake.direction when the key is pressed, then you update snake.center_y, but snake.rect remains the same and so does the position of the rectangle because that is what you are passing to pygame.draw.rect() in your render() function)