中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

深圳手機(jī)報(bào)價(jià)網(wǎng)站谷歌seo推廣培訓(xùn)班

深圳手機(jī)報(bào)價(jià)網(wǎng)站,谷歌seo推廣培訓(xùn)班,哪里網(wǎng)站備案快,wordpress漫畫商城碰撞功能應(yīng)該是一個(gè)核心功能,它能自動(dòng)產(chǎn)生相應(yīng)的數(shù)據(jù),比如目標(biāo)對(duì)象進(jìn)入、離開本對(duì)象的檢測(cè)區(qū)域。 基于屬性設(shè)置,能碰撞的都具備這樣的屬性:Layer、Mask. 在Godot 4中,Collision屬性中的Layer和Mask屬性是用于定義碰撞…

碰撞功能應(yīng)該是一個(gè)核心功能,它能自動(dòng)產(chǎn)生相應(yīng)的數(shù)據(jù),比如目標(biāo)對(duì)象進(jìn)入、離開本對(duì)象的檢測(cè)區(qū)域。

基于屬性設(shè)置,能碰撞的都具備這樣的屬性:Layer、Mask.

在Godot 4中,Collision屬性中的Layer和Mask屬性是用于定義碰撞過濾的重要參數(shù)。它們?cè)试S控制哪些物體可以與該節(jié)點(diǎn)進(jìn)行碰撞檢測(cè)。

  1. Layer(圖層):

    • Layer是所有節(jié)點(diǎn)都具有的屬性,用于將節(jié)點(diǎn)分組到不同的圖層中。Layer是一組位掩碼(bitmask),每個(gè)位代表一個(gè)特定的碰撞圖層。每個(gè)物體都可以分配一個(gè)或多個(gè)碰撞圖層。通過將物體分配到特定的碰撞圖層,可定義其所屬的邏輯組
    • 每個(gè)節(jié)點(diǎn)可以屬于一個(gè)或多個(gè)圖層。你可以在節(jié)點(diǎn)的屬性面板中的Layer部分選擇一個(gè)或多個(gè)圖層。
    • Layer屬性定義了節(jié)點(diǎn)所屬的圖層。默認(rèn)情況下,節(jié)點(diǎn)屬于基本圖層(Base Layer)。
    • 使用不同圖層將場(chǎng)景中的節(jié)點(diǎn)分組,可以使你能夠僅與特定圖層上的節(jié)點(diǎn)進(jìn)行碰撞檢測(cè)。
  2. Mask(掩碼):

    • Mask也是所有節(jié)點(diǎn)都具有的屬性,用于指定該節(jié)點(diǎn)對(duì)碰撞的興趣。Mask也是一組位掩碼,用于指示物體可以與哪些碰撞圖層的物體發(fā)生碰撞檢測(cè)。每個(gè)物體都可以指定一個(gè)碰撞掩碼。通過設(shè)置碰撞掩碼,可定義物體與哪些碰撞圖層的物體發(fā)生碰撞
    • 每個(gè)節(jié)點(diǎn)都有一個(gè)掩碼值??梢栽诠?jié)點(diǎn)的屬性面板中的Collision屬性下設(shè)置掩碼。
    • Mask屬性定義了該節(jié)點(diǎn)對(duì)哪些圖層的節(jié)點(diǎn)感興趣,該節(jié)點(diǎn)將與這些圖層中的其他節(jié)點(diǎn)進(jìn)行碰撞檢測(cè)。
    • 每個(gè)節(jié)點(diǎn)的掩碼值是一個(gè)32位的整數(shù),每一位代表一個(gè)圖層。0表示不興趣該圖層,1表示興趣該圖層??梢允褂梦徊僮?#xff08;如按位與和按位或)來設(shè)置和檢查掩碼值。

通過使用Layer和Mask屬性,你可以靈活地控制碰撞檢測(cè),使得只特定圖層中的節(jié)點(diǎn)相互交互。例如,你可以設(shè)置一個(gè)節(jié)點(diǎn)僅與屬于某個(gè)特定圖層的節(jié)點(diǎn)進(jìn)行碰撞,而忽略其他圖層的節(jié)點(diǎn)。

需要注意的是,為了讓兩個(gè)節(jié)點(diǎn)進(jìn)行碰撞檢測(cè),它們的Layer和Mask需要同時(shí)滿足一定條件。具體而言,一個(gè)節(jié)點(diǎn)的Layer值必須包含在另一個(gè)節(jié)點(diǎn)的Mask值中,同時(shí)另一個(gè)節(jié)點(diǎn)的Layer值必須包含在該節(jié)點(diǎn)的Mask值中。

通過合理設(shè)置Layer和Mask屬性,可在Godot 4中創(chuàng)建精細(xì)且靈活的碰撞過濾系統(tǒng),以實(shí)現(xiàn)各種復(fù)雜的物理效果和游戲機(jī)制。

假設(shè)有兩個(gè)碰撞圖層,一個(gè)是"Player",另一個(gè)是"Enemy"。有一個(gè)玩家角色和一些敵人,想要確保玩家和敵人之間發(fā)生碰撞,但是敵人之間不發(fā)生碰撞。

  • 對(duì)于玩家對(duì)象:將其分配到"Player"碰撞圖層,并將其Collision Mask設(shè)置為"Enemy"的位掩碼。這將使玩家只與"Enemy"圖層的物體發(fā)生碰撞。

  • 對(duì)于敵人對(duì)象:將它們分配到"Enemy"碰撞圖層,并將其Collision Mask設(shè)置為"Player"的位掩碼。這將使敵人只與"Player"圖層的物體發(fā)生碰撞。

對(duì)于敵人對(duì)象之間,可將它們分配到相同的碰撞圖層并設(shè)置相應(yīng)的碰撞掩碼,以確保它們不會(huì)互相碰撞。

通過這種方式,可在復(fù)雜的場(chǎng)景中更精細(xì)地控制碰撞的交互,使碰撞邏輯更加清晰和可管理。

從理解角度來說,邏輯說起來復(fù)雜,技術(shù)上實(shí)現(xiàn)很簡(jiǎn)單

Layer與Mask應(yīng)該都是32位整數(shù),對(duì)象A有Layer與Mask屬性,對(duì)象B也有Layer與Mask屬性

如果 A.Layer & B.Mask?非零,則?A要與B發(fā)生碰撞

如果 A.Mask & B.Layer非零,則B要與A發(fā)生碰撞

還是有點(diǎn)繞,再多想一下,以下是我自己的想法,不一定正確:

其實(shí),Layer與Mask都是邏輯概念,虛擬的。在真實(shí)場(chǎng)景中,A、B都占據(jù)相應(yīng)的空間位置(3D)或平面位置(2D),在運(yùn)行過程中,A、B至少有一個(gè)能動(dòng),它們的相對(duì)位置可能會(huì)變化,在某個(gè)時(shí)刻會(huì)有交疊。這個(gè)時(shí)候,godot引擎知道,因?yàn)樗軐?shí)時(shí)計(jì)算。那么,godot發(fā)現(xiàn)兩個(gè)對(duì)象發(fā)生交疊了,怎么辦呢?

那就檢查A、B的Layer與Mask。

  • 如果 A.Layer & B.Mask?非零,則B能檢測(cè)到A,觸發(fā)B的body_entered信號(hào),實(shí)參為A。
  • 如果 B.Layer & A.Mask?非零,則A能檢測(cè)到B,觸發(fā)A的body_entered信號(hào),實(shí)參為B。

其實(shí)上面的說法不嚴(yán)謹(jǐn),因?yàn)閎ody_entered信號(hào)不應(yīng)該連續(xù)發(fā)送,而是有個(gè)進(jìn)出狀態(tài)。整體連起來應(yīng)該就是:

  • A、B分別維護(hù)自己的body_map,知道與自己交疊的對(duì)象列表。這個(gè)工作不能交給godot引擎做,它多忙的,還是各自管好自己的事
  • 從源碼看出,檢測(cè)進(jìn)出的狀態(tài)標(biāo)志,還是A、B自己完成,也就是說,遍歷所有的監(jiān)控對(duì)象monitored_bodies,看與自己的??狀態(tài)E->value,若為0,則啥事沒有,不再監(jiān)控該對(duì)象。如果>0,則為AREA_BODY_ADDED,表示進(jìn)入。如果<0,則為AREA_BODY_REMOVED,表示離開。
void GodotArea2D::call_queries() {if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) {if (monitor_callback.is_valid()) {Variant res[5];Variant *resptr[5];for (int i = 0; i < 5; i++) {resptr[i] = &res[i];}for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_bodies.begin(); E;) {if (E->value.state == 0) { // Nothing happenedHashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_bodies.remove(E);E = next;continue;}res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;res[1] = E->key.rid;res[2] = E->key.instance_id;res[3] = E->key.body_shape;res[4] = E->key.area_shape;HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_bodies.remove(E);E = next;Callable::CallError ce;Variant ret;monitor_callback.callp((const Variant **)resptr, 5, ret, ce);if (ce.error != Callable::CallError::CALL_OK) {ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(monitor_callback, (const Variant **)resptr, 5, ce));}}} else {monitored_bodies.clear();monitor_callback = Callable();}}if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) {if (area_monitor_callback.is_valid()) {Variant res[5];Variant *resptr[5];for (int i = 0; i < 5; i++) {resptr[i] = &res[i];}for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_areas.begin(); E;) {if (E->value.state == 0) { // Nothing happenedHashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_areas.remove(E);E = next;continue;}res[0] = E->value.state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;res[1] = E->key.rid;res[2] = E->key.instance_id;res[3] = E->key.body_shape;res[4] = E->key.area_shape;HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;++next;monitored_areas.remove(E);E = next;Callable::CallError ce;Variant ret;area_monitor_callback.callp((const Variant **)resptr, 5, ret, ce);if (ce.error != Callable::CallError::CALL_OK) {ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(area_monitor_callback, (const Variant **)resptr, 5, ce));}}} else {monitored_areas.clear();area_monitor_callback = Callable();}}
}
  • 根據(jù)是否為AREA_BODY_ADDED確定body_in標(biāo)志。若為body_in,則觸發(fā)tree_entered、tree_exiting信號(hào),如果本對(duì)象在工作場(chǎng)景中,則觸發(fā)body_entered,參數(shù)為node。順便還觸發(fā)了body_shape_entered信號(hào),看著用吧。
  • 若body_in為false,則觸發(fā)tree_entered、tree_exiting。如果本對(duì)象在工作場(chǎng)景中,則觸發(fā)body_exited、body_shape_exited
void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {bool body_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;ObjectID objid = p_instance;Object *obj = ObjectDB::get_instance(objid);Node *node = Object::cast_to<Node>(obj);HashMap<ObjectID, BodyState>::Iterator E = body_map.find(objid);if (!body_in && !E) {return; //does not exist because it was likely removed from the tree}lock_callback();locked = true;if (body_in) {if (!E) {E = body_map.insert(objid, BodyState());E->value.rid = p_body;E->value.rc = 0;E->value.in_tree = node && node->is_inside_tree();if (node) {node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree).bind(objid));node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree).bind(objid));if (E->value.in_tree) {emit_signal(SceneStringNames::get_singleton()->body_entered, node);}}}E->value.rc++;if (node) {E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));}if (!node || E->value.in_tree) {emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);}} else {E->value.rc--;if (node) {E->value.shapes.erase(ShapePair(p_body_shape, p_area_shape));}bool in_tree = E->value.in_tree;if (E->value.rc == 0) {body_map.remove(E);if (node) {node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree));node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree));if (in_tree) {emit_signal(SceneStringNames::get_singleton()->body_exited, obj);}}}if (!node || in_tree) {emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);}}locked = false;unlock_callback();
}

到此,就該關(guān)注monitored_bodies,它在add_body_to_query、remove_body_from_query中維護(hù)


void GodotArea2D::add_body_to_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {BodyKey bk(p_body, p_body_shape, p_area_shape);monitored_bodies[bk].inc();if (!monitor_query_list.in_list()) {_queue_monitor_update();}
}void GodotArea2D::remove_body_from_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {BodyKey bk(p_body, p_body_shape, p_area_shape);monitored_bodies[bk].dec();if (!monitor_query_list.in_list()) {_queue_monitor_update();}
}

但這沒看到Layer與Mask屬性的作用。那就倒查。最終發(fā)現(xiàn)在GodotCollisionObject2D類中:

_FORCE_INLINE_ bool collides_with(GodotCollisionObject2D *p_other) const {return p_other->collision_layer & collision_mask;
}

果然,與猜測(cè)的一致。具體調(diào)用collides_with是在一些setup函數(shù)中。

bool GodotAreaPair2D::setup(real_t p_step) {bool result = false;if (area->collides_with(body) && GodotCollisionSolver2D::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {result = true;}process_collision = false;has_space_override = false;if (result != colliding) {if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {has_space_override = true;} else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {has_space_override = true;} else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {has_space_override = true;}process_collision = has_space_override;if (area->has_monitor_callback()) {process_collision = true;}colliding = result;}return process_collision;
}bool GodotBodyPair2D::setup(real_t p_step) {check_ccd = false;if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {collided = false;return false;}collide_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) && A->collides_with(B);collide_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) && B->collides_with(A);report_contacts_only = false;if (!collide_A && !collide_B) {if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {report_contacts_only = true;} else {collided = false;return false;}}//use local A coordinates to avoid numerical issues on collision detectionoffset_B = B->get_transform().get_origin() - A->get_transform().get_origin();_validate_contacts();const Vector2 &offset_A = A->get_transform().get_origin();Transform2D xform_Au = A->get_transform().untranslated();Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A);Transform2D xform_Bu = B->get_transform();xform_Bu.columns[2] -= offset_A;Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B);GodotShape2D *shape_A_ptr = A->get_shape(shape_A);GodotShape2D *shape_B_ptr = B->get_shape(shape_B);Vector2 motion_A, motion_B;if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_SHAPE) {motion_A = A->get_motion();}if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_SHAPE) {motion_B = B->get_motion();}bool prev_collided = collided;collided = GodotCollisionSolver2D::solve(shape_A_ptr, xform_A, motion_A, shape_B_ptr, xform_B, motion_B, _add_contact, this, &sep_axis);if (!collided) {oneway_disabled = false;if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_A) {check_ccd = true;return true;}if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && collide_B) {check_ccd = true;return true;}return false;}if (oneway_disabled) {return false;}if (!prev_collided) {if (shape_B_ptr->allows_one_way_collision() && A->is_shape_set_as_one_way_collision(shape_A)) {Vector2 direction = xform_A.columns[1].normalized();bool valid = false;for (int i = 0; i < contact_count; i++) {Contact &c = contacts[i];if (c.normal.dot(direction) > -CMP_EPSILON) { // Greater (normal inverted).continue;}valid = true;break;}if (!valid) {collided = false;oneway_disabled = true;return false;}}if (shape_A_ptr->allows_one_way_collision() && B->is_shape_set_as_one_way_collision(shape_B)) {Vector2 direction = xform_B.columns[1].normalized();bool valid = false;for (int i = 0; i < contact_count; i++) {Contact &c = contacts[i];if (c.normal.dot(direction) < CMP_EPSILON) { // Less (normal ok).continue;}valid = true;break;}if (!valid) {collided = false;oneway_disabled = true;return false;}}}return true;
}

這就沒有必要再跟下去了。至于這些setup函數(shù)什么時(shí)候被調(diào)用,可以用一個(gè)實(shí)際項(xiàng)目調(diào)試來看看。

主要核心思想是理解碰撞的Layer與Mask配置問題。

http://www.risenshineclean.com/news/8613.html

相關(guān)文章:

  • 網(wǎng)站同時(shí)做競(jìng)價(jià)和seo寧波百度seo排名優(yōu)化
  • 怎么做招標(biāo)公司網(wǎng)站石家莊谷歌seo
  • 遼寧省城鄉(xiāng)住房建設(shè)廳網(wǎng)站搜狗站長工具綜合查詢
  • 如何做國外外貿(mào)網(wǎng)站百度手機(jī)app
  • 網(wǎng)站開發(fā)之ios知識(shí)擴(kuò)展百度手機(jī)助手應(yīng)用商店下載
  • 專業(yè)網(wǎng)站優(yōu)化公司報(bào)價(jià)自助建站網(wǎng)站
  • 保定網(wǎng)站公司那家好百度競(jìng)價(jià)托管費(fèi)用
  • 男女做曖曖試看網(wǎng)站49網(wǎng)站建設(shè)主要推廣方式
  • 設(shè)計(jì)網(wǎng)站客戶體驗(yàn)建設(shè)網(wǎng)站前的市場(chǎng)分析
  • 做網(wǎng)站生成二維碼競(jìng)價(jià)外包推廣
  • 北京青鳥培訓(xùn)機(jī)構(gòu)哪家是正規(guī)的廣州網(wǎng)站優(yōu)化價(jià)格
  • 做二維碼簽到的網(wǎng)站百度推廣開戶怎么開
  • 網(wǎng)站推廣托管培訓(xùn)機(jī)構(gòu)退費(fèi)法律規(guī)定
  • 個(gè)人微信公共號(hào)可以做微網(wǎng)站么在線識(shí)別圖片來源
  • 如何制作個(gè)人作品網(wǎng)站16種營銷模型
  • 用asp做網(wǎng)站谷歌seo外鏈平臺(tái)
  • 城鄉(xiāng)和建設(shè)部建造師網(wǎng)站江西seo
  • 做域名后就得做網(wǎng)站嗎軟文廣告有哪些
  • 寧波網(wǎng)站建設(shè)在哪里今日頭條新聞軍事
  • 淄博做網(wǎng)站的公司排名seo推廣的全稱是
  • 如何做微信商城網(wǎng)站建設(shè)百度提問登陸入口
  • 學(xué)生為學(xué)校做網(wǎng)站谷歌廣告代理商
  • java 制作網(wǎng)站開發(fā)莆田seo推廣公司
  • 做資源網(wǎng)站怎么不封抖音關(guān)鍵詞挖掘工具
  • 中鐵快運(yùn)關(guān)于網(wǎng)站建設(shè)企業(yè)網(wǎng)站推廣優(yōu)化公司
  • word文檔怎么做網(wǎng)站跳轉(zhuǎn)鏈接關(guān)鍵詞排名優(yōu)化官網(wǎng)
  • 哪些網(wǎng)站可以做微商品牌宣傳軟文營銷的案例
  • 用一個(gè)域名免費(fèi)做網(wǎng)站怎么做一個(gè)網(wǎng)站
  • 肇東網(wǎng)站制作廣州優(yōu)化網(wǎng)站排名
  • 商丘幼兒園網(wǎng)站建設(shè)策劃方案廊坊網(wǎng)絡(luò)推廣公司