So the question is simple:
screen
and x,y
coordinates, can I get anything that lays at that coordinates on that Surface?For example, let's say we have typical, Player attack, and if the attack reach the Enemy position x,y then enemy dies.
So given this simple app (is an example only not a real app)
import pygame as pg
from pygame.math import Vector2
# pygame constants
CLOCK = pg.time.Clock()
WIN_SIZE = (1280, 640)
# pygame setup
pg.init()
# screen
window = pg.display.set_mode(WIN_SIZE, 0, 32)
background = pg.Surface(WIN_SIZE)
player = pg.Surface(Vector2(12, 64))
player_rect = player.get_rect(topleft=Vector2(150, 150))
player_attack = False
player.fill((102, 255, 178))
player_attack_range = 20 # player can hit at min 20 pixel from target
enemy = pg.Surface(Vector2(12, 64))
enemy_rect = player.get_rect(topleft=Vector2(175, 150))
enemy.fill(pg.Color("green"))
while True:
background.fill((0, 0, 0)) # screen clear
# Render enemy
attacked = False
if player_attack:
# !!!!! HERE !!!!!
# Now we check if the playuer is close enough to the enemy, so we MUST know the enemy pos
distance_x = abs(player_rect.x - enemy_rect.x)
if distance_x > player_attack_range:
attacked = True
enemy.fill(pg.Color("red"))
if not attacked:
enemy.fill(pg.Color("green"))
background.blit(enemy, enemy_rect.topleft)
# Render player
background.blit(player, player_rect.topleft)
# Events
for event in pg.event.get():
if event.type == pg.QUIT or (
event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE): # x button and esc terminates the game!
exit(1)
# ............. Mouse ............. #
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
player_attack = True
if event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
player_attack = False
pg.display.update() # 2) Update the game
window.blit(background, (0, 0)) # 3) Repaint the screen
CLOCK.tick(60) # 4) Wait 60 Frames
When is attacked
Now I always seen it done this way more or less:
distance_x = abs(player_rect.x - enemy_rect.x)
if distance_x > player_attack_range:
attacked = True
enemy.fill(pg.Color("red"))
With this example, I'm not pointing out the code implementation but the fact that, the player must know the target position and then check whether or not the target is hit
But what I want to know, let's say I don't know the enemy position, and the player just attacks, is there a way that we can get what's currently on the surface at the attack range?
So do something like
attacked_area_x = abs(player_rect.x + player_attack_range) # only care of x coords
rects_or_surfaces_in_area = background.what_have_we_got_here(Vector(attacked_area, 0))
for r in rects_or_surfaces_in_area:
print("Hit!")
So By checking MDN documentation of Game Development MDN I actually find a game algorithm / Technique that is similar (but concept is the same) of my solution.
Is called the Broad Phase
From the documentation:
road phase should give you a list of entities that could be colliding. This can be implemented with a spacial data structure that will give you a rough idea of where the entity exists and what exist around it. Some examples of spacial data structures are Quad Trees, R-Trees or a Spacial Hashmap.
So yes, it seems one of many good approach to solve this problem.
So, after some research and thanks to Rabbid76 and his answer here How do I detect collision in pygame? which covers in details the most common collisions in Pygame, it seems that what I was looking for natively is just not possible.
Maybe is normal, I'm also new to game development and maybe what I want to do just doesn't make any sense, but I bet it does.
The scenario I'm facing is, just one player with a sword hitting, so I asked my self, why should I need to know prior what objects lie on the sword path and check if is hit, instead, do the hit and request to the parent screen "what object are in the sword path"? , which, is for sure faster because we don't need to know what object that have collision are (and avoid a for loop and check for each react/surface).
So, let's say there are many many object that have collision and a player may hit it, it would be way faster do don't know what' there but request it instead to the surface, so basically the surface should be aware of its children / objects.
I tried a bit the Surface.subsurface() and the Surface.get_parent() but couldn't make it work, anyway still, in a surface area we may have many thinks like:
I have only 2 solutions in my mind:
This only really works if, the entities are static, if so, then we could create a dict
with key x:y
coordinates and then check if the sword is in within a certain x:y and exist in the dict, then the entity is hit.
But with entity then moves by themself, is a nigtmare and will have a worst problem than before, you would need to update the keys at each frame and so on..
So, this could apply to each entity that is moving and may or may not hit something that has a collision. But staying on the example context, let's say we are iterating thourgh entities / object that at each frame are updating their position.
We could check how distant are from the player, let's say 2 chunks away (or the sword lenght) and collect them in a list
Then we that list, we check if, once the sword is updated, is hitting anything close by.
Still, pretty sure there are better ways (without changing or extending pygame its self).
And maybe, by extending pygame, there may be a way to implement a 'surface aware' class that when we request a specific Rect area, it tells us what's there.