问题
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