@@ -163,6 +163,9 @@ public interface WhenKeyPressedHandler {
163163 private boolean hitboxDisabled = false ;
164164 private final Text text ;
165165 private boolean isUI ;
166+ private Origin origin = Origin .CENTER ;
167+ private double originX = 0 ;
168+ private double originY = 0 ;
166169
167170 private WhenIReceiveHandler whenIReceiveHandler = (sprite , msg ) -> {
168171 };
@@ -253,6 +256,9 @@ public Sprite(Sprite s) {
253256 this .whenKeyReleasedHandler = s .whenKeyReleasedHandler ;
254257 this .whenKeyPressedHandler = s .whenKeyPressedHandler ;
255258 this .isUI = s .isUI ;
259+ this .origin = s .origin ;
260+ this .originX = s .originX ;
261+ this .originY = s .originY ;
256262 }
257263
258264 /**
@@ -1024,6 +1030,98 @@ public void setRotationStyle(RotationStyle style) {
10241030 this .rotationStyle = style ;
10251031 }
10261032
1033+ /**
1034+ * Sets the origin of the sprite to one of the predefined positions.
1035+ * The origin determines the reference point for the sprite's position and rotation.
1036+ * By default, the origin is at the center of the sprite (Origin.CENTER).
1037+ *
1038+ * @see Origin
1039+ * @param origin the origin position to set
1040+ */
1041+ public void setOrigin (Origin origin ) {
1042+ this .origin = origin ;
1043+ if (origin != Origin .CUSTOM ) {
1044+ this .originX = 0 ;
1045+ this .originY = 0 ;
1046+ }
1047+ }
1048+
1049+ /**
1050+ * Sets a custom origin offset for the sprite relative to its center.
1051+ * Positive x values move the origin to the right, negative to the left.
1052+ * Positive y values move the origin up, negative y values move it down.
1053+ * For example, setOrigin(-50, -50) offsets the origin 50 pixels left and 50 pixels down from center.
1054+ *
1055+ * @param x the x offset from center in pixels
1056+ * @param y the y offset from center in pixels
1057+ */
1058+ public void setOrigin (double x , double y ) {
1059+ this .origin = Origin .CUSTOM ;
1060+ this .originX = x ;
1061+ this .originY = y ;
1062+ }
1063+
1064+ /**
1065+ * Returns the current origin setting of the sprite.
1066+ *
1067+ * @return the current origin
1068+ */
1069+ public Origin getOrigin () {
1070+ return this .origin ;
1071+ }
1072+
1073+ /**
1074+ * Returns the x offset of the origin from the center of the sprite.
1075+ * For predefined origins (non-custom), this calculates the offset based on
1076+ * the sprite's current dimensions.
1077+ *
1078+ * @return the x offset of the origin in pixels
1079+ */
1080+ public double getOriginX () {
1081+ if (this .origin == Origin .CUSTOM ) {
1082+ return this .originX ;
1083+ }
1084+ double halfWidth = this .getWidth () / 2.0 ;
1085+ switch (this .origin ) {
1086+ case TOP_LEFT :
1087+ case CENTER_LEFT :
1088+ case BOTTOM_LEFT :
1089+ return -halfWidth ;
1090+ case TOP_RIGHT :
1091+ case CENTER_RIGHT :
1092+ case BOTTOM_RIGHT :
1093+ return halfWidth ;
1094+ default :
1095+ return 0 ;
1096+ }
1097+ }
1098+
1099+ /**
1100+ * Returns the y offset of the origin from the center of the sprite.
1101+ * For predefined origins (non-custom), this calculates the offset based on
1102+ * the sprite's current dimensions.
1103+ *
1104+ * @return the y offset of the origin in pixels
1105+ */
1106+ public double getOriginY () {
1107+ if (this .origin == Origin .CUSTOM ) {
1108+ return this .originY ;
1109+ }
1110+ double halfHeight = this .getHeight () / 2.0 ;
1111+ switch (this .origin ) {
1112+ case TOP_LEFT :
1113+ case TOP_CENTER :
1114+ case TOP_RIGHT :
1115+ return halfHeight ;
1116+ case BOTTOM_LEFT :
1117+ case BOTTOM_CENTER :
1118+ case BOTTOM_RIGHT :
1119+ return -halfHeight ;
1120+ default :
1121+ return 0 ;
1122+ }
1123+ }
1124+
10271125 /**
10281126 * Sets the position of the sprite
10291127 *
@@ -1497,6 +1595,10 @@ public Hitbox getHitbox() {
14971595 var spriteWidth = this .show ? costumeWidth : this .pen .getSize ();
14981596 var spriteHeight = this .show ? costumeHeight : this .pen .getSize ();
14991597
1598+ // Get origin offset - the image is drawn offset from position by -originX, -originY
1599+ var originOffsetX = -this .getOriginX ();
1600+ var originOffsetY = this .getOriginY ();
1601+
15001602 var rotation = this .direction - 90 ;
15011603 if (this .rotationStyle == RotationStyle .DONT
15021604 || this .rotationStyle == RotationStyle .LEFT_RIGHT ) {
@@ -1506,22 +1608,38 @@ public Hitbox getHitbox() {
15061608 if (this .hitbox != null ) {
15071609 this .hitbox .translateAndRotateAndResize (
15081610 rotation ,
1509- this .x ,
1510- -this .y ,
1511- this .x - spriteWidth / 2.0f ,
1512- -this .y - spriteHeight / 2.0f ,
1611+ this .x + originOffsetX ,
1612+ -this .y + originOffsetY ,
1613+ this .x + originOffsetX - spriteWidth / 2.0f ,
1614+ -this .y + originOffsetY - spriteHeight / 2.0f ,
15131615 this .size );
15141616 return this .hitbox ;
15151617 }
15161618
15171619 var cornerTopLeft = Utils .rotateXY (
1518- this .x - spriteWidth / 2.0f , -this .y - spriteHeight / 2.0f , this .x , -this .y , rotation );
1620+ this .x + originOffsetX - spriteWidth / 2.0f ,
1621+ -this .y + originOffsetY - spriteHeight / 2.0f ,
1622+ this .x + originOffsetX ,
1623+ -this .y + originOffsetY ,
1624+ rotation );
15191625 var cornerTopRight = Utils .rotateXY (
1520- this .x + spriteWidth / 2.0f , -this .y - spriteHeight / 2.0f , this .x , -this .y , rotation );
1626+ this .x + originOffsetX + spriteWidth / 2.0f ,
1627+ -this .y + originOffsetY - spriteHeight / 2.0f ,
1628+ this .x + originOffsetX ,
1629+ -this .y + originOffsetY ,
1630+ rotation );
15211631 var cornerBottomLeft = Utils .rotateXY (
1522- this .x - spriteWidth / 2.0f , -this .y + spriteHeight / 2.0f , this .x , -this .y , rotation );
1632+ this .x + originOffsetX - spriteWidth / 2.0f ,
1633+ -this .y + originOffsetY + spriteHeight / 2.0f ,
1634+ this .x + originOffsetX ,
1635+ -this .y + originOffsetY ,
1636+ rotation );
15231637 var cornerBottomRight = Utils .rotateXY (
1524- this .x + spriteWidth / 2.0f , -this .y + spriteHeight / 2.0f , this .x , -this .y , rotation );
1638+ this .x + originOffsetX + spriteWidth / 2.0f ,
1639+ -this .y + originOffsetY + spriteHeight / 2.0f ,
1640+ this .x + originOffsetX ,
1641+ -this .y + originOffsetY ,
1642+ rotation );
15251643
15261644 double [] xPoints = new double [4 ];
15271645 double [] yPoints = new double [4 ];
@@ -2275,7 +2393,16 @@ protected void draw(PGraphics buffer) {
22752393 var shader = this .getCurrentShader ();
22762394 this .costumes
22772395 .get (this .currentCostume )
2278- .draw (buffer , this .size , this .direction , this .x , this .y , this .rotationStyle , shader );
2396+ .draw (
2397+ buffer ,
2398+ this .size ,
2399+ this .direction ,
2400+ this .x ,
2401+ this .y ,
2402+ this .rotationStyle ,
2403+ shader ,
2404+ this .getOriginX (),
2405+ this .getOriginY ());
22792406 }
22802407 }
22812408
@@ -2293,7 +2420,15 @@ protected void drawDebug(PGraphics buffer) {
22932420 if (this .costumes .size () > 0 && this .show ) {
22942421 this .costumes
22952422 .get (this .currentCostume )
2296- .drawDebug (buffer , this .size , this .direction , this .x , this .y , this .rotationStyle );
2423+ .drawDebug (
2424+ buffer ,
2425+ this .size ,
2426+ this .direction ,
2427+ this .x ,
2428+ this .y ,
2429+ this .rotationStyle ,
2430+ this .getOriginX (),
2431+ this .getOriginY ());
22972432 }
22982433 }
22992434
@@ -2303,7 +2438,9 @@ private Stamp getStamp() {
23032438 this .direction ,
23042439 this .x ,
23052440 this .y ,
2306- this .rotationStyle );
2441+ this .rotationStyle ,
2442+ this .getOriginX (),
2443+ this .getOriginY ());
23072444
23082445 return stamp ;
23092446 }
0 commit comments