physics.inc
physics.inc
CPP1/****s* PawnLibs/physics/PHYSICS_CIRCLE_DATA2 * Summary3 * Array with named fields which represents a round object.4 * Synopsis5 */6#define PHYSICS_CIRCLE_DATA .posX, .posY, .simplePosX, .simplePosY, .spdX, .spdY, .mass, .radius, .CoR, .module, .screen, .moduleT, .screenT,7/*8 * Description9 * Fields:10 * * posX - circle position on X axis (fixed point)11 * * posY - circle position on Y axis (fixed point)12 * * simplePosX - circle position on X axis13 * * simplePosY - circle position on Y axis14 * * spdX - circle X speed15 * * spdY - circle Y speed16 * * mass - circle mass (fixed point)17 * * radius - circle radius18 * * CoR - Coefficient of restitution (fixed point)19 * * module - module owner of this circle20 * * screen - screen owner of this circle21 * * moduleT - module transfer, last module owner. Can be used for resending messages22 * * screenT - screen transfer, last screen owner. Can be used for resending messages23 ******/2425#include "math.inc"2627/****f* PawnLibs/physics/Physics_Overlap28 * Summary29 * TBD: inner function30 * Synopsis31 */32stock Physics_Overlap(overlap, positionDifference, distance)33/*34 * Source35 */36{37 if (distance != 0) {38 return overlap * positionDifference / distance;39 } else {40 return overlap * positionDifference;41 }42}43/******/4445/****f* PawnLibs/physics/Physics_Circle_Vs_Circle_obj46 * Summary47 * Check if there is a collision between two round objects.48 * Synopsis49 */50stock Physics_Circle_Vs_Circle_obj(circle1[PHYSICS_CIRCLE_DATA], circle2[PHYSICS_CIRCLE_DATA])51/*52 * Inputs53 * * circle1, circle2 - objects for whom collision is checked54 * Return value55 * True if collision happens, false otherwise.56 * See also57 * * Physics_Res_CvC_Coll_Mass()58 * * Physics_Res_CvC_Coll_Massless()59 * Source60 */61{62 new r = (circle1.radius + circle2.radius) * (circle1.radius + circle2.radius);63 return r > CheapDistance(circle1.simplePosX - circle2.simplePosX, circle1.simplePosY - circle2.simplePosY);64}65/******/6667/****f* PawnLibs/physics/Physics_Circle_vs_AABB_obj68 * Summary69 * Check if there is a collision between round object and the axis-aligned70 * bounding box.71 * Synopsis72 */73stock Physics_Circle_vs_AABB_obj(circle[PHYSICS_CIRCLE_DATA], rectX, rectY, rectWidth, rectHeight, fakeCircle[PHYSICS_CIRCLE_DATA] = 0)74/*75 * Inputs76 * * circle - an object for whom collision is checked77 * * rectX, rectY, - coordinates of the AABB object78 * * rectWidth, rectHeight - dimensions of the AABB object79 * Outputs80 * * fakeCircle - collision point, can be used for resolving collision81 * Return value82 * True if collision happens, false otherwise.83 * See also84 * * Physics_Res_CvC_Coll_Mass()85 * * Physics_Res_CvC_Coll_Massless()86 * Source87 */88{89 new x = Max(rectX, Min(circle.simplePosX, rectX + rectWidth));90 new y = Max(rectY, Min(circle.simplePosY, rectY + rectHeight));91 new distance = CheapDistance(x - circle.simplePosX, y - circle.simplePosY);92 if (distance < (circle.radius * circle.radius)) {93 fakeCircle.spdX = -circle.spdX;94 fakeCircle.spdY = -circle.spdY;95 fakeCircle.mass = (circle.mass * 230) >> 8;96 fakeCircle.radius = 1;97 fakeCircle.CoR = 256;9899 new dotProd = 0;100101 new toPointX = x - circle.simplePosX;102 new toPointY = y - circle.simplePosY;103104 if ((x == circle.simplePosX) && (y == circle.simplePosY)) {105 if (circle.spdX > 0) {106 x = rectX;107 } else {108 x = rectX + rectWidth;109 }110 if (circle.spdY > 0) {111 y = rectY;112 } else {113 y = rectY + rectHeight;114 }115 toPointX = circle.simplePosX - x;116 toPointY = circle.simplePosY - y;117 }118 dotProd = Vector2D_Dot_Product(toPointX, toPointY, circle.spdX, circle.spdY);119 fakeCircle.simplePosX = x;120 fakeCircle.simplePosY = y;121 // If not it's unnecessary do further calculations122 return (dotProd > 0);123 }124 return 0;125}126/******/127128/****f* PawnLibs/physics/Physics_Circle_Vs_LineSegment129 * Summary130 * Check if there is a collision between round object and the line.131 * Synopsis132 */133stock Physics_Circle_Vs_LineSegment(circle[PHYSICS_CIRCLE_DATA], lineSX, lineSY, lineEX, lineEY, fakeCircle[PHYSICS_CIRCLE_DATA] = 0)134/*135 * Inputs136 * * circle - an object for whom collision is checked137 * * lineSX, lineSY, lineEX, lineEY - the line start and end coordinates138 * Outputs139 * * fakeCircle - collision point, can be used for resolving collision140 * Return value141 * True if collision happens, false otherwise.142 * See also143 * * Physics_Res_CvC_Coll_Mass()144 * * Physics_Res_CvC_Coll_Massless()145 * Source146 */147{148 new lineX1 = lineEX - lineSX;149 new lineY1 = lineEY - lineSY;150151 new lineX2 = circle.simplePosX - lineSX;152 new lineY2 = circle.simplePosY - lineSY;153154 new boundaryLength = lineX1 * lineX1 + lineY1 * lineY1;155156 // Sort of coeficient that shows how deep our circle penetrate line segment, values from 0 - 1 (in fixed point representation)157 new t = (Max(0, Min(boundaryLength, (lineX1 * lineX2 + lineY1 * lineY2))) << 8) / boundaryLength;158159 new closestPointX = lineSX + (t * lineX1 >> 8);160 new closestPointY = lineSY + (t * lineY1 >> 8);161162 new distance = Distance(circle.simplePosX - closestPointX, circle.simplePosY - closestPointY);163164 // 1 is thickness of line segment165 if (distance <= (circle.radius + 1)) {166167 // We treat collision point as a unmoveble circle168 fakeCircle.simplePosX = closestPointX;169 fakeCircle.simplePosY = closestPointY;170 // Need to make a bounce171 fakeCircle.spdX = -circle.spdX;172 fakeCircle.spdY = -circle.spdY;173 fakeCircle.mass = (circle.mass * 230) >> 8;174 fakeCircle.radius = 1;175 fakeCircle.CoR = 256;176177 // Find if we moving toward the segment178 new dotProd = 0;179 if ((lineX1 * lineY2 - lineX2 * lineY1) > 0) {180 // Left181 dotProd = Vector2D_Dot_Product(-lineY1, lineX1, circle.spdX, circle.spdY);182 } else {183 // Right184 dotProd = Vector2D_Dot_Product(lineY1, -lineX1, circle.spdX, circle.spdY);185 }186187 // If not it's unnecessary do further calculations188 return (dotProd < 0);189 }190 return 0;191}192/******/193194/****f* PawnLibs/physics/Physics_Res_CvC_Coll_Massless195 * Summary196 * Resolve collision without mass.197 * Synopsis198 */199stock Physics_Res_CvC_Coll_Massless(circle1[PHYSICS_CIRCLE_DATA], circle2[PHYSICS_CIRCLE_DATA])200/*201 * Outputs202 * * circle1, circle2 - objects for whom collision is resolved203 * See also204 * * Physics_Res_CvC_Coll_Mass()205 * Source206 */207{208209 new diffX = circle1.simplePosX - circle2.simplePosX;210 new diffY = circle1.simplePosY - circle2.simplePosY;211212 new magnitude = Distance(diffX, diffY);213214 // Overlap215 new overlap = ((magnitude - circle1.radius - circle2.radius) >> 1) + 1;216217 circle1.posX = (circle1.simplePosX -= Physics_Overlap(overlap, diffX, magnitude)) << 8;218 circle1.posY = (circle1.simplePosY -= Physics_Overlap(overlap, diffY, magnitude)) << 8;219 circle2.posX = (circle2.simplePosX += Physics_Overlap(overlap, diffX, magnitude)) << 8;220 circle2.posY = (circle2.simplePosY += Physics_Overlap(overlap, diffY, magnitude)) << 8;221222 // Normal223 if (magnitude == 0) {224 magnitude = 1;225 }226 new normalX = ((diffX << 8) / magnitude);227 new normalY = ((diffY << 8) / magnitude);228229 new relativeVelocityX = circle1.spdX - circle2.spdX;230 new relativeVelocityY = circle1.spdY - circle2.spdY;231232 new speed = relativeVelocityX * normalX + relativeVelocityY * normalY;233234 circle1.spdX -= (speed * normalX) >> 16;235 circle1.spdY -= (speed * normalY) >> 16;236237 circle2.spdX += (speed * normalX) >> 16;238 circle2.spdY += (speed * normalY) >> 16;239}240/******/241242/****f* PawnLibs/physics/Physics_Res_CvC_Coll_Mass243 * Summary244 * Resolve collision with mass245 * Synopsis246 */247stock Physics_Res_CvC_Coll_Mass(circle1[PHYSICS_CIRCLE_DATA], circle2[PHYSICS_CIRCLE_DATA])248/*249 * Outputs250 * * circle1, circle2 - objects for whom collision is resolved251 * See also252 * * Physics_Res_CvC_Coll_Massless()253 * Source254 */255{256 new diffX = circle1.simplePosX - circle2.simplePosX;257 new diffY = circle1.simplePosY - circle2.simplePosY;258259 new magnitude = Distance(diffX, diffY);260261 // Overlap262 new overlap = ((magnitude - circle1.radius - circle2.radius) >> 1) + 1;263264 circle1.posX = (circle1.simplePosX -= Physics_Overlap(overlap, diffX, magnitude)) << 8;265 circle1.posY = (circle1.simplePosY -= Physics_Overlap(overlap, diffY, magnitude)) << 8;266267 circle2.posX = (circle2.simplePosX += Physics_Overlap(overlap, diffX, magnitude)) << 8;268 circle2.posY = (circle2.simplePosY += Physics_Overlap(overlap, diffY, magnitude)) << 8;269270 // Normal271 if (magnitude == 0) {272 magnitude = 1;273 }274 new normalX = (diffX << 8) / magnitude;275 new normalY = (diffY << 8) / magnitude;276277 new relativeVelocityX = circle1.spdX - circle2.spdX;278 new relativeVelocityY = circle1.spdY - circle2.spdY;279280 new speed = relativeVelocityX * normalX + relativeVelocityY * normalY;281282 speed = (speed * Min(circle1.CoR, circle2.CoR)) >> 8;283284 new impulse = ((speed << 1) << 8) / (circle1.mass + circle2.mass)285286 circle1.spdX -= ((impulse * circle2.mass >> 16) * normalX) >> 8;287 circle1.spdY -= ((impulse * circle2.mass >> 16) * normalY) >> 8;288289 circle2.spdX += ((impulse * circle1.mass >> 16) * normalX) >> 8;290 circle2.spdY += ((impulse * circle1.mass >> 16) * normalY) >> 8;291}292/******/293294/****f* PawnLibs/physics/Physics_DeserializeCircle295 * Summary296 * Deserialize circle object data received from network.297 * Synopsis298 */299stock Physics_DeserializeCircle(serializedData_1, serializedData_2, circle[PHYSICS_CIRCLE_DATA])300/*301 * Inputs302 * * serializedData_1, serializedData_2 - data to deserialize303 * Outputs304 * * circle - deserialized data305 * See also306 * * Physics_SerializeCircle()307 * * ON_Message()308 * Source309 */310{311 new negativeFlags = serializedData_2 & 0xF;312 circle.posY = (circle.simplePosY = ( serializedData_1 & 0xFF) * ((negativeFlags & 1) ? (-1) : (1))) << 8;313 circle.posX = (circle.simplePosX = ((serializedData_1 >> 8) & 0xFF) * ((negativeFlags & 2) ? (-1) : (1))) << 8;314 circle.spdY = ((serializedData_1 >> 16) & 0xFF) * ((negativeFlags & 4) ? (-1) : (1));315 circle.spdX = ((serializedData_1 >> 24) & 0xFF) * ((negativeFlags & 8) ? (-1) : (1));316 circle.mass = ((serializedData_2 >> 4) & 0xF) << 8;317 circle.radius = ((serializedData_2 >> 8) & 0x3F);318 circle.screen = ((serializedData_2 >> 14) & 0x3);319 circle.module = ((serializedData_2 >> 16) & 0x7);320 circle.screenT = ((serializedData_2 >> 19) & 0x3);321 circle.moduleT = ((serializedData_2 >> 21) & 0x7);322}323/******/324325/****f* PawnLibs/physics/Physics_SerializeCircle326 * Summary327 * Serialize circle object data to send it over network.328 * Synopsis329 */330stock Physics_SerializeCircle(obj[PHYSICS_CIRCLE_DATA], &serializedData_1, &serializedData_2)331/*332 * Inputs333 * * obj - an object to serialize334 * Outputs335 * * serializedData_1, serializedData_2 - serialized data336 * See also337 * * Physics_DeserializeCircle()338 * * broadcastMessage()339 * Source340 */341{342 new posX = obj.simplePosX;343 new posY = obj.simplePosY;344 new spdX = obj.spdX;345 new spdY = obj.spdY;346 new negativeFlags = 0;347 if (posY < 0) {348 posY = -posY;349 negativeFlags |= 1;350 }351 if (posX < 0) {352 posX = -posX;353 negativeFlags |= 2;354 }355 if (spdY < 0) {356 spdY = -spdY;357 negativeFlags |= 4;358 }359 if (spdX < 0) {360 spdX = -spdX;361 negativeFlags |= 8;362 }363 serializedData_1 = (spdX << 24) | (spdY << 16) | (posX << 8) | posY;364 serializedData_2 = (obj.moduleT << 21) | (obj.screenT << 19) | (obj.module << 16) | (obj.screen << 14) | (obj.radius << 8) | ((obj.mass >> 8) << 4) | negativeFlags365}366/******/367368
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.