Fixed clipping through walls; map is now an overlay
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
+316
-257
@@ -3,23 +3,6 @@ import "dart:math" as math;
|
||||
import "package:flutter/services.dart";
|
||||
import "package:flutter/widgets.dart";
|
||||
|
||||
// dart format off
|
||||
const List<int> map = [
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,1,0,0,0,0,1,
|
||||
1,0,1,0,0,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,0,0,0,2,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
];
|
||||
// dart format on
|
||||
|
||||
const int mapX = 8;
|
||||
const int mapY = 8;
|
||||
const int mapSize = 32;
|
||||
|
||||
const double gameWidth = 320;
|
||||
const double gameHeight = 256;
|
||||
|
||||
@@ -67,13 +50,15 @@ extension GameValues on double {
|
||||
extension WorldValues on Offset {
|
||||
// The current "tile" we're in on the map
|
||||
Offset get currentTile => Offset(
|
||||
(dx / mapSize).floorToDouble(),
|
||||
(dy / mapSize).floorToDouble(),
|
||||
(dx / GameMap.size).floorToDouble(),
|
||||
(dy / GameMap.size).floorToDouble(),
|
||||
);
|
||||
|
||||
// The index of the current "tile" we're in
|
||||
// index = row * stride + column
|
||||
int get index => (currentTile.dy.toInt() * mapX) + currentTile.dx.toInt();
|
||||
int get index =>
|
||||
(currentTile.dy.toInt() * GameMap.dimensions.width.toInt()) +
|
||||
currentTile.dx.toInt();
|
||||
}
|
||||
|
||||
void main() {
|
||||
@@ -90,7 +75,7 @@ class MainApp extends StatefulWidget {
|
||||
class _MainAppState extends State<MainApp> {
|
||||
RayData rayData = const RayData(
|
||||
playerAngle: 0,
|
||||
playerPosition: Offset(1.5 * mapSize, 1.5 * mapSize),
|
||||
playerPosition: Offset(1.5 * GameMap.size, 1.5 * GameMap.size),
|
||||
rays: [],
|
||||
);
|
||||
|
||||
@@ -99,16 +84,19 @@ class _MainAppState extends State<MainApp> {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => Row(
|
||||
spacing: mapSize / 1,
|
||||
builder: (context, constraints) => Stack(
|
||||
textDirection: TextDirection.ltr,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Transform.translate(
|
||||
offset: const Offset(16, 0),
|
||||
child: Center(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
Stack(
|
||||
children: [
|
||||
const Background(),
|
||||
Walls(rayData),
|
||||
],
|
||||
),
|
||||
Opacity(
|
||||
opacity: 0.5,
|
||||
child: SizedBox.square(
|
||||
dimension: GameMap.size * GameMap.dimensions.width / 2,
|
||||
child: Stack(
|
||||
children: [
|
||||
Map(rayData),
|
||||
@@ -141,17 +129,6 @@ class _MainAppState extends State<MainApp> {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Background(),
|
||||
Walls(rayData),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -214,25 +191,38 @@ class _PlayerState extends State<Player> {
|
||||
|
||||
/// Get the map tile at a given pixel coordinate
|
||||
int tileAt(Offset position) {
|
||||
final int col = (position.dx / mapSize).floor();
|
||||
final int row = (position.dy / mapSize).floor();
|
||||
final int col = (position.dx / GameMap.size).floor();
|
||||
final int row = (position.dy / GameMap.size).floor();
|
||||
|
||||
if (col < 0 || col >= mapX || row < 0 || row >= mapY) return 1; // solid
|
||||
if (col < 0 ||
|
||||
col >= GameMap.dimensions.width ||
|
||||
row < 0 ||
|
||||
row >= GameMap.dimensions.height)
|
||||
return 1; // solid
|
||||
|
||||
return map[row * mapX + col];
|
||||
return GameMap.map[row * GameMap.dimensions.width.toInt() + col];
|
||||
}
|
||||
|
||||
/// How far until we hit a wall in the movement direction?
|
||||
double safeDistanceToWall(Offset position, Offset direction) {
|
||||
const int maxCheck = 64;
|
||||
const int stepSize = 8;
|
||||
final List<double> choices = [
|
||||
RayHit.castRay(
|
||||
position,
|
||||
direction.dx,
|
||||
).distance,
|
||||
RayHit.castRay(
|
||||
position,
|
||||
direction.direction.normalizeAngle - 0.05,
|
||||
).distance,
|
||||
RayHit.castRay(
|
||||
position,
|
||||
direction.direction.normalizeAngle + 0.05,
|
||||
).distance,
|
||||
];
|
||||
|
||||
for (double d = 0; d < maxCheck; d += stepSize) {
|
||||
final Offset p = position + Offset(direction.dx, direction.dy) * d;
|
||||
if (tileAt(p) > 0) return d;
|
||||
}
|
||||
choices.sort();
|
||||
|
||||
return double.infinity;
|
||||
return choices.first;
|
||||
}
|
||||
|
||||
bool keyPressHandler(KeyEvent event) {
|
||||
@@ -243,6 +233,9 @@ class _PlayerState extends State<Player> {
|
||||
|
||||
// Where is the player now?
|
||||
Offset playerPosition = widget.rayData.playerPosition;
|
||||
final Offset playerCenter =
|
||||
playerPosition +
|
||||
Offset(GameMap.dimensions.width / 2, GameMap.dimensions.height / 2);
|
||||
double playerAngle = widget.rayData.playerAngle;
|
||||
|
||||
// How many pixels away from a wall to stay
|
||||
@@ -262,14 +255,13 @@ class _PlayerState extends State<Player> {
|
||||
final Offset direction = playerAngle.direction;
|
||||
|
||||
if (keys.contains(LogicalKeyboardKey.keyW)) {
|
||||
if (safeDistanceToWall(playerPosition, direction) >
|
||||
Player.speed + buffer) {
|
||||
if (safeDistanceToWall(playerCenter, direction) > Player.speed + buffer) {
|
||||
// Move forward
|
||||
playerPosition += playerAngle.playerDelta;
|
||||
}
|
||||
handled = true;
|
||||
} else if (keys.contains(LogicalKeyboardKey.keyS)) {
|
||||
if (safeDistanceToWall(playerPosition, -direction) >
|
||||
if (safeDistanceToWall(playerCenter, -direction) >
|
||||
Player.speed + buffer) {
|
||||
// Move backwwards
|
||||
playerPosition -= playerAngle.playerDelta;
|
||||
@@ -291,198 +283,29 @@ class _PlayerState extends State<Player> {
|
||||
|
||||
List<Ray> calculateRays(Offset offset, double playerAngle) {
|
||||
const double dr = math.pi / 180;
|
||||
final double baseAngle = (playerAngle - dr * 30).normalizeAngle;
|
||||
|
||||
final List<Ray> rays = [];
|
||||
|
||||
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 = 0;
|
||||
|
||||
double rayAngle = (playerAngle - (dr * 30)).normalizeAngle;
|
||||
final Offset playerCenter =
|
||||
offset +
|
||||
Offset(
|
||||
GameMap.dimensions.width / 2,
|
||||
GameMap.dimensions.height / 2,
|
||||
);
|
||||
|
||||
int r;
|
||||
for (r = 0; r < 60; r++) {
|
||||
// * --- Check Horizontal Lines ---
|
||||
dof = 0;
|
||||
double distanceHor = 1000000;
|
||||
double hx = playerCenter.dx;
|
||||
double hy = playerCenter.dy;
|
||||
final double angle = (baseAngle + r * dr).normalizeAngle;
|
||||
final RayHit hit = RayHit.castRay(playerCenter, angle);
|
||||
|
||||
// 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,
|
||||
rays.add(
|
||||
Ray(
|
||||
hit.hitPosition,
|
||||
hit.distance,
|
||||
hit.colorFor(hit.tileValue, hit.axis),
|
||||
),
|
||||
);
|
||||
|
||||
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 = const Color.fromRGBO(0, 0, 0, 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
rays.add(Ray(Offset(rayX, rayY), disT, wallColor));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
rays.add(Ray(Offset(rayX, rayY), disT, wallColor));
|
||||
}
|
||||
|
||||
// * Increase the ray angle to draw the next ray
|
||||
rayAngle =
|
||||
(playerAngle.normalizeAngle - (dr * 30) + r * dr).normalizeAngle;
|
||||
}
|
||||
|
||||
return rays;
|
||||
@@ -595,7 +418,7 @@ class WallPainter extends CustomPainter {
|
||||
|
||||
final double disT = ray.distance * math.cos(correctedAngle);
|
||||
|
||||
double lineHeight = (mapSize * gameHeight) / disT;
|
||||
double lineHeight = (GameMap.size * gameHeight) / disT;
|
||||
if (lineHeight > gameHeight) {
|
||||
lineHeight = gameHeight;
|
||||
}
|
||||
@@ -621,9 +444,9 @@ class WallPainter extends CustomPainter {
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant oldDelegate) => false;
|
||||
bool shouldRepaint(covariant oldDelegate) => true;
|
||||
@override
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => false;
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => true;
|
||||
}
|
||||
|
||||
// * Map
|
||||
@@ -637,18 +460,15 @@ class Map extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const double width = mapX * mapSize / 1;
|
||||
const double height = mapY * mapSize / 1;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
const CustomPaint(
|
||||
size: Size(width, height),
|
||||
CustomPaint(
|
||||
size: GameMap.dimensions,
|
||||
painter: MapPainter(
|
||||
mapData: map,
|
||||
mapX: mapX,
|
||||
mapY: mapY,
|
||||
tileSize: mapSize / 1,
|
||||
mapData: GameMap.map,
|
||||
mapX: GameMap.dimensions.width,
|
||||
mapY: GameMap.dimensions.height,
|
||||
tileSize: GameMap.size / 1,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -664,8 +484,8 @@ class Map extends StatelessWidget {
|
||||
|
||||
class MapPainter extends CustomPainter {
|
||||
final List<int> mapData;
|
||||
final int mapX;
|
||||
final int mapY;
|
||||
final double mapX;
|
||||
final double mapY;
|
||||
final double tileSize;
|
||||
|
||||
const new({
|
||||
@@ -698,9 +518,9 @@ class MapPainter extends CustomPainter {
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant oldDelegate) => false;
|
||||
bool shouldRepaint(covariant oldDelegate) => true;
|
||||
@override
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => false;
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => true;
|
||||
}
|
||||
|
||||
class MapRayPainter extends CustomPainter {
|
||||
@@ -726,9 +546,9 @@ class MapRayPainter extends CustomPainter {
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant oldDelegate) => false;
|
||||
bool shouldRepaint(covariant oldDelegate) => true;
|
||||
@override
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => false;
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => true;
|
||||
}
|
||||
|
||||
// * Background
|
||||
@@ -823,7 +643,7 @@ class Floor extends CustomPainter {
|
||||
bool shouldRebuildSemantics(covariant oldDelegate) => false;
|
||||
}
|
||||
|
||||
// * Ray Data
|
||||
// * Rays
|
||||
class Ray(
|
||||
/// Where it hit on the 2D map
|
||||
var Offset hitPosition,
|
||||
@@ -863,3 +683,242 @@ class RayData {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RayHit(
|
||||
/// Exact boundary crossing where the ray stopped
|
||||
var Offset hitPosition,
|
||||
|
||||
/// Euclidean, from ray origin
|
||||
var double distance,
|
||||
|
||||
/// 0 means "no hit within map"
|
||||
var int tileValue,
|
||||
|
||||
/// [Axis] of the corresponding ray hit
|
||||
var Axis axis,
|
||||
) {
|
||||
factory castRay(Offset origin, double angle) {
|
||||
// 1. run horizontal-axis DDA → hit position + distance (or none)
|
||||
// 2. run vertical-axis DDA → hit position + distance (or none)
|
||||
// 3. return the nearer one
|
||||
|
||||
final RayHit hitHorizontal = RayHit._marchHorizontal(origin, angle);
|
||||
final RayHit hitVertical = RayHit._marchVertical(origin, angle);
|
||||
|
||||
if (hitVertical.distance < hitHorizontal.distance) {
|
||||
return hitVertical;
|
||||
}
|
||||
|
||||
return hitHorizontal;
|
||||
}
|
||||
|
||||
factory _marchHorizontal(Offset origin, double angle) {
|
||||
// * --- Check Horizontal Lines ---
|
||||
int dof = 0;
|
||||
double distanceHor = double.infinity;
|
||||
Offset hit = origin;
|
||||
|
||||
// Negative inverse of tangent
|
||||
final double aTan = -1.0 / math.tan(angle);
|
||||
|
||||
double rayY = 0;
|
||||
double rayX = 0;
|
||||
double yOffset = 0;
|
||||
double xOffset = 0;
|
||||
|
||||
// ? Looking up (ray angle > π)
|
||||
if (angle > math.pi) {
|
||||
rayY =
|
||||
((origin.dy / GameMap.size).floorToDouble() * GameMap.size) - 0.0001;
|
||||
|
||||
rayX = (origin.dy - rayY) * aTan + origin.dx;
|
||||
|
||||
yOffset = -GameMap.size / 1;
|
||||
xOffset = -yOffset * aTan;
|
||||
}
|
||||
|
||||
// ? Looking down
|
||||
if (angle < math.pi) {
|
||||
rayY =
|
||||
((origin.dy / GameMap.size).floorToDouble() * GameMap.size) +
|
||||
GameMap.size;
|
||||
|
||||
rayX = (origin.dy - rayY) * aTan + origin.dx;
|
||||
|
||||
yOffset = GameMap.size / 1;
|
||||
xOffset = -yOffset * aTan;
|
||||
}
|
||||
|
||||
int mapPointX = 0;
|
||||
int mapPointY = 0;
|
||||
int mapPoint = 0;
|
||||
int mapHit = 0;
|
||||
|
||||
while (dof < 8) {
|
||||
mapPointX = rayX ~/ GameMap.size;
|
||||
mapPointY = rayY ~/ GameMap.size;
|
||||
|
||||
mapPoint = mapPointY * GameMap.dimensions.width.toInt() + mapPointX;
|
||||
|
||||
if (mapPoint > 0 &&
|
||||
mapPoint <
|
||||
GameMap.dimensions.width.toInt() *
|
||||
GameMap.dimensions.height.toInt() &&
|
||||
GameMap.map[mapPoint] > 0) {
|
||||
// We hit a wall!
|
||||
mapHit = GameMap.map[mapPoint];
|
||||
|
||||
hit = Offset(rayX, rayY);
|
||||
|
||||
distanceHor = dist(
|
||||
origin,
|
||||
hit,
|
||||
angle,
|
||||
);
|
||||
|
||||
dof = 8;
|
||||
} else {
|
||||
rayX += xOffset;
|
||||
rayY += yOffset;
|
||||
dof += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return RayHit(hit, distanceHor, mapHit, Axis.horizontal);
|
||||
}
|
||||
|
||||
factory _marchVertical(Offset origin, double angle) {
|
||||
// * --- Check Vertical Lines ---
|
||||
int dof = 0;
|
||||
double distanceVert = double.infinity;
|
||||
Offset hit = origin;
|
||||
|
||||
// Negative of tangent
|
||||
final double nTan = -math.tan(angle);
|
||||
|
||||
const double pi2 = math.pi / 2;
|
||||
const double pi3 = 3 * math.pi / 2;
|
||||
|
||||
double rayX = 0;
|
||||
double rayY = 0;
|
||||
double xOffset = 0;
|
||||
double yOffset = 0;
|
||||
|
||||
// ? Looking left
|
||||
if (angle > pi2 && angle < pi3) {
|
||||
rayX =
|
||||
((origin.dx / GameMap.size).floorToDouble() * GameMap.size) - 0.0001;
|
||||
rayY = (origin.dx - rayX) * nTan + origin.dy;
|
||||
xOffset = -GameMap.size / 1;
|
||||
yOffset = -xOffset * nTan;
|
||||
}
|
||||
|
||||
// ? Looking right
|
||||
if (angle < pi2 || angle > pi3) {
|
||||
rayX =
|
||||
((origin.dx / GameMap.size).floorToDouble() * GameMap.size) +
|
||||
GameMap.size;
|
||||
rayY = (origin.dx - rayX) * nTan + origin.dy;
|
||||
xOffset = GameMap.size / 1;
|
||||
yOffset = -xOffset * nTan;
|
||||
}
|
||||
|
||||
// ? Looking straight up or down
|
||||
if (angle == pi2 || angle == pi3) {
|
||||
rayX = origin.dx;
|
||||
rayY = origin.dy;
|
||||
dof = 8;
|
||||
}
|
||||
|
||||
int mapPointX = 0;
|
||||
int mapPointY = 0;
|
||||
int mapPoint = 0;
|
||||
int mapHit = 0;
|
||||
|
||||
while (dof < 8) {
|
||||
mapPointX = rayX ~/ GameMap.size;
|
||||
mapPointY = rayY ~/ GameMap.size;
|
||||
|
||||
mapPoint = mapPointY * GameMap.dimensions.width.toInt() + mapPointX;
|
||||
|
||||
if (mapPoint > 0 &&
|
||||
mapPoint <
|
||||
GameMap.dimensions.width.toInt() *
|
||||
GameMap.dimensions.height.toInt() &&
|
||||
GameMap.map[mapPoint] > 0) {
|
||||
// We hit a wall!
|
||||
mapHit = GameMap.map[mapPoint];
|
||||
|
||||
// Save the values and calculate the distance from the player
|
||||
hit = Offset(rayX, rayY);
|
||||
|
||||
distanceVert = dist(
|
||||
origin,
|
||||
hit,
|
||||
angle,
|
||||
);
|
||||
|
||||
// Break the loop - no need to calculate more.
|
||||
dof = 8;
|
||||
} else {
|
||||
// If we didn't hit a wall, we check the next horizontal line by adding
|
||||
// the x and y offset.
|
||||
rayX += xOffset;
|
||||
rayY += yOffset;
|
||||
dof += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return RayHit(hit, distanceVert, mapHit, Axis.vertical);
|
||||
}
|
||||
|
||||
static double dist(Offset a, Offset b, double ang) {
|
||||
return math.sqrt(
|
||||
(b.dx - a.dx) * (b.dx - a.dx) + (b.dy - a.dy) * (b.dy - a.dy),
|
||||
);
|
||||
}
|
||||
|
||||
Color colorFor(int tileValue, Axis axis) {
|
||||
Color wallColor = const Color.fromRGBO(0, 0, 0, 0);
|
||||
|
||||
if (axis == Axis.vertical) {
|
||||
// Vertical walls are drawn a little brighter than horizontal walls
|
||||
wallColor = const Color.fromRGBO(230, 0, 0, 1);
|
||||
|
||||
if (tileValue == 2) {
|
||||
wallColor = const Color.fromRGBO(0, 179, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (axis == Axis.horizontal) {
|
||||
// Horizontal walls are drawn a little darker than vertical walls
|
||||
wallColor = const Color.fromRGBO(179, 0, 0, 1);
|
||||
|
||||
if (tileValue == 2) {
|
||||
wallColor = const Color.fromRGBO(0, 102, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return wallColor;
|
||||
}
|
||||
}
|
||||
|
||||
// * Map
|
||||
|
||||
abstract class GameMap {
|
||||
// dart format off
|
||||
static const List<int> map = [
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,1,0,0,0,0,1,
|
||||
1,0,1,0,0,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,0,0,0,2,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
];
|
||||
// dart format on
|
||||
|
||||
static const Size dimensions = Size(8, 8);
|
||||
static const int size = 32;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user