I'm trying to build a mobile interface in pygame. I have a folder called apps and every app contains two files: "app.py" and "app.png". Currently I can get the app name the folder contents. the file contents are saved in an array. I am trying to get the "app.png" from every folder and add it to the pygame screen?
Here is my current code:
from pygame import *
import os
import pygame
import time
import random
_image_library = {}
class SeedOS():
def home(self):
def get_image(path):
global _image_library
image = _image_library.get(path)
if image == None:
canonicalized_path = path.replace('/', os.sep).replace('\\', os.sep)
image = pygame.image.load(canonicalized_path)
_image_library[path] = image
return image
(width, height) = (240, 320)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Seed OS')
BLACK = (0,0,0)
screen.fill(BLACK)
apps = os.walk("apps").next()[1]
app_count = 0
while app_count < len(apps):
print apps[app_count]
icon_width = 0
icon_height = 0
screen.blit(get_image("apps/" + apps[app_count] + "/app.png"), (icon_width, 0))
icon_width+=70
app_count += 1
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
phone = SeedOS()
phone.home()
Notice that icon_width is getting re-initialized to zero with each iteration through the while-loop:
while app_count < len(apps):
print apps[app_count]
icon_width = 0
icon_height = 0
screen.blit(get_image("apps/" + apps[app_count] + "/app.png"), (icon_width, 0))
icon_width+=70
app_count += 1
So the screen.blit will always place the image at (0, 0); icon_width+=70 is nugatory. Instead you could use something like:
icon_width = 0
icon_height = 0
max_width = 240 # <-- you'll need to decide how to set this, depending on size of screen
while app_count < len(apps):
print apps[app_count]
screen.blit(get_image("apps/" + apps[app_count] + "/app.png"),
(icon_width, icon_height))
icon_width += 70
if icon_width > max_width:
icon_width = 0
icon_height += 70 # <-- assuming app.pngs have constant height
app_count += 1
This is still pretty rudimentary -- it does not address the possibility of
different sized app.pngs nor what to do if there are more images than can fit
on the screen. But this should get you over the first hump -- how to place the images at different locations.
Related
I need some help creating a video renderer in Pygame. It has a 48x36 display and has 3 colours. Black, white and grey. The data that goes into the project is in the form of a .txt file and each frame of the video in a line(as an example my video uses 6567 frames so there are 6567 lines in the text file). To render the frames I am using the rectangle function.
pygame.draw.rect(canvas, rect_color, pygame.Rect(30,30,60,60))
(By the way in the .txt file 0=black, 1=white and 2=grey)
After finally making a window pop up it stayed a rather boring black color...
After finally making a window pop up it stayed a rather boring black color...
If you could give any help it would be greatly needed!
(The code is messy i know)
import time
from datetime import datetime
import pygame
file= open(r"C:\Users\User\Downloads\video Data.txt","r")
lines = file.readlines()
current_l = 1
start_time = time.perf_counter()
pygame.init()
surface = pygame.display.set_mode((480,360))
color = (150,75,75)
def start_vid():
current_l = 1
for frame in range(1, 6572):
xpos = 0
ypos = 0
now = datetime.now()
count = 0
seconds = now.second
frame_data = lines[current_l]
current = frame_data[count]
for y in range(0, 36):
for x in range(0, 48):
if current == '0':
pygame.draw.rect(surface, (0, 0, 255),[xpos, xpos+10, ypos, ypos+10], 0)
elif current == '1':
pygame.draw.rect(surface, (255, 255, 255),[xpos, ypos, xpos, ypos], 0)
else:
pygame.draw.rect(surface, (130, 130, 130),[xpos, ypos, xpos, ypos], 0)
#print(current)
#pygame.display.update()
xpos = xpos + 10
current = frame_data[count]
count = count + 1
timer = round(abs((start_time - time.perf_counter())), 1)
current_l = seconds*30
current_l = int(timer*30)
ypos = ypos + -10
print(current_l)
pygame.display.update()
start_vid()
The reason why you can't see anything is because in Pygame, the origin (0, 0) of the screen is in the top left. The right side of the screen is where the x increases, and the bottom is where the y increases. So, the line:
ypos = ypos + -10
draws everything "above" the screen, hence invisible. You need to remove the - sign.
I also saw a couple of things in your code that could be improved, such as:
The fact that you never close the data file. To do that automatically, you could use the with statement:
with open('video.txt') as file:
lines = file.readlines()
# the file is closed
This will allow other applications to access the file.
You are drawing empty rects
You are using the pygame.draw.rect method incorrectly. You should use rect objects like such:
rect = pygame.Rect(x, y, width, height)
pygame.draw.rect(surface, color, rect)
You don't need the time and datetime modules, Pygame handles time like this. For example:
framerate = 30
start = pygame.time.get_ticks()
... # main loop
current_frame = int((pygame.time.get_ticks()-start) / 1000 * framerate)
And, most importantly
In Pygame, you need a main loop with events handling:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
...
pygame.quit()
quit()
A correct implementation of your code could look like this:
import pygame
with open('video.txt') as file:
lines = file.readlines()
pygame.init()
surface = pygame.display.set_mode((480,360))
framerate = 30
start = pygame.time.get_ticks()
run = True
while run:
# get pygame events
for event in pygame.event.get():
if event.type == pygame.QUIT: # user closes the window
run = False
current_frame = int((pygame.time.get_ticks()-start) / 1000 * framerate)
if current_frame < len(lines): # is the video still running?
count = 0
for y in range(36):
for x in range(48):
current_pixel = lines[current_frame][count] # current pixel data
if current_pixel == '0':
color = (0, 0, 0)
elif current_pixel == '1':
color = (127, 127, 127)
else:
color = (255, 255, 255)
pygame.draw.rect(surface, color, pygame.Rect(x*10, y*10, 10, 10))
count += 1 # next pixel
pygame.display.flip()
# user closed the window
pygame.quit()
quit()
(In this example, you can reduce the amount of resources used since you know the framerate of the video using pygame.time.Clock)
I want to run a python file and have all the prints redirect into a txt file.
note the files are in the same folder.
I used this command in a batch file:
code.py > log.txt
I also tried:
C:/mypath/code.py > log.txt
START /B C:/mypath/code.py > log.txt
START /B C:/mypath/code.py > C:/mypath/log.txt
START /B C:/mypath/code.py > C:/mypath/log.txt
All of these run the python script and created a log file but didn't save anything in the file.
EDIT:
people wanted to see the code so here it is: (There are some pictures and other assets so here's a google drive with all the files) https://drive.google.com/drive/folders/1rbUfoQ79CiC-DHViRXx89z8IaY1MIqlP?usp=sharing
#!/usr/bin/env python3
#dvd screensaver that runs when the computer is idle for a certain amount of time
from ctypes import Structure, windll, c_uint, sizeof, byref #afktime imports
#behind the scenes imports
from random import randint
import time
from datetime import datetime
import ctypes
import sys
#behind the scenes imports
import pygame #visual imports
# Settings
user32 = ctypes.windll.user32
SIZE1 = user32.GetSystemMetrics(78), user32.GetSystemMetrics(79)
SIZE = width, height = SIZE1
BG_COLOR = (0, 0, 0)
fullscreen = True
AFK_threshold = 10 #seconds
color = 1
round_afk = 0
last_print = 0
now = datetime.now()
exit = False
seconds_in_day = 60 * 60 * 24
seconds_in_hour = 60 * 60
seconds_in_minute = 60
start = True
#settings
#afktime
class LASTINPUTINFO(Structure): #class for afktime
_fields_ = [
('cbSize', c_uint), #set the size of the struct
('dwTime', c_uint), #set the time
]
def get_idle_duration(): #function for afktime
lastInputInfo = LASTINPUTINFO() #create a struct
lastInputInfo.cbSize = sizeof(lastInputInfo) #set the size of the struct
windll.user32.GetLastInputInfo(byref(lastInputInfo)) #get the time
millis = windll.kernel32.GetTickCount() - lastInputInfo.dwTime #get the time
return millis / 1000.0 #return the time in seconds
#adktime
#main loop
while True:
sys.stdout = open("log.txt", "w") #log file
if start == True: #start screen
dt_string = now.strftime("%d/%m/%Y %H:%M:%S") #current date and time
print("program started " + dt_string) #print program start time and date
print(" ") #print a empty line
round_afk = round(get_idle_duration()) #round afktime
if round_afk != last_print: #if last printed number is not the same as the current afktime
print(round_afk) #print afktime rounded to the nearest second
last_print = round_afk #set last printed number to the current afktime
if get_idle_duration() >= AFK_threshold: #if afktime is greater than threshold
dt_string = now.strftime("%d/%m/%Y %H:%M:%S") #get current time and date
start = time.time() #start the timer
print(" ") #print a empty line
print("your are afk ", dt_string) #print afktime and current time and date
print(" ") #print a empty line
#visual portion
logo = pygame.image.load("assets/logo_color/logo{}.png".format(color)) #load dvd logo
logo = pygame.transform.scale(logo, (100, 50)) #resize dvd logo
clock = pygame.time.Clock() #create clock
img_size = logo.get_rect().size #get dvd logo size
screen = pygame.display.set_mode(SIZE) #set screen size
pygame.display.set_caption('DVD Corner') #set caption
if fullscreen: #if fullscreen
DISPLAYSURF = pygame.display.set_mode((0, 0), pygame.FULLSCREEN) #set fullscreen
pygame.mouse.set_visible(False) #hide mouse
x = randint(50, width-60) #random x position
y = randint(50, height-60) #random y position
x_speed = 2.5 #x speed
y_speed = 2.5 #y speed
def move(x, y): #function for moving dvd logo
screen.blit(logo, (x, y)) #blit dvd logo
while exit == False: #while exit is false
screen.fill(BG_COLOR) #fill screen with background color
if (x + img_size[0] >= width) or (x <= 0): #change color if dvd logo hits the edge of the screen
if color == 8: #if color is 8
color = 1 #set color to 1
else: #if color is not 8
color += 1 #add 1 to color
logo = pygame.image.load("assets/logo_color/logo{}.png".format(color)) #load dvd logo after color change
logo = pygame.transform.scale(logo, (100, 50)) #resize dvd logo
img_size = logo.get_rect().size #get dvd logo size
x_speed = -x_speed #change x speed
if (y + img_size[1] >= height) or (y <= 0): #change color if dvd logo hits the edge of the screen
if color == 8: #if color is 8
color = 1 #set color to 1
else: #if color is not 8
color += 1 #add 1 to color
logo = pygame.image.load("assets/logo_color/logo{}.png".format(color)) #load dvd logo after color change
logo = pygame.transform.scale(logo, (100, 50)) #resize dvd logo
img_size = logo.get_rect().size #get dvd logo size
y_speed = -y_speed #change y speed
if (y + img_size[1] >= height) and (x + img_size[0] >= width): #check if dvd hit the corner
print("corner") #print corner
#move dvd logo
x += x_speed
y += y_speed
move(x, y)
#move dvd logo
pygame.display.update() #update the display
clock.tick(60)
for event in pygame.event.get(): #if evet exit exit
if event.type == pygame.QUIT:
exit = True
if get_idle_duration() <= AFK_threshold: #if idle duration is smaller then threshhold exit
pygame.quit()
break
dt_string = now.strftime("%d/%m/%Y %H:%M:%S") #get current time and date
end = time.time() #end the timer
gap = end - start #gap between start and end
gap_round = round(gap) #round gap
days = gap_round // seconds_in_day #get days
hours = (gap_round - (days * seconds_in_day)) // seconds_in_hour #get hours
minutes = (gap_round - (days * seconds_in_day) - (hours * seconds_in_hour)) // seconds_in_minute #get minutes
gap = str(days) + " days, " + str(hours) + " hours, " + str(minutes) + " minutes and " + str(gap_round) + " seconds" #create gap string
print(" ") #print blank line
print("you are no longer idle " + dt_string) #print you are no longer idle and current time and date and for how long
print("total time idle: ", gap) #print total time idle
print(" ") #print blank line
sys.stdout.close()
pygame.quit() #exit
#visual portion
#main loop
The code is a screensaver app that after a certain amount of time opens the screensaver.
you have 2 ways to do it:
in cmd -> python script.py > log.txt
in your python code:
example:
import sys
sys.stdout = open(PATH_TO_LOG_FILE, "w")
print("hello world")
sys.stdout.close()
output: hello world (in log text file)
I want to display an each object of the class "Obstacle" on the screen. The objects are stored in the list obstacle_list. I dont get an error message, but the window just freezes and no objects are displayed on the screen. I think the problem must be somewhere in def spawn_obstacle(self): but I have no idea where I made a mistake.
import pygame
import random
import time
import math
# Initialize pygame
pygame.init()
# Create window (width, height)
screen = pygame.display.set_mode(((800, 600)))
ScreenHeight = screen.get_height()
ScreenWidth = screen.get_width()
# Background picture
background = pygame.image.load("background.jpg")
# Title and Icon
pygame.display.set_caption("F22-Raptor Simulator")
icon = pygame.image.load("jet1.png")
pygame.display.set_icon(icon)
# Object List (obstacles)
obstacle_list = []
class Obstacle(object):
def __init__(self): # removed unused parameters
self.obstacleImg = 'rock.png' # pygame.image.load("rock.png")
self.obstacleX = random.randint(600, 700)
self.obstacleY = random.randint(0, ScreenHeight - 64)
self.obstacleX_change = random.uniform(-0.3, -0.2)
def __repr__(self):
return f'Obstacle(image={self.obstacleImg!r}, X={self.obstacleX}, Y={self.obstacleY}, change={self.obstacleX_change})'
def spawn_obstacle(self):
image = pygame.image.load(self.obstacleImg)
screen.blit(image, (self.obstacleX, self.obstacleY))
# Keep window running (Infinite-Loop)
running = True
# Timer
timer1_start = time.time()
timer1_current = 0
# Counter while-loop to display objects
count_object_display = 0
# While-Loop (Everything that takes place during the game is inside here)
while running:
timer1_current = time.time()
if timer1_current - timer1_start >= 1:
timer1_start = time.time() # Timer of start set to current time
obstacle = Obstacle() # Create instance of class obstacle
obstacle_list.append(obstacle)
print(obstacle)
# Insert Background
screen.blit(background, (0, 0))
# End game / close window
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
while count_object_display <= len(obstacle_list)-1:
obstacle_list[count_object_display].spawn_obstacle()
count_object_display += 1
if count_object_display > len(obstacle_list)-1:
count_object_display = 0
# Update after each iteration of the while-loop
pygame.display.update()
You have an infinite loop here:
while count_object_display <= len(obstacle_list)-1:
obstacle_list[count_object_display].spawn_obstacle()
count_object_display += 1
if count_object_display > len(obstacle_list)-1:
count_object_display = 0
You enter the while loop and set count_object_display to 1.
In the next line, 1 > 0 so you set count_object_display back to 0.
And since 0 <= 0 the while loop runs forever.
I don't know what you're trying to do there, but maybe just use a simple for loop, like:
for o in obstacle_list:
o.spawn_obstacle()
I have the following code. Which basically gets all the images from the folder apps and the subfolders of it. My problem is that I am trying to add a click event to all of the images to do the same thing. Basically "exec("apps/" + apps[app_count] + "/app.py")"
# -*- coding: utf-8 -*-
from pygame import *
import os
import pygame
import time
import random
import sys
_image_library = {}
class SeedOS():
def home(self):
(width, height) = (240, 320)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Seed OS')
pygame.font.init()
Font30 = pygame.font.SysFont('Arial', 30)
WHITE = (255,255,255)
BLACK = (0,0,0)
screen.fill(WHITE)
apps = os.walk("apps").next()[1]
app_count = 0
icon_width = 15
icon_height = 0
max_width = 155
pygame.display.flip()
while True:
while app_count < len(apps):
print apps[app_count]
image = pygame.image.load("apps/" + apps[app_count] + "/app.png").convert()
screen.blit(image, (icon_width, icon_height))
icon_width+=70
if icon_width > max_width:
icon_width = 15
icon_height +=70
app_count += 1
time2 = time.strftime('%H:%M:%S')
pygame.display.flip()
pygame.draw.rect(screen,BLACK,(0,290,240,30))
clock = Font30.render(time2, False, WHITE)
screen.blit(clock,(60,288))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.quit()
phone = SeedOS()
phone.home()
This is the part of the code that checks all of the things in the folder "apps"
while app_count < len(apps):
print apps[app_count]
image = pygame.image.load("apps/" + apps[app_count] + "/app.png").convert()
screen.blit(image, (icon_width, icon_height))
icon_width+=70
if icon_width > max_width:
icon_width = 15
icon_height +=70
app_count += 1
and appends all the images from each folder. I want on every icon click , execute it's "app.py" as in every app folders there are two files: "app.png" and "app.py".
You can add the coordinates of every image in the apps list and then use these coordinates with the pygame.mouse.get_pos() method :
while True:
while app_count < len(apps):
print apps[app_count]
apps[app_count] = (apps[app_count], icon_width, icon_height) # Adding coordinates to the list
image = pygame.image.load("apps/" + apps[app_count][0] + "/app.png").convert() # Adding an index to find the image in the tuple
screen.blit(image, (icon_width, icon_height))
icon_width+=70
if icon_width > max_width:
icon_width = 15
icon_height +=70
app_count += 1
time2 = time.strftime('%H:%M:%S')
pygame.display.flip()
pygame.draw.rect(screen,BLACK,(0,290,240,30))
clock = Font30.render(time2, False, WHITE)
screen.blit(clock,(60,288))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # MOUSEBUTTONLEFT
for a in apps:
if a[1] < pygame.mouse.get_pos()[0] < a[1]+IMAGEWIDTH and a[2] < pygame.mouse.get_pos()[1] < a[2] + IMAGEHEIGHT:
# Instruction to launch ("apps/" + a[0] + "/app.py")
All you have to do is to define is the width and the height from your icons (what you could do with pygame.Surface.get_size() if it's not the same for every app) and to replace the last line with the correct syntax. On windows you could use :
os.system("apps\\"+a[0]+"\\app.py") # of course you should import os first
I am currently trying to place wall sprites at certain coordinates based on a string from a text file.
What I would like for it to do is read the textfile(getting the string from it). Then based on the character at the index of the string, place a wall sprite at certain coordinates. If it is not a certain character, then just skip placing a wall sprite and move on.
In this case, I want to use # to place a wall. It wont let me post images yet so ill draw it.
TEXTFILE:
###...
As you can see, I place 3 #'s to tell the script I want 3 walls and thats it.
The 3 dots after them are not #, so there should be no wall placed.
In this case it works, as it shows up in my game like such
"# = Wall"
"P = Player"
###
P
But when I try to make a hole in my wall using this kind of placement
TEXTFILE:
###...###
It shows up in my game like such, with no hole in between the two sections of #'s
"# = Wall"
"P = Player"
#########
P
Here is my full main script so far(minus classes), let me know if you need more information. Thanks again!
#I - Import and Initialize
import pygame, IceBackground, Player, Wall, IceBlock
pygame.init()
#D - Display Configuration
screen = pygame.display.set_mode((700, 600))
def main():
pygame.display.set_caption("Sliders")
#E - Entities(Just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((213, 220, 255))
screen.blit(background, (0, 0))
icebackground = IceBackground.IceBG()
player = Player.Box(90, 150)
iceblock = IceBlock.Box(90, 0)
coords = []
with open("TestLevel.txt") as file:
testLevel = file.read()
print(testLevel)
file.close()
strLength = len(testLevel)
xcoord = 0
ycoord = 0
for i in range(strLength):
print(i)
coordInsert = (xcoord, ycoord)
coords.insert(i, coordInsert)
if testLevel[i] == "#":
print("Wall placed!")
print(coordInsert)
print("\n")
walls = [Wall.Box(xcoord, ycoord) for xcoord, ycoord in coords]
elif testLevel[i] != "#":
print("Nothing placed")
print(coordInsert)
print("\n")
xcoord += 30
#iceblock = [IceBlock.Box(xcoord, ycoord) for xcoord, ycoord, in coords]
backgroundSprites = pygame.sprite.Group(icebackground)
wallSprites = pygame.sprite.Group(*walls)
playerSprites = pygame.sprite.Group(player)
#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True
#L - Set up the Main Loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(60)
#E - Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
hitWalls = pygame.sprite.spritecollide(player, wallSprites, False)
if hitWalls:
if player.dx > 0:
player.dx = 0
player.rect.centerx = player.rect.centerx - 10
if player.dx < 0:
player.dx = 0
player.rect.centerx = player.rect.centerx + 10
if player.dy > 0:
player.dy = 0
player.rect.centery = player.rect.centery - 10
if player.dy < 0:
player.dy = 0
player.rect.centery = player.rect.centery + 10
#R - Refresh Display
backgroundSprites.update()
wallSprites.update()
playerSprites.update()
backgroundSprites.draw(screen)
wallSprites.draw(screen)
playerSprites.draw(screen)
pygame.display.flip()
if __name__ == "__main__":
main()
You forgot to increment ycoord by 30 when xcoord == 270. If you don't do so, all your sprite will be aligned.