Collision detection / physics for simple game

江枫思渺然 提交于 2021-02-07 23:01:09

问题


Hi i am currently working on a mini game for class (first time doing something like this) and i dont really know how to start with collision detection at all. Okay the game i'm creating is a top down sumo fighting game on a icy circular arena where you move around gaining momentum and velocity and try to knock each other off to gain points. So far i have the movement acceleration/friction pretty much down and I also have a system to detect when a collision occurs, i just don't know how to actually push the characters away when they collide. I think i will base the knock back amount/ damage on the velocity the attacker has against their velocity alongside the character's resistance stat that i will be adding. I also assume that I will have to do some intense math with like tangents and stuff to get the direction correct but i'm not sure how to do that at all. I would greatly appreciate any help and i am open to future help if u want to assist me on this project later via through like discord or something. Thanks for everything

import pygame, sys, time
from pygame.locals import *
import random
import math


#Colors
colorRed=pygame.Color(241,59,62)
colorPurple=pygame.Color(200,254,249)
colorBlue=pygame.Color(52, 207, 235)
colorGreen=pygame.Color(100,182,100)
colorWhite=pygame.Color(255,250,250)
colorBlack=pygame.Color(0,0,0)
colorOrange=pygame.Color(242,164,0)
colorBrown=pygame.Color(148,103,58)

#Dimensions
w=800
h=600
pygame.init()
fpsClock=pygame.time.Clock()
screen=pygame.display.set_mode((w,h))
pygame.display.set_caption ('SUMO')
centerX=w//2
centerY=h//2

#Stage
stageR=250
def stage (centerX,centerY):
    """stage (centerX,centerY) - creates a stage with given centerpoint"""
    pygame.draw.circle(screen, colorBlue, (centerX,centerY),stageR)

#Character 1
xR=int((stageR//10))
x1=int(centerX-(stageR*0.8))
y1=centerY
x1_dir=0
y1_dir=0
def char1 (x1,y1):
    """char1 (x1,y1) - creates char1 at given coordinates"""
    pygame.draw.circle(screen, colorRed, (x1,y1),xR)
print (x1)
print (centerX)

#Character 2
x2=int(centerX+(stageR*0.8))
y2=centerY
x2_dir=0
y2_dir=0
def char2 (x2,y2):
    """char2 (x2,y2) - creates char1 at given coordinates"""
    pygame.draw.circle(screen, colorGreen, (x2,y2),xR)





while True:
    screen.fill(colorBlack)
    for event in pygame.event.get():
        #Game Exit
        if event.type== QUIT:
            pygame.quit()
            sys.exit()

    distance=math.hypot(x1-x2,y1-y2)
    if distance <= 2*xR:
        print ("HIT")

    keys = pygame.key.get_pressed()

    if keys[K_d] or keys[K_a]:
        x1_dir += 0.1 if keys[K_d] else -0.1
    else:
        x1_dir *= 0.98

    if keys[K_w] or keys[K_s]:
        y1_dir += 0.1 if keys[K_s] else -0.1
    else:
        y1_dir *= 0.98

# -------------------- CHAR2 MOVEMENT --------------------

    if keys[K_RIGHT] or keys[K_LEFT]:
        x2_dir += 0.1 if keys[K_RIGHT] else -0.1
    else:
        x2_dir *= 0.98

    if keys[K_UP] or keys[K_DOWN]:
        y2_dir += 0.1 if keys[K_DOWN] else -0.1
    else:
        y2_dir *= 0.98


    stage (centerX,centerY)
    char1 (round(x1),round(y1))
    char2 (round(x2),round(y2))
    x1+=x1_dir
    y1+=y1_dir
    x2+=x2_dir
    y2+=y2_dir
    pygame.display.update()
    fpsClock.tick(60)

回答1:


You have to reflect the movement vectors (x1_dir, y1_dir) and (x2_dir, y2_dir) when the objects hit. For a given incident vector I and surface normal N, the reflection direction calculated as I - 2.0 * dot(N, I) * N.

The normal vector is the Unit vector from one center point to the other, when the objects hit, Detect the hit and normalize the vector between the center points (divide the vector by distance):

nv = [x1-x2, y1-y2]
distance=math.hypot(nv[0], nv[1])
if distance <= 2*xR:
   nv = [nv[0]/distance, nv[1]/distance]

Use pygame.math.Vector2.reflect to calculate the reflection. Use pygame.math.Vector2.length to compute the length of the reflected vectors and exchange there length by pygame.math.Vector2.scale_to_length:

nv = [x1-x2, y1-y2]
distance=math.hypot(nv[0], nv[1])
if distance <= 2*xR:
    nv = pygame.math.Vector2(nv[0], nv[1]) / distance

    rd1 = pygame.math.Vector2(x1_dir, y1_dir).reflect(nv)
    rd2 = pygame.math.Vector2(x2_dir, y2_dir).reflect(nv)

    len1, len2 = rd1.length(), rd2.length()
    if len1 > 0:
        rd1.scale_to_length(len2)
        x1_dir, y1_dir = rd1.x, rd1.y
    else:
        x1_dir, y1_dir = -x2_dir, -y2_dir
    if len2 > 0:
        rd2.scale_to_length(len1)
        x2_dir, y2_dir = rd2.x, rd2.y
    else:
        x2_dir, y2_dir = -x1_dir, -y1_dir


Since it is not possible to detect the "hit" exactly, when the distance between the players is 2*xR it is necessary to correct the position of the players and to find the point when the distance is exactly 2*xR:

v12 = pygame.math.Vector2(x1-x2, y1-y2)
distance = v12.length()
hit_dist = 2*xR
if distance <= hit_dist:
    # vector beteween center points
    nv = v12.normalize()
    # movement direction and combined relative movement
    d1 = pygame.math.Vector2(x1_dir, y1_dir)
    d2 = pygame.math.Vector2(x2_dir, y2_dir)
    dd = d1 - d2
    if dd.length() == 0:
        # normalized movement and normal distances
        ddn = dd.normalize()
        dir_dist  = ddn.dot(v12)
        norm_dist = pygame.math.Vector2(-ddn[0], ddn[1]).dot(v12)
        # minimum distance along the line of relative movement
        min_dist = math.sqrt(hit_dist*hit_dist - norm_dist*norm_dist)
        if dir_dist < min_dist:
            # update postions of the players so that the distance is 2*xR
            d1l, d2l = d1.length(), d2.length()
            d1n = d1/d1l if d1l > 0 else d1
            d2n = d2/d2l if d2l > 0 else d2
            x1 -= d1n.x * d1l / (d1l+d2l)
            y1 -= d1n.y * d1l / (d1l+d2l)
            x2 -= d2n.x * d2l / (d1l+d2l)
            y2 -= d2n.y * d2l / (d1l+d2l)
            # recalculate vector beteween center points
            v12 = pygame.math.Vector2(x1-x2, y1-y2)
            nv = v12.normalize()

        # reflect movement vectors
        rd1 = d1.reflect(nv)
        rd2 = d2.reflect(nv)
        len1, len2 = rd1.length(), rd2.length()
        if len1 > 0:
            rd1 = rd1 * len2 / len1
            x1_dir, y1_dir = rd1.x, rd1.y
        else:
            x1_dir, y1_dir = -x2_dir, -y2_dir
        if len2 > 0:
            rd2 = rd2 * len1 / len2
            x2_dir, y2_dir = rd2.x, rd2.y
        else:
            x2_dir, y2_dir = -x1_dir, -y1_dir


来源:https://stackoverflow.com/questions/59656983/collision-detection-physics-for-simple-game

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!