-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPiece.java
More file actions
230 lines (207 loc) · 8.09 KB
/
Piece.java
File metadata and controls
230 lines (207 loc) · 8.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import java.awt.Color;
import java.awt.Graphics;
public class Piece extends Sprite {
private int[][] shape;
private Color color;
private boolean selected, flipped;
private boolean lastFlipHorizontal; // axis of the most recent flip, so it can be undone correctly
private int squares, ogX, ogY, rotationAmount;
// Replace the old target fields with these
private int targetX, targetY;
private double velX, velY;
private double floatX, floatY; // sub-pixel accumulator to prevent rounding drift
private boolean hasTarget = false;
private float speed;
public Piece(int x, int y, int squareSize, int[][] shape, Color color) {
super(x, y, squareSize);
this.shape = shape;
this.color = color;
selected = false;
ogX = x;
ogY = y;
rotationAmount = 0;
flipped = false;
for (int r = 0; r < shape.length; r++) {
for (int c = 0; c < shape[r].length; c++) {
squares += shape[r][c];
}
}
speed = 35;
}
/*
* Rotates the piece 90 degrees.
* @param clockwise true to rotate clockwise, false to rotate counter-clockwise.
*/
public void rotate(boolean clockwise) {
int oldRows = shape.length;
int oldCols = shape[0].length;
// Both directions result in swapped dimensions
int[][] rotatedShape = new int[oldCols][oldRows];
for (int r = 0; r < oldRows; r++) {
for (int c = 0; c < oldCols; c++) {
if (clockwise) {
// Clockwise mapping
rotatedShape[c][oldRows - 1 - r] = shape[r][c];
} else {
// Counter-clockwise mapping
rotatedShape[oldCols - 1 - c][r] = shape[r][c];
}
}
}
if (clockwise) {
rotationAmount += 90;
if (rotationAmount == 360) {
rotationAmount = 0;
}
} else {
rotationAmount -= 90;
if (rotationAmount == -90) {
rotationAmount = 270;
}
}
this.shape = rotatedShape;
}
/**
* Flips the piece 180 degrees over a designated axis.
* @param horizontal true to flip left-to-right, false to flip top-to-bottom.
*/
public void flip(boolean horizontal) {
int rows = shape.length;
int cols = shape[0].length;
int[][] mirroredShape = new int[rows][cols];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (horizontal) {
// Reverse columns
mirroredShape[r][cols - 1 - c] = shape[r][c];
} else {
// Reverse rows
mirroredShape[rows - 1 - r][c] = shape[r][c];
}
}
}
this.shape = mirroredShape;
this.flipped = !this.flipped; // Every flip toggles face-up vs face-down
this.lastFlipHorizontal = horizontal; // remember the axis so resetPosition can undo it
}
/**
* Shifts the sprite's position by a relative offset amount.
* @param dx The change in X coordinates (delta X)
* @param dy The change in Y coordinates (delta Y)
*/
public void move(int dx, int dy) {
this.setX(this.getX() + dx);
this.setY(this.getY() + dy);
}
/**
* Sets the destination and immediately computes the X/Y velocity components
* so the piece travels exactly 5 pixels per frame toward the target.
*/
public void setTarget(int tx, int ty) {
this.targetX = tx;
this.targetY = ty;
this.hasTarget = true;
// Initialize the float accumulator from the current integer position
this.floatX = getX();
this.floatY = getY();
// Decompose 5px/frame into X and Y components along the direction vector
double dx = tx - getX();
double dy = ty - getY();
double dist = Math.sqrt(dx * dx + dy * dy);
if (dist == 0) { velX = 0; velY = 0; }
else { velX = speed * dx / dist;
velY = speed * dy / dist; }
}
/**
* Advances the piece one frame toward its target using the pre-computed velocity.
* @return true once the piece has arrived
*/
public boolean stepTowardsTarget() {
double dx = targetX - floatX;
double dy = targetY - floatY;
// Snap once the remaining distance is within one step
if (Math.sqrt(dx * dx + dy * dy) <= speed) {
setPosition(targetX, targetY);
floatX = targetX;
floatY = targetY;
hasTarget = false;
return true;
}
floatX += velX;
floatY += velY;
setX((int) Math.round(floatX));
setY((int) Math.round(floatY));
return false;
}
public void draw(Graphics g) {
int size = getSquareSize();
for (int r = 0; r < shape.length; r++) {
for (int c = 0; c < shape[0].length; c++) {
if (shape[r][c] == 1) {
int drawX = getX() + (c * size);
int drawY = getY() + (r * size);
drawSquare(g, drawX, drawY, color);
}
}
}
}
/**
* Checks if a specific screen coordinate (mouseX, mouseY) falls inside
* any of the active '1' blocks of this piece.
* * @return true if the point collides with the piece, false otherwise.
*/
public boolean containsPoint(int mouseX, int mouseY) {
int size = getSquareSize();
for (int r = 0; r < shape.length; r++) {
for (int c = 0; c < shape[0].length; c++) {
// Only check collisions for active segments of the piece
if (shape[r][c] == 1) {
// Calculate the bounding box for this individual square
int blockLeft = getX() + (c * size);
int blockRight = blockLeft + size;
int blockTop = getY() + (r * size);
int blockBottom = blockTop + size;
// Check if the mouse point is within this block's bounds
if (mouseX >= blockLeft && mouseX <= blockRight &&
mouseY >= blockTop && mouseY <= blockBottom) {
return true; // Collision detected!
}
}
}
}
return false; // Point is not touching any block of this piece
}
/**
* Snaps the piece's X and Y anchor coordinates to the nearest multiple of 25.
* This aligns the piece perfectly with the board grid lines.
*/
public void autoAlign() {
int currentX = getX();
int currentY = getY();
// Divide by 25.0 to preserve the decimal, round to nearest integer, scale back up
int snappedX = (int) Math.round(currentX / 25.0) * 25;
int snappedY = (int) Math.round(currentY / 25.0) * 25;
setPosition(snappedX, snappedY);
}
public void resetPosition() {
setX(ogX);
setY(ogY);
while (rotationAmount != 0) {
rotate(false);
}
if (flipped) {
flip(lastFlipHorizontal); // undo on the SAME axis the player flipped, not always horizontal
}
}
public boolean getSelected() {return selected;}
public void setSelected(boolean selected) {this.selected = selected;}
public int[][] getLayout() {return shape;}
public void setShape(int[][] layout) {shape = layout;}
public void setOgPosition(int ogX, int ogY) {
this.ogX = ogX;
this.ogY = ogY;
}
public boolean isFlipped() {return flipped;}
public int getSquares() {return squares;}
public boolean hasTarget() { return hasTarget; }
}