feat: Enhance rendering with pushwall and enemy color support in ASCII, Sixel, and Software renderers
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import 'package:wolf_3d_dart/src/menu/menu_manager.dart';
|
|||||||
import 'package:wolf_3d_dart/src/rendering/fizzle_fade.dart';
|
import 'package:wolf_3d_dart/src/rendering/fizzle_fade.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||||
|
import 'package:wolf_3d_dart/wolf_3d_entities.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_menu.dart';
|
import 'package:wolf_3d_dart/wolf_3d_menu.dart';
|
||||||
|
|
||||||
import 'cli_renderer_backend.dart';
|
import 'cli_renderer_backend.dart';
|
||||||
@@ -416,8 +417,10 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
|
|||||||
final int floorColor = ColorPalette.vga32Bit[8];
|
final int floorColor = ColorPalette.vga32Bit[8];
|
||||||
final int wallColor = ColorPalette.vga32Bit[7];
|
final int wallColor = ColorPalette.vga32Bit[7];
|
||||||
final int doorColor = ColorPalette.vga32Bit[14];
|
final int doorColor = ColorPalette.vga32Bit[14];
|
||||||
|
final int pushwallColor = ColorPalette.vga32Bit[6];
|
||||||
|
final int enemyColor = ColorPalette.vga32Bit[12];
|
||||||
final int playerColor = ColorPalette.vga32Bit[10];
|
final int playerColor = ColorPalette.vga32Bit[10];
|
||||||
final int facingColor = ColorPalette.vga32Bit[12];
|
final int facingColor = ColorPalette.vga32Bit[15];
|
||||||
|
|
||||||
if (_usesTerminalLayout) {
|
if (_usesTerminalLayout) {
|
||||||
_fillTerminalRect(
|
_fillTerminalRect(
|
||||||
@@ -460,9 +463,14 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
|
|||||||
for (int y = 0; y < 64; y++) {
|
for (int y = 0; y < 64; y++) {
|
||||||
for (int x = 0; x < 64; x++) {
|
for (int x = 0; x < 64; x++) {
|
||||||
final int tileId = engine.currentLevel[y][x];
|
final int tileId = engine.currentLevel[y][x];
|
||||||
final int color = tileId == 0
|
final bool isPushwall = engine.pushwallManager.pushwalls.containsKey(
|
||||||
|
'$x,$y',
|
||||||
|
);
|
||||||
|
final int color = isPushwall
|
||||||
|
? pushwallColor
|
||||||
|
: (tileId == 0
|
||||||
? floorColor
|
? floorColor
|
||||||
: (tileId >= 90 ? doorColor : wallColor);
|
: (tileId >= 90 ? doorColor : wallColor));
|
||||||
_fillMapRect(
|
_fillMapRect(
|
||||||
mapStartX + (x * tileSize),
|
mapStartX + (x * tileSize),
|
||||||
mapStartY + (y * tileSize),
|
mapStartY + (y * tileSize),
|
||||||
@@ -473,6 +481,23 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int enemyRadius = math.max(0, tileSize ~/ 3);
|
||||||
|
final int enemySize = (enemyRadius * 2) + 1;
|
||||||
|
for (final entity in engine.entities) {
|
||||||
|
if (entity is! Enemy || entity.state == EntityState.dead) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final int enemyX = (mapStartX + (entity.x * tileSize)).floor();
|
||||||
|
final int enemyY = (mapStartY + (entity.y * tileSize)).floor();
|
||||||
|
_fillMapRect(
|
||||||
|
enemyX - enemyRadius,
|
||||||
|
enemyY - enemyRadius,
|
||||||
|
enemySize,
|
||||||
|
enemySize,
|
||||||
|
enemyColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final int playerX = (mapStartX + (engine.player.x * tileSize)).floor();
|
final int playerX = (mapStartX + (engine.player.x * tileSize)).floor();
|
||||||
final int playerY = (mapStartY + (engine.player.y * tileSize)).floor();
|
final int playerY = (mapStartY + (engine.player.y * tileSize)).floor();
|
||||||
final int markerRadius = math.max(1, tileSize ~/ 2);
|
final int markerRadius = math.max(1, tileSize ~/ 2);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'package:wolf_3d_dart/src/menu/menu_manager.dart';
|
|||||||
import 'package:wolf_3d_dart/src/rendering/fizzle_fade.dart';
|
import 'package:wolf_3d_dart/src/rendering/fizzle_fade.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||||
|
import 'package:wolf_3d_dart/wolf_3d_entities.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_menu.dart';
|
import 'package:wolf_3d_dart/wolf_3d_menu.dart';
|
||||||
|
|
||||||
import 'cli_renderer_backend.dart';
|
import 'cli_renderer_backend.dart';
|
||||||
@@ -370,8 +371,10 @@ class SixelRenderer extends CliRendererBackend<String> {
|
|||||||
const int floorColor = 8;
|
const int floorColor = 8;
|
||||||
const int wallColor = 7;
|
const int wallColor = 7;
|
||||||
const int doorColor = 14;
|
const int doorColor = 14;
|
||||||
|
const int pushwallColor = 6;
|
||||||
|
const int enemyColor = 12;
|
||||||
const int playerColor = 10;
|
const int playerColor = 10;
|
||||||
const int facingColor = 12;
|
const int facingColor = 15;
|
||||||
|
|
||||||
for (int i = 0; i < _screen.length; i++) {
|
for (int i = 0; i < _screen.length; i++) {
|
||||||
_screen[i] = mapBgColor;
|
_screen[i] = mapBgColor;
|
||||||
@@ -392,9 +395,14 @@ class SixelRenderer extends CliRendererBackend<String> {
|
|||||||
for (int y = 0; y < 64; y++) {
|
for (int y = 0; y < 64; y++) {
|
||||||
for (int x = 0; x < 64; x++) {
|
for (int x = 0; x < 64; x++) {
|
||||||
final int tileId = engine.currentLevel[y][x];
|
final int tileId = engine.currentLevel[y][x];
|
||||||
final int color = tileId == 0
|
final bool isPushwall = engine.pushwallManager.pushwalls.containsKey(
|
||||||
|
'$x,$y',
|
||||||
|
);
|
||||||
|
final int color = isPushwall
|
||||||
|
? pushwallColor
|
||||||
|
: (tileId == 0
|
||||||
? floorColor
|
? floorColor
|
||||||
: (tileId >= 90 ? doorColor : wallColor);
|
: (tileId >= 90 ? doorColor : wallColor));
|
||||||
_fillMapRect(
|
_fillMapRect(
|
||||||
mapStartX + (x * tileSize),
|
mapStartX + (x * tileSize),
|
||||||
mapStartY + (y * tileSize),
|
mapStartY + (y * tileSize),
|
||||||
@@ -405,6 +413,23 @@ class SixelRenderer extends CliRendererBackend<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int enemyRadius = math.max(0, tileSize ~/ 3);
|
||||||
|
final int enemySize = (enemyRadius * 2) + 1;
|
||||||
|
for (final entity in engine.entities) {
|
||||||
|
if (entity is! Enemy || entity.state == EntityState.dead) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final int enemyX = (mapStartX + (entity.x * tileSize)).floor();
|
||||||
|
final int enemyY = (mapStartY + (entity.y * tileSize)).floor();
|
||||||
|
_fillMapRect(
|
||||||
|
enemyX - enemyRadius,
|
||||||
|
enemyY - enemyRadius,
|
||||||
|
enemySize,
|
||||||
|
enemySize,
|
||||||
|
enemyColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final int playerX = (mapStartX + (engine.player.x * tileSize)).floor();
|
final int playerX = (mapStartX + (engine.player.x * tileSize)).floor();
|
||||||
final int playerY = (mapStartY + (engine.player.y * tileSize)).floor();
|
final int playerY = (mapStartY + (engine.player.y * tileSize)).floor();
|
||||||
final int markerRadius = math.max(1, tileSize ~/ 2);
|
final int markerRadius = math.max(1, tileSize ~/ 2);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:wolf_3d_dart/src/rendering/menu_font.dart';
|
|||||||
import 'package:wolf_3d_dart/src/rendering/renderer_backend.dart';
|
import 'package:wolf_3d_dart/src/rendering/renderer_backend.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||||
|
import 'package:wolf_3d_dart/wolf_3d_entities.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_menu.dart';
|
import 'package:wolf_3d_dart/wolf_3d_menu.dart';
|
||||||
|
|
||||||
/// Pixel-accurate software renderer that writes directly into [FrameBuffer].
|
/// Pixel-accurate software renderer that writes directly into [FrameBuffer].
|
||||||
@@ -150,8 +151,10 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
|
|||||||
final int floorColor = ColorPalette.vga32Bit[8];
|
final int floorColor = ColorPalette.vga32Bit[8];
|
||||||
final int wallColor = ColorPalette.vga32Bit[7];
|
final int wallColor = ColorPalette.vga32Bit[7];
|
||||||
final int doorColor = ColorPalette.vga32Bit[14];
|
final int doorColor = ColorPalette.vga32Bit[14];
|
||||||
|
final int pushwallColor = ColorPalette.vga32Bit[6];
|
||||||
|
final int enemyColor = ColorPalette.vga32Bit[12];
|
||||||
final int playerColor = ColorPalette.vga32Bit[10];
|
final int playerColor = ColorPalette.vga32Bit[10];
|
||||||
final int facingColor = ColorPalette.vga32Bit[12];
|
final int facingColor = ColorPalette.vga32Bit[15];
|
||||||
|
|
||||||
_fillMenuPanel(0, 0, width, height, mapBgColor);
|
_fillMenuPanel(0, 0, width, height, mapBgColor);
|
||||||
|
|
||||||
@@ -170,9 +173,14 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
|
|||||||
for (int y = 0; y < 64; y++) {
|
for (int y = 0; y < 64; y++) {
|
||||||
for (int x = 0; x < 64; x++) {
|
for (int x = 0; x < 64; x++) {
|
||||||
final int tileId = engine.currentLevel[y][x];
|
final int tileId = engine.currentLevel[y][x];
|
||||||
final int color = tileId == 0
|
final bool isPushwall = engine.pushwallManager.pushwalls.containsKey(
|
||||||
|
'$x,$y',
|
||||||
|
);
|
||||||
|
final int color = isPushwall
|
||||||
|
? pushwallColor
|
||||||
|
: (tileId == 0
|
||||||
? floorColor
|
? floorColor
|
||||||
: (tileId >= 90 ? doorColor : wallColor);
|
: (tileId >= 90 ? doorColor : wallColor));
|
||||||
_fillMenuPanel(
|
_fillMenuPanel(
|
||||||
mapStartX + (x * tileSize),
|
mapStartX + (x * tileSize),
|
||||||
mapStartY + (y * tileSize),
|
mapStartY + (y * tileSize),
|
||||||
@@ -183,6 +191,23 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int enemyRadius = math.max(0, tileSize ~/ 3);
|
||||||
|
final int enemySize = (enemyRadius * 2) + 1;
|
||||||
|
for (final entity in engine.entities) {
|
||||||
|
if (entity is! Enemy || entity.state == EntityState.dead) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final int enemyX = (mapStartX + (entity.x * tileSize)).floor();
|
||||||
|
final int enemyY = (mapStartY + (entity.y * tileSize)).floor();
|
||||||
|
_fillMenuPanel(
|
||||||
|
enemyX - enemyRadius,
|
||||||
|
enemyY - enemyRadius,
|
||||||
|
enemySize,
|
||||||
|
enemySize,
|
||||||
|
enemyColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final int playerX = (mapStartX + (engine.player.x * tileSize)).floor();
|
final int playerX = (mapStartX + (engine.player.x * tileSize)).floor();
|
||||||
final int playerY = (mapStartY + (engine.player.y * tileSize)).floor();
|
final int playerY = (mapStartY + (engine.player.y * tileSize)).floor();
|
||||||
final int markerRadius = math.max(1, tileSize ~/ 2);
|
final int markerRadius = math.max(1, tileSize ~/ 2);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
import 'package:wolf_3d_dart/src/entities/entities/enemies/guard.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||||
import 'package:wolf_3d_dart/wolf_3d_input.dart';
|
import 'package:wolf_3d_dart/wolf_3d_input.dart';
|
||||||
@@ -11,6 +12,16 @@ void main() {
|
|||||||
test('software renderer draws fullscreen map overlay when enabled', () {
|
test('software renderer draws fullscreen map overlay when enabled', () {
|
||||||
final engine = _buildEngine();
|
final engine = _buildEngine();
|
||||||
engine.init();
|
engine.init();
|
||||||
|
expect(engine.pushwallManager.pushwalls.containsKey('5,5'), isTrue);
|
||||||
|
engine.entities.add(
|
||||||
|
Guard(
|
||||||
|
x: 8.5,
|
||||||
|
y: 8.5,
|
||||||
|
angle: 0,
|
||||||
|
mapId: MapObject.guardStart,
|
||||||
|
difficulty: Difficulty.medium,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final renderer = SoftwareRenderer();
|
final renderer = SoftwareRenderer();
|
||||||
final frameNormal = renderer.render(engine);
|
final frameNormal = renderer.render(engine);
|
||||||
@@ -28,6 +39,8 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(changedPixels, greaterThan(mapPixels.length ~/ 5));
|
expect(changedPixels, greaterThan(mapPixels.length ~/ 5));
|
||||||
|
expect(mapPixels.contains(ColorPalette.vga32Bit[6]), isTrue);
|
||||||
|
expect(mapPixels.contains(ColorPalette.vga32Bit[12]), isTrue);
|
||||||
expect(mapPixels.contains(ColorPalette.vga32Bit[10]), isTrue);
|
expect(mapPixels.contains(ColorPalette.vga32Bit[10]), isTrue);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -57,7 +70,9 @@ WolfEngine _buildEngine() {
|
|||||||
_fillBoundaries(wallGrid, 2);
|
_fillBoundaries(wallGrid, 2);
|
||||||
wallGrid[2][4] = 1;
|
wallGrid[2][4] = 1;
|
||||||
wallGrid[2][5] = 90;
|
wallGrid[2][5] = 90;
|
||||||
|
wallGrid[5][5] = 1;
|
||||||
objectGrid[2][2] = MapObject.playerEast;
|
objectGrid[2][2] = MapObject.playerEast;
|
||||||
|
objectGrid[5][5] = MapObject.pushwallTrigger;
|
||||||
|
|
||||||
return WolfEngine(
|
return WolfEngine(
|
||||||
data: WolfensteinData(
|
data: WolfensteinData(
|
||||||
|
|||||||
Reference in New Issue
Block a user