I'm trying to find a way to have enemies track the player in my 2d game (pygame) but not clump up
Currently, when I shoot at them, the bullet collides into and damages all of the enemies that are clumped. I would like it to be a hoard but spread out just enough to where I can't hit every single enemy at once
It looks like this
Here's a gif of them clumping
I'm not sure how I would get the individual values of the enemies' positions so I can move them when they collide or how I should move them
This is what I currently have for the enemies to track the player:
for aliveEnemies in enemy:
if playerObj.rect.x - aliveEnemies.rect.x != 0:
if playerObj.rect.x > aliveEnemies.rect.x:
aliveEnemies.rect.x += 1
if playerObj.rect.x < aliveEnemies.rect.x:
aliveEnemies.rect.x -= 1
if playerObj.rect.y - aliveEnemies.rect.y != 0:
if playerObj.rect.y > aliveEnemies.rect.y:
aliveEnemies.rect.y += 1
if playerObj.rect.y < aliveEnemies.rect.y:
aliveEnemies.rect.y -= 1"
Any help or points in the right direction would be greatly appreciated
You can do collision detection between the enemies, to determine which ones are too close. You'll also need to change their behavior, to decide what to do when they actually get too close.
If you know you'll never get too many enemies, you can try comparing every enemy with every other enemy. This will take O(N^2) work, but that is probably OK if N is limited.
If you are comparing every enemy to every other anyway, you have a wider variety of options than just "collision detection": like the Boids algorithm (which does collision avoidance instead).
Pygame rect objects have a function called "colliderect" which tests whether two rect objects are overlapping: https://www.pygame.org/docs/ref/rect.html#pygame.Rect.colliderect
You can use this to test each enemy whether they're overlapping any other enemy before moving them.
Related
Im using an if statement to detect whether the player's coordinates after moving up (y coordinate increases) are equal to an open space's coordinates.
Ex:
player_coordinate = player.pos() # We can say that the coordinate returned is (-10.00,10.00)
space_coordinate = space.pos() # And the coordinate returned is (-10.00,20.00)
movement = 10 # How far the player can move at once
if (player_coordinate[0], player_coordinate[1] + movement) == space_coordinate:
player can move
Now, I used this same method, however when the player's position has a negative y value, the statement is false.
For example:
# Works:
if (-90.0, 30.0) == (-90.00,30.00)
# Doesn't Work
if (-90.0, -10.0) == (-90.00,-10.00)
(By the way the first tuple uses the vales stated previously, player_coordinate[0], player_coordinate[1] + movement, so i have no clue why it returns with one decimal place instead of two like in the original .pos() tuple but it shouldn't matter because the problem only occurs when the y-value is negative)
It looks like it is saying that -10.0 is not equal to -10.00. Any ideas on why this might not be working?
Here is the actual code too if it helps. I use 'in' because Im storing all of the space coordinates in a dictionary:
def player_movement(player, total, direction):
current = player.pos()
if direction == 'up':
if (current[0], current[1] + total) in space_coordinates.values():
player.shape('Player_Up.gif') # Changes player sprite
player.goto(current[0], current[1] + total) # Moves player
I already checked if the coordinate I needed was in the dictionary and it was
Turtles wander a floating point plane so exact comparisons are to be avoided. Instead of asking:
turtle_1.position() == turtle_2.position()
you should consider asking:
turtle_1.distance(turtle_2) < 10
That is, are they in close proximity to each other, not on the exact same coordinate.
This question already has answers here:
pygame: I want to calculate the distance between the player sprite and enemy1
(1 answer)
Im currently making a game with pygame and I need an explanation on some vector code
(2 answers)
Closed 4 months ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I tried to portrait my progress chart for my pygame test(simple test for making sure what function I should use) project, here is the chart:
1. call Player:
Make player into all_sprite(), players() group,
and shoot() the skill every second.
2. call Enemy:
Make Enemy into all_sprite(), mobs() group,
and gradually approach to the player.
3. call Skill:
shoot():
Make skill into all_sprite(), skills()
the skill make per second will link to the Enemy that is the nearest to the player
and maybe tag these two or someway else to make sure they will finally collide
4. attack:
When the Skill gets linked to the Enemy, the skill will apporach the moving Enemy with same speed.
This is the brief progress chart I designed for the fucntion I want to display, however, there must be several Enemiese exist on the screen while the porgram is functioning, how can I analyze all the Enemies' position everytime the Player shoots the Skill out?
I use the code
for i in range(8):
enemy = Enemy()
all_sprites.add(enemy)
mob.add(enemy)
to call out 8 Enemies at the same time from different dicrection, how can I check each one's position and tag or make it have number? For example, for Player at O( 0, 0), EnemyA at A( 10, 15), EnemyB at B(20, 15), EnemyC at ( 3, 4), when Skill1 get shot out it get linked to the EnemyC while it's the nearest to the Player.
or should I use different way to call the Enemies?
The point is that how can I get the list of the sprite I created at the same time?
Because I used the for loop to call out 8 sprite in same class, does the system consider them as the same element, or is there a list that can show the number of the sprite indivisually?
Like[sprite_1(x1,y1), sprite_2(x2,y2),...,sprite_n(xn,yn)]
Also how should I make the skill that is tagged approach to the Enemies it got linked to ?
can use trigonometric here
import math
def measure_distance(x1, y1, x2, y2):
dx = abs(x2-x1)
dy = abs(y2-y1)
distance = math.sqrt((dx*dx)+(dy*dy))
return distance
then compare the distance between A-O and B-O
In my game, I have a population of fish (10). Each fish has a line of sight (an arc object in front of them). There are sharks, which are predators (they are moving around the room randomly). Each fish is assigned an intelligence number at the beginning. When a shark enters in a fish' line of sight, I want the fish to reverse his direction (or at least get away in the best direction) only if his intelligence number is greater than a random generated number.
The issue is that when I try to implement this and the shark gets in the line of sight of the fish, pygame keeps detecting a collision, so python keeps generating a random number. For example, a fish might have a very low intelligence level, but still has a very high probability to escape from the shark because python keeps detecting the collision, and it has many tries to pass the bar. For that example, I'd actually want the fish to very likely not change directions when the shark is in the line of sight.
Ideally, I want python to detect the collision once, and of course detect again if the shark goes through the line of sight again a separate time.
Here is my code, don't know how much it'd help:
class RedFish(pygame.sprite.Sprite):
def __init__(self, newDNA):
pygame.sprite.Sprite.__init__(self)
self.direction = random.uniform(0, math.pi*2)
self.speed = 2
self.intelligence = 100
def update(self):
self.rect.x -= math.sin(self.direction) * self.speed
self.rect.y -= math.cos(self.direction) * self.speed
for shark in sharks:
if pygame.sprite.collide_mask(arcsList[self.arcIndex], shark):
temp = random.randrange(400)
if (temp < self.intelligence):
self.direction = self.direction*-1
Thanks!
You can store the last shark that the fish "saw" and compare that in each iteration of the update loop.
If the fish sees the same shark again, don't recalculate.
If the fish sees another shark, recalculate and remember that shark.
If it sees no sharks, reset its "memory".
Note: I've intentionally left out a lot of your calculation code to keep this example as simple as possible.
class RedFish(pygame.sprite.Sprite):
def __init__(self, newDNA):
self.last_shark_seen = None
def update(self):
# track how many sharks we have collisions with
shark_collisions = 0
for shark in sharks:
if pygame.sprite.collide_mask(arcsList[self.arcIndex], shark):
shark_collisions += 1
if shark != self.last_shark_seen:
self.last_shark_seen = shark
# calculate new direction here
break
# no collisions means no sharks seen, reset the fish's memory
self.last_shark_seen = None
You need to track when the shark was seen, or which shark was seen. Basically update the collision detector one tenth (or 12th or 100th) as often as you update position.
Or, once a fish fails to see a shark, it's doomed, so you can add that list to a list of sharks it's seen and failed to avoid (in case it sees another shark), then when you update you can just go through the list saying that in order to change direction, a fish must beat the random number generator and also not have lost to the shark already
You could try a different random distribution, maybe something that skews left, so even if a dumb fish had multiple tries, the combined probability would still be low
Then again, if you're trying to simulate "real" fish, some might be slower to react, but they still get multiple chances.
Maybe you could shorten the arc?
I'm trying to create a game in which 100 rocks are scattered through a large series of coordinates randomly. The problem is that sometimes the rocks may overlap each other. The solution I came up with was to check if the rocks overlap each other, and if they do, create new randomly generate coordinates for the rock again and again until it collides with nothing. I'm not entirely sure how to do this; I've tried detecting collision between the rock and the rock list, but all that ends up happening is that it thinks that it collides with itself and always returns as True. The __init__ function generates the coordinates with random.randint(-2500,2500). When the rocks are created in the for loop, each rock is added to the list. In the update function it checks for rectangular collision between the rocks. How can I fix this? Thanks, an answer would be much appreciated. Ask me if you need more information.
Well, I guess there are a few ways you can approach this problem:
1) The first would be the one you already used, you would check for collisions each time you generate a rock and if a collision exist you would regenerate a position for the given rock
2) The second one would be to slice your "field" into rectangles of the size of the rock, just like a tilemap, therefore creating a list of possible positions, something like this:
possible_positions = [(i, j) for i in range(x_size_field//x_size_rock) for j in range(y_size_field//y_size_rock)]
for i in range(n_of_rocks):
rock_pos = random.choice(possible_positions)
possible_positions.remove(rock_pos)
But this approach would implicate in a given set of possible positions that make a "uniform" rock distribution
3) So if its really necessary to make put the rocks on absolute random positions you could create a list of possible positions like the following:
possible_positions = [[(i, j) for j in range(y_size_field-y_size_rock)] for i in range(x_size_field-x_size_rock)]
for i in range(n_of_rocks):
# X and Y represente positions on the list not on the field
x = random.randint(0, len(possible_positions))
y = random.randint(0, len(possible_positions[x]))
# The rock positions
rock_pos = possible_positions[x][y]
# Now we remove the positions on the region of the new rock
for i in range(x,x+x_size_rock):
possible_positions[i] = possible_positions[i][0:y] + possible_positions[i][y+y_size_rock:-1]
if [] in possible_positions:
possible_positions.remove([])
Of course this code may generate errors (its a rather simple code) and it needs some optimizations, but i think you may get the general ideia from this.
Sorry about my english
In an RPG I am making, in the main game loop, I need to check if at any time a creature is within the 4-space range of a player (user) so I can initiate/ call the battle_loop function.
I have a class Creature which is used for all of the enemies, which has attributes PosX and PosY. (These coordinates are included when initializing a new instance of Creature, and are never changed). The player also has PosX and PosY variables of its own, which can change upon the player moving around.
So is there a way that I can check if any instance of Creature's PosX value is within two less or two more than the player's PosX value and if any instance of Creature's PosY value is within two more or two less of the player's PosY value?
You can maintain a list of Creature objects and loop through them. For each Creature, calculate the distance from the player and call battle_loop accordingly:
for creature in creatures:
if abs(creature.x - player.x) <= 2 and abs(creature.y - player.y) <= 2:
battle_loop()
Just run a for loop.
for creature in creatureList:
Then do something like this:
if (creature.PosX > self.PosX - 2 & creature.PosX < self.PosX + 2) : doSomething()
...and a similar one for the y-values. The if statement will return true if the creature is within 2 x and 2 y of the player.
This is common, what you may want is to calculate either the Manhattan or euclidean distance between the two location points (x,y), depending on how creatures can move in your game.