The first problem that im getting is with my random numbers. every other time i try and run the program i get an error with a random number. The program worked and would make a sierpinski triangle every other time until i tried to add color into the equation now the display box pops up then everything freezes
import sys, pygame, random, math, array
####initializes pygame
pygame.init()
#####deffining all my functions
def verticiePos(verticies):
for i in range(2):
screen.set_at(verticies[i], (0,0,255))
def randV(verticies):
v = random.choice(verticies)
return v
def Show(delay):
pygame.display.flip()
pygame.time.delay(delay)
def randPoint(h,w):
yRand = random.randint(0,h-1)
#maxX = ((w - yRand) * 2)
xRand = random.randint(0, w-1)
return (xRand, yRand)
def mainFunc():
verticiePos(verticies)
randPoint(h,w)
def colors(point, maxRed, maxBlue, maxGreen, bv, gv):
howRed = (math.sqrt(point[0]**2 + point[1]**2) / maxRed) * 255
howRed = int(howRed)
howGreen = ((math.sqrt((point[0] - gv[0])**2 + (point[1] - gv[1])**2)) / maxGreen) * 255
howGreen = int(howGreen)
howBlue = ((math.sqrt((point[0] - bv[0])**2 + (point[1] - bv[1])**2)) / maxBlue) * 255
howBlue = int(howBlue)
return (howRed, howGreen, howBlue)
#####global variables
xRand = 0
yRand = 0
howRed = 0
howBlue = 0
howGreen = 0
#####Let the user choose the size of the display and setting screne
w = input("What do you want the width of the dcreen to be: ")
w = int(w)
h = input("What do you want the height of the dcreen to be: ")
h = int(h)
size = [w,h]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Project 1, Spierpinski triangle")
######setting up my verticies and all the functions i made
verticies = [(1,h - 1), (int(w/2), 1), (w-1,h-1)]
gv = verticies[1]
bv = verticies[2]
lengthOne = w
lengthTwo = math.sqrt(((w/2)**2) + (h**2))
if lengthOne >= lengthTwo:
maxRed = lengthOne
maxBlue = lengthOne
else:
maxRed = lengthTwo
maxBlue = lengthTwo
maxGreen = lengthTwo
############################################
mainFunc()
point = [yRand,xRand]
iteration = 0
delay = 2
#######the main loop thats plots points
for i in range(10000):
v = randV(verticies)
#colors(point, maxRed, maxBlue, maxGreen, bv, gv)
point = (int((point[0] + v[0])/2), int((point[1] + v[1])/2))
howRed = (math.sqrt(point[0]**2 + point[1]**2) / maxRed) * 200
howRed = int(howRed)
howGreen = ((math.sqrt((point[0] - gv[0])**2 + (point[1] - gv[1])**2)) / maxGreen) * 200
howGreen = int(howGreen)
howBlue = ((math.sqrt((point[0] - bv[0])**2 + (point[1] - bv[1])**2)) / maxBlue) * 200
howBlue = int(howBlue)
screen.set_at(point,(howRed,howGreen,howBlue))
Show(delay)
iteration = iteration + 1
#####the loop went really fast and was hard to see it coming into shape so i added this
if iteration > 2000:
delay = 0
#howRed,howGreen,howBlue
This is an updated version of the code that works i just need to clean it up now
Problem with random:
You use random.randint(yRand, maxX) in randPoint() and sometimes yRand > maxX
but random.randint(a, b) require a <= b
http://docs.python.org/2/library/random.html#random.randint
Problem with freeze ???
I have not problem with freeze but you have loop for i in range(50000): and it takes 1 minute to finish. At first run I thought that program freeze.
You have no event loop to get keyboard event and stop program with ESC.
Function color() always return (0,0,0) - it is black - so I don't see Sierpinski triangle.
#EDIT:
Sierpinski Triangle with recursion
import pygame
import math
class Sierpinski():
def __init__(self):
h = w = int(input("Triangle size: "))
level = int(input("Recursion level: "))
margin = 50 # add to size to make margin around triangle
# initializes pygame and setting screne
pygame.init()
self.screen = pygame.display.set_mode( (w + margin*2, h + margin*2) ) # self. - to make accessible in all function
pygame.display.set_caption("Sierpinski Triangle - Recursion")
# offset to move triangle to middle of window
const_height = math.sqrt(3)/2 # h = a * sqrt(3)/2 = a * const_height
invert_const_height = 1 - const_height
offset = int(h * invert_const_height / 2) # to move triange up - to middle
# main vertices A, B, C
a = (margin, h + margin - offset)
b = (w + margin, h + margin - offset)
c = (w/2 + margin, int(h * invert_const_height) + margin - offset)
self.screen.set_at(a, (255,255,255))
self.screen.set_at(b, (255,255,255))
self.screen.set_at(c, (255,255,255))
# recursion
self.drawTriangle(a, b, c, level)
# main loop (in game)
clock = pygame.time.Clock()
running = True
while running:
# keyboard & mouse event
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# move objects - nothing to do here
# draw object & redraw on screen
pygame.display.set_caption("Sierpinski Triangle - Recursion [FPS: %f]" % (clock.get_fps()))
pygame.display.update()
# frametime
clock.tick(25) # max 25 Frames Per Second
# end program
pygame.quit()
#-------------------------------------------------------
def drawTriangle(self, a, b, c, level):
if level == 0:
return
ab = self.middlePoint(a, b)
ac = self.middlePoint(a, c)
bc = self.middlePoint(b, c)
self.screen.set_at(ab, (255,255,255))
self.screen.set_at(bc, (255,255,255))
self.screen.set_at(ac, (255,255,255))
self.drawTriangle(a, ab, ac, level-1)
self.drawTriangle(b, ab, bc, level-1)
self.drawTriangle(c, bc, ac, level-1)
#-------------------------------------------------------
def middlePoint(self, a, b):
x = (a[0] + b[0])/2
y = (a[1] + b[1])/2
return (x,y)
#----------------------------------------------------------------------
if __name__ == '__main__':
Sierpinski()
Related
This question already has answers here:
How do I fix wall warping in my raycaster?
(1 answer)
Problem with recognising where a ray in raycaster intersects a wall along the horizontal axis
(1 answer)
cant get raycast to work from angles 90 to 270 pygame
(1 answer)
Why my raycasting keeps going through walls?
(1 answer)
Closed 3 months ago.
I am trying to create a raycast visualizer. The lines are supposed to shoot out and stop when they collide with a wall. Currently the length is entirely random and sometimes the rays point in directions that are even behind me. I am using an scale of 47 when i draw things to the screen for tiling purposes. I have tried for 10 or so hours every scale in the raycast code and I can't see what I am missing.
import pygame
import numpy
from PygameEngine import GameEngine
import sys
import math
class RayCasting:
FOV = numpy.pi/5
HALF_FOV = FOV/2
NUM_RAYS = GameEngine.WIDTH//2
HALF_NUM_RAYS = NUM_RAYS//2
DELTA_ANGLE = FOV/NUM_RAYS
MAX_DEPTH = 20
def __init__(self, game):
self.game = game
def rayCast(self):
ox, oy = self.game.wasd.pos
x_map = int(ox)
y_map = int(oy)
ray_angle = self.game.wasd.angle - self.HALF_FOV + 0.000001
for ray in range(self.NUM_RAYS):
sin_a = math.sin(ray_angle)
cos_a = math.cos(ray_angle)
# horizontals
y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1)
depth_hor = (y_hor - oy) / sin_a
x_hor = ox + depth_hor * cos_a
delta_depth = dy / sin_a
dx = delta_depth * cos_a
print("YHor: ",y_hor, " DY:", dy, " Depth Hor: ", depth_hor, "X Hor: ", x_hor,
" Delta Depth: ", delta_depth, " DX: ", dx)
for i in range(self.MAX_DEPTH):
tile_hor = int(x_hor), int(y_hor)
if tile_hor in self.game.MAP.wallMap:
# print("INSIDE HOR")
break
x_hor += dx
y_hor += dy
depth_hor += delta_depth
# verticals
x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1)
depth_vert = (x_vert - ox) / cos_a
y_vert = oy + depth_vert * sin_a
delta_depth = dx / cos_a
dy = delta_depth * sin_a
for i in range(self.MAX_DEPTH):
tile_vert = int(x_vert), int(y_vert)
if tile_vert in self.game.MAP.wallMap:
# print("INSIDE VERT")
break
x_vert += dx
y_vert += dy
depth_vert += delta_depth
# depth, texture offset
if depth_vert < depth_hor:
depth = depth_vert
#y_vert %= 1
#offset = y_vert if cos_a > 0 else (1 - y_vert)
else:
depth = depth_hor
#x_hor %= 1
#offset = (1 - x_hor) if sin_a > 0 else x_hor
# remove fishbowl effect
#depth *= math.cos(self.game.wasd.angle - ray_angle)
# projection
#proj_height = SCREEN_DIST / (depth + 0.0001)
# ray casting result
#self.ray_casting_result.append((depth, proj_height, texture, offset))
ray_angle += self.DELTA_ANGLE
pygame.draw.line(self.game.screen, "yellow", (ox*self.game.CELLSIZE,oy*self.game.CELLSIZE), (ox*self.game.CELLSIZE+depth*cos_a, oy*self.game.CELLSIZE+depth*sin_a), 1)
def update(self):
self.rayCast()
from PygameEngine import GameEngine
from Circle import Circle
import pygame
from pygame.locals import *
import sys
import numpy
from map import Map
from RaycastFunction import RayCasting
class RaycastGame(GameEngine):
# Space bar to place this circle which will connect to the WASD with a line
planet = Circle((0,0,0))
planet.keyX = 5
planet.keyY = 5
# Grid set up
def __init__(self):
super().__init__()
self.load()
self.MAP = Map()
self.CELLSIZE = self.MAP.CELLSIZE
# Circle controllable with WASD
self.wasd = Circle((123, 255, 123))
self.raycast = RayCasting(self)
def DDA(self):
# -
# * |
# Remember the Plane is - --m-- +
# * = target |
# m = mouse +
distX = self.wasd.keyX - self.planet.pos[0]
distY = self.wasd.keyY - self.planet.pos[1]
#hypotenuse = numpy.sqrt(distX**2+distY**2)
theta = numpy.arctan((distY/(distX+.0001)))
theta += numpy.deg2rad(90)
# print(numpy.rad2deg(theta), " THETA")
collisionPos = (0,0)
def draw(self):
# Draw MAP array
self.MAP.drawMap()
self.MAP.drawGrid()
# Draw mouse character
#pygame.draw.circle(self.screen, (0, 0, 0),
#(self.plane), Circle.radius)
# Draw planet
# self.planet.draw(self.screen)
# Draw wasd character
self.wasd.draw(self.screen)
# Connect mouse and wasd characters with a line
#pygame.draw.line(self.screen, (255, 255, 255), self.planet.pos, (self.wasd.keyX, self.wasd.keyY), 5)
def update(self):
self.planet.placePlanet()
self.wasd.move()
self.DDA()
self.raycast.update()
def run(self):
# Game loop.
while True:
#This gets written over. Only for clearing screen before each draw
self.screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Update.
self.update()
# Draw
self.draw()
pygame.display.flip()
self.fpsClock.tick(self.FPS)
I do not understand why the rays are not stopping in the proper area.
I have high resolution scans of old navigational maps, that I have turned into map tiles with gdal2tiles. Now I want to write code for a live video stream that records a panning movement between two random points on the maps.
Initially, I had the code working by generating an image for each videoframe, that was assembled from a grid of map tiles. These are small jpg files of 256px x 256px. The next videoframe would then show the same map, but translated a certain amount in the x and y direction.
But opening each jpg with Image.open proved to be a bottleneck. So I tried to make the process faster by reusing the opened tiles until they disappeared off the frame, and only opening fresh tiles as needed. I basically first translate the whole image like so: newframe = oldframe.transform(oldframe.size, Image.AFFINE, data). Then I add a row of fresh tiles on top (or bottom, depending on direction of the panning motion), and on the side.
The problem
I seem to run into some rounding errors (I think), because the opened tiles do not always line up well with the existing, translated content. I have thin lines appearing. But I can't figure out where the rounding errors may come from. Nor how to avoid them.
Here is some code which shows the lines appearing, using colored empty images rather than the map tiles:
import time
import math
from random import randint, uniform
from PIL import Image
import numpy as np
import cv2
FRAMESIZE = (1920, 1080)
TILESIZE = 256
class MyMap:
'''A map class, to hold all its properties'''
def __init__(self) -> None:
self.maxzoom = 8
self.dimensions = (40000, 30000)
self.route, self.zoom = self.trajectory()
pass
def trajectory(self):
'''Calculate random trajectories from map dimensions'''
factor = uniform(1, 8)
extentwidth = FRAMESIZE[0] * factor
extentheight = FRAMESIZE[1] * factor
mapwidth, mapheight = (self.dimensions)
zdiff = math.log2(factor)
newzoom = math.ceil(self.maxzoom - zdiff)
a = (randint(0 + math.ceil(extentwidth / 2), mapwidth - math.floor(extentwidth / 2)),
randint(0 + math.ceil(extentheight / 2), mapheight - math.floor(extentheight / 2))) # Starting point
b = (randint(0 + math.ceil(extentwidth / 2), mapwidth - math.floor(extentwidth / 2)),
randint(0 + math.ceil(extentheight / 2), mapheight - math.floor(extentheight / 2))) # Ending point
x_distance = b[0] - a[0]
y_distance = b[1] - a[1]
distance = math.sqrt((x_distance**2)+(y_distance**2)) # Pythagoras
speed = 3 * factor # pixels per 25th of a second (video framerate)
steps = math.floor(distance / speed)
trajectory = []
for step in range(steps):
x = a[0] + step * x_distance / steps
y = a[1] + step * y_distance / steps
trajectory.append((x, y))
return trajectory, newzoom
def CreateFrame(self, point, oldframe = None):
x = round(self.route[point][0] / (2 ** (self.maxzoom - self.zoom)))
y = round(self.route[point][1] / (2 ** (self.maxzoom - self.zoom)))
if oldframe:
xtrns = x - round(self.route[point - 1][0] / (2 ** (self.maxzoom - self.zoom)))
ytrns = y - round(self.route[point - 1][1] / (2 ** (self.maxzoom - self.zoom)))
# print(x, self.route[point - 1][0] / (2 ** (self.maxzoom - self.zoom)))
west = int(x - FRAMESIZE[0] / 2)
east = int(x + FRAMESIZE[0] / 2)
north = int(y - FRAMESIZE[1] / 2)
south = int(y + FRAMESIZE[1] / 2)
xoffset = west % TILESIZE
yoffset = north % TILESIZE
xrange = range(math.floor(west / TILESIZE), math.ceil(east / TILESIZE))
yrange = range(math.floor(north / TILESIZE), math.ceil(south / TILESIZE))
if oldframe:
data = (
1, #a
0, #b
xtrns, #c +left/-right
0, #d
1, #e
ytrns #f +up/-down
)
newframe = oldframe.transform(oldframe.size, Image.AFFINE, data)
if ytrns < 0:
singlerow_ytile = yrange.start
elif ytrns > 0:
singlerow_ytile = yrange.stop - 1
if ytrns != 0:
for xtile in xrange:
try:
tile = Image.new('RGB', (TILESIZE, TILESIZE), (130,100,10))
newframe.paste(
tile,
(
(xtile - west // TILESIZE) * TILESIZE - xoffset,
(singlerow_ytile - north // TILESIZE) * TILESIZE - yoffset
)
)
except:
tile = None
if xtrns < 0:
singlerow_xtile = xrange.start
elif xtrns > 0:
singlerow_xtile = xrange.stop - 1
if xtrns != 0:
for ytile in yrange:
try:
tile = Image.new('RGB', (TILESIZE, TILESIZE), (200, 200, 200))
newframe.paste(
tile,
(
(singlerow_xtile - west // TILESIZE) * TILESIZE - xoffset,
(ytile - north // TILESIZE) * TILESIZE - yoffset
)
)
except:
tile = None
else:
newframe = Image.new('RGB',FRAMESIZE)
for xtile in xrange:
for ytile in yrange:
try:
tile = Image.new('RGB', (TILESIZE, TILESIZE), (100, 200, 20))
newframe.paste(
tile,
(
(xtile - west // TILESIZE) * TILESIZE - xoffset,
(ytile - north // TILESIZE) * TILESIZE - yoffset
)
)
except:
tile = None
return newframe
def preparedisplay(img, ago):
quit = False
open_cv_image = np.array(img)
# Convert RGB to BGR
open_cv_image = open_cv_image[:, :, ::-1].copy()
# Write some Text
font = cv2.FONT_HERSHEY_TRIPLEX
bottomLeftCornerOfText = (10,1050)
fontScale = 1
fontColor = (2,2,2)
thickness = 2
lineType = 2
cv2.putText(open_cv_image,f"Press q to exit. Frame took {(time.process_time() - ago) * 100}",
bottomLeftCornerOfText,
font,
fontScale,
fontColor,
thickness,
lineType)
return open_cv_image
#===============================================================================
quit = False
while not quit:
currentmap = MyMap()
previousframe = None
step = 0
while step < len(currentmap.route):
start = time.process_time()
currentframe = currentmap.CreateFrame(step, previousframe)
previousframe = currentframe
cv2.imshow('maps', preparedisplay(currentframe, start))
timeleft = (time.process_time() - start)
# print(timeleft)
# if cv2.waitKey(40 - int(timeleft * 100)) == ord('q'):
if cv2.waitKey(1) == ord('q'):
# press q to terminate the loop
cv2.destroyAllWindows()
quit = True
break
step += 1
I created a program that generates the placement of the pendulum, length, position of the ball, velocity, angles, and trajectory. The program's task is to find a solution where the ball can land safely through a 'cave'. The pendulum is inside an 85.75 by 66.75 area, length < 65, ball radius = 1.25
I want to create a simulation of the experiment in pygame, that will run my 1st program to generate all the parameters, and then display the solution and path the ball will follow. I have spent the past couple days learning pygame, but can't figure out how to 'transfer' my first program. Ive looked at other pendulum simulators, and tried to change it to work for my experiment, but I got lost and decided to come to StackOverflow for advice. If anyone could show me where I went wrong in making the simulation, it would be very appreciated.
first program
import math as m
import numpy as np
# Variables
c = 28.5
Wx = 20
Wy = 30
d = 85.75
f = 66.75
g = 385.826772
ay = -g
# Calculations
for theta in np.arange(1, 90, .01):
l = Wx + (m.tan(m.radians(theta)) * (f - Wy))
if Wx <= l <= d:
phi = 90 - theta
v = (d - l) / m.sin(m.radians(phi))
vc = v - 1.25
if (f - Wy) <= v <= 65:
h = f - (m.cos(m.radians(phi)) * v)
a = v * m.sin(m.radians(theta))
b = v * m.cos(m.radians(theta))
by = f - b
bx = l - a
if h <= f and by <= c:
vel = m.sqrt((2 * g) * (h - by)) * .95
velx = vel * m.cos(m.radians(theta))
vely = vel * m.sin(m.radians(theta))
y = (-vely**2) / (2 * ay)
Ymax = y + by
if m.isclose(Ymax, c, abs_tol= .01):
t1 = -vely / ay
t2 = m.sqrt((2 * Ymax) / -ay)
T = t1 + t2
x = velx * T
print(' l: {0} v: {1} vc: {2} h: {3}\n bx: {4} by: {5}\n vel: {6} velx: {7} vely: {8}\n y: {9} Ymax: {10} x: {11} T: {12}\n theta: {13} phi: {14}\n'
.format(l, v, vc, h, bx, by, vel, velx, vely, y, Ymax, x, T, theta, phi))
Simulator
import pygame
import numpy as np
import math as m
from math import pi
# Tarzan Variables
c = 28.5
Wy = 30
Wx = 20
d = 85.75
f = 66.75
# Colors
black = (0, 0, 0)
red = (255, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
# Pygame Variables
theta = 0
v = 0
vel = 0
acc = 0
# Start Pygame
width, height = 900, 700
pygame.init()
background = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
# Tarzan
class Pendulum(object):
def __init__(self, XY, l, radius):
self.x = XY[0]
self.y = XY[1]
self.l = l
self.radius = radius
def draw(self, bg):
pygame.draw.line(bg, white, (self.l, 0), (self.x, self.y), 4)
pygame.draw.circle(bg, red, (self.x, self.y), self.radius)
pygame.draw.line(bg, green, (Wx, height), (Wx, (height - Wy)), 4)
# pygame.draw.circle(bg, white, (self.l, 0), int(v)) --- to see if pendulum is following an arc
def theta_v():
v = m.sqrt(m.pow(pendulum.x - (width / 2), 2) + m.pow(pendulum.y, 2))
theta = m.asin(((pendulum.x - (width / 2)) / v))
return theta, v
def get_path(theta, v):
pendulum.x = round(pendulum.l + (v * m.sin(theta)))
pendulum.y = round(v * m.cos(theta))
pendulum.l = pendulum.x - (v * m.sin(m.radians(theta)))
def redraw():
background.fill(black)
pendulum.draw(background)
pygame.display.update()
pendulum = Pendulum((75, 67), 500, 15)
# Close Pygame
stop = False
acceleration = False
while not stop:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
stop = True
if event.type == pygame.MOUSEBUTTONDOWN:
pendulum = Pendulum(pygame.mouse.get_pos(), 500, 15)
theta, v = theta_v()
acceleration = True
if acceleration:
acc = -.005 * m.sin(theta)
vel += acc
vel *= .995
theta += vel
get_path(theta, v)
print(pendulum.x, pendulum.y, (theta * (180 / pi)), v, vel, pendulum.l)
redraw()
pygame.quit()
quit()
I suppose you wanted this program to create a hanging pendulum swinging around correctly. There were a few things wrong with your code:
In order to calculate your pendulum.l value, you converted theta to radians first. As your theta value was already in radians, This was absolutely not nessary, and makes your pendulum.l value almost not change.
When you now execute your code, you might see that the attachment point of the pendulum is changing. This is because you are changing pendulum.l, and use it for drawingg the pendulum at the same time. This can be easily fixed by saving your first pendulum.l value, and use that value to draw the pendulum.
Your program keeps attampting to move the pendulum forever, giving sometimes unexpected results. You should add some way to figure out whether the pendulum is still moving (probably by chenking whether one of the variables is not changing enough - I had not enough time to figure it out)
Rounding your x and y values causes a buildup if rounding errors on the end, making the pendulium coming to a stop while still being tilted a bit. You can just round while drawing the penduluim to fix this.
The entire code should look like this:
import time
import pygame
import numpy as np
import math as m
from math import pi
# Tarzan Variables
c = 28.5
Wy = 30
Wx = 20
d = 85.75
f = 66.75
# Colors
black = (0, 0, 0)
red = (255, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
# Pygame Variables
theta = 0
v = 0
vel = 0
acc = 0
# Start Pygame
width, height = 900, 700
pygame.init()
background = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
# Tarzan
class Pendulum(object):
def __init__(self, XY, l, radius):
self.x = XY[0]
self.y = XY[1]
self.l = l
self.lfixed = l
self.radius = radius
def draw(self, bg):
pygame.draw.line(bg, white, (self.lfixed, 0), (self.x, self.y), 4)
pygame.draw.circle(bg, red, (round(self.x), round(self.y)), self.radius)
pygame.draw.line(bg, green, (Wx, height), (Wx, (height - Wy)), 4)
# pygame.draw.circle(bg, white, (self.l, 0), int(v)) --- to see if pendulum is following an arc
def theta_v():
v = m.sqrt(m.pow(pendulum.x - (width / 2), 2) + m.pow(pendulum.y, 2))
theta = m.asin(((pendulum.x - (width / 2)) / v))
return theta, v
def get_path(theta, v):
pendulum.x = pendulum.l + (v * m.sin(theta))
pendulum.y = v * m.cos(theta)
pendulum.l = pendulum.x - (v * m.sin((theta)))
def redraw():
background.fill(black)
pendulum.draw(background)
pygame.display.update()
pendulum = Pendulum((75, 67), 500, 15)
# Close Pygame
stop = False
acceleration = False
while not stop:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
stop = True
if event.type == pygame.MOUSEBUTTONDOWN:
pendulum = Pendulum(pygame.mouse.get_pos(), 500, 15)
theta, v = theta_v()
acceleration = True
if acceleration:
acc = -.005 * m.sin(theta)
vel += acc
vel *= .995
theta += vel
get_path(theta, v)
print(pendulum.x, pendulum.y, (theta * (180 / pi)), v, vel, pendulum.l)
redraw()
time.sleep(0.1)
pygame.quit()
quit()
In this program I am able to get the green object to move but not the other one. I commented 'PROBLEM' above an 'if' statement written under function pygame() where I believe the problem exists. Am I supposed to make an elif statement to get the other object to move? Break after if valid(r, c)? etc. Here is the code:
from graphics import *
from time import sleep
''''''
def main():
global win,msg
win = GraphWin("PYGAME", winW, winH)
msg = Text(Point(100, winH - off_field//2), "PYGAME")
msg.draw(win)
make_field()
button_Exit, button_Restart = create_buttons()
pygame()
win.getMouse()
win.close()
''''''
column, row = 12, 10
adjacent = ( ( -1, -1), (0, -1), (1, -1),
( -1, 0), (1, 0),
( -1, 1), (0, 1), (1, 1) )
square_size = 30 # Size of each square on the field
off_field = 100 # Display off the field
# field : main game variable; 'I' = ice, 'B': broken
field = [ [ 'I' for c in range (column)] for r in range (row) ]
# user: identifies whose turn it is to play (click)
user = 0 # How do I switch users?
# Initial users' positions: [r, c]; None later replaced by Circle
users = [ [ row//2, 0, None],
[ row//2, column-1, None] ]
winW, winH = column * square_size, row * square_size + off_field # 360, 400
win = None # main app window
msg = None # main information Text
button_Exit = None # exit button
button_Restart = None # restart button
# squares: grid of squares, initially white, later changed to blue:
squares = None
''''''
# pygame_reset(): resets positions and squares turn white
def pygame_reset():
global win, squares
for r in range(row):
for c in range(column):
squares[r][c].setFill('white')
users[0][:2] = [row//2, 0]
users[1][:2] = [row//2, 0]
# User 1 and 2 are repositioned
# make_field(): makes visual grid of squares
def make_field():
global win, squares
# Allocate memory space for Rectangle objects:
squares = [ [ None for c in range (column)] for r in range (row) ]
for r in range(row):
for c in range(column):
x, y = c * square_size, r * square_size
squares[r][c] = Rectangle(Point(x,y), Point(x + square_size, y + square_size) )
squares[r][c].draw(win)
users[0][2] = Circle(Point(square_size//2, square_size//2 + row //2 *square_size),
square_size//2-5)
users[0][2].setFill('green')
users[0][2].draw(win)
users[1][2] = Circle(Point(square_size*11.5, square_size//2 + row //2 *square_size),
square_size//2-5)
users[1][2].setFill('yellow')
users[1][2].draw(win)
# Reset user's positions and all squares to white:
pygame_reset()
# returns True if position (r, c) is adjacent to
# current user's position
# Recall: users = [ [ r, c, Circle],[ r, c, Circle] ]
def valid(r, c):
pr, pc = users[user][0:2]
for dc, dr in adjacent:
if pr + dr == r and pc + dc == c:
return True
return False
def button_template(win, x, y, w, h, txt):
r = Rectangle(Point(x, y), Point(x+w, y+h))
r.setFill("white")
r.draw(win)
t = Text(r.getCenter(), txt) # same as Point(x+w//2, y+h//2)
t.draw(win)
return [ r, t ]
def create_buttons():
global win, field, squares, msg
button_Exit = button_template(win, 260, winH - off_field//1.25, 60, 25, "Exit")
button_Restart = button_template(win, 260, winH - off_field//2.25, 60, 25, "Restart")
return (button_Exit, button_Restart)
def temporary_color(r, c):
global squares
color = squares[r][c].config['fill']
squares[r][c].setFill('red')
sleep(0.5)
squares[r][c].setFill(color)
def move_user(r, c):
global msg, user, users
pr, pc = users[user][0:2]
dx, dy = square_size * (c - pc), square_size * (r - pr)
users[user][2].move(dx, dy)
users[user][0:2] = [ r, c]
msg.setText("User moves in: " + str((r, c)))
def pygame():
global win, field, squares, msg
while True:
pt = win.getMouse()
if pt.x > 260 and pt.y > winH - off_field//1.25:
msg.setText("Exit")
break
if pt.x > 260 and pt.y > winH - off_field//2.25:
msg.setText("Restart")
break
if pt.y < row * square_size:
r, c = pt.y // square_size, pt.x // square_size
msg.setText(str((r, c)))
# PROBLEM - DO I USE 'break' SOMEWHERE HERE?
if valid(r, c):
move_user(r, c)
# Do I use elif? Break? What to do next?
else:
temporary_color(r, c)
msg.setText("Invalid move")
continue
if valid(r, c):
squares[r][c].setFill('orange')
field[r][c] = 'B'
else:
msg.setText("Not in field")
main()
You need a more sophisticated loop for taking turns. The loop has to keep accepting mouse input until a valid move is made, then switch users. Here's a slightly streamlined version of your program with such a loop:
from time import sleep
from graphics import *
COLUMNS, ROWS = 12, 10
ADJACENT = (
(-1, -1), (0, -1), (1, -1),
(-1, 0), (1, 0),
(-1, 1), (0, 1), (1, 1)
)
SQUARE_SIZE = 30 # Size of each square on the field
OFF_FIELD = 20 # Display off the field
WIN_W, WIN_H = COLUMNS * SQUARE_SIZE, ROWS * SQUARE_SIZE + OFF_FIELD
# pygame_reset(): resets positions and squares turn white
def pygame_reset():
for r in range(ROWS):
for c in range(COLUMNS):
squares[r][c].setFill('white')
# User 1 and 2 are repositioned
users[0][:2] = [ROWS // 2, 0]
users[1][:2] = [ROWS // 2, COLUMNS - 1]
# make_field(): makes visual grid of squares
def make_field():
for r in range(ROWS):
y = r * SQUARE_SIZE
for c in range(COLUMNS):
x = c * SQUARE_SIZE
squares[r][c] = Rectangle(Point(x, y), Point(x + SQUARE_SIZE, y + SQUARE_SIZE))
squares[r][c].draw(win)
users[0][2] = Circle(Point(SQUARE_SIZE//2, SQUARE_SIZE//2 + ROWS//2 * SQUARE_SIZE), SQUARE_SIZE//2 - 5)
users[0][2].setFill('green')
users[1][2] = Circle(Point(SQUARE_SIZE * 11.5, SQUARE_SIZE//2 + ROWS//2 * SQUARE_SIZE), SQUARE_SIZE//2 - 5)
users[1][2].setFill('yellow')
# Reset user's positions and all squares to white:
pygame_reset()
users[0][2].draw(win)
users[1][2].draw(win)
# returns True if position (r, c) is adjacent to
# current user's position
# Recall: users = [[r, c, Circle], [r, c, Circle]]
def valid(r, c):
pr, pc = users[user][:2]
for dc, dr in ADJACENT:
if pr + dr == r and pc + dc == c:
return True
return False
def temporary_color(r, c):
color = squares[r][c].config['fill']
squares[r][c].setFill('red')
sleep(0.5)
squares[r][c].setFill(color)
def move_user(r, c):
pr, pc = users[user][:2]
dx, dy = SQUARE_SIZE * (c - pc), SQUARE_SIZE * (r - pr)
users[user][2].move(dx, dy)
users[user][:2] = r, c
msg.setText("User {} moves to: {}".format(user, (r, c)))
squares[r][c].setFill('orange')
field[r][c] = 'B'
def pygame():
global user
while True:
finished_move = False
while not finished_move:
pt = win.getMouse()
if pt.y < ROWS * SQUARE_SIZE:
r, c = int(pt.y // SQUARE_SIZE), int(pt.x // SQUARE_SIZE)
if valid(r, c):
move_user(r, c)
finished_move = True
else:
temporary_color(r, c)
msg.setText("Invalid move for user {}".format(user))
else:
msg.setText("Not in field")
user = 1 - user # switch user
# field : main game variable; 'I' = ice, 'B': broken
field = [['I' for c in range(COLUMNS)] for r in range(ROWS)]
# squares: grid of squares, initially white, later changed to blue:
squares = [[None for c in range(COLUMNS)] for r in range(ROWS)]
# user: identifies whose turn it is to play (click)
user = 0 # How do I switch users?
# Initial users' positions: [r, c]; None later replaced by Circle
users = [
[ROWS // 2, 0, None],
[ROWS // 2, COLUMNS - 1, None]
]
win = GraphWin("PYGAME", WIN_W, WIN_H) # main app window
msg = Text(Point(WIN_W//2, WIN_H - OFF_FIELD//2), "PYGAME") # main information Text
msg.draw(win)
make_field()
pygame()
win.getMouse()
win.close()
Code-wise, you need to (re)read about the global statement and when it's used.
I'm going to create a python game by using a modules called graphics.
I have created a board with ice and I'm confusing how to create the position for the player in the beginning.
link to the graphics modules:
http://mcsp.wartburg.edu/zelle/python/graphics.py
Here is my code:
from graphics import *
from random import *
column, row = 7, 10
WIN_W, WIN_H = 450, 315
WIN_SZ, GAP = 40, 5
COLORS = [ 'blue', 'white']
player = 'X'
win = None
ices = []
def draw_ice(x, y):
global ices
left = GAP + x* (WIN_SZ+GAP)
top = GAP + y* (WIN_SZ+GAP)
r = Rectangle(Point(left, top), Point(left+WIN_SZ, top+WIN_SZ))
ices[x][y].append(r)
bit = randint(1,1)
ices[x][y].append(bool(bit))
ices[x][y][0].setFill(COLORS[bit])
ices[x][y][0].draw(win)
def draw_ices():
for i in range(row):
ices.append([])
for j in range(column):
ices[i].append([])
draw_ice(i, j)
def MS1():
global win
win = GraphWin("Icebreaker", WIN_W, WIN_H)
draw_ices()
while True:
pt = win.getMouse()
x = int((pt.x - GAP)/(WIN_SZ + GAP))
y = int((pt.y - GAP)/(WIN_SZ + GAP))
print(str((pt.x, pt.y)) + ' --> ' + str((x, y)))
ices[x][y][1] = not ices[x][y][0]
ices[x][y][0].setFill(COLORS[ices[x][y][1]])
position in the beginningMS1()
let's say 'X' is the red circle and 'O' is the blue circle.
I don't know anything about the Icebreaker game but I'm hoping the additional logic I provided you below gives you enough to move forward:
from graphics import *
COLUMN, ROW = 7, 10
WIN_W, WIN_H = 455, 320
WIN_SZ, GAP = 40, 5
COLORS = ['blue', 'white']
CIRCLE, RECTANGLE, COLOR = range(3)
player = 'X'
ices = []
def draw_ice(x, y):
left = GAP + x * (WIN_SZ + GAP)
top = GAP + y * (WIN_SZ + GAP)
r = Rectangle(Point(left, top), Point(left + WIN_SZ, top + WIN_SZ))
c = Circle(r.getCenter(), WIN_SZ / 4)
bit = 1
c.setFill(COLORS[bit])
c.setOutline('white')
r.draw(win)
c.draw(win)
ices[x][y] = [c, r, bool(bit)]
def draw_ices():
for i in range(ROW):
ices.append([])
for j in range(COLUMN):
ices[i].append(None)
draw_ice(i, j)
def MS1():
draw_ices()
x_player = ices[0][3][CIRCLE] # X / Red Player
x_player.setFill('red')
o_player = ices[9][3][CIRCLE] # O / Red Player
o_player.setFill('blue')
while True:
pt = win.getMouse()
x = int((pt.x - GAP) / (WIN_SZ + GAP))
y = int((pt.y - GAP) / (WIN_SZ + GAP))
print((pt.x, pt.y), '-->', (x, y))
ices[x][y][COLOR] = not ices[x][y][COLOR]
ices[x][y][CIRCLE].setFill(COLORS[ices[x][y][COLOR]])
win = GraphWin("Icebreaker", WIN_W, WIN_H)
MS1()