Why Ursina collider doesn't work properly? - python

I create an object:
class Tube(Entity):
def __init__(self, position):
super().__init__(
model = 'quad',
color = color.white,
position = position,
scale = Vec2(0.6,6),
collider = 'box'
and a ball object:
class Ball(Entity):
def __init__(self, color, position, neuronWeights):
super().__init__(
model = 'circle',
color = color,
position = position,
scale = 0.4,
collider = 'sphere'
)
self.tube = 0
self.speed = 0
def update(self):
# Move
self.y -= self.speed*time.dt
self.speed += 8*time.dt
# Update tube ID
if tubes[self.tube].upTube.x +1 <= self.x:
self.tube += 1
# Get tube coordinates
tubeX = tubes[self.tube].upTube.x
tubeY = tubes[self.tube].y_position
tubeX -= self.x
tubeY -= self.y
# Check position
if self.y <= -4 or self.y >= 4:
self.disable()
# Hit
hit_info = self.intersects(ignore=(self,),debug=True)
if str(hit_info.entity) == 'tube':
print(hit_info.entities)
self.disable()
def jump(self):
self.speed = -4
Then I use the "intersects" method to check the collision:
hit_info = self.intersects(ignore=(self,),debug=True)
if str(hit_info.entity) == 'tube':
self.disable()
But every time a "ball" pass the "tube" x coordinate (even when the ball is under the tube and doesn't touch it, like the image below) it say they ara intersects.
How can I fix it?
Here the entire code (I removed only some functions that I had created in my opinion useless to bring back here):
from ursina import *
from random import *
from math import *
app = Ursina()
tubes = []
balls = []
start = True
gen = 1
ballsPerGen = 50
tubeDistance = 4
tubeSpace = 1
class Ball(Entity):
def __init__(self, color, position, neuronWeights):
super().__init__(
model = 'circle',
color = color,
collider = 'box',
position = position,
scale = 0.4
)
self.tube = 0
self.speed = 0
self.neuron = Neuron(neuronWeights[0],neuronWeights[1],neuronWeights[2],neuronWeights[3],
neuronWeights[4],neuronWeights[5],neuronWeights[6],neuronWeights[7],
neuronWeights[8],neuronWeights[9],neuronWeights[10],neuronWeights[11],
neuronWeights[12],neuronWeights[13],neuronWeights[14],neuronWeights[15], neuronWeights[16])
def update(self):
# Move
self.y -= self.speed*time.dt
self.speed += 8*time.dt
# Update tube ID
if tubes[self.tube].upTube.x +1 <= self.x:
self.tube += 1
# Get tube coordinates
tubeX = tubes[self.tube].upTube.x
tubeY = tubes[self.tube].y_position
tubeX -= self.x
tubeY -= self.y
# Jump
jump = self.neuron.jump(tubeX, tubeY)
if jump == 1:
self.jump()
# Check position
if self.y <= -4 or self.y >= 4:
self.disable()
# Hit
hit_info = self.intersects(ignore=(self,),debug=True)
if str(hit_info.entity) == 'tube':
print(hit_info.entities)
self.disable()
def jump(self):
self.speed = -4
class Tube(Entity):
def __init__(self, position):
super().__init__(
model = 'quad',
color = color.white,
collider = 'box',
position = position,
scale = Vec2(0.6,6)
)
self.spawn = True
def update(self):
self.x -= 2*time.dt
# Spawn new tube
if self.y>=2 and self.x<tubeDistance and self.spawn:
self.spawn = False
new_tube = Tubes()
tubes.append(new_tube)
class Tubes():
def __init__(self):
self.y_position = uniform(-2,2)
self.upTube = Tube(Vec2(8,3+tubeSpace+self.y_position))
self.downTube = Tube(Vec2(8,-(3+tubeSpace)+self.y_position))
class Neuron:
def __init__(self, ...):
...
def jump(self, tubeX, tubeY):
# return 1 or 0
def firstGeneration():
balls = []
for _ in range(ballsPerGen):
ball = Ball(randomColor(), Vec2(-5, uniform(-3,3)), initRandomWeights())
balls.append(ball)
return balls
def newGeneration(weights):
balls = []
for _ in range(ballsPerGen):
ball = Ball(randomColor(), Vec2(-5, uniform(-3,3)), mutations(weights))
balls.append(ball)
return balls
def update():
global start
global tubes
global balls
global gen
global lastBall
if held_keys['space']:
application.time_scale = 0.1
else:
application.time_scale = 1
# Start
if start:
start = False
tube = Tubes()
tubes.append(tube)
balls = firstGeneration()
print("\nGen 1")
# New gen
finish = True
for ball in balls:
if ball.enabled == True:
lastBall = ball
finish = False
break
if finish:
for tube in tubes:
tube.upTube.disable()
tube.downTube.disable()
tubes = []
tube = Tubes()
tubes.append(tube)
max = 0
bestBall = balls[0]
# Best ball
for ball in balls:
if ball.tube>max:
max = ball.tube
bestBall = ball
print("Best score: ", bestBall.tube)
balls = []
newWeights = lastBall.neuron.weights
balls = newGeneration(newWeights)
gen += 1
print('\nGen ', gen)
app.run()

It seems you were having some problems with the intersection.
I will comment in code where the problem was:
from ursina import *
from ursina.prefabs import *
app = Ursina()
EditorCamera()
ground = Entity(model='plane', scale = 30, collider='plane')
bird = Entity(model = 'circle',
color = color.yellow,
position=(0,10,0),
scale = 0.4,
collider = 'sphere'
)
tube = Entity(model = 'quad',
color = color.white,
position = (0,0,0),
scale = Vec2(20,6),
collider = 'box'
)
def update():
# Hit
hit_info = bird.intersects(ignore=(),debug=True)
if hit_info.entity == tube: ## HERE <------------
# You had if str(hit_info.entity) == 'tube':
print(hit_info.entities)
def input(key):
if key == 'a':
bird.y -= 1
app.run()

Related

Putting the scrolling camera in a mini-window in pygame

I'm trying to create a game where the action is shown in a little box within the main screen object, freeing up the surrounding space for text and menus and what-not. Since the map is larger than the allotted window, I coded a basic "camera" that follows the player around. It mostly works, but I'm having trouble "trimming off" the area outside of this window.
Here's the relevant bits of code (EDITED to provide Working Example):
import pygame, os, sys
from pygame.locals import *
pygame.init()
RIGHT = 'RIGHT'
LEFT = 'LEFT'
UP = 'UP'
DOWN = 'DOWN'
class Camera():
def __init__(self, screen, x_ratio = 1, y_ratio = 1, x_offset = 0, y_offset = 0):
self.screen = screen.copy()
self.rec = self.screen.get_rect()
self.rec.width *= x_ratio
self.rec.height *= y_ratio
self.x_offset = x_offset
self.y_offset = y_offset
def get_pos(self):
return (self.x_offset - self.rec.x, self.y_offset - self.rec.y)
def get_window(self):
w = pygame.Rect(self.rec)
w.topleft = (0 - self.rec.x, 0 - self.rec.y)
return w
def move(self, x, y):
"""Move camera into new position"""
self.rec.x = x
self.rec.y = y
def track(self, obj):
while obj.rec.left < self.rec.left:
self.rec.x -= 1
while obj.rec.right > self.rec.right:
self.rec.x += 1
while obj.rec.top < self.rec.top:
self.rec.y -= 1
while obj.rec.bottom > self.rec.bottom:
self.rec.y += 1
class Map:
def __init__(self, width, height):
self.width = width
self.height = height
self.rec = pygame.Rect(0,0,self.width,self.height)
def draw(self, screen):
pygame.draw.rect(screen, (200,200,200), self.rec)
class Obj:
def __init__(self, char, x = 0, y = 0, width = 0, height = 0):
self.width = width
self.height = height
self.rec = pygame.Rect(x, y, width, height)
self.cur_map = None
self.timers = {}
#Dummying in chars for sprites
self.char = char
self.x_dir = 1
self.y_dir = 1
self.speed = 1
self.moving = False
def move(self):
if self.x_dir != 0 or self.y_dir != 0:
new_x = self.rec.x + (self.x_dir*self.speed)
new_y = self.rec.y + (self.y_dir*self.speed)
new_rec = pygame.Rect(new_x, new_y, self.width, self.height)
#Keep movement within bounds of map
while new_rec.left < self.cur_map.rec.left:
new_rec.x += 1
while new_rec.right > self.cur_map.rec.right:
new_rec.x -= 1
while new_rec.top < self.cur_map.rec.top:
new_rec.y += 1
while new_rec.bottom > self.cur_map.rec.bottom:
new_rec.y -= 1
self.rec = new_rec
def set_dir(self, d):
self.x_dir = 0
self.y_dir = 0
if d == LEFT:
self.x_dir = -1
elif d == RIGHT:
self.x_dir = 1
elif d == UP:
self.y_dir = -1
elif d == DOWN:
self.y_dir = 1
def set_moving(self, val = True):
self.moving = val
class Game:
def __init__(self):
self.screen_size = (800, 600)
self.screen = pygame.display.set_mode(self.screen_size)
self.map_screen = self.screen.copy()
self.title = 'RPG'
pygame.display.set_caption(self.title)
self.camera = Camera(self.screen, 0.75, 0.75)#, 10, 75)
self.fps = 80
self.clock = pygame.time.Clock()
self.debug = False
self.bg_color = (255,255,255)
self.text_size = 18
self.text_font = 'Arial'
self.text_style = pygame.font.SysFont(self.text_font, self.text_size)
self.key_binds = {LEFT : [K_LEFT, K_a], RIGHT : [K_RIGHT, K_d], UP : [K_UP, K_w], DOWN : [K_DOWN, K_s],
'interact' : [K_RETURN, K_z], 'inventory' : [K_i, K_SPACE], 'quit' : [K_ESCAPE]}
self.player = Obj('p', 0, 0, 10, self.text_size)
def draw(self, obj):
char = obj.char
self.draw_text(char, obj.rec.x, obj.rec.y, screen = self.map_screen)
def draw_text(self, text, x, y, color = (0,0,0), screen = None):
textobj = self.text_style.render(text, 1, color)
textrect = textobj.get_rect()
textrect.x = x
textrect.y = y
if screen == None:
"""Use default screen"""
self.screen.blit(textobj, textrect)
else:
screen.blit(textobj, textrect)
def play(self):
done = False
cur_map = Map(800, 800)
self.map_screen = pygame.Surface((cur_map.width, cur_map.height))
self.map_screen.fill(self.bg_color)
bg = pygame.Surface((cur_map.width, cur_map.height))
cur_map.draw(bg)
self.player.cur_map = cur_map
while not done:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key in self.key_binds[LEFT]:
self.player.set_dir(LEFT)
self.player.set_moving()
elif event.key in self.key_binds[RIGHT]:
self.player.set_dir(RIGHT)
self.player.set_moving()
elif event.key in self.key_binds[UP]:
self.player.set_dir(UP)
self.player.set_moving()
elif event.key in self.key_binds[DOWN]:
self.player.set_dir(DOWN)
self.player.set_moving()
elif event.type == KEYUP:
self.player.set_moving(False)
if self.player.moving:
self.player.move()
self.camera.track(self.player)
self.clock.tick()
self.screen.fill(self.bg_color)
self.map_screen.blit(bg, (0,0))
self.draw(self.player)
pygame.draw.rect(self.map_screen, (0,0,0), self.camera.rec, 1)
#self.screen.blit(self.map_screen, (0,0), [0 - self.camera.rec.x, 0 - self.camera.rec.y, self.camera.rec.width, self.camera.rec.height])
self.screen.blit(self.map_screen, self.camera.get_pos(), self.camera.get_window())
pygame.display.flip()
game = Game()
game.play()
Moving the player past past the bounds of the camera's window causes the window to roll up completely and disappear. I tried adjusting the blitting coordinates, as advised earlier, but it seems to only change the direction in which the window rolls up.
From your updated code, the blitting coordinates for self.screen.blit(...) are still changing: self.camera.get_window() changes value because rec.x and rec.y are values referring to the player position within the map. Hence you should define a constant minimap coordinate, this should be the same as the camera offset.
self.screen.blit(self.map_screen, (self.camera.x_offset,self.camera.y_offset), (*self.camera.get_pos(), self.camera.rec.width, self.camera.rec.height))
Change the Camera().get_pos() to:
def get_pos(self):
return (self.rec.x, self.rec.y)
I believe I only changed the self.screen.blit(...) and stopped using or rewrote your Camera functions as you're confusing yourself with all the rec variables.
To illustrate it working amend the Map().draw(screen) to:
def draw(self, screen):
pygame.draw.rect(screen, (200,200,200), self.rec)
pygame.draw.circle(screen, (255, 255, 255), (50, 50), 20, 2)
One tip as well don't draw the entire map at each loop, just the part that will be visible.

Trying to delete sprite with kill(), but sprite isn't disappearing

This is my first time asking here, so sorry if I don't ask very well.
Lately I've been trying to make a Terraria-type game where you can break/place blocks in a randomly generated landscape. While trying to implement the breaking-block mechanic (which is triggered by clicking on a block), I ran into an issue. The block no longer became solid (that's a good thing), but the block's image is still there, and I can walk right through it.
A visual example:
Before breaking block vs.
After breaking block
Here's the code
Main file (hopefully only the relevant bits):
# Imports
import pygame as pg
import json
import sys
import random
import os
from settings import *
from world_handler import *
# Initialize pygame
pg.mixer.pre_init()
pg.init()
# Fonts
# NOTE: put fonts in here
# Helper functions
def load_image(file_path):
# Loads an image
img = pg.image.load(file_path)
return img
def play_sound(sound, loops=0, maxtime=0, fade_ms=0):
# Plays some audio
if sound_on:
sound.play(loops, maxtime, fade_ms)
def play_music():
# Plays background music
if sound_on:
pg.mixer.music.play(-1)
# File paths
current_path = os.path.dirname(__file__)
assets_path = os.path.join(current_path, "assets")
image_path = os.path.join(assets_path, "img")
# Images
player_standing = load_image((os.path.join(image_path, "player", "standing", "player-standing.png")))
player_walking1 = load_image((os.path.join(image_path, "player", "walking", "player-walking1.png")))
player_walking2 = load_image((os.path.join(image_path, "player", "walking", "player-walking2.png")))
player_walking3 = load_image((os.path.join(image_path, "player", "walking", "player-walking3.png")))
player_walking4 = load_image((os.path.join(image_path, "player", "walking", "player-walking4.png")))
player_jumping = load_image((os.path.join(image_path, "player", "jumping", "player-jumping.png")))
player_images = {"walking": [player_walking1, player_walking2, player_walking3, player_walking4],
"jumping": player_jumping,
"standing": player_standing}
block_images = {"Grass": load_image((os.path.join(image_path, "blocks", "grass.png"))),
"Dirt": load_image((os.path.join(image_path, "blocks", "dirt.png"))),
"Stone": load_image((os.path.join(image_path, "blocks", "stone.png")))}
cursor_tracker = load_image((os.path.join(image_path, "misc", "clear-single-pixel.png")))
class Entity(pg.sprite.Sprite):
def __init__(self, x, y, image):
# Initialize an entity
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.vx = 0
self.vy = 0
def apply_gravity(self, world):
# Let the enemy be affected by gravity
self.vy += world.gravity
self.vy = min(self.vy, world.terminal_velocity)
class Block(Entity):
def __init__(self, x, y, image):
# Initialize the block
super().__init__(x, y, image)
class Cursor(Entity):
def __init__(self, x, y, image):
# Initialize the invisible mouse cursor object
# This will be used to track where the mouse goes and if the mouse is on a block
super().__init__(x, y, image)
self.on_block = False
def follow_mouse(self):
# Make object follow the mouse
self.mouse_x, self.mouse_y = pg.mouse.get_pos()
self.rect.x = self.mouse_x
self.rect.y = self.mouse_y
def detect_block_collision(self, world):
# Detects collsion between cursor tracker and a block
hit_list = pg.sprite.spritecollide(self, world.blocks, True)
if len(hit_list) > 0:
pass
def update(self, world):
# Update the cursor object
self.follow_mouse()
world.active_sprites.add(self)
class Player(Entity):
def __init__(self, images):
# Initialize the player
super().__init__(0, 0, images["standing"])
# Images in each direction
self.image_standing_right = images["standing"]
self.image_standing_left = pg.transform.flip(self.image_standing_right, 1, 0)
self.images_walking_right = images["walking"]
self.images_walking_left = [pg.transform.flip(img, 1, 0) for img in self.images_walking_right]
self.image_jumping_right = images["jumping"]
self.image_jumping_left = pg.transform.flip(self.image_jumping_right, 1, 0)
# Player variables
self.running_images = self.images_walking_right
self.image_index = 0
self.steps = 0
self.speed = 3.5
self.jump_power = 12
self.vx = 0
self.vy = 0
self.direction = "right"
self.on_ground = True
self.score = 0
self.health = 100
self.max_health = 100
self.invincibility = 0
def move_left(self):
# Move to the left
self.vx = -self.speed + 0.9
self.direction = "left"
def move_right(self):
# Move to the rightS
self.vx = self.speed
self.direction = "right"
def stop(self):
# Stop it right there
self.vx = 0
def jump(self, blocks):
# Jump up, jump up, and get down
self.rect.y += 1
hit_list = pg.sprite.spritecollide(self, blocks, False)
if len(hit_list) > 0:
self.vy = -1 * self.jump_power
self.rect.y -= 1
def check_world_boundaries(self, world):
# Make sure the player doesn"t walk off the world
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > world.width:
self.rect.right = world.width
def move_and_process_blocks(self, blocks):
# Detect block collisions
# Block side collisions
self.rect.x += self.vx
hit_list = pg.sprite.spritecollide(self, blocks, False)
for block in hit_list:
if self.vx > 0:
self.rect.right = block.rect.left
self.vx = 0
elif self.vx < 0:
self.rect.left = block.rect.right
self.vx = 0
self.on_ground = False
# Block top and bottom collisions
self.rect.y += self.vy + 1 # The +1 isn"t necessary, but it helps
hit_list = pg.sprite.spritecollide(self, blocks, False)
for block in hit_list:
if self.vy > 0:
self.rect.bottom = block.rect.top
self.on_ground = True
self.vy = 0
elif self.vy < 0:
self.rect.top = block.rect.bottom
self.on_ground = True
self.vy = 0
def set_image(self):
# Set images and animate
if self.on_ground:
if self.vx != 0:
if self.direction == "right":
self.walking_images = self.images_walking_right
elif self.direction == "left":
self.walking_images = self.images_walking_left
self.steps = (self.steps + 1) % self.speed
if self.steps == 0:
self.image_index = (self.image_index + 1) % len(self.walking_images)
self.image = self.walking_images[self.image_index]
else:
if self.direction == "right":
self.image = self.image_standing_right
elif self.direction == "left":
self.image = self.image_standing_left
else:
if self.direction == "right":
self.image = self.image_jumping_right
elif self.direction == "left":
self.image = self.image_jumping_left
def die(self):
# D E D
pass
def check_block_breaks(self, blocks):
# Break a block
# mouse_pos = pg.mouse.get_pos()
# for block in blocks:
# if block.rect.collidepoint(mouse_pos):
# print("hi")
pass
def respawn(self, world):
# Hey, you"re back!
self.rect.x = world.start_x
self.rect.y = world.start_y
self.health = self.max_health
self.invincibility = 0
self.direction = "right"
def update(self, world):
# Constantly update the player
self.apply_gravity(world)
self.move_and_process_blocks(world.blocks)
self.check_world_boundaries(world)
self.set_image()
self.check_block_breaks(world.blocks)
if self.health > 0:
if self.invincibility > 0:
self.invincibility -= 1
else:
self.die()
class Game():
def __init__(self):
# Initialize the game itself
self.window = pg.display.set_mode([WINDOWWIDTH, WINDOWHEIGHT])
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.done = False
self.reset()
def start(self):
# Start the whole thing up
self.world = World(worlds[self.current_world])
self.cursor = Cursor(0, 0, cursor_tracker)
self.world.reset()
self.player.respawn(self.world)
def reset(self):
# Reset the game
self.player = Player(player_images)
self.current_world = 0
self.start()
def update(self):
# Update things in the game
self.player.update(self.world)
self.cursor.update(self.world)
if self.player.health <= 0:
self.player.respawn(self.world)
def calculate_offset(self):
# Calculate x/y coordinates after screen scrolls
x = -1 * self.player.rect.centerx + WINDOWWIDTH / 2
if self.player.rect.centerx < WINDOWWIDTH / 2:
x = 0
elif self.player.rect.centerx > self.world.width - WINDOWWIDTH / 2:
x = -1 * self.world.width + WINDOWWIDTH
y = -1 * self.player.rect.centery + WINDOWHEIGHT / 2
if self.player.rect.centery < WINDOWHEIGHT / 2:
y = 0
elif self.player.rect.centery > self.world.height - WINDOWHEIGHT / 2:
y = -1 * self.world.height + WINDOWHEIGHT
return x, y
def draw(self):
# Draw sprites to the screen
self.offset_x, self.offset_y = self.calculate_offset()
self.world.active_layer.fill(TRANSPARENT)
self.world.active_sprites.draw(self.world.active_layer)
if self.player.invincibility % 3 < 2:
self.world.active_layer.blit(self.player.image, [self.player.rect.x, self.player.rect.y])
self.window.blit(self.world.background_layer, [self.offset_x / 3, self.offset_y])
self.window.blit(self.world.inactive_layer, [self.offset_x, self.offset_y])
self.window.blit(self.world.active_layer, [self.offset_x, self.offset_y])
self.offset_cursor_x = self.cursor.rect.x - self.offset_x
self.offset_cursor_y = self.cursor.rect.y - self.offset_y
self.cursor.rect.x = self.offset_cursor_x
self.cursor.rect.y = self.offset_cursor_y
pg.display.update(0, 0, WINDOWWIDTH, WINDOWHEIGHT)
def process_events(self):
# Handle events (key presses, mouse clicks, etc)
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
elif event.type == pg.KEYDOWN:
# Jump
if event.key == JUMP:
self.player.jump(self.world.blocks)
# Debug reset
elif event.key == pg.K_r:
self.reset()
# Debug close
elif event.key == pg.K_q:
self.done = True
# Break a block if you click on it
if event.type == pg.MOUSEBUTTONDOWN:
# for block in self.world.blocks:
# if block.rect.collidepoint(self.offset_cursor_x, self.offset_cursor_y):
# block.kill()
self.cursor.detect_block_collision(self.world)
pressed = pg.key.get_pressed()
if pressed[LEFT]:
self.player.move_left()
elif pressed[RIGHT]:
self.player.move_right()
else:
self.player.stop()
def loop(self):
# Loop through essential functions
while not self.done:
self.process_events()
self.update()
self.draw()
self.clock.tick(FPS)
if __name__ == "__main__":
# Begin the loop and pre-initialize the game
game = Game()
game.start()
game.loop()
pg.quit()
sys.exit()
World Handler (generated blocks and adds them to groups):
Some parts are commented out because they serve no purpose yet, but will soon.
# Imports
import pygame as pg
import json
import random
import os
from settings import *
from main import *
# Initialize pygame
pg.init()
class World():
def __init__(self, file_path):
# Initialize the world
# Starting entities
self.starting_blocks = []
# Entity groups
self.blocks = pg.sprite.Group()
# Sprite groups (active/inactive)
self.active_sprites = pg.sprite.Group()
self.inactive_sprites = pg.sprite.Group()
# Read the world json file
with open(file_path, "r") as f:
data = f.read()
map_data = json.loads(data)
# World width and height
self.width = map_data["width"] * GRID_SIZE
self.height = map_data["height"] * GRID_SIZE
# Player start position
self.start_x = map_data["start"][0] * GRID_SIZE
self.start_y = map_data["start"][1] * GRID_SIZE
# Load blocks
for item in map_data["blocks"]:
x, y = item[0] * GRID_SIZE, item[1] * GRID_SIZE
img = block_images[item[2]]
self.starting_blocks.append(Block(x, y, img))
# Layers
self.background_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
self.inactive_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
self.active_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32)
# Load background color
if map_data["bg-color"] != "":
self.background_layer.fill(map_data["bg-color"])
# Load background image
# if map_data["bg-image"] != "":
# bg_image = pg.image.load(map_data["bg-image"]).convert_alpha()
#
# if map_data["bg-fill-y"]:
# h = bg_image.get_height()
# w = int(bg_image.get_width() * WINDOWHEIGHT / h)
# bg_image = pg.transform.scale(bg_image, (w, WINDOWHEIGHT))
#
# if "top" in map_data["bg-position"]:
# start_y = 0
# elif "bottom" in map_data["bg-postion"]:
# start_y = self.height = bg_image.get_height()
#
# if map_data["bg-repeat-x"]:
# for x in range(0, self.width, bg_image.get_width()):
# self.background_layer.blit(bg_image, [x, start_y])
# else:
# self.background_layer.blit(bg_image, [0, start_y])
# Load background music
# pg.mixer.music.load(map_data["music"])
# Set the world's gravity strength and terminal velocity
self.gravity = map_data["gravity"]
self.terminal_velocity = map_data["terminal-velocity"]
# Grass generator
if map_data["gen-type"] == "earth":
gen_loop = map_data["width"]
x = 0
y = 56 * GRID_SIZE # The general y coordinate for block placing
y_gen = 56 * GRID_SIZE # Stored to be referenced in order to make a smoother landscape
for i in range (0, map_data["width"]):
# Generate grass
img = block_images["Grass"]
self.starting_blocks.append(Block(x, y, img))
y += GRID_SIZE
# Generate dirt
for i in range(0, 6):
img = block_images["Dirt"]
self.starting_blocks.append(Block(x, y, img))
y += GRID_SIZE
# Generate stone
for i in range(1, int((self.height / GRID_SIZE))):
img = block_images["Stone"]
self.starting_blocks.append(Block(x, y, img))
y += GRID_SIZE
y = y_gen
x += GRID_SIZE
gen_loop -= 1
# Randomly decide what the next grass' y will be in relation to the previous one
random_grass = random.randint(0, 5)
# The lowest point you'll find a block of grass
lowest_grass_y = 53 * GRID_SIZE
# How extreme the changes in block heights will be
# 0 is flat, 1 will have pretty smooth terrain, while something like 10 would be super steep
gen_extremity = 1
# Keep the grass at the same y
if random_grass == 0 or random_grass == 1 or random_grass == 2 or random_grass == 3:
gen_loop -= 1
if y <= lowest_grass_y:
y += GRID_SIZE
# Increase y
elif random_grass == 4:
y_gen += GRID_SIZE * gen_extremity
if y <= lowest_grass_y:
y += GRID_SIZE
# Decrease y
elif random_grass == 5:
y_gen -= GRID_SIZE * gen_extremity
if y <= lowest_grass_y:
y += GRID_SIZE
else:
raise ValueError("How did we get here? Grass generator somehow generated an invalid number.")
# Add starting entities to their groups
self.blocks.add(self.starting_blocks)
# Add sprites to inactive/active sprite groups
self.inactive_sprites.add(self.blocks)
# Does... something?
for s in self.active_sprites:
s.image.convert()
for s in self.inactive_sprites:
s.image.convert()
# Draw inactive sprites to the inactive layer
self.inactive_sprites.draw(self.inactive_layer)
# Convert layers
self.background_layer.convert()
self.inactive_layer.convert()
self.active_layer.convert()
Setting file (to help you recreate the issue and find out what's going on
# Imports
import pygame as pg
import os
# File paths
current_path = os.path.dirname(__file__)
assets_path = os.path.join(current_path, 'assets')
image_path = os.path.join(assets_path, 'img')
# Window settings
TITLE = "Mooncraft"
WINDOWWIDTH = 960
WINDOWHEIGHT = 640
FPS = 60
GRID_SIZE = 32
# Options
sound_on = True
# Controls
LEFT = pg.K_a
RIGHT = pg.K_d
JUMP = pg.K_SPACE
# Colors
TRANSPARENT = (0, 0, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# World files
worlds = [(os.path.join(assets_path, 'worlds', 'earth.json'))]
If someone could explain what I'm doing wrong, it would be much appreciated.
Update 2: Added player class and settings file to help anyone willing to assist me find the issue.
From just a glance, it looks like you might not be clearing the screen at any point in the update loop, but rather drawing over what was already there. This would result in the block still being visible, but not actually there. Try adding screen.fill(#Color here) before flipping the display. Also try using pygame.display.update() instead of pygame.display.flip()
You can do this:
all_sprites = pg.sprite.Group()
all_sprites.add(your_sprite)
#your event:
all_sprites.remove(your_sprite)

Why isn't my pygame display displaying anything?

I am working on a program that evolves creatures over time using a genetic algorithm. However, for some reason, my pygame display stopped working and I have absolutely no idea why. When I run the program, the window opens but then it just sits on a black screen. I have tested to see where the program gets to and about 38 creatures die then nothing happens. However, these creatures should be displaying before their deaths also, but they aren't.Any help would be wonderful! Thank you for all your time!
Here's my code:
import numpy as np
import pygame
import random
#Initializes Pygame & Creates Window
pygame.init()
backgroundColor = (255, 255, 255)
screenSize = (800, 600)
screen = pygame.display.set_mode(screenSize)
pygame.display.set_caption("Genetic Algorithm")
screen.fill(backgroundColor)
clock = pygame.time.Clock()
#Loads Images & Rectangles
creaturePNG = pygame.image.load("Creature.png").convert_alpha()
foodPNG = pygame.image.load("Food.png").convert_alpha()
#Establishes Size Of Population
creatureCount = 40
deadCreatures = []
numGenerations = 10
#Generates Random 12 Digit DNA For First Generation
def initialDNA():
while True:
randomDNA = ""
total = 0
for i in range(12):
digit = random.randint(1, 9)
total += digit
digit = str(digit)
randomDNA = randomDNA + digit
if total <= 60:
break
return randomDNA
def reproduce(deadCreatureList, creatureCount):
reproducingCreatures = deadCreatureList[0.5*creatureCount:creatureCount]
for i in range(0.25*creatureCount):
creature1 = reproducingCreatures[0]
del reproducingCreatures[0]
creature2 = reproducingCreatures[0]
del reproducingCreatures[0]
DNA1 = str(creature1.DNA)
DNA2 = str(creature2.DNA)
crosspoint = random.randint(0, 12)
newDNA1 = int(DNA1[0:crosspoint] + DNA2[crosspoint:])
newDNA2 = int(DNA2[0:crosspoint] + DNA1[crosspoint:])
return newDNA1, newDNA2
#Creates Creatures From DNA
class Creature:
def __init__(self, DNA, image):
self.DNA = DNA
self.speed = (int(self.DNA[0:2])/100) + 1
self.strength = int(DNA[2:4])/10
self.foodCap = int(DNA[4:6])
self.maxHealth = int(DNA[6:8])
self.health = self.maxHealth
self.regeneration = int(DNA[8:10])/10
self.turnProbability = int(DNA[10:12])
self.currentFood = self.foodCap
self.image = image
self.rect = self.image.get_rect()
self.directions = [-1, 1]
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.isAlive = True
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def move(self):
changeDirection = random.randint(0, 100)
if changeDirection < self.turnProbability:
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.x += self.directionX * self.speed
self.y += self.directionY * self.speed
if self.x > 775:
self.x = 775
elif self.x < 25:
self.x = 25
elif self.y > 575:
self.y = 575
elif self.y < 25:
self.y = 25
self.loc = (self.x, self.y)
self.rect.center = self.loc
def foodCollision(self, foodList):
foodRects = []
for i in range(25):
food = foodList[i]
foodRect = food.rect
foodRects.append(foodRect)
collision = self.rect.collidelist(foodRects)
if collision > 0:
self.currentFood += 20
if self.currentFood > self.foodCap:
self.currentFood = self.foodCap
def creatureCollision(self, creatureList, creatureCount, creatureNumber):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRect = creature.rect
creatureRects.append(creatureRect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if collision != creatureNumber:
if creature.health > 0:
self.health -= creature.strength
if self.health < 0:
self.health = 0
def starve(self):
if self.currentFood == 0:
self.health -= 1
def display(self):
screen.blit(self.image, self.loc)
#Creates Food Objects For Creatures To Eat
class Food:
def __init__(self, image):
self.image = image
self.rect = self.image.get_rect()
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def creatureCollision(self, creatureList, creatureCount):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRects.append(creature.rect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if creature.health > 0:
self.spawn()
def display(self):
screen.blit(self.image, self.loc)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(backgroundColor)
for i in range(numGenerations):
if i == 0:
#Spawns Creatures Into World
creatures = []
for i in range(creatureCount):
DNA = initialDNA()
print (DNA)
creature = Creature(DNA, creaturePNG)
creature.spawn()
creatures.append(creature)
elif i > 0:
creatures = []
for i in range(0.5*creatureCount):
DNA1, DNA2 = reproduce(deadCreatures, creatureCount)
print (DNA1, DNA2)
creature1, creature2 = Creature(DNA1, creaturePNG), Creature(DNA2, creaturePNG)
creature.spawn()
creatures.append(creature)
#Spawns Food Into World
foodList = []
for i in range(25):
food = Food(foodPNG)
food.spawn()
foodList.append(food)
livingCreatures = True
while livingCreatures:
for i in range(25):
food = foodList[i]
food.creatureCollision(creatures, creatureCount)
food.display()
for i in range(creatureCount):
creature = creatures[i]
if creature.health > 0:
creature.move()
creature.foodCollision(foodList)
creature.creatureCollision(creatures, creatureCount, i)
creature.currentFood -= 0.5
if creature.currentFood < 0:
creature.currentFood = 0
if creature.currentFood > 0:
creature.health += creature.regeneration
if creature.health > creature.maxHealth:
creature.health = creature.maxHealth
creature.starve()
creature.display()
if creature.isAlive == True:
if creature.health == 0:
print ("DEATH")
deadCreatures.append(i)
creature.isAlive = False
if len(deadCreatures) == creatureCount:
livingCreatures = False
pygame.display.flip()
clock.tick(10)
I suspect the livingCreatures variable is never set to False, so the pygame.display.flip() never gets called--and you won't see anything on the screen at all until you flip the buffers. The fact that you're filling the screen with a color, but then still seeing black, is a dead giveaway for this sort of problem.
In the future, you should also try to reproduce the problem in a simpler example without domain-specific, irrelevant code.

python 2.6, pygame, pong ball wont go on y corrodinate correctly

trying to get the ball to move along the y coordinate, it wont work, more explanation at bottom
from livewires import games, color
games.init(screen_width = 640, screen_height = 480, fps = 50)
points = games.Text(value = 0, size = 25, color = color.green,
bottom = games.screen.height - 5, left = 10)
games.screen.add(points)
class Paddle(games.Sprite):
image = games.load_image("paddle.bmp")
def __init__(self):
super(Paddle, self).__init__(image = Paddle.image, y = games.mouse.y, right = games.screen.width)
def update(self):
""" Move to mouse x position. """
self.y = games.mouse.y
if self.top < 0:
self.top = 0
if self.bottom > games.screen.height:
self.bottom = games.screen.height
self.check_bounce()
def check_bounce(self):
for bouncingBall in self.overlapping_sprites:
bouncingBall.handle_bounce()
class BouncingBall(games.Sprite):
image = games.load_image("ball.bmp")
def __init__(self, x, y, dx, dy):
super(BouncingBall, self).__init__(image = BouncingBall.image, x = x, y = y, dx = dx, dy = dy)
def update(self):
""" Check if bottom edge has reached screen bottom. """
if self.top > 0 or self.bottom < games.screen.height:
self.dy = -self.dy
if self.left < 0:
self.dx = -self.dx
if self.right > games.screen.width:
self.end_game()
def handle_bounce(self):
global points
points.value += 10
points.left = 10
self.dx = -self.dx
def end_game(self):
end_message = games.Message(value = "GAME OVER",
size = 90,
color = color.red,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 10 * games.screen.fps,
after_death = games.screen.quit)
games.screen.add(end_message)
def main():
background_image = games.load_image("background.png", transparent = False)
games.screen.background = background_image
the_paddle = Paddle()
games.screen.add(the_paddle)
games.mouse.is_visible = False
new_ball = BouncingBall(x = games.screen.width/2, y = games.screen.height/2, dx = 2, dy = 2) #<-believe it is right here im messing up
games.screen.add(new_ball)
games.screen.mainloop()
main()
I am having a horrible time at getting my ball to correctly follow the y coordinate, I believe I am doing it wrong when i create instance new_ball, (main function) but i have no idea lol, anyone see what im doing wrong?
Make sure that this line
if self.top > 0 or self.bottom < games.screen.height:
self.dy = -self.dy
Isn't constantly evaluating to True. If so, your y-velocity will constantly toggle and the ball will never appear to change y coordinate.

Python Packman score

I did a packman game using Python but Im having 2 problems. First my score is not updating, so the score remains 1. Second after a while my packman game crashes it, it shows me 2 error message saying an attribute error: in packman.handle_collide() and self.check_collide().I dnt knw how to fix it.
here is my code:
# Create a SNAPMAN
from livewires import games, color
import random
games.init(screen_width = 200, screen_height = 150, fps = 50)
explosion_files = ["explosion1.bmp",
"explosion2.bmp",
"explosion3.bmp",
"explosion4.bmp",
"explosion5.bmp",
"explosion6.bmp",
"explosion7.bmp",
"explosion8.bmp",
"explosion9.bmp"]
def display_score(score):
display_score = games.Text(value = score + 1, size = 25, color = color.black,
top = 5, right = games.screen.width - 10)
games.screen.add(display_score)
#increase the score
score = score + 1
class Packman(games.Sprite):
"""Create a Gumpy that is controlled by the mouse"""
image = games.load_image("packman.png")
def __init__(self, x = games.mouse.x, y = games.mouse.y):
"""Initialise packman"""
super(Packman,self).__init__(image = Packman.image,
x = games.mouse.x,
y = games.mouse.y)
oldx = games.mouse.x
oldy = games.mouse.y
def display_score(score):
display_score = games.Text(value = score + 1, size = 25, color = color.black,
top = 5, right = games.screen.width - 10)
games.screen.add(display_score)
#increase the score
score = score + 1
def update(self):
"""Move Packman's x and y coordinates"""
oldx = self.x
oldy = self.y
self.x = games.mouse.x
self.y = games.mouse.y
if(self.x < oldx):
self.angle = 180
if(self.x > oldx):
self.angle = 0
self.check_collide()
def check_collide(self):
"""Check if collides with ball"""
for packman in self.overlapping_sprites:
packman.handle_collide()
class Ball(games.Sprite):
""" Create the moving balls"""
def update(self):
"""Change the direction when the ball reached the edge"""
if self.right > games.screen.width or self.left < 0:
self.dx = -self.dx
if self.bottom > games.screen.height or self.top < 0:
self.dy = -self.dy
def handle_collide(self):
"""Something must happen when the ball collides"""
#Explosive sound
sound = games.load_sound("explosion.wav")
sound.play()
explosion = games.Animation(images = explosion_files, x = self.x, y = self.y,
n_repeats = 5, repeat_interval = 5,
is_collideable = False)
games.screen.add(explosion)
self.x = random.randrange(games.screen.width)
self.y = random.randrange(games.screen.height)
display_score(1)
def randomX():
"""Generate random x values"""
rx = random.randrange(games.screen.width)
return rx
def ramdomY():
"""Generate random y values"""
ry = random.randrange(games.screen.width)
return ry
def main():
#Set background
wall_image = games.load_image("wall.jpg", transparent = False)
games.screen.background = wall_image
games.mouse.is_visible = False
games.screen.event_grab = True
#Display score
display_score(0)
#Load and display the balls( red, green and blue)
ball_image = games.load_image("ball_red.png")
ball_red = Ball(image = ball_image,
x = random.randrange(games.screen.width),
y = random.randrange(games.screen.height),
dx = 1, dy = 1)
games.screen.add(ball_red)
ball_image = games.load_image("ball_green.png")
ball_green = Ball(image = ball_image,
x = random.randrange(games.screen.width),
y = random.randrange(games.screen.height),
dx = 1, dy = 1)
games.screen.add(ball_green)
ball_image = games.load_image("ball_blue.png")
ball_blue = Ball(image = ball_image,
x = random.randrange(games.screen.width),
y = random.randrange(games.screen.height),
dx = 1, dy = 1)
games.screen.add(ball_blue)
packman_1 = Packman()
games.screen.add(packman_1)
games.screen.mainloop()
main()
The score is not updating because you are incrementing a local variable of the method display_score. You can make it a class member of Packman, for example:
def __init__(self, x = games.mouse.x, y = games.mouse.y):
"""Initialise packman"""
# do something ...
# initialize the score variable
self._score = 0
And then,
def display_score(self):
display_score = games.Text(value = self._score, size = 25,
color = color.black, top = 5, right = games.screen.width - 10)
games.screen.add(display_score)
#increase the score
self._score += 1 # add one to the current value
You missed the self argument in the definition of the method!

Categories