+256
-5
@@ -133,11 +133,22 @@ class _PlayerState extends State<Player> {
|
||||
|
||||
return KeyEventResult.ignored;
|
||||
},
|
||||
child: CustomPaint(
|
||||
painter: PlayerPainter(
|
||||
offset: playerPosition,
|
||||
delta: playerDelta,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
CustomPaint(
|
||||
painter: RayPainter(
|
||||
playerAngle: playerAngle,
|
||||
offset: playerPosition,
|
||||
delta: playerDelta,
|
||||
),
|
||||
),
|
||||
CustomPaint(
|
||||
painter: PlayerPainter(
|
||||
offset: playerPosition,
|
||||
delta: playerDelta,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -176,6 +187,240 @@ class PlayerPainter extends CustomPainter {
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => false;
|
||||
}
|
||||
|
||||
class RayPainter extends CustomPainter {
|
||||
final double playerAngle;
|
||||
final Offset offset;
|
||||
final Offset delta;
|
||||
|
||||
const new({
|
||||
required this.playerAngle,
|
||||
required this.offset,
|
||||
required this.delta,
|
||||
});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
const double dr = math.pi / 180;
|
||||
|
||||
int dof;
|
||||
int mx;
|
||||
int my;
|
||||
int mapPoint;
|
||||
|
||||
double yo = 1;
|
||||
double xo = 1;
|
||||
|
||||
final Offset playerCenter = offset + const Offset(4, 4);
|
||||
|
||||
double rayX = 0;
|
||||
double rayY = 0;
|
||||
double disT;
|
||||
|
||||
double rayAngle = delta.direction - (dr * 30);
|
||||
|
||||
if (rayAngle < 0) {
|
||||
rayAngle += 2 * math.pi;
|
||||
}
|
||||
if (rayAngle > 2 * math.pi) {
|
||||
rayAngle -= 2 * math.pi;
|
||||
}
|
||||
|
||||
int r;
|
||||
for (r = 0; r < 60; r++) {
|
||||
// * --- Check Horizontal Lines ---
|
||||
dof = 0;
|
||||
double distanceHor = 1000000;
|
||||
double hx = playerCenter.dx;
|
||||
double hy = playerCenter.dy;
|
||||
|
||||
// Negative inverse of tangent
|
||||
final double aTan = -1.0 / math.tan(rayAngle);
|
||||
|
||||
// ? Looking up (ray angle > π)
|
||||
if (rayAngle > math.pi) {
|
||||
rayY = ((playerCenter.dy / mapSize).floorToDouble() * mapSize) - 0.0001;
|
||||
|
||||
rayX = (playerCenter.dy - rayY) * aTan + playerCenter.dx;
|
||||
|
||||
yo = -mapSize / 1;
|
||||
xo = -yo * aTan;
|
||||
}
|
||||
|
||||
// ? Looking down
|
||||
if (rayAngle < math.pi) {
|
||||
rayY =
|
||||
((playerCenter.dy / mapSize).floorToDouble() * mapSize) + mapSize;
|
||||
|
||||
rayX = (playerCenter.dy - rayY) * aTan + playerCenter.dx;
|
||||
|
||||
yo = mapSize / 1;
|
||||
xo = -yo * aTan;
|
||||
}
|
||||
|
||||
// ? Looking straight left or right
|
||||
if (rayAngle == 0.0 || rayAngle == math.pi) {
|
||||
// It's impossible to ever hit a horizontal line
|
||||
rayX = playerCenter.dx;
|
||||
rayY = playerCenter.dy;
|
||||
dof = 8;
|
||||
}
|
||||
|
||||
int mv = 0;
|
||||
int mh = 0;
|
||||
|
||||
while (dof < 8) {
|
||||
mx = rayX ~/ mapSize;
|
||||
my = rayY ~/ mapSize;
|
||||
|
||||
mapPoint = my * mapX + mx;
|
||||
|
||||
if (mapPoint > 0 && mapPoint < mapX * mapY && map[mapPoint] > 0) {
|
||||
// We hit a wall!
|
||||
|
||||
mh = map[mapPoint];
|
||||
|
||||
hx = rayX;
|
||||
hy = rayY;
|
||||
distanceHor = dist(
|
||||
playerCenter.dx,
|
||||
playerCenter.dy,
|
||||
hx,
|
||||
hy,
|
||||
rayAngle,
|
||||
);
|
||||
|
||||
dof = 8;
|
||||
} else {
|
||||
rayX += xo;
|
||||
rayY += yo;
|
||||
dof += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// * --- Check Vertical Lines ---
|
||||
dof = 0;
|
||||
double distanceVert = 1000000;
|
||||
double vx = playerCenter.dx;
|
||||
double vy = playerCenter.dy;
|
||||
|
||||
// Negative of tangent
|
||||
final double nTan = -math.tan(rayAngle);
|
||||
|
||||
const double pi2 = math.pi / 2;
|
||||
const double pi3 = 3 * math.pi / 2;
|
||||
|
||||
// ? Looking left
|
||||
if (rayAngle > pi2 && rayAngle < pi3) {
|
||||
rayX = ((playerCenter.dx / mapSize).floorToDouble() * mapSize) - 0.0001;
|
||||
rayY = (playerCenter.dx - rayX) * nTan + playerCenter.dy;
|
||||
xo = -mapSize / 1;
|
||||
yo = -xo * nTan;
|
||||
}
|
||||
|
||||
// ? Looking right
|
||||
if (rayAngle < pi2 || rayAngle > pi3) {
|
||||
rayX =
|
||||
((playerCenter.dx / mapSize).floorToDouble() * mapSize) + mapSize;
|
||||
rayY = (playerCenter.dx - rayX) * nTan + playerCenter.dy;
|
||||
xo = mapSize / 1;
|
||||
yo = -xo * nTan;
|
||||
}
|
||||
|
||||
// ? Looking straight up or down
|
||||
if (rayAngle == pi2 || rayAngle == pi3) {
|
||||
rayX = playerCenter.dx;
|
||||
rayY = playerCenter.dy;
|
||||
dof = 8;
|
||||
}
|
||||
|
||||
while (dof < 8) {
|
||||
mx = rayX ~/ mapSize;
|
||||
my = rayY ~/ mapSize;
|
||||
|
||||
mapPoint = my * mapX + mx;
|
||||
|
||||
if (mapPoint > 0 && mapPoint < mapX * mapY && map[mapPoint] > 0) {
|
||||
// We hit a wall!
|
||||
|
||||
mv = map[mapPoint];
|
||||
|
||||
// Save the values and calculate the distance from the player
|
||||
vx = rayX;
|
||||
vy = rayY;
|
||||
distanceVert = dist(
|
||||
playerCenter.dx,
|
||||
playerCenter.dy,
|
||||
vx,
|
||||
vy,
|
||||
rayAngle,
|
||||
);
|
||||
|
||||
dof = 8; // Break the loop - no need to calculate more.
|
||||
} else {
|
||||
// If we didn't hit a wall, we check the next horizontal line by adding
|
||||
// the x and y offset.
|
||||
rayX += xo;
|
||||
rayY += yo;
|
||||
dof += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Color wallColor = Colors.transparent;
|
||||
|
||||
if (distanceVert < distanceHor) {
|
||||
rayX = vx;
|
||||
rayY = vy;
|
||||
disT = distanceVert;
|
||||
// Vertical walls are drawn a little brighter than horizontal walls
|
||||
wallColor = const Color.fromRGBO(230, 0, 0, 1);
|
||||
|
||||
if (mv == 2) {
|
||||
wallColor = const Color.fromRGBO(0, 179, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (distanceHor < distanceVert) {
|
||||
rayX = hx;
|
||||
rayY = hy;
|
||||
disT = distanceHor;
|
||||
// Horizontal walls are drawn a little darker than vertical walls
|
||||
wallColor = const Color.fromRGBO(179, 0, 0, 1);
|
||||
|
||||
if (mh == 2) {
|
||||
wallColor = const Color.fromRGBO(0, 102, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
canvas.drawLine(
|
||||
playerCenter,
|
||||
Offset(rayX, rayY),
|
||||
Paint()
|
||||
..color = wallColor
|
||||
..isAntiAlias = false
|
||||
..strokeWidth = 1.5,
|
||||
);
|
||||
|
||||
rayAngle += dr;
|
||||
|
||||
if (rayAngle < 0) {
|
||||
rayAngle += 2 * math.pi;
|
||||
}
|
||||
if (rayAngle > 2 * math.pi) {
|
||||
rayAngle -= 2 * math.pi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double dist(double ax, double ay, double bx, double by, double ang) {
|
||||
return math.sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay));
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant oldDelegate) => false;
|
||||
@override
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => false;
|
||||
}
|
||||
|
||||
// * Map
|
||||
class Map extends StatelessWidget {
|
||||
const new({super.key});
|
||||
@@ -214,6 +459,12 @@ class MapPainter extends CustomPainter {
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paintWhite = Paint()..color = Colors.white;
|
||||
final paintBlack = Paint()..color = Colors.black;
|
||||
final paintGrey = Paint()..color = Colors.grey;
|
||||
|
||||
canvas.drawRect(
|
||||
Rect.fromLTWH(0, 0, tileSize * mapX, tileSize * mapY),
|
||||
paintGrey,
|
||||
);
|
||||
|
||||
for (int i = 0; i < mapData.length; i++) {
|
||||
final double x = (i % mapX) * tileSize;
|
||||
|
||||
Reference in New Issue
Block a user