Digging terrain

Hello,
do you know Dig Dug (Arcade Longplay - DigDug (1982) Namco - YouTube)?
What is the best approach for a similar game where the character digs holes in the terrain? I thought I’d create a texture to store the terrain in and then use GetData / SetData to delete parts of the texture gradually, but it feels too slow.

It shouldn’t be too slow, especially since you can index directly instead of having to iterate over all the pixels, just what you’re drawing. Should be totally fine, especially on modern hardware.

I watched a bit of that gameplay and it does look pixel perfect. They probably did a bunch of optimization to make it fast enough for the hardware back in the day, but you probably won’t need to worry about that :smiley:

1 Like

The actual Arcade game uses Tiles for the playfield. As Dig Dug moves over them it changes the tiles based on the direction they are digging in and how far into the Tile they are.

You can see the Tiles here:

https://www.spriters-resource.com/fullview/125268/?source=genre

1 Like

I think this is not going to be a pixel perfect texture treatment. The game also exists for NES, and I see the same effect in it, but if I’m not mistaken, the smallest sprite that can be used is 8x8 pixels. I think they were just very adept at tricking the texture atlas. So I think they just create the illusion that you are pixel perfect manipulating the texture.
A similar effect can be observed in Battle City, but it’s not necessarily as accurate there, because collision detection is a bit strange in some texture states.

Edit: While watching a NES gameplay video, I noticed that two tricks were applied, one was the texture atlas and the other was the player’s black background. This is why the disappearance of the texture can seem so smooth while digging. Just look at the flower behind it, but it doesn’t happen to enemies:

Imgur

As a first attempt, I created an image containing the entire terrain (224x256 pixels). Then, during the initialization, I loaded the image into the backgroundTexture field and added the following lines:

Color[] backgroundColorData;
...
backgroundColorData = new Color[backgroundTexture.Width * backgroundTexture.Height];
backgroundTexture.GetData(backgroundColorData);

In the Update method I added the following lines to paint a single pixel black at the character’s position:

var data = new[] { new Color(0, 0, 0) };
backgroundTexture.SetData(0, new Rectangle(center.X, center.Y, 1, 1), data, 0, data.Length);

Then in the Draw method I draw the backgroundTexture. So far, so good: the pixel corresponding to the character’s position is colored black.
As a next step, I added the following lines to color an 8x8 pixel rectangle black:

for (int y = 0; y < 8; y++)
{
  for (int x = 0; x < 8; x++)
  {
    backgroundTexture.SetData(0, new Rectangle(center.X + x, center.Y + y, 1, 1), data, 0, data.Length);
  }
}

The game got terribly jerky.
I don’t know exactly how the SetData method works, but I thought the line backgroundTexture.SetData (0, new Rectangle (center.X + x, center.Y + y, 1, 1), data, 0, data.Length) to modify the color of a single pixel was fast, however, evidently, even if I specify a rectangle of 1x1 pixels as the area to be modified, it affects the entire image every time (8x8=64 total times), so it becomes very, very slow.
Probably, instead of creating a single image for the entire terrain, you need to think about creating many small tiles, each with its own image (for example 16x16 pixels) and acting with SetData only on the tiles corresponding to the position of the character.
I don’t know what complications there might be in MonoGame, but I wonder why there is no ultra-fast method of changing the color of a single pixel of an existing texture. Or if there is a way, I’d like someone to point it out to me.

As for Dig Dug, I also noticed that a black rectangle is drawn behind the character. Another thing I noticed is that as the character moves, let’s say, to the right, in addition to the black rectangle that gives the impression that it is being cut out one pixel at a time (nice gimmick for programmers of the time!), as soon as the character turns left, a hole is created where it was not there a moment before (see green arrow in the image) to confirm that the excavations are 8x8 tiles and not pixel perfect (see also link indicated by Arcadenut).
Imgur

Imgur

Another approach would be each tile has a certain amount in that its cleared from each side.

So if the bottom side is 30% percent cleared and the left side is 20% cleared your output sprite would be drawn 30 percent smaller on the bottom and 20% smaller from the left side.

As your walking along consuming tiles the percentage cleared will change

Boy. Do not use get/setData for this, you’re literally trying to software render without any reason to. People have already pointed out that it’s all tile-based – that’s it. Forget about whatever overengineered solutions you came up with and just use tiles. In the video you’ve shown the easiest solution is to just draw black tiles on top of the playfield.

Yes, this is exactly the solution I was thinking of at the moment. Thank you. :grinning:

Yes, now I am convinced. Thank you all. :smile: :+1:

I forgot to add that I had come across this discussion https://www.gamedev.net/forums/topic.asp?topic_id=535726 where it is suggested to draw the terrain first, then the deformations (caused by explosions) and then convert what is displayed into a new texture (via RenderTarget.GetTexture()) to be used during the next frame. Unfortunately, the GetTexture() method no longer exists. Is this a limitation of MonoGame compared to XNA?

Another approach is to just get data once modify the color array itself and only set data when something changes probably not the best way as others have said.

Another approach is the draw the map to a rendertarget call it maprendertarget.
when dig dug digs draw the maprendertarget to another rendertarget.
draw a empty hole sprite to the desired location on the render target.
then set that new rendertarget back to the old one maprendertarget rinse and repeat.

But the tile approach is how id go it really does seem the best to me as all the logic is going to have to be in line with the tiles.