How can I show explosion image when collision happens?
The explosion is just shown for a short moment. Use pygame.time.get_ticks()
to return the number of milliseconds since pygame.init()
was called. Calculate the point in time after that the explosion image has to be removed. Add the coordinates of the explosion and the end time point to the head of a list (explosionList
). Draw the explosion(s) in the main application loop. Remove the expired explosions from the tail of the list:
explosionList = []
while run:
current_time = pygame.time.get_ticks()
# [...]
for missile_idx, missile_val in enumerate(missiles)
# [...]
if missile_rect.colliderect(rock_rect):
explosion_sound.play()
explosion_pos_x = missile_pos_x
explosion_pos_y = missile_pos_y
end_time = current_time + 2000 # 2000 milliseconds = 2 seconds
explosionList.insert(0, (end_time, explosion_pos_x, explosion_pos_y))
# [...]
for i in range(len(explosionList)):
if current_time < explosionList[i][0]:
screen.blit(explosion, (explosionList[i][1], explosionList[i][2]))
else:
explosionList = explosionList[:i]
break
# [...]
With this algorithm it is possible to manage multiple explosions.
See Time, timer event and clock
Minimal example
import pygame
pygame.init()
window = pygame.display.set_mode((210, 210))
def create_rectangles():
global rectangles
w, h = window.get_size()
rectangles = []
for x in range(0, w - 60, 60):
for y in range(0, h - 60, 60):
rectangles.append(pygame.Rect(x + 30, y + 30, 30, 30))
create_rectangles()
hit_list = []
fade_out_time = 3000
run = True
while run:
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
point = pygame.mouse.get_pos()
collideindex = pygame.Rect(point, (1, 1)).collidelist(rectangles)
if collideindex >= 0:
end_time = current_time + fade_out_time
hit_list.insert(0, (end_time, rectangles[collideindex].center))
del rectangles[collideindex]
if not hit_list and not rectangles:
create_rectangles()
window.fill(0)
for r in rectangles:
pygame.draw.rect(window, (255, 0, 0), r)
for i in range(len(hit_list)):
delta_time = hit_list[i][0] - current_time
if delta_time > 0:
radius = round(30 * delta_time / fade_out_time)
pygame.draw.circle(window, (255, 255, 0), hit_list[i][1], radius)
else:
hit_list = hit_list[:i]
break
pygame.display.flip()
Loading image of explosion when collision with character sprite in Pygame
First load the images globally. (I've put them into a directory with the name 'Explosions'.)
EXPLOSION_IMGS = [pg.image.load(os.path.join('Explosions', img)).convert_alpha()
for img in os.listdir('Explosions')]
Then reduce the Explosions class to this version. It accesses the global constant EXPLOSION_IMGS
list and then just increments the frame counter in its update
method, after the required time has passed.
class Explosion(pg.sprite.Sprite):
def __init__(self, center):
pg.sprite.Sprite.__init__(self)
self.image = EXPLOSION_IMGS[0]
self.rect = self.image.get_rect(center=center)
self.frame = 0
self.last_update = pg.time.get_ticks()
self.frame_rate = 50
def update(self):
now = pg.time.get_ticks()
if now - self.last_update > self.frame_rate:
self.last_update = now
self.frame += 1
if self.frame == len(EXPLOSION_IMGS):
self.kill()
else:
self.image = EXPLOSION_IMGS[self.frame]
self.rect = self.image.get_rect(center=self.rect.center)
In the update
method of the game class, create the expl
instance and add it to the self.all_sprites
group. Done.
class Game:
def update(self):
# ...
TrumpHits = pg.sprite.spritecollide(self.trump, self.projectiles, True)
for hit in TrumpHits:
print("TRUMP HIT!!!")
expl = Explosion(hit.rect.center)
self.all_sprites.add(expl)
how to display animation after sprites collide/overlap using p5.js/p5.play
When the collision happens, you could create a new object which contains the information about the collision, and how long you want the collision to take place for, and then add that object to a new explosions = []
. Something like this:
explosions.push({
x: towers[j].position.x,
y: towers[j].position.y,
time: 20
});
Of course, in your example, you'll want to create the object at the position of the bullet when the collision happens.
And then in your draw()
you could simply iterate through that array backwards and display the animation:
function draw() {
...
// loop backwards so we can remove from array
for (let i = explosions.length - 1; i >= 0; i--) {
animation(explodeAnimation, explosions[i].x, explosions[i].y);
explosions[i].time--;
if (explosions[i].time <= 0) {
explosions.splice(i, 1);
}
}
}
You could also potentially use a setTimeout
but this is probably clearer.
Here's an example I created (The animation is a bit dodgy, I just copied it from this animation reference):
let numAsteroids = 10;
let towers;
let rock;
let spriteSheet;
let explosions = [];
function setup() {
createCanvas(400, 400);
spriteSheet = loadSpriteSheet('spritesheet.png', 171, 158, 11);
explodeAnimation = loadAnimation(spriteSheet);
rock = Group();
towers = Group();
createTowers();
createAsteroids();
}
function draw() {
background(220);
drawSprites(rock);
drawSprites(towers);
updateAsteroids();
// loop backwards so we can remove from array
for (let i = explosions.length - 1; i >= 0; i--) {
animation(explodeAnimation, explosions[i].x, explosions[i].y);
explosions[i].time--;
if (explosions[i].time <= 0) {
explosions.splice(i, 1);
}
}
}
function createAsteroids() {
// code to spawn asteroids at random locations
for (let i = 0; i < numAsteroids; i++) {
let asteroid = createSprite(random(0, width), random(-50, -350), 40, 40);
asteroid.maxSpeed = random(1, 3);
rock.add(asteroid);
let tower = floor(random(3))
asteroid.attractionPoint(asteroid.maxSpeed, towers[tower].position.x, towers[tower].position.y);
}
}
function updateAsteroids() {
// draws asteroids moving down and checking collision
for (let i = rock.length - 1; i >= 0; i--) {
if (rock[i].position.y > height) {
rock[i].position.y = 0;
rock[i].position.x = random(0, width);
}
for (let j = towers.length - 1; j >=0; j--) {
if (rock[i].overlap(towers[j])) {
rock[i].position.y = 0;
rock[i].position.x = random(0, width);
explosions.push({
x: towers[j].position.x,
y: towers[j].position.y,
time: 20
});
}
}
}
}
function createTowers() {
towers.push(createSprite(40, height - 30, 40, 90));
towers.push(createSprite(width/2, height - 30, 40, 90));
towers.push(createSprite(width-40, height - 30, 40, 90));
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/molleindustria/p5.play/lib/p5.play.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
how to replace picture and check for collision with new image and and a moving image in pygame
Look at pygame.time.Clock(). If you set an FPS rate (say 20), All you have to do is:
myClock = pg.time.Clock()
FPS = 20
bomb_placed = True
bomb_timer = 0
main_loop():
myClock.tick(FPS) # This will keep your FPS at 20 or below so you can estimate time
if bomb_placed:
bomb_timer += myClock.get_time()
if bomb_timer >= 3000:
# Draw the bomb explosion to the screen
if bomb_timer >= 5000:
bomb_timer = 0
bomb_placed = False # Stops displaying the bomb explosion
Hope that helped. Feel free to check out the pygame docs on the subject:
https://www.pygame.org/docs/ref/time.html#pygame.time.Clock.get_time
Example for multiple bombs:
myClock = pg.time.Clock()
FPS = 20
bombA, bombB, bombC = False, False, False
bombA_timer, bombB_timer, bombC_timer = 0, 0, 0
bombs = [bombA, bombB, bombC]
bomb_timers = [bombA_timer, bombB_timer, bombC_timer]
main_loop():
myClock.tick(FPS)
for i in len(bombs):
if bombs[i]:
bomb_timers[i] += myClock.get_time()
if bomb_timers[i] >= 3000:
draw_explosion()
if bomb_timer >= 5000:
bomb_timers[i] = 0
bomb_placed[i] = False
This example simply loops through each of the bomb variables that represent the possible bombs on the screen- in this case a max of 3.
For lots of bombs, first create two dictionaries to hold the values of the bombs (active or not active) and their respective timers. Then loop through each of the bombs and, if the bomb is active, update the timer accordingly:
bombs = {"bomb0": False} # Create dictionaries for the bombs and their timers, with 0-1 entries. (I did one to show you what it looks like).
bombTimers = {bombTimer0: 0}
main_loop():
myClock.tick(FPS)
for i in len(bombs): # For each bomb you have created
bombName = "bomb" + str(i) # get the name of the bomb and corresponding timer
timerName = "bombTimer" + str(i)
if bombs[bombName]: # If the bomg has a value of True:
bombTimers[timerName] += myClock.get_time() # Update the timer
if bombTimers[timerName] >= 3000: # Check if you need to draw the explosion
draw_explosion()
if bomb_timer >= 5000: # Check if the bomb animation is over, and reset the bomb so that it can be used again in the future
bombTimers[timerName] = 0
bombs[bombName] = False
This code works exactly the same as the previous example, but it is much easier to work with. You can easily add more bombs while not starting with an unnecessary amount, like so:
bombCount = 1
bombs = {"bomb0": False}
bombTimers = {"bombTimer0": 0}
main_loop():
if player_placed_bomb(): # When the player drops a bomb in your game:
placed = False # Make a variable saying that you have not activaded the bomb and timer yet
for key, val in bombs: # For each bomb in the bombs dictionary:
if not val: # If the value of that bomb is False (Not being used):
val = True # Activates the bomb that was already created
placed = True # Updates the placed variable indicating that you set a bomb to active
break
if not placed: # After looping through the dictionary, if there were no inactive bomb variables:
bombs["bomb" + str(bombCounter)] = True # Create a new bomb in your dictionary, with a unique name.
bombTimers["bombTimer" + str(bombCounter)] = 0 # Created a new corresponding timer
bombCounter += 1 # Add 1 to the bombCounter, which is used to create the unique name of the next bomb you create.
# Rest of main_loop()
This code ensures that you are working with the smallest dictionaries possible to reduce unneeded computation power. When a bomb explodes, it will become false and it's matching timer reset. The first if loop in the code above ensures that all existing bombs are active, and if not reuses the old bomb and timer. If all bombs are being used, It creates new entries in the dictionaries to allow for more bombs.
I added an unnecesarry amount of comments, but I hope it makes it more understandable for you. Let me know if you have more questions on how this works. If you are unfamiliar with python dict() objects, there are lots of resources on the internet that explain them thoughroughly.
Disclaimer: I haven't actually ran the code, but it should function how it is supposed to. Let me know if it doesn't.
Here are some thoughts on the reformed code:
You use "str(bag["bombs"])" quite a bit in your code- consider defining a variable: b = str(bag["bombs"]), and using that. It would make it much simpler.
I don't know why you delete the "bombs_dict" and "explosions_dict" entries after you are finished with them. The way your loop is set up, I will result in an error. I would suggest rather than deleting the entries, you keep them and attempt to reuse them, as shown in the code snippet above.
Or, if you like deleting them, you need to figure out a way to rename certain keys in your dictionaries so that the names are in order. (if you delete bomb2 from bombs_dict, and you have bomb1 and bomb3, you need to change bomb3 to bomb2 or the loop wont work as intended). You will also need to alter your bombCount variable accordingly.
Collision Detection between two images in Java
I think your problem is that you are not using good OO design for your player and enemies. Create two classes:
public class Player
{
int X;
int Y;
int Width;
int Height;
// Getters and Setters
}
public class Enemy
{
int X;
int Y;
int Width;
int Height;
// Getters and Setters
}
Your Player should have X,Y,Width,and Height variables.
Your enemies should as well.
In your game loop, do something like this (C#):
foreach (Enemy e in EnemyCollection)
{
Rectangle r = new Rectangle(e.X,e.Y,e.Width,e.Height);
Rectangle p = new Rectangle(player.X,player.Y,player.Width,player.Height);
// Assuming there is an intersect method, otherwise just handcompare the values
if (r.Intersects(p))
{
// A Collision!
// we know which enemy (e), so we can call e.DoCollision();
e.DoCollision();
}
}
To speed things up, don't bother checking if the enemies coords are offscreen.
trying to get sprite to disappear from screen after certain amount of time
You have to add another group for the explosions and to add the new Explosion
object to this group, too:
class AlienInvasion:
# [...]
def __init__(self):
# [...]
self.explosions = pygame.sprite.Group()
# [...]
def _update_bullets(self):
# [...]
for collision in collisions:
expl = Explosion(collision.rect.center)
self.explosions.add(expl)
self.all_sprites.add(expl)
Get the current time (pygame.time.get_ticks()
) when the Explosion
object is constructed and kill()
the object in the update method after a certain time span:
class Explosion(Sprite):
def __init__(self, center):
super().__init__()
self.image = pygame.image.load('images/explo.bmp')
self.rect = self.image.get_rect()
self.rect.center = center
self.start_time = pygame.time.get_ticks()
def update(self):
current_time = pygame.time.get_ticks()
timespan = 1000 # 1000 milliseconds = 1 second
if current_time > self.start_time + timespan:
self.kill()
Do not forget to invoke self.explosions.update()
in AlienInvasion._update_bullets
:
class AlienInvasion:
# [...]
def _update_bullets(self):
# [...]
self.explosions.update()
Related Topics
Pythonic Way to Create Union of All Values Contained in Multiple Lists
Pandas Dataframe Fillna() Only Some Columns in Place
Manifest.In Ignored on "Python Setup.Py Install" - No Data Files Installed
Compare Two CSV Files and Search for Similar Items
How to Strip the Whitespace from Pandas Dataframe Headers
Use Groupby in Pandas to Count Things in One Column in Comparison to Another
Pandas Deleting Row with Df.Drop Doesn't Work
Deleting Multiple Columns Based on Column Names in Pandas
Group Duplicate Column Ids in Pandas Dataframe
How to Use a Custom Comparison Function in Python 3
Python Mixed Integer Linear Programming
Django Signals VS. Overriding Save Method
Error Running Basic Tensorflow Example
List' Object Has No Attribute 'Get_Attribute' While Iterating Through Webelements
How to Import Data from Mongodb to Pandas
Read a Small Random Sample from a Big CSV File into a Python Data Frame