I would like create a two layered scrolling background but everytime I run the programm below it make everything wrong, and I don't know why :/
Can you help me ?
I've try the code below :
'bg scrolling try'
import pygame as pg
from pygame.locals import *
pg.init()
screen = pg.display.set_mode((1920, 1080), pg.NOFRAME)
a = True
land_0 = pg.image.load('sprites/land_0.png').convert_alpha()
land_1 = pg.image.load('sprites/land_1.png').convert_alpha()
bg = pg.image.load('sprites/bg.png').convert_alpha()
pos_l0_0 = 2
pos_l0_1 = 1920
pos_l1_0 = -1000
pos_l1_1 = 920
hight_land = 500
hight_land_1 = 400
s_speed = 2
while a:
screen.blit(bg,(0, 0))
pos_l1_0 = pos_l1_0 - s_speed
pos_l1_1 = pos_l1_1 - s_speed
if pos_l1_0 == - 1920:
pos_l1_0 = 1920
elif pos_l1_1 == - 1920:
pos_l1_0 = 1920
screen.blit(land_1,(pos_l1_0, hight_land_1))
screen.blit(land_1,(pos_l1_1, hight_land_1))
# 2nd
pos_l0_0 = pos_l0_0 - s_speed/2
pos_l0_1 = pos_l0_1 - s_speed/2
if pos_l0_0 == - 1920:
pos_l0_0 = 1920
elif pos_l0_1 == - 1920:
pos_l0_0 = 1920
screen.blit(land_0,(pos_l0_0, hight_land))
screen.blit(land_0,(pos_l0_1, hight_land))
pg.display.update()
I would like the first layer scroll fast and the second ( in background scroll slow ), I working prettry during the first 20 seconds but after this it random : one layer diseappear or one is blitting, so strange...
The scrolling land can be imagined as a endless row of tiles. If you want to draw the background at a certain position, then you have to calculate the position of the tile relative to the screen by the modulo (%) operator. The position of the 2nd part tile is shifted by the width of the land surface (e.g. land_0.get_width()).
This means it is sufficient to define 1 position (offset) for each background land, because the 2nd position can be calculated by the width of the land.
Write a function which shifts the land by a certain offset (speed), draws the land surface and returns the new position:
def drawLand(pos, height, speed, land):
width = land.get_width()
pos = (pos + speed) % width
screen.blit(land, (pos, height))
pos_2 = pos + width if pos < 0 else pos - width
screen.blit(land, (pos_2, height))
return pos
Call the function for each land in the main loop of the application:
pos_l0, hight_land = 2, 500
pos_l1, hight_land_1 = -1000, 400
s_speed = 2
while a:
# [...]
screen.blit(bg,(0, 0))
pos_l1 = drawLand(pos_l1, hight_land_1, -s_speed, land_1)
pos_l0 = drawLand(pos_l0, hight_land, -s_speed // 2, land_0)
pg.display.update()
Related
I am trying to create a program to move the turtle to where the mouse is.
I am doing:
import turtle
t = turtle.Turtle()
canvas = turtle.getcanvas()
while True:
mouseX, mouseY = canvas.winfo_pointerxy()
t.goto(mouseX, mouseY)
but the turtle keeps moving off the screen.
I read from this question that canvas.winfo_pointerxy() returns 'window coordinates' (0, 0 at the top left of the window) and that I need to convert them to 'turtle coordinates' (0, 0 at the center of the window) but I don't know how to do that.
First, you need to find the size of the canvas. for this example, I used a set width and height, but for your purposes, you may find it easier to find the size instead of entering it.
width = 500
height = 300
t = turtle.Turtle()
canvas = turtle.getcanvas()
turtle.screensize(canvwidth=width, canvheight=height)
you can use this code to find the width and height
width = canvas.winfo_width()
height = canvas.winfo_height()
When you measure the mouse's position, however, you'll need to do this calculation to get the right value.
mouseX = canvas.winfo_pointerx() - width/2
mouseY = (canvas.winfo_pointery()*-1) + height/2
t.goto(mouseX, mouseY)
You have to use the dimensions of the window to calculate the center of the window. You just need to subtract the midpoint from the mouse coordinates (since the 0,0 for that is the top-left of the screen) to get it.
You need to add the following:
width = canvas.winfo_width()
height = canvas.winfo_height()
midpoint_x = width / 2
midpoint_y = height / 2
turtleX = mouseX - midpoint_x
turtleY = mouseY - midpoint_y
You end up with something like this:
import turtle
t = turtle.Turtle()
canvas = turtle.getcanvas()
width = canvas.winfo_width()
height = canvas.winfo_height()
midpoint_x = width / 2
midpoint_y = height / 2
while True:
mouseX, mouseY = canvas.winfo_pointerxy()
turtleX = mouseX - midpoint_x
turtleY = mouseY - midpoint_y
t.goto(turtleX, turtleY)
I've gotten the Conway Game of Life in Python 3.9 from git-hub (there's also a great video on youtube here, made by the author)
All works fine.
Now I'd like to auto-detect when the evolution gets stuck, that is when the cell and cell group shapes are all static or regular oscillators (see pics attached at the end of this post).
My first idea was to compare the next generation grid backwards to 4 generations, that is: if the next generation grid is equal to ny of the previous four generation then it's safe to assume that the evolution has stopped.
So I first thought to make copies of the last 4 grids in 4x2D indipendent arrays and compare at each passage the next generation with each of them.
What would be the most efficient (in terms of time lag) way to compare two bidimentional arrays with say 400 columns and 200 rows?
The scripts use pygame.
here is a copy of what I am using (my plan is to use the check_if_over function in the grid.py module to return True if the evolution has stopped).
MAIN MODULE:
modules = ["pygame", "numpy", "ctypes"]
import sys
import importlib
import subprocess
def install(package):
# install packages if needed
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
# check for needed pacjakes/modules
for needed_module in modules:
try:
i = importlib.import_module(needed_module)
print(f"{needed_module} successfully imported")
except ImportError as e:
install(needed_module)
i = importlib.import_module(needed_module)
except:
"Something went wrong"
import pygame
import os
import grid
import ctypes
from pygame.locals import *
## ADJUSTABLE PARMAS
reduction_factor = 2 # reduces the width/height of the window vs screen size
fps = 60 # max frames per second
scaler = 5 # scales down, the smaller the scaler the greater the number of cells
offset = 1 # thickness of grid separator, must be < scaler
#### COLORS
black = (0, 0, 0)
white = (255, 255, 255)
blue = (0, 14, 71)
os.environ["SDL_VIDEO_CENTERED"] = '1'
user32 = ctypes.windll.user32
screensize = user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)
width, height = int(screensize[0]/reduction_factor), int(screensize[1]/reduction_factor)
size = (width, height)
pygame.init()
pygame.display.set_caption("Conway Game of Life")
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
Grid = grid.Grid(width, height, scaler, offset)
Grid.random2d_array()
run = True
# game loop
while run:
clock.tick(fps)
screen.fill(black)
for event in pygame.event.get():
if event.type == QUIT:
run = False
Grid.Conway(off_color=white, on_color=blue, surface=screen)
pygame.display.update()
pygame.quit()
exit(0)
grid.py:
import pygame
import numpy as np
import random
class Grid:
def __init__(self, width, height, scale, offset):
self.scale = scale
self.columns = int(height / scale)
self.rows = int(width / scale)
self.size = (self.rows, self.columns)
self.grid_array = np.ndarray(shape=(self.size))
# next 3 lines defines the set of array copies to save
# the past 4 generations
self.grid_array_copies = []
for i in range(0, 4):
self.grid_array_copies.append(np.ndarray(shape=(self.size)))
self.offset = offset
self.alive = 0
self.evolution_stopped = False
def random2d_array(self):
for x in range(self.rows):
for y in range(self.columns):
self.grid_array[x][y] = random.randint(0, 1)
def Conway(self, off_color, on_color, surface):
for x in range(self.rows):
for y in range(self.columns):
y_pos = y * self.scale
x_pos = x * self.scale
if self.grid_array[x][y] == 1:
pygame.draw.rect(surface, on_color, [x_pos, y_pos, self.scale - self.offset, self.scale - self.offset])
else:
pygame.draw.rect(surface, off_color, [x_pos, y_pos, self.scale - self.offset, self.scale - self.offset])
next = np.ndarray(shape=(self.size))
self.alive = 0
for x in range(self.rows):
for y in range(self.columns):
state = self.grid_array[x][y]
neighbours = self.get_neighbours(x, y)
if state == 0 and neighbours == 3:
next[x][y] = 1
self.alive += 1
elif state == 1 and (neighbours < 2 or neighbours > 3):
next[x][y] = 0
else:
next[x][y] = state
self.alive += state
self.grid_array = next
self.check_if_over(next)
with open("survivors.txt", "w") as f:
f.write(str(self.alive))
def get_neighbours(self, x, y):
total = 0
for n in range(-1, 2):
for m in range(-1, 2):
x_edge = (x + n + self.rows) % self.rows
y_edge = (y + m + self.columns) % self.columns
total += self.grid_array[x_edge][y_edge]
total -= self.grid_array[x][y]
return total
def check_if_over(self, next):
pass
Thanx for the patience.
Initial conditions:
Evolution stopped:
EDIT
I forgot to mention something that may be not that straightforward.
Unlike Golly (another open source for the Conway's Game of Life), the environment where this Game of Life plays is a finite one (see pictures above), that is it's kinda rendering of a spherical suface into a rectangle, so the cells colonies evolving past the right edge of the window re-enter at the left edge, those at the bottom edge re-enter at the top. While in Golly, for example the plan environment is theoretically infinite.
Golly starting conditions, zoomed in:
Golly starting conditions partially zoomed out (could go futher out until cells invisibility and further). The black surface is the environment, the white squares the cells
Objects all go off in the same line (45 degrees to the left)...
When I extract the random_direction function to test it by itself, it gives the same vectors just flipped 180 or the x is the same and y is the same but negative... stuff like that.
import pygame
import os
import math
import random
from pygame.math import Vector2
def random_direction():
vector = Vector2(random.uniform(-max_speed, max_speed), random.uniform(-max_speed, max_speed))
if vector.length() == 0:
return vector
else:
return Vector2.normalize(vector)
def scaled(vector, scale):
if vector.length() == 0:
return vector
else:
return Vector2.normalize(vector) * scale
def clamped(vector, limit):
if vector.length() <= limit or vector.length() == 0:
return vector
else:
return Vector2.normalize(vector) * limit
def shoot():
for i in range(len(boids)):
boids[i]['velocity'] = boids[i]['desired_direction'] * max_speed
boids[i]['boid'].x += boids[i]['velocity'].x
boids[i]['boid'].y += boids[i]['velocity'].x
# if boids[i]['boid'].x >= WIDTH:
# boids[i]['boid'].x = 0
# elif boids[i]['boid'].x <= 0:
# boids[i]['boid'].x = WIDTH
# elif boids[i]['boid'].y >= HEIGHT:
# boids[i]['boid'].y = 0
# elif boids[i]['boid'].y <= 0:
# boids[i]['boid'].y = HEIGHT
def draw_window():
WIN.fill((0, 0, 0))
# for i in range(n):
# rot_image = pygame.transform.rotate(image_scaled, math.degrees(math.atan2(boids[i]['velocity'].x, boids[i]['velocity'].y)) +180)
# WIN.blit(rot_image, (boids[i]['boid'].x - int(rot_image.get_width()/2), boids[i]['boid'].y - int(rot_image.get_height()/2))) #########
for i in range(len(boids)):
WIN.blit(image_scaled, (boids[i]['boid'].x, boids[i]['boid'].y))
pygame.display.update()
WIDTH, HEIGHT = 1440, 720 #1680, 990
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Sim')
FPS = 60
image = pygame.image.load(os.path.join('Assets', 'long_fish.png'))
image_width, image_height = 40, 40
image_scaled = pygame.transform.scale(image, (image_width, image_height))
#boid = pygame.Rect(WIDTH/2, HEIGHT/2, image_width, image_height)
max_speed = 10 #2
steer_strength = 0.04 #2
wander_strength = 0.4 #0.2
# desired_direction = Vector2(0, 0)
# velocity = Vector2(0, 0)
# shoot_direction = random_direction()
n = 30
boids = []
for i in range(n):
boids.append({'boid': pygame.Rect(WIDTH/2, HEIGHT/2, image_width, image_height),
'desired_direction': random_direction(),
'velocity': Vector2(0,0)})
def main():
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
shoot()
draw_window()
pygame.quit()
if __name__ == '__main__':
main()
I've made things like this before on pygame and they work but I'm not sure why they do and this doesn't.
Your vector generator generates with bounds of a square:
because of the way you set it up. You then normalize the vector, putting whatever it raised into the bounding circle. Because of this method, values nearer to the corners are more likely to be chosen. From the origin to the edge, there is a distance of one. From the origin to the corner, there is a distance of 1.41 . Thus, values that normalize to a corner are more likely to be chosen
This can give you the impression of not having truly random values, as some values pop up more frequently than others.
The way around this is to generate an already normalized vector, py choosing a point from a circle.
The best way to do this is to generate an angle, in radians. Ex:
>>> angle = math.radians(random.randint(0, 360))
Then, use some basic trigonometry to turn that angle into a point
>>> x = math.cos(angle)
>>> y = math.sin(angle)
The tuple (x, y) should be an unbiased value, that is as random as your pseudorandom (how computers do random, it's actually a big complex equation that generates a value really close to random, but it actually isn't) generator will get.
Implementing this into your code:
def random_direction():
a = math.radians(random.randint(0, 360))
return pygame.Vector2(math.cos(a), math.sin(a))
i am trying to make a flappy bird game in pygame for school but i am struggling with adding the obstacles. I can add one obstacle but i want to add infinite obstacles and i already have an infinite loop to run my game so when i add an extra infinite, loop my game just crashes. I am using a time.sleep() function when add the obstacle in my infinite loop which makes the game crash.
This is my code so far:
import time
import pygame
pygame.init()
xSpeler = 450
ySpeler = 100
widthSpeler = 40
heightSpeler = 40
vel = 10
vel1 = 10
#obstacle 1
xo1 = 900
yo1 = 0
ho1 = 200
wo1 = 50
xo2 = 900
yo2 = 350
ho2 = 200
wo2 = 50
#obstacle 2
xo3 = 900
yo3 = 0
ho3 = 250
wo3 = 50
xo4 = 900
yo4 = 350
ho4 = 150
wo4 = 50
win = pygame.display.set_mode((1000, 500))
bi = pygame.image.load('bada.png')
pygame.display.flip()
run = True
while run:
win.blit(bi, (0, 0))
pygame.time.delay(1)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
ySpeler += vel
if ySpeler >= 500 - heightSpeler:
ySpeler = 500 - heightSpeler
xo1 -= vel1
xo2 -= vel1
if keys[pygame.K_SPACE] and xSpeler> vel and ySpeler > 0:
ySpeler -= jump
pygame.draw.rect(win, (255, 0, 0), (xSpeler, ySpeler, widthSpeler, heightSpeler))
for x in range(100):
pygame.draw.rect(win, (0, 255, 0), (xo1, yo1, wo1, ho1)) or pygame.draw.rect(win, (0, 255, 0),(xo1, yo1, wo1, ho1))
pygame.draw.rect(win, (0, 255, 0), (xo2, yo2, wo2, ho2)) or pygame.draw.rect(win, (0, 255, 0),(xo2, yo2, wo2, ho2))
time.sleep(7)
pygame.display.update()
im came from netherland so my inglish is not so good and my variables are in dutch so sorry for it
i realy hope someone can help me.
Your screen stays black because of time.sleep(7). It is in a for loop that iterate 100 times so that's your program sleeping 700 seconds every frame. To make an obstacle, make a function that generates and returns 2 obstacles, one for top and the other one for bottom.
def genObstacle():
# generate and return
#1. pygame surface for top and bottom rects
#2. initial position for top rect and bottom rect
topHeight = random.randint(10, 200) # height for bottom obstacle
botHeight = random.randint(10, 200) # height for top obstacle
top = pygame.Surface((10, topHeight)).convert()
bot = pygame.Surface((10, botHeight)).convert()
# return: top rect, bottom rect, top rect's position, bottom rect's position
return [top, bot, [800, 0], [800, 500-botHeight]]
Return the initial positions for both of the obstacles as well, so it is easier to work with. I would really recommend using a class for obstacle, so working with attributes of obstacles like position is easier.
Now that we have a function to generate obstacle, we can make a list to hold those obstacles obstacles = []. Now, we can generate the obstacles every 3 seconds like this:
#other code
start = time.time()
while True:
#other code
now = time.time()
if now - start > 3:
obstacles.append(genObstacle())
start = now
Now that we have obstacles, we can change draw them and change their values like this:
for i in range(len(obstacles)):
# remember, third item in list is position for top and
# fourth item is the position for bottom
# draw the obstacles
win.blit(obstacles[i][0], (obstacles[i][2][0], obstacles[i][3][1]))
win.blit(obstacles[i][1], (obstacles[i][2][0], obstacles[i][3][1]))
# change the x values for it to move to the right
obstacles[i][2][0] -= 1
obstacles[i][2][0] -= 1
So I have been trying to implement a scrolling background in my game recently, however the game background when moved to the left as I move forward leaves a huge trail such as so:
The code is here down below:
#Game background
background = pg.transform.scale(pg.image.load('splash.jpg'), (WIDTH,HEIGHT))#background size being adjusted to fit a particular screen size
background_xpos = 0 #the x position of the background is at 0 of (0,0)
background_xpos2 = background.get_width() #obtains the width of the background at a certain coordinate
def UpdateGame():
window.blit(background,(background_xpos,0))
window.blit(background,(background_xpos,0))
pg.display.update()
run = True #while the game is running
while run:
clock.tick(FPS) #determines the amount of frames per second
background_xpos = background_xpos - 2
background_xpos2 = background_xpos - 2
if background_xpos < background.get_width() * -1:
background_xpos = background.get_width()
if background_xpos2 < background.get_width() * -1:
background_xpos2 = background.get_width()
You have to clear the screen before.
#Game background
background = pg.transform.scale(pg.image.load('splash.jpg'), (WIDTH,HEIGHT))#background size being adjusted to fit a particular screen size
background_xpos = 0 #the x position of the background is at 0 of (0,0)
background_xpos2 = background.get_width() #obtains the width of the background at a certain coordinate
def UpdateGame():
window.blit(background,(background_xpos,0))
window.blit(background,(background_xpos,0))
pg.display.update()
run = True #while the game is running
while run:
screen.fill((0,0,0))
clock.tick(FPS) #determines the amount of frames per second
background_xpos = background_xpos - 2
background_xpos2 = background_xpos - 2
if background_xpos < background.get_width() * -1:
background_xpos = background.get_width()
if background_xpos2 < background.get_width() * -1:
background_xpos2 = background.get_width()