1+ #include " HitboxNode.hpp"
2+ #include " HitboxColours.hpp"
3+
4+ using namespace geode ::prelude;
5+
6+ bool HitboxNode::init ()
7+ {
8+ if (!CCDrawNode::init ())
9+ return false ;
10+
11+ return true ;
12+ }
13+
14+ void HitboxNode::updateNode ()
15+ {
16+ this ->clear ();
17+
18+ if (auto gjbgl = GJBaseGameLayer::get ())
19+ {
20+ forEachObject (gjbgl, [this ](GameObject* obj)
21+ {
22+ if (shouldObjectDraw (obj))
23+ drawObjectHitbox (obj);
24+ });
25+ }
26+ }
27+
28+ HitboxColourType HitboxNode::getObjectColour (GameObject* obj)
29+ {
30+ if (objTypeMatchesAny (obj, { GameObjectType::Hazard, GameObjectType::AnimatedHazard }))
31+ return HitboxColourType::Hazard;
32+
33+ if (objTypeMatchesAny (obj, { GameObjectType::Solid, GameObjectType::Slope }))
34+ return HitboxColourType::Solid;
35+
36+ if (objTypeMatchesAny (obj, { GameObjectType::Breakable }) || obj->m_isPassable )
37+ return HitboxColourType::Passable;
38+
39+ if (objTypeMatchesAny (obj, { GameObjectType::UserCoin, GameObjectType::Collectible, GameObjectType::SecretCoin }))
40+ return HitboxColourType::Interactable;
41+
42+ if (objTypeMatchesAny (obj, {
43+ GameObjectType::InverseGravityPortal,
44+ GameObjectType::NormalGravityPortal,
45+ GameObjectType::ShipPortal,
46+ GameObjectType::CubePortal,
47+ GameObjectType::YellowJumpPad,
48+ GameObjectType::PinkJumpPad,
49+ GameObjectType::GravityPad,
50+ GameObjectType::YellowJumpRing,
51+ GameObjectType::PinkJumpRing,
52+ GameObjectType::GravityRing,
53+ GameObjectType::InverseMirrorPortal,
54+ GameObjectType::NormalMirrorPortal,
55+ GameObjectType::BallPortal,
56+ GameObjectType::RegularSizePortal,
57+ GameObjectType::MiniSizePortal,
58+ GameObjectType::UfoPortal,
59+ GameObjectType::DualPortal,
60+ GameObjectType::SoloPortal,
61+ GameObjectType::WavePortal,
62+ GameObjectType::RobotPortal,
63+ GameObjectType::TeleportPortal,
64+ GameObjectType::GreenRing,
65+ GameObjectType::DropRing,
66+ GameObjectType::SpiderPortal,
67+ GameObjectType::RedJumpPad,
68+ GameObjectType::RedJumpRing,
69+ GameObjectType::CustomRing,
70+ GameObjectType::DashRing,
71+ GameObjectType::GravityDashRing,
72+ GameObjectType::SwingPortal,
73+ GameObjectType::GravityTogglePortal,
74+ GameObjectType::SpiderOrb,
75+ GameObjectType::SpiderPad,
76+ GameObjectType::TeleportOrb,
77+ }))
78+ return HitboxColourType::Interactable;
79+
80+ return HitboxColourType::Unk;
81+ }
82+
83+ bool HitboxNode::objTypeMatchesAny (GameObject* obj, std::vector<GameObjectType> types)
84+ {
85+ return std::find (types.begin (), types.end (), obj->m_objectType ) != types.end ();
86+ }
87+
88+ cocos2d::ccColor3B HitboxNode::colourForType (HitboxColourType colour)
89+ {
90+ switch (colour)
91+ {
92+ case HitboxColourType::Hazard:
93+ return HitboxHazard::get ()->getColour ();
94+
95+ case HitboxColourType::Solid:
96+ return HitboxSolid::get ()->getColour ();
97+
98+ case HitboxColourType::Passable:
99+ return HitboxPassable::get ()->getColour ();
100+
101+ case HitboxColourType::Interactable:
102+ return HitboxInteractable::get ()->getColour ();
103+
104+ case HitboxColourType::PlayerReg:
105+ return HitboxPlayer::get ()->getColour ();
106+
107+ case HitboxColourType::PlayerRot:
108+ return HitboxPlayerRot::get ()->getColour ();
109+
110+ default :
111+ return ccWHITE;
112+ }
113+ }
114+
115+ bool HitboxNode::shouldObjectDraw (GameObject* obj)
116+ {
117+ if (obj->m_isDecoration || obj->m_isDecoration2 )
118+ return false ;
119+
120+ if (objTypeMatchesAny (obj, { GameObjectType::EnterEffectObject, GameObjectType::Modifier }))
121+ return false ;
122+
123+ if (obj->m_unk3ee )
124+ return false ;
125+
126+ if (getObjectColour (obj) == HitboxColourType::Unk)
127+ return false ;
128+
129+ return true ;
130+ }
131+
132+ bool HitboxNode::shouldFillHitboxes ()
133+ {
134+ return HitboxFill::get ()->getRealEnabled ();
135+ }
136+
137+ float HitboxNode::getHitboxThickness ()
138+ {
139+ return 0 .35f * (HitboxThickOutline::get ()->getRealEnabled () ? 2 : 1 );
140+ }
141+
142+ void HitboxNode::drawObjectHitbox (GameObject* obj)
143+ {
144+ auto col = colourForType (getObjectColour (obj));
145+ auto col2 = ccc4f (col.r / 255 .0f , col.g / 255 .0f , col.b / 255 .0f , 1 );
146+
147+ if (obj->m_objectRadius != 0 )
148+ {
149+ drawCircle (ccp (obj->m_positionX , obj->m_positionY ), obj->m_objectRadius * std::max<float >(obj->m_scaleX , obj->m_scaleY ), ccc4f (0 , 0 , 0 , 0 ), getHitboxThickness (), col2, 69 );
150+ return ;
151+ }
152+
153+ if (obj->m_isOrientedBoxDirty )
154+ obj->calculateOrientedBox ();
155+
156+ auto rect = obj->m_orientedBox ;
157+
158+ if (!rect)
159+ return ;
160+
161+ if (obj->m_objectType == GameObjectType::Slope)
162+ {
163+ auto r = obj->getObjectRect ();
164+
165+ CCPoint vertices[] = {
166+ ccp (r.getMaxX (), r.getMinY ()), // br
167+ ccp (r.getMinX (), r.getMaxY ()), // tl
168+ ccp (r.getMinX (), r.getMinY ()), // bl
169+ };
170+
171+ switch (obj->m_slopeDirection )
172+ {
173+ case 0 :
174+ case 7 :
175+ vertices[1 ] = ccp (r.getMaxX (), r.getMaxY ());
176+ break ;
177+
178+ case 3 :
179+ case 6 :
180+ vertices[0 ] = ccp (r.getMaxX (), r.getMaxY ());
181+ break ;
182+
183+ case 1 :
184+ case 5 :
185+ vertices[2 ] = ccp (r.getMinX (), r.getMaxY ());
186+ vertices[1 ] = ccp (r.getMaxX (), r.getMaxY ());
187+ vertices[0 ] = ccp (r.getMaxX (), r.getMinY ());
188+ break ;
189+ }
190+
191+ drawPolygon (vertices, 3 , ccc4f (0 , 0 , 0 , 0 ), getHitboxThickness (), col2, BorderAlignment::Inside);
192+ return ;
193+ }
194+
195+ CCPoint vertices[] = {
196+ rect->m_corners [0 ],
197+ rect->m_corners [1 ],
198+ rect->m_corners [2 ],
199+ rect->m_corners [3 ]
200+ };
201+
202+ // obj->m_isOrientedBoxDirty = true;
203+
204+ float v = 0 ;
205+
206+ if (shouldFillHitboxes ())
207+ v = HitboxFillOpacity::get ()->getValue ();
208+
209+ drawPolygon (vertices, 4 , ccc4f (0 , 0 , 0 , 0 ), getHitboxThickness (), col2, BorderAlignment::Inside);
210+ }
211+
212+ void HitboxNode::forEachObject (GJBaseGameLayer* game, const std::function<void (GameObject*)>& callback)
213+ {
214+ if (!callback || !game)
215+ return ;
216+
217+ int count = game->m_sections .empty () ? -1 : game->m_sections .size ();
218+ for (int i = game->m_leftSectionIndex ; i <= game->m_rightSectionIndex && i < count; ++i)
219+ {
220+ auto leftSection = game->m_sections [i];
221+ if (!leftSection) continue ;
222+
223+ auto leftSectionSize = leftSection->size ();
224+ for (int j = game->m_bottomSectionIndex ; j <= game->m_topSectionIndex && j < leftSectionSize; ++j)\
225+ {
226+ auto section = leftSection->at (j);
227+ if (!section) continue ;
228+
229+ auto sectionSize = game->m_sectionSizes [i]->at (j);
230+ for (int k = 0 ; k < sectionSize; ++k)
231+ {
232+ auto obj = section->at (k);
233+ if (!obj) continue ;
234+
235+ if (obj == game->m_player1CollisionBlock )
236+ continue ;
237+
238+ if (obj == game->m_player2CollisionBlock )
239+ continue ;
240+
241+ if (obj == game->m_anticheatSpike )
242+ continue ;
243+
244+ callback (obj);
245+ }
246+ }
247+ }
248+ }
0 commit comments