简单游戏的碰撞检测/物理
Collision detection / physics for simple game
你好,我目前正在为 class 开发一个迷你游戏(第一次做这样的事情),我真的不知道如何开始使用 碰撞检测 全部。好的,我正在创建的游戏是在冰冷的圆形竞技场上进行的自上而下的相扑格斗游戏,您可以在其中四处移动以获得动力和 速度 并尝试将对方击倒以获得积分。到目前为止,我的移动 acceleration/friction 几乎已经下降,而且我还有一个系统可以检测碰撞何时发生,我只是不知道如何在角色碰撞时真正将它们推开。我想我会根据攻击者的 速度 速度以及我将添加的角色的 抵抗力 统计数据来确定击退量/伤害.我还假设我将不得不用切线之类的东西做一些密集的数学运算才能获得正确的方向,但我完全不确定该怎么做。我将不胜感激任何帮助,如果你以后想通过 discord 之类的方式帮助我完成这个项目,我愿意接受未来的帮助。感谢一切
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)
当物体撞击时,您必须反映运动矢量 (x1_dir
、y1_dir
) 和 (x2_dir
、y2_dir
)。
对于给定的入射矢量 I
和表面法线 N
,反射方向计算为 I - 2.0 * dot(N, I) * N
.
法向量是Unit vector从一个中心点到另一个中心点,当物体撞击时,
检测命中并归一化中心点之间的向量(将向量除以 distance
):
nv = [x1-x2, y1-y2]
distance=math.hypot(nv[0], nv[1])
if distance <= 2*xR:
nv = [nv[0]/distance, nv[1]/distance]
使用pygame.math.Vector2.reflect
计算反射。
使用 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
由于无法准确检测到"hit",所以当玩家之间的距离为2*xR
时,需要修正玩家的位置,并找到距离时的点正好是 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
你好,我目前正在为 class 开发一个迷你游戏(第一次做这样的事情),我真的不知道如何开始使用 碰撞检测 全部。好的,我正在创建的游戏是在冰冷的圆形竞技场上进行的自上而下的相扑格斗游戏,您可以在其中四处移动以获得动力和 速度 并尝试将对方击倒以获得积分。到目前为止,我的移动 acceleration/friction 几乎已经下降,而且我还有一个系统可以检测碰撞何时发生,我只是不知道如何在角色碰撞时真正将它们推开。我想我会根据攻击者的 速度 速度以及我将添加的角色的 抵抗力 统计数据来确定击退量/伤害.我还假设我将不得不用切线之类的东西做一些密集的数学运算才能获得正确的方向,但我完全不确定该怎么做。我将不胜感激任何帮助,如果你以后想通过 discord 之类的方式帮助我完成这个项目,我愿意接受未来的帮助。感谢一切
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)
当物体撞击时,您必须反映运动矢量 (x1_dir
、y1_dir
) 和 (x2_dir
、y2_dir
)。
对于给定的入射矢量 I
和表面法线 N
,反射方向计算为 I - 2.0 * dot(N, I) * N
.
法向量是Unit vector从一个中心点到另一个中心点,当物体撞击时,
检测命中并归一化中心点之间的向量(将向量除以 distance
):
nv = [x1-x2, y1-y2]
distance=math.hypot(nv[0], nv[1])
if distance <= 2*xR:
nv = [nv[0]/distance, nv[1]/distance]
使用pygame.math.Vector2.reflect
计算反射。
使用 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
由于无法准确检测到"hit",所以当玩家之间的距离为2*xR
时,需要修正玩家的位置,并找到距离时的点正好是 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