name 'delta_scroll' is not defined even though I defined it? - python

so I am trying to make my enemy not scroll with my camera when it moves left and right
I someone helped me make a function to stop my enemy from scrolling all it suppose to do is not make my enemy scroll example vid
def onscroll(enemying, delta_scroll):
for enemys in enemying:
enemys.position = (enemys.position[0] - delta_scroll, enemys.position[1])
then on my main loop I called that function so my enemy doesnt scroll with my screen
# camera left and right movement
if playerman.y < 250:
playerman.y += 1
for enemys in enemying:
enemys.y += delta_scroll
but for some reason I keep getting the same error
name 'delta_scroll' is not defined
Enemy Class
my full code

Quick tip- there are a TON of pg.image.load("myImg.png") commands. here is a better way of doing it:
standingright = []
for i in range(1, 16):
imgPath = "d"+str(i)+".png"
img = pg.image.load(imgPath)
standingright.append(img)
This is a much more concise way of loading the images. It will result in the exact same list of images in the exact same order, but I thought I would mention it to you because it will make your code much neater.
About the issue at hand: I searched your code for mentions of delta_scroll, and found it being used, but never defined. Also I saw you defined the function "onscroll", but never used it. Are you getting these two mixed up perhaps?

Related

Using recursion in pygame

I'm new to python and programming in general and am working on a final project for a python centric class. One of the requirements that I cant seem to figure out how to make work is to integrate recursion into our code in order to show a working knowledge. I've worked up a simple "bullet hell" style game using pygame.
My goal is that when contact is made between a bullet and an enemy, that a series of bullet sets will be launched from the player position as a sort of short-term modifier.
This code runs in the main loop whenever a bullet hits an enemy:
for i in reversed(range(len(bullets))):
for j in reversed(range(len(enemies))):
if bullets[i].collided(enemies[j].rect):
del enemies[j]
del bullets[I]
s.global_score += 100
more_bullets(10)
#print("Hit!")
#print(s.global_score)
break
The "more_bullets" function is the focus of my recursion, and calls this:
def more_bullets(n):
if(n > 0):
spawnx = sq.rect.x+10 + sq.rect.width/2 - 10
b = Square(s.red, spawnx,sq.rect.y, 10,30)
b.direction = 'N'
b.player_speed = 10
bullets.append(b)
spawnx = sq.rect.x-10 + sq.rect.width/2 - 10
b = Square(s.red, spawnx,sq.rect.y, 10,30)
b.direction = 'N'
b.player_speed = 10
bullets.append(b)
pygame.display.update()
more_bullets(n-1)
print(f"Fired x {n}")
The outcome currently is that my debug does print 10 times making me think that the recursion is functioning correctly, however only one set of bullets is firing when the collision occurs. I'm thinking that all 10 bullets are firing faster than I can register it and just stacking on the screen.
Is there an easy-to-use function that might slow down the firing of the bullets? or have messed up something more fundamentally here?
I'm thinking that all 10 bullets are firing faster than I can register it and just stacking on the screen.
You're correct.
I don't believe there's an "easy way" to do what you're asking the way you think. The recursion is immediate, meaning that the function runs 10 times right away when it's called. For it to send out a burst of staggered bullets, you'd need some kind of timer or queue or something along those lines that runs alongside your main loop, and recursion isn't really a natural fit for that. The same will go for any kind of game logic function that plays out over a period of time.
This isn't what's being asked, but here's an idea of what you could do, even though it's kind of a redundant use of recursion: add a parameter to that function that dictates the angle the bullet is being shot. Then, add a little bit to that parameter on every recursive call. That way an arc of bullets will be shot at the same time.

Is there a way to keep an object in bounds in pygame, and make it move when you hold the directional keys down?

I am using pygame 1.9.6 and python 3.7.7. I am looking for a way to have something drawn by pygame(or maybe even an image) that stays inside the window border(and stops when I release the key. I started with the “if keys[]:” method:
if keys[pygame.K_LEFT] and x>0:
x-=speed
that made it stay in bounds, but it only moved a few pixels and then did not repeat.
Next I tried the “event.key” method:
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
xchange=-speed
ychange=-0
but that just makes the object move forever. I tried putting “and x>0” on the same line right after the direction, an “if x>0:” before, an “if x<0:” after, but the event never updates to see that the coordinates are past the edge, even with update commands. It just keeps going and going. I also don’t know how to make the object stop moving when I release the key, since event.key’s have the event always on.
Thank you for all the help you can offer.
In order for something to stay within a frame, you must check if it's coordinates are not past the border before moving it.
keys = pygame.key.get_pressed()
if(keys[K_LEFT]):
if(square.left > 0):
square.left -= 10
if(keys[K_RIGHT]):
if(square.right < 600):
square.left += 10
if(keys[K_UP]):
if(square.top > 0):
square.top -= 10
if(keys[K_DOWN]):
if(square.bottom < 600):
square.bottom += 10
This is an example of how you would do this with a Rect object, it checks for border and then moves the object if its within those border and the appropriate key is being pressed. I can't apply this to your code as I cannot see enough of it but you just have to replace the coordinates. For example, you might have thing.x instead of square.left

How to speed up or optimize for loop used for collision detection using pygame/pytmx?

I am using a for loop combined with .colliderect() for collision detection while attempting to make a game using pygame, the loop gets too slow with ~340 wall Rectangles, I was wondering if it could be faster somehow because it severely effects the game play loop?
I have tried using coordinate points on different places on every wall but only works if you're moving certain amounts of pixels at a time and every time you half the movement speed it quadruples the amount of coordinate points you save.
#disregard indent, this is all in an update function that is called every time that a player decides to move.
self._old_position = self.position
PlayerRectangle = pygame.Rect(self.position[0]+ x,self.position[1]+y,16,16)
cwd = os.getcwd()
tmxData = load_pygame(cwd+"\\Maps\\TestfileMap.tmx")
movement = True
for obj in self.walls:
if(pygame.Rect(obj[0],obj[1],16,16).colliderect(PlayerRectangle)):
movement = False
self.move_back()
else:
continue
if movement:
self.position[0] += x
self.position[1] += y
self.stats["position"]=self.position
self.rect.topleft = self.position
self.feet.midbottom = self.rect.midbottom
The provided code works, however it is too slow, I was wondering if there is a different method in collision detection or if there is a way to make what is shown faster, it bogs down things greatly. Thank you
EDIT:
So the solution was basically that I had load_pygame that ran literally every time it looped simply take out the line that does that and it clears things up a lot more, for further optimization change the line that makes a Rect for each object and just use a list of Rects that are already constructed, this limits function calls.
Without a minimal working example it is tough to give assertive advice.
As I stated in the comments, there is a spurious call to a "load_pygame" function that seems to read file data inside this code - that alone could be the cause of your slowdown. Moreover, the data read is not used in the collision detection.
The other advice I't have is to let your walls rectangles pre-calculated in a sprite group, instead of creating new rectangles for all walls in every check with:
pygame.Rect(obj[0],obj[1],16,16).colliderect(PlayerRectangle)). then you can use the sprite method "spritecollideany" - https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollideany - that should optimize the rectangle-collision verification.
(This will also require your Player object to be a Sprite if it is not already).

Python thread executing function twice

Atm I'm working on a game using tkinter. I'm working on algorithm that moves enemies through the game map.
I will post only relevant lines, since the code is quiet hard-to-read.
I'm using class Timer imported from threading.
2 relevant functions are:
def add_enemies(self):
enemy = self.enemies.pop(0)
if enemy in '.':
Timer(1, self.add_enemies).start()
else:
self.move_enemy(enemy,set())
if not self.game_ended and self.enemies:
Timer(1, self.add_enemies).start()
def move_enemy(self, enemy, visited):
if type(enemy) == str:
if enemy in 'm':
enemy = Mongol(self.canvas, *self.start)
visited.add((enemy.x,enemy.y))
for move in (-1,0),(0,1),(1,0),(0,-1):
pos = (enemy.x + move[0], enemy.y+move[1])
if pos in self.way and pos not in visited:
print(pos)
enemy.move(*move)
enemy.take_shot(6)
visited.add(pos)
Timer(0.5, lambda: self.move_enemy(enemy, visited)).start()
This function should move the enemy, wait 0.5 second, then create a thread in which it recursively calls itself and moves the enemy again.
It might not be the best solution the create another thread inside the thread, but all other solutions made my GUI to freeze while executing the function.
Problem is, that Timer executes function move_enemy twice. Nothing else in the code can cause this problem.
Simple print test of enemy position shows this:
It simply moves the enemy twice, and increases its position twice as shown on the picture.
This is a wild guess, but substituting the enemy object with a new enemy object with a modified location in
Timer(0.5, lambda: self.move_enemy(enemy, visited)).start() might get the inbetween coordinates ((3,1),(5,1) and others). (If you do the same thing twice with the same input, you get two identical values.)
From the output I deduce: visited.add(pos) doesn't add positions to visited hence the if pos in self.way and pos not in visited: clause doesn't filter out already tested values (hence the (2,1)(2,1) printout). Try, if .append() works better.
I tried my best :D gl hf
Judging from the output, it looks like what's actually happening is that you were expecting things to execute in this order
print
move
print
move
print
move
print
move
....
but you failed to include enough synchronization and they are instead happening in this order:
print
print
move
move
print
print
move
move
....
It's not doing anything extra: it's just doing things not in the order you were hoping for.
Problem was, that tkinter is not thread safe hence it doesn't act deterministic.
I solved the problem by using Queue. My main thread, in which tkinter runs, periodically checks wheter or not it has something to draw.

My Character Sprite Doesn't Move Off Screen

I have been going over Paul Craven's Python and Pygame tutorial and lately I am trying to understand everything in Sprites. So, being inspired by Craven's multiple levels code, I've written my own code on it and it worked fine.
The logic is, if player sprite is off screen(for example screen width is equal to 640 and player's x value is greater than 640, than you are in the next level). Than, I decided to add menu to my game(?) and menu works fine as well.
The problem is, now my character can't get to second level. It seems it's x value is unable to pass 640, and I don't know why.
Since I am not able to use Stackoverflow editor good enough to share Python code(you know, intended), I will be using Pastebin to share my code.
http://pastebin.ubuntu.com/10392389/
Stackoverflow doesn't let me post the image files I've used, but they are classic pictures I got from the internet.
Any help is appreciated, thanks.
if current_level_num == 1 and player.rect.x > SCREEN_WIDTH:
current_level_num = 2
current_level = levels[current_level_num]
player.rect.x = 0
if current_level_num == 2 and player.rect.x < 1:
current_level_num = 1
current_level = levels[current_level_num]
player.rect.x = SCREEN_WIDTH
The character moves to the 2nd level, then immediately moves back to the 1st. The player should be moved farther to the right than the level 2 boundary.

Categories

Resources