So I'm making a basic 2D platformer game with the pygame module in python. Recently I've been trying to implement infinite world generation, but have been having some problems. The generation works fine, however, at the player's spawn, a bunch of random tiles spawn, obstructing the whole spawn area. I can't seem to find what's causing this.
Here's everything you need to replicate my situation:
map generation:
def generate_chunk(x,y):
chunk_data = []
for y_pos in range(CHUNK_SIZE):
for x_pos in range(CHUNK_SIZE):
target_x = x * CHUNK_SIZE + x_pos
target_y = y * CHUNK_SIZE + y_pos
tile_type = 0 # nothing
if target_y > 10:
tile_type = 2 # dirt
elif target_y == 10:
tile_type = 1 # grass
elif target_y < 10:
tile_type = 0
if tile_type != 0:
chunk_data.append([[target_x,target_y],tile_type])
return chunk_data
...
while True:
...
tile_rects = []
for y in range(3):
for x in range(4):
target_x = x - 1 + int(round(scroll[0]/(CHUNK_SIZE*16)))
target_y = y - 1 + int(round(scroll[1]/(CHUNK_SIZE*16)))
target_chunk = str(target_x) + ';' + str(target_y)
if target_chunk not in game_map:
game_map[target_chunk] = generate_chunk(target_x,target_y)
for tile in game_map[target_chunk]:
display.blit(tile_index[tile[1]],(tile[0][0]*16-scroll[0],tile[0][1]*16-scroll[1]))
if tile[1] in [1,2]:
tile_rects.append(pygame.Rect(tile[0][0]*16,tile[0][1]*16,16,16))
full code:
https://github.com/nice-404/Platformer
I can't seem to figure out what is causing the random tile spawning.
(I have been following DaFluffyPotato's platformer tutorial series because I am new to pygame)
After 2 weeks of debugging and further looking into the chunk generating code, I couldn't find out anything. However, I did figure out that the issue only happened in a small area, at the 0 x value. So what I did was I made the player spawn very far away from this, and made a boundary so that it couldn't walk far enough to see the issue. Not really fixing the issue, but at least it works now.
Related
I've trying to implement transition from an amount of space to another which is similar to acceleration and deceleration, except i failed and the only thing that i got from this was this infinite stack of mess, here is a screenshot showing this in action:
you can see a very black circle here, which are in reality something like 100 or 200 circles stacked on top of each other
and i reached this result using this piece of code:
def Place_circles(curve, circle_space, cs, draw=True, screen=None):
curve_acceleration = []
if type(curve) == tuple:
curve_acceleration = curve[1][0]
curve_intensity = curve[1][1]
curve = curve[0]
#print(curve_intensity)
#print(curve_acceleration)
Circle_list = []
idx = [0,0]
for c in reversed(range(0,len(curve))):
for p in reversed(range(0,len(curve[c]))):
user_dist = circle_space[curve_intensity[c]] + curve_acceleration[c] * p
dist = math.sqrt(math.pow(curve[c][p][0] - curve[idx[0]][idx[1]][0],2)+math.pow(curve [c][p][1] - curve[idx[0]][idx[1]][1],2))
if dist > user_dist:
idx = [c,p]
Circle_list.append(circles.circles(round(curve[c][p][0]), round(curve[c][p][1]), cs, draw, screen))
This place circles depending on the intensity (a number between 0 and 2, random) of the current curve, which equal to an amount of space (let's say between 20 and 30 here, 20 being index 0, 30 being index 2 and a number between these 2 being index 1).
This create the stack you see above and isn't what i want, i also came to the conclusion that i cannot use acceleration since the amount of time to move between 2 points depend on the amount of circles i need to click on, knowing that there are multiple circles between each points, but not being able to determine how many lead to me being unable to the the classic acceleration formula.
So I'm running out of options here and ideas on how to transition from an amount of space to another.
any idea?
PS: i scrapped the idea above and switched back to my master branch but the code for this is still available in the branch i created here https://github.com/Mrcubix/Osu-StreamGenerator/tree/acceleration .
So now I'm back with my normal code that don't possess acceleration or deceleration.
TL:DR i can't use acceleration since i don't know the amount of circles that are going to be placed between the 2 points and make the time of travel vary (i need for exemple to click circles at 180 bpm of one circle every 0.333s) so I'm looking for another way to generate gradually changing space.
First, i took my function that was generating the intensity for each curves in [0 ; 2]
Then i scrapped the acceleration formula as it's unusable.
Now i'm using a basic algorithm to determine the maximum amount of circles i can place on a curve.
Now the way my script work is the following:
i first generate a stream (multiple circles that need to be clicked at high bpm)
this way i obtain the length of each curves (or segments) of the polyline.
i generate an intensity for each curve using the following function:
def generate_intensity(Circle_list: list = None, circle_space: int = None, Args: list = None):
curve_intensity = []
if not Args or Args[0] == "NewProfile":
prompt = True
while prompt:
max_duration_intensity = input("Choose the maximum amount of curve the change in intensity will occur for: ")
if max_duration_intensity.isdigit():
max_duration_intensity = int(max_duration_intensity)
prompt = False
prompt = True
while prompt:
intensity_change_odds = input("Choose the odds of occurence for changes in intensity (1-100): ")
if intensity_change_odds.isdigit():
intensity_change_odds = int(intensity_change_odds)
if 0 < intensity_change_odds <= 100:
prompt = False
prompt = True
while prompt:
min_intensity = input("Choose the lowest amount of spacing a circle will have: ")
if min_intensity.isdigit():
min_intensity = float(min_intensity)
if min_intensity < circle_space:
prompt = False
prompt = True
while prompt:
max_intensity = input("Choose the highest amount of spacing a circle will have: ")
if max_intensity.isdigit():
max_intensity = float(max_intensity)
if max_intensity > circle_space:
prompt = False
prompt = True
if Args:
if Args[0] == "NewProfile":
return [max_duration_intensity, intensity_change_odds, min_intensity, max_intensity]
elif Args[0] == "GenMap":
max_duration_intensity = Args[1]
intensity_change_odds = Args[2]
min_intensity = Args[3]
max_intensity = Args[4]
circle_space = ([min_intensity, circle_space, max_intensity] if not Args else [Args[0][3],circle_space,Args[0][4]])
count = 0
for idx, i in enumerate(Circle_list):
if idx == len(Circle_list) - 1:
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
else:
curve_intensity.append(0)
else:
curve_intensity.append(1)
if random.randint(0,100) < intensity_change_odds:
if random.randint(0,100) > 50:
curve_intensity.append(2)
count += 1
else:
curve_intensity.append(0)
count += 1
else:
if curve_intensity:
if curve_intensity[-1] == 2 and not count+1 > max_duration_intensity:
curve_intensity.append(2)
count += 1
continue
elif curve_intensity[-1] == 0 and not count+1 > max_duration_intensity:
curve_intensity.append(0)
count += 1
continue
elif count+1 > 2:
curve_intensity.append(1)
count = 0
continue
else:
curve_intensity.append(1)
else:
curve_intensity.append(1)
curve_intensity.reverse()
if curve_intensity.count(curve_intensity[0]) == len(curve_intensity):
print("Intensity didn't change")
return circle_space[1]
print("\n")
return [circle_space, curve_intensity]
with this, i obtain 2 list, one with the spacing i specified, and the second one is the list of randomly generated intensity.
from there i call another function taking into argument the polyline, the previously specified spacings and the generated intensity:
def acceleration_algorithm(polyline, circle_space, curve_intensity):
new_circle_spacing = []
for idx in range(len(polyline)): #repeat 4 times
spacing = []
Length = 0
best_spacing = 0
for p_idx in range(len(polyline[idx])-1): #repeat 1000 times / p_idx in [0 ; 1000]
# Create multiple list containing spacing going from circle_space[curve_intensity[idx-1]] to circle_space[curve_intensity[idx]]
spacing.append(np.linspace(circle_space[curve_intensity[idx]],circle_space[curve_intensity[idx+1]], p_idx).tolist())
# Sum distance to find length of curve
Length += abs(math.sqrt((polyline[idx][p_idx+1][0] - polyline[idx][p_idx][0]) ** 2 + (polyline [idx][p_idx+1][1] - polyline[idx][p_idx][1]) ** 2))
for s in range(len(spacing)): # probably has 1000 list in 1 list
length_left = Length # Make sure to reset length for each iteration
for dist in spacing[s]: # substract the specified int in spacing[s]
length_left -= dist
if length_left > 0:
best_spacing = s
else: # Since length < 0, use previous working index (best_spacing), could also jsut do `s-1`
if spacing[best_spacing] == []:
new_circle_spacing.append([circle_space[1]])
continue
new_circle_spacing.append(spacing[best_spacing])
break
return new_circle_spacing
with this, i obtain a list with the space between each circles that are going to be placed,
from there, i can Call Place_circles() again, and obtain the new stream:
def Place_circles(polyline, circle_space, cs, DoDrawCircle=True, surface=None):
Circle_list = []
curve = []
next_circle_space = None
dist = 0
for c in reversed(range(0, len(polyline))):
curve = []
if type(circle_space) == list:
iter_circle_space = iter(circle_space[c])
next_circle_space = next(iter_circle_space, circle_space[c][-1])
for p in reversed(range(len(polyline[c])-1)):
dist += math.sqrt((polyline[c][p+1][0] - polyline[c][p][0]) ** 2 + (polyline [c][p+1][1] - polyline[c][p][1]) ** 2)
if dist > (circle_space if type(circle_space) == int else next_circle_space):
dist = 0
curve.append(circles.circles(round(polyline[c][p][0]), round(polyline[c][p][1]), cs, DoDrawCircle, surface))
if type(circle_space) == list:
next_circle_space = next(iter_circle_space, circle_space[c][-1])
Circle_list.append(curve)
return Circle_list
the result is a stream with varying space between circles (so accelerating or decelerating), the only issue left to be fixed is pygame not updating the screen with the new set of circle after i call Place_circles(), but that's an issue i'm either going to try to fix myself or ask in another post
the final code for this feature can be found on my repo : https://github.com/Mrcubix/Osu-StreamGenerator/tree/Acceleration_v02
I'm programming game pong in python and I wan't the ball to be faster everytime it bounces of a bat. So I tried to add
global SPEED
SPEED + 25
into a function higher_speed which will trigger everytime when the ball bounces of the bat.
short version of game code here:
...
BALL_SIZE = 20
BAT_WIDTH = 10
BAT_HEIGHT = 100
SPEED = 250 # (in pixels per second)
BAT_SPEED = SPEED * 1.5 # (in pixels per second)
...
def higher_speed(SPEED, x):
x = 25
global SPEED
SPEED + x
return SPEED
# bounce left
if ball_position[0] < BAT_WIDTH + BALL_SIZE / 2:
if bat_min < bat_position[0] < bat_max:
# bat bounces ball
BALL_SPEED[0] = abs(BALL_SPEED[0])
global SPEED
higher_speed()
else:
# bat hadn't bounced the ball, player loses
score[1] += 1
reset()
# bounce right
if ball_position[0] > WIDTH7777 - (BAT_WIDTH + BALL_SIZE / 2):
if bat_min < bat_position[1] < bat_max:
BALL_SPEED[0] = -abs(BALL_SPEED[0])
higher_speed()
else:
score[0] += 1
reset()
...
Please help. I appreciate your time :).
Several things here:
First of all, the value is not being changed because it is not assigned in the first place, your function should look like this:
def higher_speed(SPEED, x):
x=25
global SPEED
SPEED += x
Second, if you're overwriting x at the beginning of the function and using SPEED as global, why pass it?:
def higher_speed():
global SPEED
SPEED += 25
Third, according to Python's PEP8 standards, capitalized words are only for constants, it would be a good use to the speed increase, so it should look like this:
SPEED_INCREASE = 25
def higher_speed():
global speed
speed += SPEED_INCREASE
And last, in general is a bad idea using global variables you can check this article or google it, so try to avoid it, then it should look like this:
def higher_speed(speed):
return speed+SPEED_INCREASE
speed = higher_speed(speed)
or you could set this inline:
speed += SPEED_INCREASE
I hope it helped!
I want to make more than two turtles when I run the modules.
So I declared two variables on turtle but there's only one turtle I can see.
What's wrong with my code?
import turtle
t1=turtle.Turtle()
t2=turtle.Turtle()
colors = ["red", "blue", "green"]
turtle.bgcolor("yellow")
t1.speed(3)
t1.width(5)
length1 = 10
t2.speed(3)
t2.width(5)
length2 = 10
while length1 < 500:
t1.fd(length1)
t1.pencolor(colors[length1%3])
t1.right (89)
length1 += 3 #length1 = length1 + 3
while length2 < 500:
t2.fd(length2)
t2.pencolor(pink)
t2.left (89)
length2 += 4 #length2 = length2 + 4
input()
Your turtles are moving one by one. The first while loop does the job with t1, and when it's done, the second while will take care of t2. It's like "t1, make your first step. Then, t1, make your second. (and repeat this until length1 isn't less than 500 anymore.) Now t1 is done, so t2, make your first step. t2, your second step. (and it continues.)"
Instead, you want them to take turns making each of their steps. That's like "t1, make your first step. Then, t2, make your first. t1, make your second step. t2, your turn for your second step. (and it continues.)"
So your while loop should look like:
t1.pencolor(colors[length1 % 3])
t2.pencolor("pink")
while length1 < 500 or length2 < 500:
if length1 < 500:
t1.fd(length1)
t1.right(89)
length1 += 3 # length1 = length1 + 3
if length2 < 500:
t2.fd(length2)
t2.left(89)
length2 += 4 # length2 = length2 + 4
(Note you don't have to set the pencolor each time you move the turtle.)
there's only one turtle I can see
Is there literally only one turtle, or do you run out of patience waiting for the first turtle to finish before the second turtle starts (and breaks, due to the unquoted 'pink')? If this is about wanting to see both turtles in action at the same time, as folks have concluded, here's my approach:
Short of using threads, I use generators to allow the two turtles to run in a coroutine-like fashion. The advantage is that the turtles can share the exact same code, if they want to, or they can use completely different code. But it avoids duplicating code or maintaining unrelated code in the same while loop:
from turtle import Screen, Turtle
screen = Screen()
screen.bgcolor("yellow")
t1 = Turtle()
t1.pencolor('blue')
t2 = Turtle()
t2.pencolor('pink')
def pattern(turtle, increment, angle):
turtle.speed('fast')
turtle.width(5)
length = 10
while length < 500:
turtle.forward(length)
turtle.right(angle)
length += increment
yield 0
generator1 = pattern(t1, 3, 89)
generator2 = pattern(t2, 4, -89)
while next(generator1, 1) + next(generator2, 1) < 2:
pass
screen.exitonclick()
So I am building a simple infinite run game for school and I am stuck on trying to spawn the obstacles. I am trying to check each obstacle sprite and if it has gone off the screen (the background and obstacles move from right to left). If it has gone off screen, I want to remove the sprite and set up another one on the right side of the screen. But every time an obstacle goes off the left side of the screen, an infinite amount of obstacles start spawning. I am new to pygame and python in general. Any help would be greatly appreciated. Thanks in advance.
def obstacle_off_screen(self):
numDeleted = 0
for cur_sprite in self.all_objects_list:
print("first loop")
if cur_sprite.rect.x < 0:
print("second")
cur_sprite.kill
numDeleted += 1
while numDeleted != 0:
print("third")
self.add_obstacle()
numDeleted -= 1
def add_obstacle(self):
#add parameters
if self.get_Speed() == 15:
x = 1000
y = 400
elif self.get_Speed() == 20:
x = 1000
y = 400
elif self.get_Speed() == 25:
x = 1000
y = 400
elif self.get_Speed() == 30:
x = 1000
y = 400
self.all_objects_list.add(Obstacle('src/paw.gif', [x, y]))
For now, I only have one obstacle that I initially spawn
cur_sprite.kill is a function, so when you want to call it use (), like cur_sprite.kill().
That's your problem. The obstacles out of screen don't get removed from their sprite groups.
good afternoon, i would like to ask a question about this error i´m getting in my game. Im doing a simple game in pygame but i cant discover why i´m having this error. i will print the relevant code:
bottomX=-1000
bottomY=300
FishList = []
NumFish=0
while NumFish<20:
xfish=random.randrange(5,2550)
yfish=random.randrange(20,150)
IsInWater=(bottom.get_at([xFish+5,yFish+7])== (80,86,210,255))
if IsInWater:
FishList.append([xFish,yFish])
NumFish= NumFish + 1
for i in range(len(FishList)):
[xFish,yFish] = FishList[i]
mXp = random.randrange(-5,5) #Move in X
mYp = random.randrange(-5,6) #Move in y
FishStillInWater = (xFish+mXp+5>0 and xFish+mXp+5<3000 and yFish+mYp+7>10 and yFish+mYp+7 < 200 and (fundo.get_at([xFish+mXp+5,yFish+mYp+7])== (80,86,210,255)))
if FishStillInWater:
# If in water, moves
FishList[i][0] = xFish + mXp
FishList[i][1] = yGish + mYp
pygame.draw.rect(screen,red,[bottomX + FishList[i][0],300 + FishList[i][1],15,10],0)
for x in range(-7,7):
for y in range(-5,5):
FishDies=screen.get_at([bottomX + FishList[i][0]+x,300 + FishList[i][1]+y])==(0,0,0,255)# 0,0,0,255 is the color of the "bullets"
if FishDies:
yFish = 10000
points= points + 5
The error is:
FishDies=screen.get_at([bottomX + FishList[i][0]+x,300 + FishList[i][1]+y])==(0,0,0,255)
IndexError: pixel index out of range
Thx for your time guys, hope you can help me, if u need any thing else to understand the code tell me plz
Let's break it down a bit.
The error is saying, that you want to access a pixel, that is not on the surface. Here are your calculations:
The smallest possible fish coordinates are the following: (5,20), while the biggest are (2550,150).
You then want to check for the color of the pixel, but the fish might have moved off the screen, or only a part of it have moved.
I would recommend a normal collide_rect to check for collisions with bullets. There are many example on how to do this.