2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								package  battle  
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"math" 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 20:17:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"resolv" 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  (  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									MAX_FLOAT64                     =  1.7e+308 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									MAX_INT32                       =  int32 ( 999999999 ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									COLLISION_PLAYER_INDEX_PREFIX   =  ( 1  <<  17 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									COLLISION_BARRIER_INDEX_PREFIX  =  ( 1  <<  16 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									COLLISION_BULLET_INDEX_PREFIX   =  ( 1  <<  15 ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									PATTERN_ID_UNABLE_TO_OP  =  - 2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									PATTERN_ID_NO_OP         =  - 1 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									WORLD_TO_VIRTUAL_GRID_RATIO  =  float64 ( 100 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									VIRTUAL_GRID_TO_WORLD_RATIO  =  float64 ( 1.0 )  /  WORLD_TO_VIRTUAL_GRID_RATIO 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									GRAVITY_X  =  int32 ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									GRAVITY_Y  =  - int32 ( float64 ( 0.5 )  *  WORLD_TO_VIRTUAL_GRID_RATIO )  // makes all "playerCollider.Y" a multiple of 0.5 in all cases 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									INPUT_DELAY_FRAMES  =  int32 ( 8 )   // in the count of render frames 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									INPUT_SCALE_FRAMES  =  uint32 ( 2 )  // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									NST_DELAY_FRAMES    =  int32 ( 16 )  // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames" 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SNAP_INTO_PLATFORM_OVERLAP    =  float64 ( 0.1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SNAP_INTO_PLATFORM_THRESHOLD  =  float64 ( 0.5 ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									NO_SKILL      =  int32 ( - 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									NO_SKILL_HIT  =  int32 ( - 1 ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// These directions are chosen such that when speed is changed to "(speedX+delta, speedY+delta)" for any of them, the direction is unchanged.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  DIRECTION_DECODER  =  [ ] [ ] int32 {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ 0 ,  0 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ 0 ,  + 2 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ 0 ,  - 2 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ + 2 ,  0 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ - 2 ,  0 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ + 1 ,  + 1 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ - 1 ,  - 1 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ + 1 ,  - 1 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									{ - 1 ,  + 1 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  (  
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_IDLE1                =  int32 ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_WALKING              =  int32 ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_ATK1                 =  int32 ( 2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_ATKED1               =  int32 ( 3 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_IDLE1_NO_JUMP  =  int32 ( 4 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP  =  int32 ( 5 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_ATK1           =  int32 ( 6 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_ATKED1         =  int32 ( 7 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_BLOWN_UP1            =  int32 ( 8 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_LAY_DOWN1            =  int32 ( 9 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_GET_UP1              =  int32 ( 10 ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_ATK2  =  int32 ( 11 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_ATK3  =  int32 ( 12 ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  inAirSet  =  map [ int32 ] bool {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_IDLE1_NO_JUMP :  true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP :  true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_ATK1 :           true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_ATKED1 :         true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_BLOWN_UP1 :            true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  noOpSet  =  map [ int32 ] bool {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_ATKED1 :        true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_INAIR_ATKED1 :  true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_BLOWN_UP1 :     true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_LAY_DOWN1 :     true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// During the invinsible frames of GET_UP1, the player is allowed to take any action 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  invinsibleSet  =  map [ int32 ] bool {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_BLOWN_UP1 :  true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_LAY_DOWN1 :  true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ATK_CHARACTER_STATE_GET_UP1 :    true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  nonAttackingSet  =  map [ int32 ] bool { }  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 20:17:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ConvertToInputFrameId ( renderFrameId  int32 ,  inputDelayFrames  int32 ,  inputScaleFrames  uint32 )  int32  {  
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  renderFrameId  <  inputDelayFrames  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ( ( renderFrameId  -  inputDelayFrames )  >>  inputScaleFrames ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 15:39:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  decodeInput ( encodedInput  uint64 )  * InputFrameDecoded  {  
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									encodedDirection  :=  ( encodedInput  &  uint64 ( 15 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									btnALevel  :=  int32 ( ( encodedInput  >>  4 )  &  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									btnBLevel  :=  int32 ( ( encodedInput  >>  5 )  &  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & InputFrameDecoded { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Dx :         DIRECTION_DECODER [ encodedDirection ] [ 0 ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Dy :         DIRECTION_DECODER [ encodedDirection ] [ 1 ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										BtnALevel :  btnALevel , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										BtnBLevel :  btnBLevel , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								type  SatResult  struct  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									Overlap        float64 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									OverlapX       float64 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									OverlapY       float64 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AContainedInB  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									BContainedInA  bool 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 18:44:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									Axis           resolv . Vector 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  CalcPushbacks ( oldDx ,  oldDy  float64 ,  playerShape ,  barrierShape  * resolv . ConvexPolygon )  ( bool ,  float64 ,  float64 ,  * SatResult )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									origX ,  origY  :=  playerShape . Position ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										playerShape . SetPosition ( origX ,  origY ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									playerShape . SetPosition ( origX + oldDx ,  origY + oldDy ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									overlapResult  :=  & SatResult { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Overlap :        0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										OverlapX :       0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										OverlapY :       0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AContainedInB :  true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										BContainedInA :  true , 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 18:44:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Axis :           resolv . Vector { 0 ,  0 } , 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  overlapped  :=  isPolygonPairOverlapped ( playerShape ,  barrierShape ,  overlapResult ) ;  overlapped  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pushbackX ,  pushbackY  :=  overlapResult . Overlap * overlapResult . OverlapX ,  overlapResult . Overlap * overlapResult . OverlapY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true ,  pushbackX ,  pushbackY ,  overlapResult 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false ,  0 ,  0 ,  overlapResult 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  isPolygonPairOverlapped ( a ,  b  * resolv . ConvexPolygon ,  result  * SatResult )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									aCnt ,  bCnt  :=  len ( a . Points ) ,  len ( b . Points ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Single point case 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  1  ==  aCnt  &&  1  ==  bCnt  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  nil  !=  result  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											result . Overlap  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  a . Points [ 0 ] [ 0 ]  ==  b . Points [ 0 ] [ 0 ]  &&  a . Points [ 0 ] [ 1 ]  ==  b . Points [ 0 ] [ 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  1  <  aCnt  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  axis  :=  range  a . SATAxes ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  isPolygonPairSeparatedByDir ( a ,  b ,  axis . Unit ( ) ,  result )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  1  <  bCnt  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  axis  :=  range  b . SATAxes ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  isPolygonPairSeparatedByDir ( a ,  b ,  axis . Unit ( ) ,  result )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 18:44:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  isPolygonPairSeparatedByDir ( a ,  b  * resolv . ConvexPolygon ,  e  resolv . Vector ,  result  * SatResult )  bool  {  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/ * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										[ WARNING ]  This  function  is  deliberately  made  private ,  it  shouldn ' t  be  used  alone  ( i . e .  not  along  the  norms  of  a  polygon ) ,  otherwise  the  pushbacks  calculated  would  be  meaningless . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Consider  the  following  example 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										a :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											anchor :  [ 1337.19  1696.74 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											points :  [ [ 0  0 ]  [ 24  0 ]  [ 24  24 ]  [ 0  24 ] ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										b :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											anchor :  [ 1277.72  1570.56 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											points :  [ [ 642.57  319.16 ]  [ 0  319.16 ]  [ 5.73  0 ]  [ 643.75  0.90 ] ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										e  =  ( - 2.98 ,  1.49 ) . Unit ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  aStart ,  aEnd ,  bStart ,  bEnd  float64  =  MAX_FLOAT64 ,  - MAX_FLOAT64 ,  MAX_FLOAT64 ,  - MAX_FLOAT64 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  p  :=  range  a . Points  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dot  :=  ( p [ 0 ] + a . X ) * e [ 0 ]  +  ( p [ 1 ] + a . Y ) * e [ 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  aStart  >  dot  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											aStart  =  dot 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  aEnd  <  dot  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											aEnd  =  dot 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  p  :=  range  b . Points  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dot  :=  ( p [ 0 ] + b . X ) * e [ 0 ]  +  ( p [ 1 ] + b . Y ) * e [ 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  bStart  >  dot  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											bStart  =  dot 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  bEnd  <  dot  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											bEnd  =  dot 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  aStart  >  bEnd  ||  aEnd  <  bStart  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Separated by unit vector "e" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  nil  !=  result  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										overlap  :=  float64 ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  aStart  <  bStart  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											result . AContainedInB  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  aEnd  <  bEnd  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												overlap  =  aEnd  -  bStart 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												result . BContainedInA  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												option1  :=  aEnd  -  bStart 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												option2  :=  bEnd  -  aStart 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  option1  <  option2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													overlap  =  option1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													overlap  =  - option2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											result . BContainedInA  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  aEnd  >  bEnd  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												overlap  =  aStart  -  bEnd 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												result . AContainedInB  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												option1  :=  aEnd  -  bStart 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												option2  :=  bEnd  -  aStart 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  option1  <  option2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													overlap  =  option1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													overlap  =  - option2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										currentOverlap  :=  result . Overlap 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										absoluteOverlap  :=  overlap 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  overlap  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											absoluteOverlap  =  - overlap 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( 0  ==  result . Axis [ 0 ]  &&  0  ==  result . Axis [ 1 ] )  ||  currentOverlap  >  absoluteOverlap  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											var  sign  float64  =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  overlap  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												sign  =  - 1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											result . Overlap  =  absoluteOverlap 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											result . OverlapX  =  e [ 0 ]  *  sign 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											result . OverlapY  =  e [ 1 ]  *  sign 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result . Axis  =  e 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  WorldToVirtualGridPos ( wx ,  wy  float64 )  ( int32 ,  int32 )  {  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// [WARNING] Introduces loss of precision! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// In JavaScript floating numbers suffer from seemingly non-deterministic arithmetics, and even if certain libs solved this issue by approaches such as fixed-point-number, they might not be used in other libs -- e.g. the "collision libs" we're interested in -- thus couldn't kill all pains. 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  virtualGridX  int32  =  int32 ( math . Floor ( wx  *  WORLD_TO_VIRTUAL_GRID_RATIO ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  virtualGridY  int32  =  int32 ( math . Floor ( wy  *  WORLD_TO_VIRTUAL_GRID_RATIO ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  virtualGridX ,  virtualGridY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  VirtualGridToWorldPos ( vx ,  vy  int32 )  ( float64 ,  float64 )  {  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// No loss of precision 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  wx  float64  =  float64 ( vx )  *  VIRTUAL_GRID_TO_WORLD_RATIO 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  wy  float64  =  float64 ( vy )  *  VIRTUAL_GRID_TO_WORLD_RATIO 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  wx ,  wy 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  WorldToPolygonColliderBLPos ( wx ,  wy ,  halfBoundingW ,  halfBoundingH ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY  float64 )  ( float64 ,  float64 )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  wx  -  halfBoundingW  -  leftPadding  +  collisionSpaceOffsetX ,  wy  -  halfBoundingH  -  bottomPadding  +  collisionSpaceOffsetY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  PolygonColliderBLToWorldPos ( cx ,  cy ,  halfBoundingW ,  halfBoundingH ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY  float64 )  ( float64 ,  float64 )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  cx  +  halfBoundingW  +  leftPadding  -  collisionSpaceOffsetX ,  cy  +  halfBoundingH  +  bottomPadding  -  collisionSpaceOffsetY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  PolygonColliderBLToVirtualGridPos ( cx ,  cy ,  halfBoundingW ,  halfBoundingH ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY  float64 )  ( int32 ,  int32 )  {  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									wx ,  wy  :=  PolygonColliderBLToWorldPos ( cx ,  cy ,  halfBoundingW ,  halfBoundingH ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  WorldToVirtualGridPos ( wx ,  wy ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  VirtualGridToPolygonColliderBLPos ( vx ,  vy  int32 ,  halfBoundingW ,  halfBoundingH ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY  float64 )  ( float64 ,  float64 )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									wx ,  wy  :=  VirtualGridToWorldPos ( vx ,  vy ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  WorldToPolygonColliderBLPos ( wx ,  wy ,  halfBoundingW ,  halfBoundingH ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  calcHardPushbacksNorms ( joinIndex  int32 ,  playerCollider  * resolv . Object ,  playerShape  * resolv . ConvexPolygon ,  snapIntoPlatformOverlap  float64 ,  pEffPushback  * Vec2D )  * [ ] Vec2D  {  
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ret  :=  make ( [ ] Vec2D ,  0 ,  10 )  // no one would simultaneously have more than 5 hardPushbacks 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collision  :=  playerCollider . Check ( 0 ,  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  nil  ==  collision  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  & ret 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//playerColliderCenterX, playerColliderCenterY := playerCollider.Center() 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//fmt.Printf("joinIndex=%d calcHardPushbacksNorms has non-empty collision;playerColliderPos=(%.2f,%.2f)\n", joinIndex, playerColliderCenterX, playerColliderCenterY) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  _ ,  obj  :=  range  collision . Objects  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										isBarrier  :=  false 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										switch  obj . Data . ( type )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										case  * PlayerDownsync : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  * MeleeBullet : 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											// By default it's a regular barrier, even if data is nil, note that Golang syntax of switch-case is kind of confusing, this "default" condition is met only if "!*PlayerDownsync && !*MeleeBullet". 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											isBarrier  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! isBarrier  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										barrierShape  :=  obj . Shape . ( * resolv . ConvexPolygon ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										overlapped ,  pushbackX ,  pushbackY ,  overlapResult  :=  CalcPushbacks ( 0 ,  0 ,  playerShape ,  barrierShape ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! overlapped  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// ALWAY snap into hardPushbacks! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// [OverlapX, OverlapY] is the unit vector that points into the platform 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pushbackX ,  pushbackY  =  ( overlapResult . Overlap - snapIntoPlatformOverlap ) * overlapResult . OverlapX ,  ( overlapResult . Overlap - snapIntoPlatformOverlap ) * overlapResult . OverlapY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ret  =  append ( ret ,  Vec2D { X :  overlapResult . OverlapX ,  Y :  overlapResult . OverlapY } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pEffPushback . X  +=  pushbackX 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pEffPushback . Y  +=  pushbackY 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										//fmt.Printf("joinIndex=%d calcHardPushbacksNorms found one hardpushback; immediatePushback=(%.2f,%.2f)\n", joinIndex, pushbackX, pushbackY) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & ret 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  deriveOpPattern ( currPlayerDownsync ,  thatPlayerInNextFrame  * PlayerDownsync ,  currRenderFrame  * RoomDownsyncFrame ,  inputsBuffer  * RingBuffer ,  inputDelayFrames  int32 ,  inputScaleFrames  uint32 )  ( int ,  bool ,  int32 ,  int32 )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// returns (patternId, jumpedOrNot, effectiveDx, effectiveDy) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delayedInputFrameId  :=  ConvertToInputFrameId ( currRenderFrame . Id ,  inputDelayFrames ,  inputScaleFrames ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delayedInputFrameIdForPrevRdf  :=  ConvertToInputFrameId ( currRenderFrame . Id - 1 ,  inputDelayFrames ,  inputScaleFrames ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  0  >=  delayedInputFrameId  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  PATTERN_ID_UNABLE_TO_OP ,  false ,  0 ,  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  _ ,  existent  :=  noOpSet [ currPlayerDownsync . CharacterState ] ;  existent  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  PATTERN_ID_UNABLE_TO_OP ,  false ,  0 ,  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									delayedInputList  :=  inputsBuffer . GetByFrameId ( delayedInputFrameId ) . ( * InputFrameDownsync ) . InputList 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  delayedInputListForPrevRdf  [ ] uint64  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  0  <  delayedInputFrameIdForPrevRdf  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										delayedInputListForPrevRdf  =  inputsBuffer . GetByFrameId ( delayedInputFrameIdForPrevRdf ) . ( * InputFrameDownsync ) . InputList 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									jumpedOrNot  :=  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									joinIndex  :=  currPlayerDownsync . JoinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									decodedInput  :=  decodeInput ( delayedInputList [ joinIndex - 1 ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									effDx ,  effDy  :=  int32 ( 0 ) ,  int32 ( 0 ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									prevBtnALevel ,  prevBtnBLevel  :=  int32 ( 0 ) ,  int32 ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  nil  !=  delayedInputListForPrevRdf  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										prevDecodedInput  :=  decodeInput ( delayedInputListForPrevRdf [ joinIndex - 1 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										prevBtnALevel  =  prevDecodedInput . BtnALevel 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										prevBtnBLevel  =  prevDecodedInput . BtnBLevel 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  0  ==  currPlayerDownsync . FramesToRecover  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Jumping and moving are only allowed here 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										effDx ,  effDy  =  decodedInput . Dx ,  decodedInput . Dy 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  decodedInput . BtnBLevel  >  prevBtnBLevel  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  _ ,  existent  :=  inAirSet [ currPlayerDownsync . CharacterState ] ;  ! existent  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												jumpedOrNot  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/ * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									   As  long  as  the  current  "CharacterState"  is  not  in  "noOpSet" ,  we  have  2  cases  where  attacking  is  allowed : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									   1.  it  happens  when  the  player  is  IDLE  or  Walking ,  i . e .  "0 == currPlayerDownsync.FramesToRecover" ,  which  is  just  the  normal  case 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									   2.  it  happens  when  the  player  is  having  non - empty  "ActiveSkillId"  which  might  be  cancellable 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* / 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									patternId  :=  PATTERN_ID_NO_OP 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  decodedInput . BtnALevel  >  prevBtnALevel  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  currPlayerDownsync . InAir  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											patternId  =  255 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											patternId  =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  PATTERN_ID_NO_OP  !=  patternId  &&  0  <  currPlayerDownsync . FramesToRecover  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// [WARN] Handle skill cancellation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										patternId  =  PATTERN_ID_NO_OP  // First, reset the patternId to no-op as it should be by default not cancelling anything 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										skillConfig  :=  skills [ int ( currPlayerDownsync . ActiveSkillId ) ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										switch  v  :=  skillConfig . Hits [ currPlayerDownsync . ActiveSkillHit ] . ( type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  * MeleeBullet : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  v . CancellableStFrame  <=  currPlayerDownsync . FramesInChState  &&  currPlayerDownsync . FramesInChState  <  v . CancellableEdFrame  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												patternId  =  int ( currPlayerDownsync . ActiveSkillId  +  1 )  // if "currPlayerDownsync.InAir", it won't map to a valid skill in the next step and thus act as PATTERN_ID_NO_OP 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  patternId ,  jumpedOrNot ,  effDx ,  effDy 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 15:39:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// [WARNING] The params of this method is carefully tuned such that only "battle.RoomDownsyncFrame" is a necessary custom struct.  
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame ( inputsBuffer  * RingBuffer ,  currRenderFrame  * RoomDownsyncFrame ,  collisionSys  * resolv . Space ,  collisionSysMap  map [ int32 ] * resolv . Object ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY  float64 ,  chConfigsOrderedByJoinIndex  [ ] * CharacterConfig )  * RoomDownsyncFrame  {  
						 
					
						
							
								
									
										
										
										
											2022-12-25 15:39:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// [WARNING] On backend this function MUST BE called while "InputsBufferLock" is locked! 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-24 13:57:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									roomCapacity  :=  len ( currRenderFrame . PlayersArr ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									nextRenderFramePlayers  :=  make ( [ ] * PlayerDownsync ,  roomCapacity ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Make a copy first 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  currPlayerDownsync  :=  range  currRenderFrame . PlayersArr  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										nextRenderFramePlayers [ i ]  =  & PlayerDownsync { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Id :               currPlayerDownsync . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											VirtualGridX :     currPlayerDownsync . VirtualGridX , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											VirtualGridY :     currPlayerDownsync . VirtualGridY , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											DirX :             currPlayerDownsync . DirX , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											DirY :             currPlayerDownsync . DirY , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											VelX :             currPlayerDownsync . VelX , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											VelY :             currPlayerDownsync . VelY , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											CharacterState :   currPlayerDownsync . CharacterState , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											InAir :            true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Speed :            currPlayerDownsync . Speed , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											BattleState :      currPlayerDownsync . BattleState , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Score :            currPlayerDownsync . Score , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Removed :          currPlayerDownsync . Removed , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											JoinIndex :        currPlayerDownsync . JoinIndex , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Hp :               currPlayerDownsync . Hp , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											MaxHp :            currPlayerDownsync . MaxHp , 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											FramesToRecover :  currPlayerDownsync . FramesToRecover  -  1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											FramesInChState :  currPlayerDownsync . FramesInChState  +  1 , 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ActiveSkillId :    currPlayerDownsync . ActiveSkillId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ActiveSkillHit :   currPlayerDownsync . ActiveSkillHit , 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  nextRenderFramePlayers [ i ] . FramesToRecover  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											nextRenderFramePlayers [ i ] . FramesToRecover  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									nextRenderFrameMeleeBullets  :=  make ( [ ] * MeleeBullet ,  0 ,  len ( currRenderFrame . MeleeBullets ) )  // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation? 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									effPushbacks  :=  make ( [ ] Vec2D ,  roomCapacity ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									hardPushbackNorms  :=  make ( [ ] * [ ] Vec2D ,  roomCapacity ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									jumpedOrNotList  :=  make ( [ ] bool ,  roomCapacity ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 1. Process player inputs 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  i ,  currPlayerDownsync  :=  range  currRenderFrame . PlayersArr  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										jumpedOrNotList [ i ]  =  false 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										chConfig  :=  chConfigsOrderedByJoinIndex [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										thatPlayerInNextFrame  :=  nextRenderFramePlayers [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										patternId ,  jumpedOrNot ,  effDx ,  effDy  :=  deriveOpPattern ( currPlayerDownsync ,  thatPlayerInNextFrame ,  currRenderFrame ,  inputsBuffer ,  INPUT_DELAY_FRAMES ,  INPUT_SCALE_FRAMES ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  jumpedOrNot  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											thatPlayerInNextFrame . VelY  =  int32 ( chConfig . JumpingInitVelY ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											jumpedOrNotList [ i ]  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										joinIndex  :=  currPlayerDownsync . JoinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  PATTERN_ID_NO_OP  !=  patternId  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  skillId ,  existent  :=  chConfig . PatternIdToSkillId [ patternId ] ;  existent  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												skillConfig  :=  skills [ skillId ] 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												thatPlayerInNextFrame . ActiveSkillId  =  int32 ( skillId ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . ActiveSkillHit  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// TODO: Respect non-zero "selfLockVel" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// Hardcoded to use only the first hit for now 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												switch  v  :=  skillConfig . Hits [ thatPlayerInNextFrame . ActiveSkillHit ] . ( type )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												case  * MeleeBullet : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													var  newBullet  MeleeBullet  =  * v  // Copied primitive fields into an onstack variable 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													newBullet . OriginatedRenderFrameId  =  currRenderFrame . Id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													newBullet . OffenderJoinIndex  =  joinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													nextRenderFrameMeleeBullets  =  append ( nextRenderFrameMeleeBullets ,  & newBullet ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . FramesToRecover  =  skillConfig . RecoveryFrames 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// TODO: How to differentiate skill cancellable among different characters, e.g. some characters might be allowed to have 4-cancellation-combo or more? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												switch  skillId  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_ATK1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  2 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_ATK2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  3 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_ATK3 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  false  ==  currPlayerDownsync . InAir  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . VelX  =  0 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												continue  // Don't allow movement if skill is used 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 18:06:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  0  ==  currPlayerDownsync . FramesToRecover  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  0  !=  effDx  ||  0  !=  effDy  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . DirX ,  thatPlayerInNextFrame . DirY  =  effDx ,  effDy 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . VelX  =  effDx  *  currPlayerDownsync . Speed 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_WALKING 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_IDLE1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . VelX  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 2. Process player movement 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  currPlayerDownsync  :=  range  currRenderFrame . PlayersArr  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										joinIndex  :=  currPlayerDownsync . JoinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										effPushbacks [ joinIndex - 1 ] . X ,  effPushbacks [ joinIndex - 1 ] . Y  =  float64 ( 0 ) ,  float64 ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										collisionPlayerIndex  :=  COLLISION_PLAYER_INDEX_PREFIX  +  joinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										playerCollider  :=  collisionSysMap [ collisionPlayerIndex ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										thatPlayerInNextFrame  :=  nextRenderFramePlayers [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										chConfig  :=  chConfigsOrderedByJoinIndex [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// Reset playerCollider position from the "virtual grid position" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										newVx ,  newVy  :=  currPlayerDownsync . VirtualGridX + currPlayerDownsync . VelX ,  currPlayerDownsync . VirtualGridY + currPlayerDownsync . VelY 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  jumpedOrNotList [ i ]  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											newVy  +=  chConfig . JumpingInitVelY  // Immediately gets out of any snapping 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										playerCollider . X ,  playerCollider . Y  =  VirtualGridToPolygonColliderBLPos ( newVx ,  newVy ,  playerCollider . W * 0.5 ,  playerCollider . H * 0.5 ,  0 ,  0 ,  0 ,  0 ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// Update in the collision system 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										playerCollider . Update ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  currPlayerDownsync . InAir  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											thatPlayerInNextFrame . VelX  +=  GRAVITY_X 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											thatPlayerInNextFrame . VelY  +=  GRAVITY_Y 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// 3. Add bullet colliders into collision system 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									bulletColliders  :=  make ( [ ] * resolv . Object ,  0 ,  len ( currRenderFrame . MeleeBullets ) )  // Will all be removed at the end of this function due to the need for being rollback-compatible 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  meleeBullet  :=  range  currRenderFrame . MeleeBullets  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( meleeBullet . OriginatedRenderFrameId + meleeBullet . StartupFrames  <=  currRenderFrame . Id )  &&  ( meleeBullet . OriginatedRenderFrameId + meleeBullet . StartupFrames + meleeBullet . ActiveFrames  >  currRenderFrame . Id )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											offender  :=  currRenderFrame . PlayersArr [ meleeBullet . OffenderJoinIndex - 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											xfac  :=  int32 ( 1 )  // By now, straight Punch offset doesn't respect "y-axis" 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  0  >  offender . DirX  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												xfac  =  - xfac 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											bulletWx ,  bulletWy  :=  VirtualGridToWorldPos ( offender . VirtualGridX + xfac * meleeBullet . HitboxOffsetX ,  offender . VirtualGridY ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											hitboxSizeWx ,  hitboxSizeWy  :=  VirtualGridToWorldPos ( meleeBullet . HitboxSizeX ,  meleeBullet . HitboxSizeY ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											newBulletCollider  :=  GenerateRectCollider ( bulletWx ,  bulletWy ,  hitboxSizeWx ,  hitboxSizeWy ,  SNAP_INTO_PLATFORM_OVERLAP ,  SNAP_INTO_PLATFORM_OVERLAP ,  SNAP_INTO_PLATFORM_OVERLAP ,  SNAP_INTO_PLATFORM_OVERLAP ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY ,  meleeBullet ,  "MeleeBullet" ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											collisionSys . Add ( newBulletCollider ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											bulletColliders  =  append ( bulletColliders ,  newBulletCollider ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											nextRenderFrameMeleeBullets  =  append ( nextRenderFrameMeleeBullets ,  meleeBullet ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 4. Calc pushbacks for each player (after its movement) w/o bullets 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  i ,  currPlayerDownsync  :=  range  currRenderFrame . PlayersArr  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										joinIndex  :=  currPlayerDownsync . JoinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										collisionPlayerIndex  :=  COLLISION_PLAYER_INDEX_PREFIX  +  joinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										playerCollider  :=  collisionSysMap [ collisionPlayerIndex ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										playerShape  :=  playerCollider . Shape . ( * resolv . ConvexPolygon ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										hardPushbackNorms [ joinIndex - 1 ]  =  calcHardPushbacksNorms ( joinIndex ,  playerCollider ,  playerShape ,  SNAP_INTO_PLATFORM_OVERLAP ,  & ( effPushbacks [ joinIndex - 1 ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										thatPlayerInNextFrame  :=  nextRenderFramePlayers [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										chConfig  :=  chConfigsOrderedByJoinIndex [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										landedOnGravityPushback  :=  false 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  collision  :=  playerCollider . Check ( 0 ,  0 ) ;  nil  !=  collision  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  _ ,  obj  :=  range  collision . Objects  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												isBarrier ,  isAnotherPlayer ,  isBullet  :=  false ,  false ,  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												switch  obj . Data . ( type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  * PlayerDownsync : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													isAnotherPlayer  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  * MeleeBullet : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													isBullet  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-25 15:39:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													// By default it's a regular barrier, even if data is nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													isBarrier  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  isBullet  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													// ignore bullets for this step 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												bShape  :=  obj . Shape . ( * resolv . ConvexPolygon ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												overlapped ,  pushbackX ,  pushbackY ,  overlapResult  :=  CalcPushbacks ( 0 ,  0 ,  playerShape ,  bShape ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ! overlapped  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												normAlignmentWithGravity  :=  ( overlapResult . OverlapX * float64 ( 0 )  +  overlapResult . OverlapY * float64 ( - 1.0 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  isAnotherPlayer  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-24 13:57:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													// [WARNING] The "zero overlap collision" might be randomly detected/missed on either frontend or backend, to have deterministic result we added paddings to all sides of a playerCollider. As each velocity component of (velX, velY) being a multiple of 0.5 at any renderFrame, each position component of (x, y) can only be a multiple of 0.5 too, thus whenever a 1-dimensional collision happens between players from [player#1: i*0.5, player#2: j*0.5, not collided yet] to [player#1: (i+k)*0.5, player#2: j*0.5, collided], the overlap becomes (i+k-j)*0.5+2*s, and after snapping subtraction the effPushback magnitude for each player is (i+k-j)*0.5, resulting in 0.5-multiples-position for the next renderFrame. 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													pushbackX ,  pushbackY  =  ( overlapResult . Overlap - SNAP_INTO_PLATFORM_OVERLAP * 2 ) * overlapResult . OverlapX ,  ( overlapResult . Overlap - SNAP_INTO_PLATFORM_OVERLAP * 2 ) * overlapResult . OverlapY 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												for  _ ,  hardPushbackNorm  :=  range  * hardPushbackNorms [ joinIndex - 1 ]  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
													projectedMagnitude  :=  pushbackX * hardPushbackNorm . X  +  pushbackY * hardPushbackNorm . Y 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  isBarrier  ||  ( isAnotherPlayer  &&  0  >  projectedMagnitude )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														pushbackX  -=  projectedMagnitude  *  hardPushbackNorm . X 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														pushbackY  -=  projectedMagnitude  *  hardPushbackNorm . Y 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												effPushbacks [ joinIndex - 1 ] . X  +=  pushbackX 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												effPushbacks [ joinIndex - 1 ] . Y  +=  pushbackY 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  SNAP_INTO_PLATFORM_THRESHOLD  <  normAlignmentWithGravity  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													landedOnGravityPushback  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													//playerColliderCenterX, playerColliderCenterY := playerCollider.Center() 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													//fmt.Printf("joinIndex=%d landedOnGravityPushback\n{renderFrame.id: %d, isBarrier: %v, isAnotherPlayer: %v}\nhardPushbackNormsOfThisPlayer=%v, playerColliderPos=(%.2f,%.2f), immediatePushback={%.3f, %.3f}, effPushback={%.3f, %.3f}, overlapMag=%.4f\n", joinIndex, currRenderFrame.Id, isBarrier, isAnotherPlayer, *hardPushbackNorms[joinIndex-1], playerColliderCenterX, playerColliderCenterY, pushbackX, pushbackY, effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, overlapResult.Overlap) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  landedOnGravityPushback  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											thatPlayerInNextFrame . InAir  =  false 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-29 12:36:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  currPlayerDownsync . InAir  &&  0  >=  currPlayerDownsync . VelY  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-26 22:42:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// fallStopping 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . VelX  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . VelY  =  0 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  ATK_CHARACTER_STATE_BLOWN_UP1  ==  thatPlayerInNextFrame . CharacterState  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_LAY_DOWN1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . FramesToRecover  =  chConfig . LayDownFramesToRecover 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_IDLE1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . FramesToRecover  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// not fallStopping, could be in LayDown or GetUp 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ATK_CHARACTER_STATE_LAY_DOWN1  ==  thatPlayerInNextFrame . CharacterState  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  0  ==  thatPlayerInNextFrame . FramesToRecover  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_GET_UP1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														thatPlayerInNextFrame . FramesToRecover  =  chConfig . GetUpFramesToRecover 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ATK_CHARACTER_STATE_GET_UP1  ==  thatPlayerInNextFrame . CharacterState  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  thatPlayerInNextFrame . FramesInChState  ==  chConfig . GetUpFrames  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														// [WARNING] Before reaching here, the player had 3 invinsible frames to either attack or jump, if it ever took any action then this condition wouldn't have been met, thus we hereby only transit it back to IDLE as it took no action 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_IDLE1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// 5. Check bullet-anything collisions 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  bulletCollider  :=  range  bulletColliders  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										collision  :=  bulletCollider . Check ( 0 ,  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										bulletCollider . Space . Remove ( bulletCollider )  // Make sure that the bulletCollider is always removed for each renderFrame 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										switch  v  :=  bulletCollider . Data . ( type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  * MeleeBullet : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  nil  ==  collision  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												nextRenderFrameMeleeBullets  =  append ( nextRenderFrameMeleeBullets ,  v ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											bulletShape  :=  bulletCollider . Shape . ( * resolv . ConvexPolygon ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											offender  :=  currRenderFrame . PlayersArr [ v . OffenderJoinIndex - 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  _ ,  obj  :=  range  collision . Objects  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												defenderShape  :=  obj . Shape . ( * resolv . ConvexPolygon ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												switch  t  :=  obj . Data . ( type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												case  * PlayerDownsync : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  v . OffenderJoinIndex  ==  t . JoinIndex  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													if  _ ,  existent  :=  invinsibleSet [ t . CharacterState ] ;  existent  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													overlapped ,  _ ,  _ ,  _  :=  CalcPushbacks ( 0 ,  0 ,  bulletShape ,  defenderShape ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  ! overlapped  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													xfac  :=  int32 ( 1 )  // By now, straight Punch offset doesn't respect "y-axis" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  0  >  offender . DirX  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														xfac  =  - xfac 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													pushbackVelX ,  pushbackVelY  :=  xfac * v . PushbackVelX ,  v . PushbackVelY 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													atkedPlayerInNextFrame  :=  nextRenderFramePlayers [ t . JoinIndex - 1 ] 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													atkedPlayerInNextFrame . VelX  =  pushbackVelX 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													atkedPlayerInNextFrame . VelY  =  pushbackVelY 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													if  v . BlowUp  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														atkedPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_BLOWN_UP1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														atkedPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_ATKED1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													oldFramesToRecover  :=  nextRenderFramePlayers [ t . JoinIndex - 1 ] . FramesToRecover 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  v . HitStunFrames  >  oldFramesToRecover  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														atkedPlayerInNextFrame . FramesToRecover  =  v . HitStunFrames 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												default : 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 6. Get players out of stuck barriers if there's any 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  i ,  currPlayerDownsync  :=  range  currRenderFrame . PlayersArr  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										joinIndex  :=  currPlayerDownsync . JoinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										collisionPlayerIndex  :=  COLLISION_PLAYER_INDEX_PREFIX  +  joinIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										playerCollider  :=  collisionSysMap [ collisionPlayerIndex ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Update "virtual grid position" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										thatPlayerInNextFrame  :=  nextRenderFramePlayers [ i ] 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										thatPlayerInNextFrame . VirtualGridX ,  thatPlayerInNextFrame . VirtualGridY  =  PolygonColliderBLToVirtualGridPos ( playerCollider . X - effPushbacks [ joinIndex - 1 ] . X ,  playerCollider . Y - effPushbacks [ joinIndex - 1 ] . Y ,  playerCollider . W * 0.5 ,  playerCollider . H * 0.5 ,  0 ,  0 ,  0 ,  0 ,  collisionSpaceOffsetX ,  collisionSpaceOffsetY ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Update "CharacterState" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  thatPlayerInNextFrame . InAir  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											oldNextCharacterState  :=  thatPlayerInNextFrame . CharacterState 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											switch  oldNextCharacterState  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											case  ATK_CHARACTER_STATE_IDLE1 ,  ATK_CHARACTER_STATE_WALKING : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  jumpedOrNotList [ i ]  ||  ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP  ==  currPlayerDownsync . CharacterState  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_INAIR_IDLE1_NO_JUMP 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											case  ATK_CHARACTER_STATE_ATK1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_INAIR_ATK1 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												// No inAir transition for ATK2/ATK3 for now 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 15:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											case  ATK_CHARACTER_STATE_ATKED1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												thatPlayerInNextFrame . CharacterState  =  ATK_CHARACTER_STATE_INAIR_ATKED1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Reset "FramesInChState" if "CharacterState" is changed 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-31 15:47:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  thatPlayerInNextFrame . CharacterState  !=  currPlayerDownsync . CharacterState  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											thatPlayerInNextFrame . FramesInChState  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-01 20:18:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Remove any active skill if not attacking 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  _ ,  existent  :=  nonAttackingSet [ thatPlayerInNextFrame . CharacterState ] ;  existent  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											thatPlayerInNextFrame . ActiveSkillId  =  NO_SKILL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											thatPlayerInNextFrame . ActiveSkillHit  =  NO_SKILL_HIT 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & RoomDownsyncFrame { 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-28 23:12:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Id :            currRenderFrame . Id  +  1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										PlayersArr :    nextRenderFramePlayers , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										MeleeBullets :  nextRenderFrameMeleeBullets , 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-23 22:31:55 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2022-12-25 14:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  GenerateRectCollider ( wx ,  wy ,  w ,  h ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  spaceOffsetX ,  spaceOffsetY  float64 ,  data  interface { } ,  tag  string )  * resolv . Object  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									blX ,  blY  :=  WorldToPolygonColliderBLPos ( wx ,  wy ,  w * 0.5 ,  h * 0.5 ,  topPadding ,  bottomPadding ,  leftPadding ,  rightPadding ,  spaceOffsetX ,  spaceOffsetY ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  generateRectColliderInCollisionSpace ( blX ,  blY ,  leftPadding + w + rightPadding ,  bottomPadding + h + topPadding ,  data ,  tag ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  generateRectColliderInCollisionSpace ( blX ,  blY ,  w ,  h  float64 ,  data  interface { } ,  tag  string )  * resolv . Object  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collider  :=  resolv . NewObject ( blX ,  blY ,  w ,  h ,  tag )  // Unlike its frontend counter part, the position of a "resolv.Object" must be specified by "bottom-left point" because "w" and "h" must be positive, see "resolv.Object.BoundsToSpace" for details 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									shape  :=  resolv . NewRectangle ( 0 ,  0 ,  w ,  h ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collider . SetShape ( shape ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collider . Data  =  data 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  collider 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  GenerateConvexPolygonCollider ( unalignedSrc  * Polygon2D ,  spaceOffsetX ,  spaceOffsetY  float64 ,  data  interface { } ,  tag  string )  * resolv . Object  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									aligned  :=  AlignPolygon2DToBoundingBox ( unalignedSrc ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  w ,  h  float64  =  0 ,  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									shape  :=  resolv . NewConvexPolygon ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  pi  :=  range  aligned . Points  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  j ,  pj  :=  range  aligned . Points  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  i  ==  j  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  math . Abs ( pj . X - pi . X )  >  w  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												w  =  math . Abs ( pj . X  -  pi . X ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  math . Abs ( pj . Y - pi . Y )  >  h  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												h  =  math . Abs ( pj . Y  -  pi . Y ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i  :=  0 ;  i  <  len ( aligned . Points ) ;  i ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										p  :=  aligned . Points [ i ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										shape . AddPoints ( p . X ,  p . Y ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collider  :=  resolv . NewObject ( aligned . Anchor . X + spaceOffsetX ,  aligned . Anchor . Y + spaceOffsetY ,  w ,  h ,  tag ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collider . SetShape ( shape ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									collider . Data  =  data 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  collider 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  AlignPolygon2DToBoundingBox ( input  * Polygon2D )  * Polygon2D  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Transform again to put "anchor" at the "bottom-left point (w.r.t. world space)" of the bounding box for "resolv" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									boundingBoxBL  :=  & Vec2D { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										X :  MAX_FLOAT64 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Y :  MAX_FLOAT64 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  p  :=  range  input . Points  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  p . X  <  boundingBoxBL . X  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											boundingBoxBL . X  =  p . X 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  p . Y  <  boundingBoxBL . Y  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											boundingBoxBL . Y  =  p . Y 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Now "input.Anchor" should move to "input.Anchor+boundingBoxBL", thus "boundingBoxBL" is also the value of the negative diff for all "input.Points" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									output  :=  & Polygon2D { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Anchor :  & Vec2D { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											X :  input . Anchor . X  +  boundingBoxBL . X , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Y :  input . Anchor . Y  +  boundingBoxBL . Y , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Points :  make ( [ ] * Vec2D ,  len ( input . Points ) ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  p  :=  range  input . Points  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										output . Points [ i ]  =  & Vec2D { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											X :  p . X  -  boundingBoxBL . X , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Y :  p . Y  -  boundingBoxBL . Y , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  output 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}