简体   繁体   中英

I am wondering why it says the distance has to be less than 27? Why less than 27? Where is 27 coming from?

My teacher gave us this code to analyze and I am not sure why he put 27 there for collision.. I asked him he said if the distance between the player and the enemy is less than 27 then I will call it a collision, but I still don't understand, can someone please kindly explain it to me in simpler terms. I don't understand where the number 27 comes from.. when my dimensions are so big?

import math
import random
import pygame

# Intialize the pygame
pygame.init()

# create the screen
screen = pygame.display.set_mode((1000, 700))

# Background
background = pygame.image.load('undersea.png')


# Player
playerImg = pygame.image.load('space-invaders.png')
playerX = 500
playerY = 600
playerX_change = 0

# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 5

for i in range(num_of_enemies):
    enemyImg.append(pygame.image.load('plastic.png'))
    enemyX.append(random.randint(0, 636))
    enemyY.append(random.randint(50, 150))
    enemyX_change.append(4)
    enemyY_change.append(40)

# Bullet

# Ready - You can't see the bullet on the screen
# Fire - The bullet is currently moving

bulletImg = pygame.image.load('bullet (1).png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 10
bullet_state = "ready"

# Score

score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)

textX = 10
testY = 10

# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)


def show_score(x, y):
    score = font.render("Score : " + str(score_value), True, (255, 255, 255))
    screen.blit(score, (x, y))


def game_over_text():
    over_text = over_font.render("GAME OVER", True, (255, 255, 255))
    screen.blit(over_text, (200, 250))


def player(x, y):
    screen.blit(playerImg, (x, y))


def enemy(x, y, i):
    screen.blit(enemyImg[i], (x, y))


def fire_bullet(x, y):
    global bullet_state
    bullet_state = "fire"
    screen.blit(bulletImg, (x + 16, y + 10))


def isCollision(enemyX, enemyY, bulletX, bulletY):
    distance = ((enemyX - bulletX) ** 2 + (enemyY - bulletY) ** 2)
    distance = math.sqrt(distance)
    print(distance)
    if distance < 27:
        return True
    else:
        return False


# Game Loop
running = True
while running:

    # RGB = Red, Green, Blue
    screen.fill((0, 0, 0))
    # Background Image
    screen.blit(background, (0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # if keystroke is pressed check whether its right or left
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                playerX_change = -5
            if event.key == pygame.K_RIGHT:
                playerX_change = 5
            if event.key == pygame.K_SPACE:
                if bullet_state is "ready":
                    # Get the current x cordinate of the spaceship
                    bulletX = playerX
                    fire_bullet(bulletX, bulletY)

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                playerX_change = 0

    # 5 = 5 + -0.1 -> 5 = 5 - 0.1
    # 5 = 5 + 0.1

    playerX += playerX_change
    if playerX <= 0:
        playerX = 0
    elif playerX >= 636:
        playerX = 636

    # Enemy Movement
    for i in range(num_of_enemies):

        # Game Over
        if enemyY[i] > 440:
            for j in range(num_of_enemies):
                enemyY[j] = 2000
            game_over_text()
            break

        enemyX[i] += enemyX_change[i]
        if enemyX[i] <= 0:
            enemyX_change[i] = 4
            enemyY[i] += enemyY_change[i]
        elif enemyX[i] >= 736:
            enemyX_change[i] = -4
            enemyY[i] += enemyY_change[i]

        # Collision
        collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
        if collision:
            bulletY = 480
            bullet_state = "ready"
            score_value += 1
            enemyX[i] = random.randint(0, 736)
            enemyY[i] = random.randint(50, 150)

        enemy(enemyX[i], enemyY[i], i)

    # Bullet Movement
    if bulletY <= 0:
        bulletY = 480
        bullet_state = "ready"

    if bullet_state is "fire":
        fire_bullet(bulletX, bulletY)
        bulletY -= bulletY_change

    player(playerX, playerY)
    show_score(textX, testY)
    pygame.display.update()

The value is 27, because you compute the Euclidean distance between (enemyX, enemyY) and (bulletX, bulletY) in the function isCollision :

 def isCollision(enemyX, enemyY, bulletX, bulletY): distance = ((enemyX - bulletX) ** 2 + (enemyY - bulletY) ** 2) distance = math.sqrt(distance) print(distance)

The Euclidean distance between 2 points (Ax, Ay) and (Bx, By) is

d = sqrt((Bx-Ax)**2 + (By-Ay)**2) = hypot(Bx-Ax, By-Ay)

In 2 dimensional space this is the same as the Pythagorean theorem . The length of the diagonal in a square with a side length of 19 is approximately 27.

Try changing the '27' to a small no. like '5' and you will see that the collision is happening too late on screen. OR if you replace the enemy/bullet image you are loading with some other small/large image you will notice that you will have to change you '27' to some other number to make things work as intended.

Simple Words The reason for the hard-coding '27' could be because the width of enemy image and the width of bullet image you load in your code seem to touch (collide) eachother at the distance '27' from the point where they are drawn.

Explanation When we load an image pygame draws it from top-left corner. For Example your background image is so large in code but when you ask your code where is this 'background' located it well tell you it is on (0,0) although it's on your full screen not a single point. Infered from screen.blit(background, (0, 0)) line in your code

Same for the images/sprites of enemy and bullets. The position you use in collision enemyX, enemyY, bulletX, bulletY are the top-left coordinates. Now to show them actually touching/colliding you may have to tell the code that 'My enemy is more than one pixel on the position. So I want to take care of it by using the constant '27' (depends on width of enemy/bullet). As soon as the both positions have a Euclidean distance of '27' this means they are colliding on my screen hence proceed as true.

If you are still confused about the positioning issue and how center of image or top-left of image matters read these, it will help.

https://stackoverflow.com/a/51182238/11672352

Why is the pygame rect not in the right place?

From reading your code there are functions called bulletX and bulletY. Is the 27 saying the range of the bullets is 27 and the play must be with that distance to be affected by those bullets?

It seems to me like the game triggers the collision once the bullet enters a circle of radius 27 pixels around the enemy. Although your enemy may not be a perfect circle, it is a lot simpler to treat them as if they were when calculating collisions as it is relatively easy to check whether a point has collided with a circle, in this case, the bullet with the enemy. the lines:

distance = ((enemyX - bulletX) ** 2 + (enemyY - bulletY) ** 2)
distance = math.sqrt(distance)

are used to calculate the distance between the middle of the enemy and the bullet by using Pythagoras' theorem (a^2 + b^2 = c^2 where a and b are two different sides of a right angled triangle and c is your hypotenuse, aka the longest side) The value 27 is likely used because the enemy is likely around 52 pixels (27 * 2) wide and tall

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM