Enhance | 实现了一部分编辑器内碰撞箱检测

This commit is contained in:
shenjack 2023-12-22 23:30:56 +08:00
parent 0e1d260bb2
commit 549f85f673
Signed by: shenjack
GPG Key ID: 7B1134A979775551
6 changed files with 157 additions and 25 deletions

View File

@ -9,3 +9,5 @@
pub mod dr; pub mod dr;
pub mod math; pub mod math;
pub mod sr1; pub mod sr1;
pub type IdType = i128;

View File

@ -1,8 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use nalgebra::Vector2; use nalgebra::Vector2;
use rapier2d_f64::geometry::{SharedShape, TriMeshFlags}; use rapier2d_f64::geometry::TriMeshFlags;
use rapier2d_f64::math::{Isometry, Point, Real}; use rapier2d_f64::math::{Point, Real};
use rapier2d_f64::parry::transformation::vhacd::VHACDParameters; use rapier2d_f64::parry::transformation::vhacd::VHACDParameters;
pub enum ConnectType { pub enum ConnectType {
@ -43,7 +43,7 @@ pub struct DRObjectProps<'a> {
use rapier2d_f64::geometry::ColliderBuilder; use rapier2d_f64::geometry::ColliderBuilder;
pub enum BoxColliderEnum { pub enum BoxColliderEnum {
/// 组合 /// 组合
Compound(Vec<(Vector2<Real>, BoxColliderEnum)>), Compound(Vec<(Vector2<Real>, BoxColliderEnum)>),
/// 球 /// 球
/// 半径 /// 半径
Ball(Real), Ball(Real),

View File

@ -13,8 +13,8 @@ use crate::sr1_data::ship::{
}; };
use crate::data_type::math::{Point2D, Rotatable}; use crate::data_type::math::{Point2D, Rotatable};
use crate::data_type::IdType;
pub type IdType = i64;
pub type ConnectionType = Vec<(Vec<SR1PartData>, Option<Vec<Connection>>)>; pub type ConnectionType = Vec<(Vec<SR1PartData>, Option<Vec<Connection>>)>;
pub fn radians_map_to_degrees(angle: f64) -> f64 { pub fn radians_map_to_degrees(angle: f64) -> f64 {

View File

@ -4,9 +4,10 @@ use pyo3::exceptions::PyValueError;
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::data_type::math::{Point2D, Rotatable}; use crate::data_type::math::{Point2D, Rotatable};
use crate::data_type::sr1::SaveStatus;
use crate::data_type::sr1::{get_max_box, SR1PartData, SR1PartListTrait}; use crate::data_type::sr1::{get_max_box, SR1PartData, SR1PartListTrait};
use crate::data_type::sr1::{IdType, SaveStatus};
use crate::data_type::sr1::{SR1PartList, SR1PartType, SR1Ship}; use crate::data_type::sr1::{SR1PartList, SR1PartType, SR1Ship};
use crate::data_type::IdType;
use crate::sr1_data::part_list::RawPartList; use crate::sr1_data::part_list::RawPartList;
#[pyclass] #[pyclass]
@ -308,21 +309,22 @@ impl PySR1Ship {
parts parts
} }
fn get_part_box(&self, part_id: i64) -> Option<((f64, f64), (f64, f64))> { fn get_part_box(&self, part_id: IdType) -> Option<((f64, f64), (f64, f64))> {
let part_data = self.ship.parts.iter().find(|&x| x.id == part_id); let part_data = self.ship.parts.iter().find(|&x| x.id == part_id);
if let Some(part_data) = part_data { if let Some(part_data) = part_data {
let part_type = self.part_list.get_part_type(&part_data.part_type_id).unwrap(); if let Some(part_type) = self.part_list.get_part_type(&part_data.part_type_id) {
// rotate // rotate
let radius = part_data.angle; let radius = part_data.angle;
let ((x1, y1), (x2, y2)) = part_type.get_box(); let ((x1, y1), (x2, y2)) = part_type.get_box();
let mut p1 = Point2D::new(x1, y1); let mut p1 = Point2D::new(x1, y1);
let mut p2 = Point2D::new(x2, y2); let mut p2 = Point2D::new(x2, y2);
p1.rotate_radius_mut(radius); p1.rotate_radius_mut(radius);
p2.rotate_radius_mut(radius); p2.rotate_radius_mut(radius);
// transform // transform
p1.add_mut(part_data.x * 2.0, part_data.y * 2.0); p1.add_mut(part_data.x * 2.0, part_data.y * 2.0);
p2.add_mut(part_data.x * 2.0, part_data.y * 2.0); p2.add_mut(part_data.x * 2.0, part_data.y * 2.0);
return Some(((p1.x, p1.y), (p2.x, p2.y))); return Some(((p1.x, p1.y), (p2.x, p2.y)));
}
} }
None None
} }

View File

@ -6,14 +6,141 @@
* ------------------------------- * -------------------------------
*/ */
use nalgebra::{Matrix2, Vector2};
use nalgebra::Vector2;
use pyo3::prelude::*; use pyo3::prelude::*;
use rapier2d_f64::math::Real;
use crate::data_type::dr::BoxColliderEnum; use crate::data_type::IdType;
/// Id 位置 碰撞体
pub type BoundedShape = (IdType, Vector2<Real>, EditorShapeEnum);
pub enum EditorShapeEnum {
/// 矩形
/// 一个方向的向量 另一个方向的向量
Cuboid(Vector2<Real>, Vector2<Real>),
/// 三角形
/// 一个方向的向量 另一个方向的向量
Triangle(Vector2<Real>, Vector2<Real>),
/// 圆
/// 半径
Ball(Real),
/// 组合
Compound(Vec<EditorShapeEnum>),
}
// #[pyclass] // #[pyclass]
pub struct EditorArea { pub struct EditorArea {
/// 存储所有碰撞箱信息 /// 存储所有碰撞箱信息
pub collision_box: Vec<BoxColliderEnum>, pub collision_box: Vec<BoundedShape>,
}
impl EditorArea {
/// 添加一个碰撞箱
pub fn add_box(&mut self, box_data: BoundedShape) {
self.collision_box.push(box_data);
}
/// 删除一个碰撞箱
pub fn remove_box_by_id(&mut self, id: IdType) -> bool {
for (i, box_data) in self.collision_box.iter().enumerate() {
if box_data.0 == id {
self.collision_box.remove(i);
return true;
}
}
false
}
/// 检查一个点是否碰撞到任意一个碰撞箱
pub fn check_hit(&self, point: Vector2<Real>) -> Option<IdType> {
for box_data in self.collision_box.iter() {
match &box_data.2 {
// 球 直接勾股定理秒了
EditorShapeEnum::Ball(r) => {
if (point - box_data.1).norm() <= *r {
return Some(box_data.0);
}
}
// 矩形
// 进行一个旋转
EditorShapeEnum::Cuboid(dir1, dir2) => {
// 先平移坐标系
let point = point - box_data.1;
// 求出逆矩阵
let inv = Matrix2::new(dir1.x, dir2.x, dir1.y, dir2.y).try_inverse().unwrap();
// 变换
let point = inv * point;
// 判断是否在矩形内
if point.x >= 0.0 && point.x <= 1.0 && point.y >= 0.0 && point.y <= 1.0 {
return Some(box_data.0);
} else {
continue;
}
},
// 三角形
EditorShapeEnum::Triangle(dir1, dir2) => {
// 先平移坐标系
let point = point - box_data.1;
// 求出逆矩阵
let inv = Matrix2::new(dir1.x, dir2.x, dir1.y, dir2.y).try_inverse().unwrap();
// 变换
let point = inv * point;
// 判断是否在三角形内
if point.x >= 0.0 && point.y >= 0.0 && point.x + point.y <= 1.0 {
return Some(box_data.0);
} else {
continue;
}
},
EditorShapeEnum::Compound(shapes) => {
for shape in shapes {
match shape {
// 球 直接勾股定理秒了
EditorShapeEnum::Ball(r) => {
if (point - box_data.1).norm() <= *r {
return Some(box_data.0);
}
}
// 矩形
// 进行一个旋转
EditorShapeEnum::Cuboid(dir1, dir2) => {
// 先平移坐标系
let point = point - box_data.1;
// 求出逆矩阵
let inv = Matrix2::new(dir1.x, dir2.x, dir1.y, dir2.y).try_inverse().unwrap();
// 变换
let point = inv * point;
// 判断是否在矩形内
if point.x >= 0.0 && point.x <= 1.0 && point.y >= 0.0 && point.y <= 1.0 {
return Some(box_data.0);
} else {
continue;
}
},
// 三角形
EditorShapeEnum::Triangle(dir1, dir2) => {
// 先平移坐标系
let point = point - box_data.1;
// 求出逆矩阵
let inv = Matrix2::new(dir1.x, dir2.x, dir1.y, dir2.y).try_inverse().unwrap();
// 变换
let point = inv * point;
// 判断是否在三角形内
if point.x >= 0.0 && point.y >= 0.0 && point.x + point.y <= 1.0 {
return Some(box_data.0);
} else {
continue;
}
},
EditorShapeEnum::Compound(_) => {
panic!("Compound in Compound");
},
}
}
}
}
}
None
}
} }

View File

@ -6,8 +6,9 @@ use serde::{Deserialize, Serialize};
use serde_xml_rs::from_str; use serde_xml_rs::from_str;
use serde_xml_rs::Error as XmlError; use serde_xml_rs::Error as XmlError;
use crate::data_type::sr1::{IdType, SR1PartData, SR1PartDataAttr, SR1Ship}; use crate::data_type::sr1::{SR1PartData, SR1PartDataAttr, SR1Ship};
use crate::data_type::sr1::{SR1PartDataTrait, SR1ShipTrait}; use crate::data_type::sr1::{SR1PartDataTrait, SR1ShipTrait};
use crate::data_type::IdType;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename = "Ship")] #[serde(rename = "Ship")]
@ -51,7 +52,7 @@ pub struct Part {
pub pod: Option<Pod>, pub pod: Option<Pod>,
#[serde(rename = "partType")] #[serde(rename = "partType")]
pub part_type_id: String, pub part_type_id: String,
pub id: i64, pub id: IdType,
pub x: f64, pub x: f64,
pub y: f64, pub y: f64,
#[serde(rename = "editorAngle")] #[serde(rename = "editorAngle")]
@ -119,7 +120,7 @@ pub struct Step {
#[serde(rename = "Activate")] #[serde(rename = "Activate")]
pub struct Activate { pub struct Activate {
#[serde(rename = "Id")] #[serde(rename = "Id")]
pub id: i64, pub id: IdType,
pub moved: i8, // 1 or 0 pub moved: i8, // 1 or 0
} }