I'm making a game with pygame and pymunk as a physics engine. I'm trying to kill a bullet whenever it hits a player or goes past its lifetime.
When I tried to space.remove(self.shape) and the second bullet hits the player, it gives me an "AssertionError: shape not in space, already removed. I simply changed it to teleport the bullets away, and then learned of the real error.
When I have more than one bullet in the space and a bullet hits the enemy player, all the current bullets teleport away, which means that when I tried to remove one bullet, it called the remove on all the bullets and thats why I had the initial error.
However the problem still remains that one bullet is being treated as every bullet.
Why is something that should be a non-static variable being called as a static variable?
I even tried to use deepcopy to see if that fixed it, but to no avail
This is my chunk of code, apologies since I don't know what is needed to understand it.
The key parts are most likely the Bullet class, the shoot() function in the Player class, and the drawBulletCollision() function
# PyGame template.
# Import modules.
import sys, random, math, time, copy
from typing import List
import pygame
from pygame.locals import *
from pygame import mixer
import pymunk
import pymunk.pygame_util
from pymunk.shapes import Segment
from pymunk.vec2d import Vec2d
pygame.mixer.pre_init(44110, -16, 2, 512)
mixer.init()
# Set up the window.
width, height = 1440, 640
screen = pygame.display.set_mode((width, height))
bg = pygame.image.load("space.png")
def draw_bg():
screen.blit(bg, (0, 0))
#load sounds
#death_fx = pygame.mixer.Sound("")
#death_fx.set_volume(0.25)
shoot_fx = mixer.Sound("shot.wav")
shoot_fx.set_volume(0.25)
#mixer.music.load("video.mp3")
#mixer.music.play()
#time.sleep(2)
#mixer.music.stop()
#gun_mode_fx = pygame.mixer.Sound("")
#gun_mode_fx.set_volume(0.25)
#thrust_mode_fx = pygame.mixer.Sound("")
#thrust_mode_fx.set_volume(0.25)
collision_fx = mixer.Sound("thump.wav")
collision_fx.set_volume(0.25)
ship_group = pygame.sprite.Group()
space = pymunk.Space()
space.gravity = 0, 0
space.damping = 0.6
draw_options = pymunk.pygame_util.DrawOptions(screen)
bulletList = []
playerList = []
environmentList = []
arbiterList = []
b0 = space.static_body
segmentBot = pymunk.Segment(b0, (0,height), (width, height), 4)
segmentTop = pymunk.Segment(b0, (0,0), (width, 0), 4)
segmentLef = pymunk.Segment(b0, (width,0), (width, height), 4)
segmentRit = pymunk.Segment(b0, (0,0), (0, height), 4)
walls = [segmentBot,segmentLef,segmentRit,segmentTop]
for i in walls:
i.elasticity = 1
i.friction = 0.5
i.color = (255,255,255,255)
environmentList.append(i)
class Player(object):
radius = 30
def __init__(self, position, space, color):
self.body = pymunk.Body(mass=5,moment=10)
self.mode = 0 # 0 is gun, 1 is thrust, ? 2 is shield
self.body.position = position
self.shape = pymunk.Circle(self.body, radius = self.radius)
#self.image
#self.shape.friction = 0.9
self.shape.elasticity= 0.2
space.add(self.body,self.shape)
self.angleGun = 0
self.angleThrust = 0
self.health = 100
self.speed = 500
self.gearAngle = 0
self.turningSpeed = 5
self.shape.body.damping = 1000
self.cooldown = 0
self.fireRate = 30
self.shape.collision_type = 1
self.shape.color = color
playerList.append(self)
def force(self,force):
self.shape.body.apply_force_at_local_point(force,(0,0))
def rocketForce(self):
radians = self.angleThrust * math.pi/180
self.shape.body.apply_force_at_local_point((-self.speed * math.cos(radians),-self.speed * math.sin(radians)),(0,0))
def draw(self):
gear = pygame.image.load("gear.png")
gearBox = gear.get_rect(center=self.shape.body.position)
gearRotated = pygame.transform.rotate(gear, self.gearAngle)
#gearRotated.rect.center=self.shape.body.position
x,y = self.shape.body.position
radianGun = self.angleGun * math.pi/180
radianThrust = self.angleThrust * math.pi/180
radiyus = 30 *(100-self.health)/100
screen.blit(gearRotated,gearBox)
self.gearAngle += 1
if radiyus == 30:
radiyus = 32
pygame.draw.circle(screen,self.shape.color,self.shape.body.position,radiyus,0)
pygame.draw.circle(screen,(0,0,0),self.shape.body.position,radiyus,0)
pygame.draw.line(
screen,(0,255,0),
(self.radius * math.cos(radianGun) * 1.5 + x,self.radius * math.sin(radianGun) * 1.5 + y),
(x,y), 5
)
pygame.draw.line(
screen,(200,200,0),
(self.radius * math.cos(radianThrust) * 1.5 + x,self.radius * math.sin(radianThrust) * 1.5 + y),
(x,y), 5
)
#more
def targetAngleGun(self,tAngle):
tempTAngle = tAngle - self.angleGun
tempTAngle = tempTAngle % 360
if(tempTAngle < 180 and not tempTAngle == 0):
self.angleGun -= self.turningSpeed
elif(tempTAngle >= 180 and not tempTAngle == 0):
self.angleGun += self.turningSpeed
self.angleGun = self.angleGun % 360
#print(tAngle, "target Angle")
#print(self.angleGun, "selfangleGun")
#print(tempTAngle, "tempTAngle")
def targetAngleThrust(self,tAngle):
tempTAngle = tAngle - self.angleThrust
tempTAngle = tempTAngle % 360
if(tempTAngle < 180 and not tempTAngle == 0):
self.angleThrust -= self.turningSpeed
elif(tempTAngle >= 180 and not tempTAngle == 0):
self.angleThrust += self.turningSpeed
self.angleThrust = self.angleThrust % 360
#print(tAngle, "target Angle")
#print(self.angleThrust, "selfangleGun")
#print(tempTAngle, "tempTAngle")
def targetAngle(self,tAngle):
if(self.mode == 0):
self.targetAngleGun(tAngle)
elif(self.mode == 1):
self.targetAngleThrust(tAngle)
def shoot(self):
if(self.cooldown == self.fireRate):
x,y = self.shape.body.position
radianGun = self.angleGun * math.pi/180
spawnSpot = (self.radius * math.cos(radianGun) * 1.5 + x,self.radius * math.sin(radianGun)*1.5+y)
self.shape.body.apply_impulse_at_local_point((-20 * math.cos(radianGun),-20 * math.sin(radianGun)),(0,0))
print(spawnSpot)
bT = Bullet(spawnSpot, 5, 50,self.shape.color)
b = copy.deepcopy(bT)
bulletList.append(b)
space.add(b.shape,b.shape.body)
b.getShot(self.angleGun)
self.cooldown = 0
print('pew')
shoot_fx.play()
# HEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
def tick(self):
self.draw()
if(self.cooldown < self.fireRate):
self.cooldown += 1
#for o in playerList:
# c = self.shape.shapes_collide(o.shape)
# if(len(c.points)>0):
# self.damage(c.points[0].distance/10)
for o in bulletList:
c = self.shape.shapes_collide(o.shape)
#print(c)
for o in walls:
c = self.shape.shapes_collide(o)
if(len(c.points)>0):
self.damage(c.points[0].distance * 3)
def damage(self, damage):
self.health -= abs(damage)
if self.health < 0:
self.health = 0
#maybe make it part of the player class
def drawWallCollision(arbiter, space, data):
for c in arbiter.contact_point_set.points:
r = max(3, abs(c.distance * 5))
r = int(r)
p = tuple(map(int, c.point_a))
pygame.draw.circle(data["surface"], pygame.Color("red"), p, r, 0)
print('magnitude', math.sqrt(arbiter.total_impulse[0]**2 + arbiter.total_impulse[1]**2))
#print('position', p)
#print(data)
print("its all arbitrary")
s1, s2 = arbiter.shapes
collision_fx.play()
def drawBulletCollision(arbiter, space, data):
s1, s2 = arbiter.shapes
for c in arbiter.contact_point_set.points:
magnitude = math.sqrt(arbiter.total_impulse[0]**2 + arbiter.total_impulse[1]**2)
for p in playerList:
avr = ((c.point_a[0] + c.point_b[0])/2, (c.point_a[1] + c.point_b[1])/2)
distance = (math.sqrt((avr[0] - p.shape.body.position[0]) **2 + (avr[1] - p.shape.body.position[1]) **2 ))
if(distance < Bullet.explosionRadius + Player.radius):
if not(s1.color == s2.color):
p.damage(magnitude)
for b in bulletList:
avr = ((c.point_a[0] + c.point_b[0])/2, (c.point_a[1] + c.point_b[1])/2)
distance = (math.sqrt((avr[0] - p.shape.body.position[0]) **2 + (avr[1] - p.shape.body.position[1]) **2 ))
if(distance < Bullet.explosionRadius + Player.radius):
if not(s1.color == s2.color):
b.damage(magnitude)
pygame.draw.circle(data["surface"], pygame.Color("red"), tuple(map(int, c.point_a)), 10, 0)
print('magnitude', magnitude)
#print('position', p)
#print(data)
print("its all arbitrary")
def drawArbitraryCollision(arbiter, space, data):
collision_fx.play()
class Ship(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("gear.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
def rotate(self):
self.image = pygame.transform.rotate(self.image,1)
class Bullet(object):
damage = 2
explosionRadius = 5
def __init__(self, position, size, speed,color):
pts = [(-size, -size), (size, -size), (size, size), (-size, size)]
self.body = copy.deepcopy(pymunk.Body(mass=0.1,moment=1))
self.shape = copy.deepcopy(pymunk.Poly(self.body, pts))
self.shape.body.position = position
self.shape.friction = 0.5
self.shape.elasticity = 1
self.shape.color = color
self.speed = speed
self.size = size
self.shape.collision_type = 2
#space.add(self.body,self.shape)
#bulletList.append(self)
self.lifetime = 0
def getShot(self,angle):
radians = angle * math.pi/180
self.shape.body.apply_impulse_at_local_point((self.speed * math.cos(radians),self.speed * math.sin(radians)),(0,0))
def tick(self):
self.lifetime += 1
if(self.lifetime > 300):
self.shape.body.position = (10000,30)
def damage(self, damage):
self.lifetime = 300
#VELOCITY OF BULLET STARTS WITH VELOCITY OF PLAYER
#MAKE VOLUME OF SOUND DEPEND ON THE IMPULSE FOR THE IMPACTS
#error on purpose so you notice this
#INSTANCES NOT WORKING????
def runPyGame():
# Initialise PyGame.
pygame.init()
# Set up the clock. This will tick every frame and thus maintain a relatively constant framerate. Hopefully.
fps = 60.0
fpsClock = pygame.time.Clock()
running = True
font = pygame.font.SysFont("Arial", 16)
p1 = Player((240,240),space,(132, 66, 245,255))
p2 = Player((1200,400),space,(47, 247, 184,255))
space.add(segmentBot,segmentTop,segmentLef,segmentRit)
# Main game loop.
ch = space.add_collision_handler(1, 0)
ch.data["surface"] = screen
ch.post_solve = drawWallCollision
ch = space.add_collision_handler(1, 2)
ch.data["surface"] = screen
ch.post_solve = drawBulletCollision
ch = space.add_collision_handler(0, 2)
ch.data["surface"] = screen
ch.post_solve = drawArbitraryCollision
dt = 1/fps # dt is the time since last frame.
while True: # Loop forever!
keys = pygame.key.get_pressed()
for event in pygame.event.get():
# We need to handle these events. Initially the only one you'll want to care
# about is the QUIT event, because if you don't handle it, your game will crash
# whenever someone tries to exit.
if event.type == QUIT:
pygame.quit() # Opposite of pygame.init
sys.exit() # Not including this line crashes the script on Windows.
if event.type == KEYDOWN:
if event.key == pygame.K_s:
p1.mode = -(p1.mode - 0.5) + 0.5
print(p1.mode)
if (event.key == pygame.K_k and p1.mode == 0):
p1.shoot()
if event.key == pygame.K_KP_5:
p2.mode = -(p2.mode - 0.5) + 0.5
print(p2.mode)
if (event.key == pygame.K_m and p2.mode == 0):
p2.shoot()
#b = Bullet((200,200),51,51)
if(keys[K_w]):
p1.targetAngle(90)
if(keys[K_q]):
p1.targetAngle(45)
if(keys[K_a]):
p1.targetAngle(0)
if(keys[K_z]):
p1.targetAngle(315)
if(keys[K_x]):
p1.targetAngle(270)
if(keys[K_c]):
p1.targetAngle(225)
if(keys[K_d]):
p1.targetAngle(180)
if(keys[K_e]):
p1.targetAngle(135)
if(keys[K_k] and p1.mode == 1):
p1.rocketForce()
if(keys[K_KP_8]):
p2.targetAngle(90)
if(keys[K_KP_7]):
p2.targetAngle(45)
if(keys[K_KP_4]):
p2.targetAngle(0)
if(keys[K_KP_1]):
p2.targetAngle(315)
if(keys[K_KP_2]):
p2.targetAngle(270)
if(keys[K_KP_3]):
p2.targetAngle(225)
if(keys[K_KP_6]):
p2.targetAngle(180)
if(keys[K_KP_9]):
p2.targetAngle(135)
if(keys[K_m] and p2.mode == 1):
p2.rocketForce()
# Handle other events as you wish.
screen.fill((250, 250, 250)) # Fill the screen with black.
# Redraw screen here.
### Draw stuff
draw_bg()
space.debug_draw(draw_options)
for i in playerList:
i.tick()
screen.blit(
font.render("P1 Health: " + str(p1.health), True, pygame.Color("white")),
(50, 10),
)
screen.blit(
font.render("P2 Health: " + str(p2.health), True, pygame.Color("white")),
(50, 30),
)
for i in bulletList:
i.tick()
ship_group.draw(screen)
# Flip the display so that the things we drew actually show up.
pygame.display.update()
dt = fpsClock.tick(fps)
space.step(0.01)
pygame.display.update()
runPyGame()
I cant point to the exact error since the code is quite long and depends on files I dont have. But here is a general advice for troubleshooting:
Try to give a name to each shape when you create them, and then print it out. Also print out the name of each shape that you add or remove from the space. This should show which shape you are actually removing and will probably make it easy to understand whats wrong.
For example:
...
self.shape = pymunk.Circle(self.body, radius = self.radius)
self.shape.name = "circle 1"
print("Created", self.shape.name)
...
print("Adding", self.shape.name)
space.add(self.body,self.shape)
...
(Note that you need to reset the name of shapes you copy, since otherwise the copy will have the same name.)
I am trying to use a map generator I made a few months ago. I remember it worked, I even showed it to some people, but now, it just doesn't work. I havent changed the python version, so this feels quite weird.
When I try to execute the code, I get this error:
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
I have made some research, and the only thing I find is people saying "add the line freeze_support() and it'll work", and it usually does, but it isn't working for me. I've tried torch.multiprocessing.freeze_support(), multiprocessing.freeze_support() and freeze_support(), but it gives the exact same error.
Here is my code:
#!/usr/bin/python3
import os
import signal
import sys
import numpy as np
from multiprocessing import Process, Manager, Value, Array
from threading import Thread
import pygame as pg
vec = pg.math.Vector2
manager = Manager()
SETTINGS = manager.dict()
start_settings = Value('i', 0)
in_settings = Value('i', 0)
quit_settings = Value('i', 0)
reset_settings = Value('i', 0)
generation_finished = Value('i', 0)
generation_started = Value('i', 0)
chunks_generated = Value('i', 0)
apply_settings = Value('i', 0)
SETTINGS["oct"] = 1
SETTINGS["scl"] = 250
SETTINGS["sea"] = 60
SETTINGS["lac"] = 2
SETTINGS["seed"] = 0
SETTINGS["wdh"] = 600
SETTINGS["hgt"] = 600
SETTINGS["offset"] = [0, 0]
SETTINGS["mwd"] = 600
SETTINGS["mhg"] = 600
SETTINGS["zoom"] = 0
SETTINGS["zoom_slider"] = 0
SETTINGS["noise"] = 2
SHARED_MAP = manager.dict()
def remap(OldValue, OldMin, OldMax, NewMin, NewMax):
OldRange = (float(OldMax) - float(OldMin))
NewRange = (float(NewMax) - float(NewMin))
NewValue = (((float(OldValue) - float(OldMin)) * NewRange) / OldRange) + float(NewMin)
return NewValue
def create_noise(iterations, x, y, scale, lacunarity, low, high, ngen):
maxAmp = 0
amp = 1
persistence = 0.5
freq = scale
noise = 0
for i in range(iterations):
noise = noise + ngen.noise2d(x/freq, y/freq) * amp
maxAmp = maxAmp + amp
amp = amp * persistence
freq = freq / lacunarity
noise = noise / maxAmp
noise = noise * (high - low) / 2 + (high + low) / 2
return int(high-noise)
def draw_colored(octv, scale, sea, width, height, lac, pos, seed, noise, offset):
from noise import pnoise2, snoise2
from opensimplex import OpenSimplex
import numpy as np
generation_started.value = 1
xoffset = offset[0] + pos[0]
yoffset = offset[1] + pos[1]
world = np.full((height, width, 3), 255, dtype=np.uint8)
normal_world = world.copy()
# Color all pixels
for x in range(width):
# print(x)
for y in range(height):
if noise == 2:
n = remap(snoise2((x+xoffset)/scale, (y+yoffset)/scale,
octaves=octv, base=seed, lacunarity=lac), -1, 1, 0, 100)
elif noise == 1:
n = remap(pnoise2((x+xoffset)/scale, (y+yoffset)/scale,
octaves=octv, base=seed, lacunarity=lac), -1, 1, 0, 100)
elif noise == 0:
ngen = OpenSimplex(seed)
n = create_noise(octv, x+xoffset, y+yoffset, scale, lac, 0, 100, ngen)
color_dist = int((100-sea)/(octv+2))
if n >= sea:
r = range(sea, 100, color_dist)
hmap = []
cmap = []
for i in r:
hmap.append(i)
cmap.append(remap(i, sea, 100, 150, 255))
d = 255-max(cmap)
for i, h in enumerate(hmap):
if n >= h:
normal_world[y][x][0] = cmap[i]/6
normal_world[y][x][1] = cmap[i] + d
normal_world[y][x][2] = cmap[i]/2
world[y][x][0] = cmap[i]/2
world[y][x][1] = cmap[i]
world[y][x][2] = cmap[i]/3
else:
r = range(0, sea, color_dist*2+1)
hmap = []
cmap = []
for i in r:
hmap.append(i)
cmap.append(remap(i, 0, sea, 50, 150))
for i, h in enumerate(hmap):
if n >= h:
normal_world[y][x][0] = 0
normal_world[y][x][1] = 0
normal_world[y][x][2] = cmap[i]
world[y][x][0] = cmap[i]
world[y][x][1] = 0
world[y][x][2] = 0
SHARED_MAP[tuple(pos)] = normal_world
generation_started.value = 0
generation_finished.value = 1
chunks_generated.value += 1
def sw():
import pygame as pg
from pgui import Slider, Entry, Button, CheckBox
import json
import os
pg.init()
pg.display.set_caption("Settings")
class CustomCheckBox:
def __init__(self, parent, *, x=0, y=0, size=20):
self.parent = parent
self.screen = parent.screen
self.box = CheckBox(self, x=x, y=y, size=size)
self.bg_color = (255, 255, 255)
self.border_width = 3
self.border_color = (0, 0, 0)
self.check_color = (0, 200, 0)
self.cross_width = 5
self.checked = False
self.check_style = "fill"
self.label_side = "top"
self.label_align = "left"
self.label_padding = 3
def update(self):
self.group = self.parent.noise_options
if self.box.clicked:
self.checked = True
for c in self.group:
if c != self:
c.checked = False
else:
pass
self.sync_attributes()
self.box.update()
def sync_attributes(self):
# ------- ATTRIBUTES -------
self.box.bg_color = self.bg_color
self.box.border_width = self.border_width
self.box.border_color = self.border_color
self.box.check_color = self.check_color
self.box.cross_width = self.cross_width
self.box.checked = self.checked
self.box.check_style = self.check_style
self.box.label_side = self.label_side
self.box.label_align = self.label_align
self.box.label_padding = self.label_padding
# --------------------------
def move(self, x, y):
self.box.move(x, y)
def set_font(self, font):
self.box.set_font(font)
def set_font_size(self, size):
self.box.set_font_size(size)
def set_font_color(self, color):
self.box.set_font_color(color)
def set_size(self, size):
self.box.set_size(size)
def set_style(self, style):
self.box.set_style(style)
def set_label(self, text):
self.box.set_label(text)
class Screen:
def create(self):
self.screen = pg.display.set_mode((800, 600))
self.load_button = Button(self, text="Load config", func=self.load)
self.load_button.move(20, 555)
self.load_button.height = 25
self.load_button.set_font_size(15)
self.save_button = Button(self, text="Save config", func=self.save)
self.save_button.move(145, 555)
self.save_button.height = 25
self.save_button.set_font_size(15)
self.reset_button = Button(self, text="Reset config", func=self.reset)
self.reset_button.move(270, 555)
self.reset_button.height = 25
self.reset_button.set_font_size(15)
self.opensimplex_option = CustomCheckBox(self, x=20, y=20)
self.opensimplex_option.check_color = (0, 0, 0)
self.opensimplex_option.set_font_size(15)
self.opensimplex_option.set_label("OpenSimplex noise")
self.opensimplex_option.label_side = "right"
self.opensimplex_option.label_padding = 5
self.perlin_noise_option = CustomCheckBox(self, x=20, y=50)
self.perlin_noise_option.check_color = (0, 0, 0)
self.perlin_noise_option.set_font_size(15)
self.perlin_noise_option.set_label("Perlin noise")
self.perlin_noise_option.label_side = "right"
self.perlin_noise_option.label_padding = 5
self.simplex_option = CustomCheckBox(self, x=20, y=80)
self.simplex_option.check_color = (0, 0, 0)
self.simplex_option.set_font_size(15)
self.simplex_option.set_label("Simplex noise")
self.simplex_option.label_side = "right"
self.simplex_option.label_padding = 5
self.settings_file = Entry(self, x=20, y=500, border=1, size=15, width=300)
self.settings_file.width = 300
self.settings_file.text = "settings.json"
self.settings_file.set_label("Settings file:")
self.noise_options = [
self.opensimplex_option,
self.perlin_noise_option,
self.simplex_option
]
self.noise_options[SETTINGS["noise"]].checked = True
self.widgets = [
self.load_button,
self.save_button,
self.reset_button,
self.opensimplex_option,
self.perlin_noise_option,
self.simplex_option,
self.settings_file
]
for w in self.widgets:
w.border_width = 1
def load(self):
filename = self.settings_file.text
if os.path.isfile(filename):
with open(filename, 'r') as f:
settings = json.load(f)
SETTINGS.update(settings)
self.apply_settings()
self.settings_file.set_label("Settings file:")
else:
self.settings_file.set_label("Settings file: No file at " + os.path.abspath(filename))
def save(self):
settings = SETTINGS.copy()
filename = "settings.json"
with open(filename, 'w') as f:
json.dump(settings, f)
def apply_settings(self):
apply_settings.value = 1
for i in self.noise_options:
i.checked = False
self.noise_options[SETTINGS["noise"]].checked = True
def reset(self):
reset_settings.value = 1
SETTINGS["noise"] = 2
self.noise_options[2].checked = True
self.noise_options[0].checked = False
self.noise_options[1].checked = False
def run(self):
if start_settings.value:
self.create()
start_settings.value = 0
in_settings.value = 1
if in_settings.value:
self.update()
self.events()
if quit_settings.value:
raise SystemExit
def update(self):
self.screen.fill((200, 200, 200))
for w in self.widgets:
w.update()
noises = [
self.opensimplex_option.checked,
self.perlin_noise_option.checked,
self.simplex_option.checked
]
for i, n in enumerate(noises):
if noises[i]:
SETTINGS["noise"] = i
pg.display.flip()
def events(self):
if in_settings.value:
for event in pg.event.get():
if event.type == pg.QUIT:
in_settings.value = 0
pg.display.quit()
elif event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
in_settings.value = 0
pg.display.quit()
sc = Screen()
while True:
sc.run()
def editor():
import pygame as pg
from pgui import Slider, Entry, Button, CheckBox
import os
import cv2
pg.init()
screen = pg.display.set_mode((1200, 704))
pg.display.set_caption("Map creator")
class Editor:
def __init__(self):
self.screen = screen
self.value = 5
self.oct_slider = Slider(self, max=7)
self.oct_slider.move(20, 40)
self.oct_slider.set_length(300)
self.oct_slider.set_font_size(15)
self.oct_slider.set_width(15)
self.oct_slider.set_label("Octaves: 1")
self.oct_slider.set_mark(0)
self.sea_level_slider = Slider(self)
self.sea_level_slider.move(20, 80)
self.sea_level_slider.set_length(300)
self.sea_level_slider.set_font_size(15)
self.sea_level_slider.set_width(15)
self.sea_level_slider.set_label("Sea level: 60")
self.sea_level_slider.set_mark(60)
self.scale_slider = Slider(self, max=599)
self.scale_slider.move(575, 660)
self.scale_slider.set_length(585)
self.scale_slider.set_font_size(15)
self.scale_slider.set_width(15)
self.scale_slider.set_label("Scale: 100")
self.scale_slider.set_mark(99)
self.zoom_slider = Slider(self, max=200, orientation="vertical")
self.zoom_slider.move(525, 25)
self.zoom_slider.set_length(585)
self.zoom_slider.label_align = "center"
self.zoom_slider.set_font_size(15)
self.zoom_slider.set_label("Zoom: 1")
self.zoom_slider.set_width(15)
self.zoom_slider.set_mark(175)
self.zoom = 1
self.map_surface = pg.Surface((600, 600))
self.map_surface.fill(0)
self.map_rect = self.map_surface.get_rect()
self.map_rect.topleft = (575, 25)
self.map = pg.Surface((SETTINGS["wdh"], SETTINGS["hgt"]))
self.map.fill((100, 100, 100))
self.width_slider = Slider(self, max=120)
self.width_slider.move(20, 120)
self.width_slider.set_length(300)
self.width_slider.set_font_size(15)
self.width_slider.set_width(15)
self.width_slider.set_label("Width: 600")
self.width_slider.set_mark(50)
self.height_slider = Slider(self, max=120)
self.height_slider.move(20, 160)
self.height_slider.set_length(300)
self.height_slider.set_font_size(15)
self.height_slider.set_width(15)
self.height_slider.set_label("Height: 600")
self.height_slider.set_mark(50)
self.pos_entry = Entry(self, x=20, y=200, border=1, size=15)
self.pos_entry.text = '0,0'
self.pos_entry.set_label("X,Y Position:")
self.lac_slider = Slider(self, max=40)
self.lac_slider.move(20, 240)
self.lac_slider.set_length(300)
self.lac_slider.set_font_size(15)
self.lac_slider.set_width(15)
self.lac_slider.set_label("Lacunarity: 2")
self.lac_slider.set_mark(10)
self.seed_entry = Entry(self, x=20, y=360, border=1, size=15)
self.seed_entry.text = '0'
self.seed_entry.set_label("Seed:")
self.draw_button = Button(self, x=20, y=625, text="Generate", func=self.draw)
self.draw_button.width = 315
self.clear_button = Button(self, x=345, y=625, text="Clear", func=self.clear)
self.settings_button = Button(self, x=20, y=570, text='Settings', func=self.settings)
self.settings_button.height = 25
self.settings_button.set_font_size(15)
self.abort_button = Button(self, x=140, y=570, text='Abort', func=self.abort_generation)
self.abort_button.height = 25
self.abort_button.set_font_size(15)
self.save_button = Button(self, x=260, y=570, text='Save', func=self.save)
self.save_button.height = 25
self.save_button.set_font_size(15)
self.save_name = Entry(self, x=380, y=570)
self.save_name.text = "image.png"
self.save_name.set_font_size(15)
self.save_name.set_label("Save to file:")
self.widgets = [
self.oct_slider,
self.sea_level_slider,
self.draw_button,
self.scale_slider,
self.zoom_slider,
self.width_slider,
self.height_slider,
self.pos_entry,
self.lac_slider,
self.seed_entry,
self.clear_button,
self.settings_button,
self.abort_button,
self.save_button,
self.save_name
]
self.width_chunks = 4
self.height_chunks = 4
for w in self.widgets:
w.border_width = 1
if isinstance(w, Slider):
w.pointer_border_width = 1
self.movable_map_rect = pg.Rect((0, 0), (600, 600))
self.dragging = False
self.dist = vec(0, 0)
def settings(self):
start_settings.value = 1
def save(self):
filename = self.save_name.text
if filename[-4:] != ".png":
filename += ".png"
surf = pg.transform.rotate(self.map, 90)
surf = pg.transform.flip(surf, 0, 1)
image = []
for x in range(SETTINGS["mwd"]):
row = []
for y in range(SETTINGS["mhg"]):
row.append(surf.get_at((x, y)))
image.append(row)
image = np.array(image)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
print("saving image")
cv2.imwrite(filename, image)
def abort_generation(self):
if generation_started.value:
print("Generation aborted")
for p in self.draw_threads:
p.terminate()
p.join()
generation_started.value = 0
def draw(self):
SETTINGS["mwd"] = SETTINGS["wdh"]
SETTINGS["mhg"] = SETTINGS["hgt"]
SHARED_MAP.clear()
chunks_generated.value = 0
self.draw_threads = []
for x in range(self.width_chunks):
for y in range(self.height_chunks):
width = int(SETTINGS["wdh"]/self.width_chunks)
height = int(SETTINGS["hgt"]/self.height_chunks)
pos = [x*width, y*height]
self.draw_threads.append(Thread(target=draw_colored, args=(SETTINGS["oct"],
SETTINGS["scl"],
SETTINGS["sea"],
width,
height,
SETTINGS["lac"],
pos,
SETTINGS["seed"],
SETTINGS["noise"],
SETTINGS["offset"])))
for p in self.draw_threads:
p.start()
def clear(self):
self.map.fill((100, 100, 100))
self.map_surface.fill(0)
SHARED_MAP.clear()
chunks_generated.value = 0
def run(self):
self.update()
self.events()
def reset_settings(self):
self.oct_slider.set_mark(0)
self.sea_level_slider.set_mark(60)
self.scale_slider.set_mark(99)
self.zoom_slider.set_mark(175)
self.map.fill((100, 100, 100))
self.width_slider.set_mark(50)
self.height_slider.set_mark(50)
self.lac_slider.set_mark(10)
self.pos_entry.text = '0,0'
self.seed_entry.text = '0'
self.mmrect.topleft = self.map_rect.topleft
self.movable_map_rect.topleft = (0, 0)
self.dist = vec(0, 0)
def update_settings(self):
self.oct_slider.set_mark(SETTINGS["oct"]-1)
self.sea_level_slider.set_mark(SETTINGS["sea"])
self.scale_slider.set_mark(SETTINGS["scl"]-1)
self.zoom_slider.set_mark(SETTINGS["zoom_slider"])
self.zoom = SETTINGS["zoom"]
self.width_slider.set_mark(int((SETTINGS["wdh"]-100)/10))
self.height_slider.set_mark(int((SETTINGS["hgt"]-100)/10))
pos = SETTINGS["offset"]
x = str(pos[0])
y = str(pos[1])
self.pos_entry.text = x+','+y
self.lac_slider.set_mark(SETTINGS["lac"]*10-10)
self.seed_entry.text = str(SETTINGS["seed"])
def update(self):
mousepos = vec(pg.mouse.get_pos())
p1 = pg.mouse.get_pressed()[0]
# print(p1, mousepos)
self.screen.fill((200, 200, 200))
if reset_settings.value:
reset_settings.value = 0
self.reset_settings()
if apply_settings.value:
apply_settings.value = 0
self.update_settings()
if generation_finished.value:
generation_finished.value = 0
width = len(SHARED_MAP.values()[0])
height = len(SHARED_MAP.values()[0][0])
self.map = pg.Surface((width*self.width_chunks, height*self.height_chunks))
self.map.fill((100, 100, 100))
self.map_surface.fill((100, 100, 100))
for c in SHARED_MAP.items():
pos = c[0]
chunk = c[1]
map_chunk = pg.pixelcopy.make_surface(chunk)
self.map.blit(map_chunk, (pos[1], pos[0]))
self.map = pg.transform.flip(pg.transform.rotate(self.map, -90), 1, 0)
self.movable_map = pg.transform.scale(
self.map, (int(SETTINGS["mwd"]*self.zoom), int(SETTINGS["mhg"]*self.zoom)))
self.movable_map_rect.size = self.movable_map.get_rect().size
self.mmrect = self.movable_map_rect.copy()
self.mmrect.topleft = vec(self.mmrect.topleft) + vec(575, 25)
if self.mmrect.collidepoint(mousepos) and self.map_rect.collidepoint(mousepos):
mpos = vec(mousepos) - vec(575, 25)
if p1 and not self.dragging:
self.dragging = True
self.dist = mousepos - vec(self.mmrect.topleft)
elif self.dragging and p1:
self.mmrect.topleft = mousepos - self.dist
self.movable_map_rect.center = vec(self.mmrect.center) - vec(575, 25)
elif self.dragging and not p1:
self.dragging = False
self.map_surface.fill(0)
self.map_surface.blit(self.movable_map, self.movable_map_rect)
self.screen.blit(self.map_surface, self.map_rect)
pg.draw.rect(self.screen, (0, 0, 0), self.map_rect, 1)
for w in self.widgets:
w.update()
SETTINGS["oct"] = self.oct_slider.mark+1
SETTINGS["scl"] = self.scale_slider.mark+1
SETTINGS["sea"] = self.sea_level_slider.mark
try:
seed = int(self.seed_entry.text)
except:
if self.seed_entry.text.strip() != '':
seed = int("".join([str(ord(c)) for c in self.seed_entry.text]))
else:
seed = 0
self.oct_slider.set_label("Octaves: "+str(self.oct_slider.mark+1))
self.sea_level_slider.set_label("Sea level: "+str(self.sea_level_slider.mark))
self.scale_slider.set_label("Scale: "+str(self.scale_slider.mark+1))
self.zoom_slider.set_label("Zoom: "+str(self.zoom_slider.max-self.zoom_slider.mark-25))
SETTINGS["zoom_slider"] = self.zoom_slider.mark
zoomval = (self.zoom_slider.max-self.zoom_slider.mark)/25
if zoomval <= 0:
self.zoom = 0.025
else:
self.zoom = zoomval
SETTINGS["zoom"] = self.zoom
self.width_slider.set_label("Width: "+str((self.width_slider.mark)*10+100))
SETTINGS["wdh"] = (self.width_slider.mark)*10+100
self.height_slider.set_label("Height: "+str((self.height_slider.mark)*10+100))
SETTINGS["hgt"] = (self.height_slider.mark)*10+100
self.lac_slider.set_label("Lacunarity: "+str((self.lac_slider.mark+10)/10))
SETTINGS["lac"] = (self.lac_slider.mark+10)/10
pos = self.pos_entry.text.strip().split(',')
for i, p in enumerate(pos):
if p != '':
try:
pos[i] = int(p)
except:
pos[i] = 0
SETTINGS["offset"] = pos
pg.display.flip()
def events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
if not in_settings.value:
quit_settings.value = 1
raise SystemExit
if event.type == pg.MOUSEWHEEL:
if self.map_rect.collidepoint(pg.mouse.get_pos()):
try:
m = self.zoom_slider.mark-event.y
self.zoom_slider.set_mark(m)
except:
self.zoom_slider.set_mark(200)
e = Editor()
while True:
e.run()
if __name__ == "__main__":
freeze_support()
set = Process(target=sw)
ed = Process(target=editor)
set.start()
ed.start()
set.join()
ed.join()
Here is the "settings.json" file needed to run the script:
{
"oct": 8,
"scl": 300,
"sea": 60,
"lac": 2.3,
"seed": 0,
"wdh": 600,
"hgt": 600,
"offset": [100, 100],
"mwd": 600,
"mhg": 600,
"zoom": 1.0,
"zoom_slider": 175,
"noise": 1
}
UPDATE: I have been able to find the line causing the error, which is line 12, manager = Manager(). I have tried looking for issues on the github repo, but I haven't been able to find anything. Is there any work around for this?
I don't have pygame installed and did not want to install it because I do not know pygame and am not really in a position to debug your program if you have other issues with your code other than the obvious things I saw. So I was not able to really test this. But I believe this is at least a good start in the right direction, if not perfect.
Instead of starting two processes, I have created a processing pool of size 2 to which I submit 2 "tasks." But what this allows me to do is to create the managed variables in my main process within the if __name__ == '__main__': block and then to initialize each process in the pool with global variables initialized with these values using a special pool initializer function. The only other change I made is based on the comment I posted to your question. I have therefore renamed method apply_settings to apply_our_settings.
#!/usr/bin/python3
import os
import signal
import sys
import numpy as np
from multiprocessing import Pool, Manager, Value
from threading import Thread
import pygame as pg
import traceback
# initialize processing pool's processes with global variables:
def init_pool(settings, shared_map, s_s, i_s, q_s, r_s, g_f, g_s, c_g, a_s):
global SETTINGS, SHARED_MAP, start_settings, in_settings, quit_settings, reset_settings, \
generation_finished, generation_started, chunks_generated, apply_settings
SETTINGS = settings
SHARED_MAP = shared_map
start_settings = s_s
in_settings = i_s
quit_settings = q_s
reset_settings = r_s
generation_finished = g_f
generation_started = g_s
chunks_generated = c_g
apply_settings = a_s
def remap(OldValue, OldMin, OldMax, NewMin, NewMax):
OldRange = (float(OldMax) - float(OldMin))
NewRange = (float(NewMax) - float(NewMin))
NewValue = (((float(OldValue) - float(OldMin)) * NewRange) / OldRange) + float(NewMin)
return NewValue
def create_noise(iterations, x, y, scale, lacunarity, low, high, ngen):
maxAmp = 0
amp = 1
persistence = 0.5
freq = scale
noise = 0
for i in range(iterations):
noise = noise + ngen.noise2d(x/freq, y/freq) * amp
maxAmp = maxAmp + amp
amp = amp * persistence
freq = freq / lacunarity
noise = noise / maxAmp
noise = noise * (high - low) / 2 + (high + low) / 2
return int(high-noise)
def draw_colored(octv, scale, sea, width, height, lac, pos, seed, noise, offset):
from noise import pnoise2, snoise2
from opensimplex import OpenSimplex
import numpy as np
generation_started.value = 1
xoffset = offset[0] + pos[0]
yoffset = offset[1] + pos[1]
world = np.full((height, width, 3), 255, dtype=np.uint8)
normal_world = world.copy()
# Color all pixels
for x in range(width):
# print(x)
for y in range(height):
if noise == 2:
n = remap(snoise2((x+xoffset)/scale, (y+yoffset)/scale,
octaves=octv, base=seed, lacunarity=lac), -1, 1, 0, 100)
elif noise == 1:
n = remap(pnoise2((x+xoffset)/scale, (y+yoffset)/scale,
octaves=octv, base=seed, lacunarity=lac), -1, 1, 0, 100)
elif noise == 0:
ngen = OpenSimplex(seed)
n = create_noise(octv, x+xoffset, y+yoffset, scale, lac, 0, 100, ngen)
color_dist = int((100-sea)/(octv+2))
if n >= sea:
r = range(sea, 100, color_dist)
hmap = []
cmap = []
for i in r:
hmap.append(i)
cmap.append(remap(i, sea, 100, 150, 255))
d = 255-max(cmap)
for i, h in enumerate(hmap):
if n >= h:
normal_world[y][x][0] = cmap[i]/6
normal_world[y][x][1] = cmap[i] + d
normal_world[y][x][2] = cmap[i]/2
world[y][x][0] = cmap[i]/2
world[y][x][1] = cmap[i]
world[y][x][2] = cmap[i]/3
else:
r = range(0, sea, color_dist*2+1)
hmap = []
cmap = []
for i in r:
hmap.append(i)
cmap.append(remap(i, 0, sea, 50, 150))
for i, h in enumerate(hmap):
if n >= h:
normal_world[y][x][0] = 0
normal_world[y][x][1] = 0
normal_world[y][x][2] = cmap[i]
world[y][x][0] = cmap[i]
world[y][x][1] = 0
world[y][x][2] = 0
SHARED_MAP[tuple(pos)] = normal_world
generation_started.value = 0
generation_finished.value = 1
chunks_generated.value += 1
def sw():
import pygame as pg
from pgui import Slider, Entry, Button, CheckBox
import json
import os
pg.init()
pg.display.set_caption("Settings")
class CustomCheckBox:
def __init__(self, parent, *, x=0, y=0, size=20):
self.parent = parent
self.screen = parent.screen
self.box = CheckBox(self, x=x, y=y, size=size)
self.bg_color = (255, 255, 255)
self.border_width = 3
self.border_color = (0, 0, 0)
self.check_color = (0, 200, 0)
self.cross_width = 5
self.checked = False
self.check_style = "fill"
self.label_side = "top"
self.label_align = "left"
self.label_padding = 3
def update(self):
self.group = self.parent.noise_options
if self.box.clicked:
self.checked = True
for c in self.group:
if c != self:
c.checked = False
else:
pass
self.sync_attributes()
self.box.update()
def sync_attributes(self):
# ------- ATTRIBUTES -------
self.box.bg_color = self.bg_color
self.box.border_width = self.border_width
self.box.border_color = self.border_color
self.box.check_color = self.check_color
self.box.cross_width = self.cross_width
self.box.checked = self.checked
self.box.check_style = self.check_style
self.box.label_side = self.label_side
self.box.label_align = self.label_align
self.box.label_padding = self.label_padding
# --------------------------
def move(self, x, y):
self.box.move(x, y)
def set_font(self, font):
self.box.set_font(font)
def set_font_size(self, size):
self.box.set_font_size(size)
def set_font_color(self, color):
self.box.set_font_color(color)
def set_size(self, size):
self.box.set_size(size)
def set_style(self, style):
self.box.set_style(style)
def set_label(self, text):
self.box.set_label(text)
class Screen:
def create(self):
self.screen = pg.display.set_mode((800, 600))
self.load_button = Button(self, text="Load config", func=self.load)
self.load_button.move(20, 555)
self.load_button.height = 25
self.load_button.set_font_size(15)
self.save_button = Button(self, text="Save config", func=self.save)
self.save_button.move(145, 555)
self.save_button.height = 25
self.save_button.set_font_size(15)
self.reset_button = Button(self, text="Reset config", func=self.reset)
self.reset_button.move(270, 555)
self.reset_button.height = 25
self.reset_button.set_font_size(15)
self.opensimplex_option = CustomCheckBox(self, x=20, y=20)
self.opensimplex_option.check_color = (0, 0, 0)
self.opensimplex_option.set_font_size(15)
self.opensimplex_option.set_label("OpenSimplex noise")
self.opensimplex_option.label_side = "right"
self.opensimplex_option.label_padding = 5
self.perlin_noise_option = CustomCheckBox(self, x=20, y=50)
self.perlin_noise_option.check_color = (0, 0, 0)
self.perlin_noise_option.set_font_size(15)
self.perlin_noise_option.set_label("Perlin noise")
self.perlin_noise_option.label_side = "right"
self.perlin_noise_option.label_padding = 5
self.simplex_option = CustomCheckBox(self, x=20, y=80)
self.simplex_option.check_color = (0, 0, 0)
self.simplex_option.set_font_size(15)
self.simplex_option.set_label("Simplex noise")
self.simplex_option.label_side = "right"
self.simplex_option.label_padding = 5
self.settings_file = Entry(self, x=20, y=500, border=1, size=15, width=300)
self.settings_file.width = 300
self.settings_file.text = "settings.json"
self.settings_file.set_label("Settings file:")
self.noise_options = [
self.opensimplex_option,
self.perlin_noise_option,
self.simplex_option
]
self.noise_options[SETTINGS["noise"]].checked = True
self.widgets = [
self.load_button,
self.save_button,
self.reset_button,
self.opensimplex_option,
self.perlin_noise_option,
self.simplex_option,
self.settings_file
]
for w in self.widgets:
w.border_width = 1
def load(self):
filename = self.settings_file.text
if os.path.isfile(filename):
with open(filename, 'r') as f:
settings = json.load(f)
SETTINGS.update(settings)
self.apply_our_settings()
self.settings_file.set_label("Settings file:")
else:
self.settings_file.set_label("Settings file: No file at " + os.path.abspath(filename))
def save(self):
settings = SETTINGS.copy()
filename = "settings.json"
with open(filename, 'w') as f:
json.dump(settings, f)
def apply_our_settings(self):
apply_settings.value = 1
for i in self.noise_options:
i.checked = False
self.noise_options[SETTINGS["noise"]].checked = True
def reset(self):
reset_settings.value = 1
SETTINGS["noise"] = 2
self.noise_options[2].checked = True
self.noise_options[0].checked = False
self.noise_options[1].checked = False
def run(self):
if start_settings.value:
self.create()
start_settings.value = 0
in_settings.value = 1
if in_settings.value:
self.update()
self.events()
if quit_settings.value:
raise SystemExit
def update(self):
self.screen.fill((200, 200, 200))
for w in self.widgets:
w.update()
noises = [
self.opensimplex_option.checked,
self.perlin_noise_option.checked,
self.simplex_option.checked
]
for i, n in enumerate(noises):
if noises[i]:
SETTINGS["noise"] = i
pg.display.flip()
def events(self):
if in_settings.value:
for event in pg.event.get():
if event.type == pg.QUIT:
in_settings.value = 0
pg.display.quit()
elif event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
in_settings.value = 0
pg.display.quit()
sc = Screen()
while True:
sc.run()
def editor():
import pygame as pg
from pgui import Slider, Entry, Button, CheckBox
import os
import cv2
pg.init()
screen = pg.display.set_mode((1200, 704))
pg.display.set_caption("Map creator")
vec = pg.math.Vector2
class Editor:
def __init__(self):
self.screen = screen
self.value = 5
self.oct_slider = Slider(self, max=7)
self.oct_slider.move(20, 40)
self.oct_slider.set_length(300)
self.oct_slider.set_font_size(15)
self.oct_slider.set_width(15)
self.oct_slider.set_label("Octaves: 1")
self.oct_slider.set_mark(0)
self.sea_level_slider = Slider(self)
self.sea_level_slider.move(20, 80)
self.sea_level_slider.set_length(300)
self.sea_level_slider.set_font_size(15)
self.sea_level_slider.set_width(15)
self.sea_level_slider.set_label("Sea level: 60")
self.sea_level_slider.set_mark(60)
self.scale_slider = Slider(self, max=599)
self.scale_slider.move(575, 660)
self.scale_slider.set_length(585)
self.scale_slider.set_font_size(15)
self.scale_slider.set_width(15)
self.scale_slider.set_label("Scale: 100")
self.scale_slider.set_mark(99)
self.zoom_slider = Slider(self, max=200, orientation="vertical")
self.zoom_slider.move(525, 25)
self.zoom_slider.set_length(585)
self.zoom_slider.label_align = "center"
self.zoom_slider.set_font_size(15)
self.zoom_slider.set_label("Zoom: 1")
self.zoom_slider.set_width(15)
self.zoom_slider.set_mark(175)
self.zoom = 1
self.map_surface = pg.Surface((600, 600))
self.map_surface.fill(0)
self.map_rect = self.map_surface.get_rect()
self.map_rect.topleft = (575, 25)
self.map = pg.Surface((SETTINGS["wdh"], SETTINGS["hgt"]))
self.map.fill((100, 100, 100))
self.width_slider = Slider(self, max=120)
self.width_slider.move(20, 120)
self.width_slider.set_length(300)
self.width_slider.set_font_size(15)
self.width_slider.set_width(15)
self.width_slider.set_label("Width: 600")
self.width_slider.set_mark(50)
self.height_slider = Slider(self, max=120)
self.height_slider.move(20, 160)
self.height_slider.set_length(300)
self.height_slider.set_font_size(15)
self.height_slider.set_width(15)
self.height_slider.set_label("Height: 600")
self.height_slider.set_mark(50)
self.pos_entry = Entry(self, x=20, y=200, border=1, size=15)
self.pos_entry.text = '0,0'
self.pos_entry.set_label("X,Y Position:")
self.lac_slider = Slider(self, max=40)
self.lac_slider.move(20, 240)
self.lac_slider.set_length(300)
self.lac_slider.set_font_size(15)
self.lac_slider.set_width(15)
self.lac_slider.set_label("Lacunarity: 2")
self.lac_slider.set_mark(10)
self.seed_entry = Entry(self, x=20, y=360, border=1, size=15)
self.seed_entry.text = '0'
self.seed_entry.set_label("Seed:")
self.draw_button = Button(self, x=20, y=625, text="Generate", func=self.draw)
self.draw_button.width = 315
self.clear_button = Button(self, x=345, y=625, text="Clear", func=self.clear)
self.settings_button = Button(self, x=20, y=570, text='Settings', func=self.settings)
self.settings_button.height = 25
self.settings_button.set_font_size(15)
self.abort_button = Button(self, x=140, y=570, text='Abort', func=self.abort_generation)
self.abort_button.height = 25
self.abort_button.set_font_size(15)
self.save_button = Button(self, x=260, y=570, text='Save', func=self.save)
self.save_button.height = 25
self.save_button.set_font_size(15)
self.save_name = Entry(self, x=380, y=570)
self.save_name.text = "image.png"
self.save_name.set_font_size(15)
self.save_name.set_label("Save to file:")
self.widgets = [
self.oct_slider,
self.sea_level_slider,
self.draw_button,
self.scale_slider,
self.zoom_slider,
self.width_slider,
self.height_slider,
self.pos_entry,
self.lac_slider,
self.seed_entry,
self.clear_button,
self.settings_button,
self.abort_button,
self.save_button,
self.save_name
]
self.width_chunks = 4
self.height_chunks = 4
for w in self.widgets:
w.border_width = 1
if isinstance(w, Slider):
w.pointer_border_width = 1
self.movable_map_rect = pg.Rect((0, 0), (600, 600))
self.dragging = False
self.dist = vec(0, 0)
def settings(self):
start_settings.value = 1
def save(self):
filename = self.save_name.text
if filename[-4:] != ".png":
filename += ".png"
surf = pg.transform.rotate(self.map, 90)
surf = pg.transform.flip(surf, 0, 1)
image = []
for x in range(SETTINGS["mwd"]):
row = []
for y in range(SETTINGS["mhg"]):
row.append(surf.get_at((x, y)))
image.append(row)
image = np.array(image)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
print("saving image")
cv2.imwrite(filename, image)
def abort_generation(self):
if generation_started.value:
print("Generation aborted")
for p in self.draw_threads:
p.terminate()
p.join()
generation_started.value = 0
def draw(self):
SETTINGS["mwd"] = SETTINGS["wdh"]
SETTINGS["mhg"] = SETTINGS["hgt"]
SHARED_MAP.clear()
chunks_generated.value = 0
self.draw_threads = []
for x in range(self.width_chunks):
for y in range(self.height_chunks):
width = int(SETTINGS["wdh"]/self.width_chunks)
height = int(SETTINGS["hgt"]/self.height_chunks)
pos = [x*width, y*height]
self.draw_threads.append(Thread(target=draw_colored, args=(SETTINGS["oct"],
SETTINGS["scl"],
SETTINGS["sea"],
width,
height,
SETTINGS["lac"],
pos,
SETTINGS["seed"],
SETTINGS["noise"],
SETTINGS["offset"])))
for p in self.draw_threads:
p.start()
def clear(self):
self.map.fill((100, 100, 100))
self.map_surface.fill(0)
SHARED_MAP.clear()
chunks_generated.value = 0
def run(self):
self.update()
self.events()
def reset_settings(self):
self.oct_slider.set_mark(0)
self.sea_level_slider.set_mark(60)
self.scale_slider.set_mark(99)
self.zoom_slider.set_mark(175)
self.map.fill((100, 100, 100))
self.width_slider.set_mark(50)
self.height_slider.set_mark(50)
self.lac_slider.set_mark(10)
self.pos_entry.text = '0,0'
self.seed_entry.text = '0'
self.mmrect.topleft = self.map_rect.topleft
self.movable_map_rect.topleft = (0, 0)
self.dist = vec(0, 0)
def update_settings(self):
self.oct_slider.set_mark(SETTINGS["oct"]-1)
self.sea_level_slider.set_mark(SETTINGS["sea"])
self.scale_slider.set_mark(SETTINGS["scl"]-1)
self.zoom_slider.set_mark(SETTINGS["zoom_slider"])
self.zoom = SETTINGS["zoom"]
self.width_slider.set_mark(int((SETTINGS["wdh"]-100)/10))
self.height_slider.set_mark(int((SETTINGS["hgt"]-100)/10))
pos = SETTINGS["offset"]
x = str(pos[0])
y = str(pos[1])
self.pos_entry.text = x+','+y
self.lac_slider.set_mark(SETTINGS["lac"]*10-10)
self.seed_entry.text = str(SETTINGS["seed"])
def update(self):
mousepos = vec(pg.mouse.get_pos())
p1 = pg.mouse.get_pressed()[0]
# print(p1, mousepos)
self.screen.fill((200, 200, 200))
if reset_settings.value:
reset_settings.value = 0
self.reset_settings()
if apply_settings.value:
apply_settings.value = 0
self.update_settings()
if generation_finished.value:
generation_finished.value = 0
width = len(SHARED_MAP.values()[0])
height = len(SHARED_MAP.values()[0][0])
self.map = pg.Surface((width*self.width_chunks, height*self.height_chunks))
self.map.fill((100, 100, 100))
self.map_surface.fill((100, 100, 100))
for c in SHARED_MAP.items():
pos = c[0]
chunk = c[1]
map_chunk = pg.pixelcopy.make_surface(chunk)
self.map.blit(map_chunk, (pos[1], pos[0]))
self.map = pg.transform.flip(pg.transform.rotate(self.map, -90), 1, 0)
self.movable_map = pg.transform.scale(
self.map, (int(SETTINGS["mwd"]*self.zoom), int(SETTINGS["mhg"]*self.zoom)))
self.movable_map_rect.size = self.movable_map.get_rect().size
self.mmrect = self.movable_map_rect.copy()
self.mmrect.topleft = vec(self.mmrect.topleft) + vec(575, 25)
if self.mmrect.collidepoint(mousepos) and self.map_rect.collidepoint(mousepos):
mpos = vec(mousepos) - vec(575, 25)
if p1 and not self.dragging:
self.dragging = True
self.dist = mousepos - vec(self.mmrect.topleft)
elif self.dragging and p1:
self.mmrect.topleft = mousepos - self.dist
self.movable_map_rect.center = vec(self.mmrect.center) - vec(575, 25)
elif self.dragging and not p1:
self.dragging = False
self.map_surface.fill(0)
self.map_surface.blit(self.movable_map, self.movable_map_rect)
self.screen.blit(self.map_surface, self.map_rect)
pg.draw.rect(self.screen, (0, 0, 0), self.map_rect, 1)
for w in self.widgets:
w.update()
SETTINGS["oct"] = self.oct_slider.mark+1
SETTINGS["scl"] = self.scale_slider.mark+1
SETTINGS["sea"] = self.sea_level_slider.mark
try:
seed = int(self.seed_entry.text)
except:
if self.seed_entry.text.strip() != '':
seed = int("".join([str(ord(c)) for c in self.seed_entry.text]))
else:
seed = 0
self.oct_slider.set_label("Octaves: "+str(self.oct_slider.mark+1))
self.sea_level_slider.set_label("Sea level: "+str(self.sea_level_slider.mark))
self.scale_slider.set_label("Scale: "+str(self.scale_slider.mark+1))
self.zoom_slider.set_label("Zoom: "+str(self.zoom_slider.max-self.zoom_slider.mark-25))
SETTINGS["zoom_slider"] = self.zoom_slider.mark
zoomval = (self.zoom_slider.max-self.zoom_slider.mark)/25
if zoomval <= 0:
self.zoom = 0.025
else:
self.zoom = zoomval
SETTINGS["zoom"] = self.zoom
self.width_slider.set_label("Width: "+str((self.width_slider.mark)*10+100))
SETTINGS["wdh"] = (self.width_slider.mark)*10+100
self.height_slider.set_label("Height: "+str((self.height_slider.mark)*10+100))
SETTINGS["hgt"] = (self.height_slider.mark)*10+100
self.lac_slider.set_label("Lacunarity: "+str((self.lac_slider.mark+10)/10))
SETTINGS["lac"] = (self.lac_slider.mark+10)/10
pos = self.pos_entry.text.strip().split(',')
for i, p in enumerate(pos):
if p != '':
try:
pos[i] = int(p)
except:
pos[i] = 0
SETTINGS["offset"] = pos
pg.display.flip()
def events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
if not in_settings.value:
quit_settings.value = 1
raise SystemExit
if event.type == pg.MOUSEWHEEL:
if self.map_rect.collidepoint(pg.mouse.get_pos()):
try:
m = self.zoom_slider.mark-event.y
self.zoom_slider.set_mark(m)
except:
self.zoom_slider.set_mark(200)
e = Editor()
while True:
e.run()
if __name__ == "__main__":
manager = Manager()
SETTINGS = manager.dict()
start_settings = Value('i', 0)
in_settings = Value('i', 0)
quit_settings = Value('i', 0)
reset_settings = Value('i', 0)
generation_finished = Value('i', 0)
generation_started = Value('i', 0)
chunks_generated = Value('i', 0)
apply_settings = Value('i', 0)
SETTINGS["oct"] = 1
SETTINGS["scl"] = 250
SETTINGS["sea"] = 60
SETTINGS["lac"] = 2
SETTINGS["seed"] = 0
SETTINGS["wdh"] = 600
SETTINGS["hgt"] = 600
SETTINGS["offset"] = [0, 0]
SETTINGS["mwd"] = 600
SETTINGS["mhg"] = 600
SETTINGS["zoom"] = 0
SETTINGS["zoom_slider"] = 0
SETTINGS["noise"] = 2
SHARED_MAP = manager.dict()
# create pool with two processes and initialize global variables:
pool = Pool(2, initializer=init_pool, initargs=(SETTINGS,
SHARED_MAP,
start_settings,
in_settings,
quit_settings,
reset_settings,
generation_finished,
generation_started,
chunks_generated,
apply_settings))
result1 = pool.apply_async(sw)
result2 = pool.apply_async(editor)
# wait for tasks to complete:
try:
return_value_1 = result1.get()
except Exception:
print(traceback.print_exc())
try:
return_value_2 = result2.get()
except Exception:
print(traceback.print_exc())
Note: Since your tasks do not actually return any values of interest, I could have awaited for the tasks to complete by issuing the following two commands in lieu of calling get() on the AsycnResult instances returned by the calls to apply_async:
pool.close()
pool.join()
But then any exceptions thrown in your tasks would not be detected.
I also question whether shared Value variables start_settings through apply_settings really needed to be implemented as shared variables; they don't seem to be shared with another process.
So I have this maze code, and it's really cool but when you play you move around a red square. Is there a way that I can change this red square that moves around into an image, instead of where it says return "red" I want to put this personaje.gif file so a little person can appear moving through the maze.
this is my code:
import random
import Tkinter as tk
import sys
from PIL import Image, ImageTk
class Application(tk.Frame):
def __init__(self, width=600, height=600, size=600):
tk.Frame.__init__(self)
self.maze = Maze(width, height)
personaje = Image.open("personaje.gif")
photo = ImageTk.PhotoImage(personaje)
self.size = size
self.steps = 0
self.grid()
self.create_widgets()
self.draw_maze()
self.create_events()
def create_widgets(self):
width = self.maze.width * self.size
height = self.maze.height * self.size
self.canvas = tk.Canvas(self, width=width, height=height)
self.canvas.grid()
self.status = tk.Label(self)
self.status.grid()
def draw_maze(self):
for i, row in enumerate(self.maze.maze):
for j, col in enumerate(row):
x0 = j * self.size
y0 = i * self.size
x1 = x0 + self.size
y1 = y0 + self.size
color = self.get_color(x=j, y=i)
id = self.canvas.create_rectangle(x0, y0, x1, y1, width=0, fill=color)
if self.maze.start_cell == (j, i):
self.cell = id
self.canvas.tag_raise(self.cell) # bring to front
self.status.config(text='Movidas mínimas: %d' % self.maze.steps)
def create_events(self):
self.canvas.bind_all('<KeyPress-Up>', self.move_cell)
self.canvas.bind_all('<KeyPress-Down>', self.move_cell)
self.canvas.bind_all('<KeyPress-Left>', self.move_cell)
self.canvas.bind_all('<KeyPress-Right>', self.move_cell)
def move_cell(self, event):
if event.keysym == 'Up':
if self.check_move(0, -1):
self.canvas.move(self.cell, 0, -self.size)
self.steps += 1
if event.keysym == 'Down':
if self.check_move(0, 1):
self.canvas.move(self.cell, 0, self.size)
self.steps += 1
if event.keysym == 'Left':
if self.check_move(-1, 0):
self.canvas.move(self.cell, -self.size, 0)
self.steps += 1
if event.keysym == 'Right':
if self.check_move(1, 0):
self.canvas.move(self.cell, self.size, 0)
self.steps += 1
args = (self.steps, self.maze.steps)
self.status.config(text='Movimientos %d/%d' % args)
self.check_status()
def check_move(self, x, y):
x0, y0 = self.get_cell_coords()
x1 = x0 + x
y1 = y0 + y
return self.maze.maze[y1][x1] == 0
def get_cell_coords(self):
position = self.canvas.coords(self.cell)
x = int(position[0] / self.size)
y = int(position[1] / self.size)
return (x, y)
def check_status(self):
if self.maze.exit_cell == self.get_cell_coords():
args = (self.steps, self.maze.steps)
self.status.config(text='Resuelto en %d/%d movidas!' % args)
def get_color(self, x, y):
if self.maze.start_cell ==(x,y):
return "red"
if self.maze.exit_cell == (x, y):
return 'green'
if self.maze.maze[y][x] == 1:
return 'black'
class Maze(object):
def __init__(self, width=21, height=21, exit_cell=(1, 1)):
self.width = width
self.height = height
self.exit_cell = exit_cell
self.create()
def create(self):
self.maze = [[1] * self.width for _ in range(self.height)] # full of walls
self.start_cell = None
self.steps = None
self.recursion_depth = None
self._visited_cells = []
self._visit_cell(self.exit_cell)
def _visit_cell(self, cell, depth=0):
x, y = cell
self.maze[y][x] = 0 # remove wall
self._visited_cells.append(cell)
neighbors = self._get_neighbors(cell)
random.shuffle(neighbors)
for neighbor in neighbors:
if not neighbor in self._visited_cells:
self._remove_wall(cell, neighbor)
self._visit_cell(neighbor, depth+1)
self._update_start_cell(cell, depth)
def _get_neighbors(self, cell):
x, y = cell
neighbors = []
# Left
if x - 2 > 0:
neighbors.append((x-2, y))
# Right
if x + 2 < self.width:
neighbors.append((x+2, y))
# Up
if y - 2 > 0:
neighbors.append((x, y-2))
# Down
if y + 2 < self.height:
neighbors.append((x, y+2))
return neighbors
def _remove_wall(self, cell, neighbor):
x0, y0 = cell
x1, y1 = neighbor
# Vertical
if x0 == x1:
x = x0
y = (y0 + y1) / 2
# Horizontal
if y0 == y1:
x = (x0 + x1) / 2
y = y0
self.maze[y][x] = 0 # remove wall
def _update_start_cell(self, cell, depth):
if depth > self.recursion_depth:
self.recursion_depth = depth
self.start_cell = cell
self.steps = depth * 2 # wall + cell
def show(self, verbose=False):
MAP = {0: ' ', # path
1: '#', # wall
2: 'B', # exit
3: 'A', # start
}
x0, y0 = self.exit_cell
self.maze[y0][x0] = 2
x1, y1 = self.start_cell
self.maze[y1][x1] = 3
for row in self.maze:
print ' '.join([MAP[col] for col in row])
if verbose:
print "Steps from A to B:", self.steps
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser(description="Random maze game")
parser.add_option('-W', '--width', type=int, default=43)
parser.add_option('-H', '--height', type=int, default=43)
parser.add_option('-s', '--size', type=int, default=11,
help="cell size")
args, _ = parser.parse_args()
for arg in ('width', 'height'):
if getattr(args, arg) % 2 == 0:
setattr(args, arg, getattr(args, arg) + 1)
print "Warning: %s must be odd, using %d instead" % (arg, getattr(args, arg))
sys.setrecursionlimit(5000)
app = Application(args.width, args.height, args.size)
app.master.title('Maze game')
app.mainloop()