[WIP] Dark Under - Dungeon Master clone prototype

@Pharap

You should note that those file sizes aren’t representative of the amount of space the resulting code will use on the Arduboy

From your experience, is it usually more, or less? (I would assume less, but worth checking)

I’m not sure what this pivot problem is.

Right now, your ‘vision’ area is always facing north: pressing left means moving left laterally. in these games usually, pressing left means rotate your character left. This means that the orientation of the visual area will become different than the orientation of the minimap.
And there is the fact that I’m struggling to find a way to efficiently treat the rotation visual render: right now I render the preview area by looping in my map array and looking at what’s in row-3, row-2 and row-1 (for the front walls, for example). Since I don’t want to rotate my array, I need switch-cases that look at orientation first, then build the preview for that orientation.
This is my code so far (just a portion of it)

void playerVision (){//draw the walls by checking row and cols ahead of player
image(visionBack,myVision.originX,myVision.originY);
//far front wall
if (row-3>=0){//make sure we don’t check row out of bound in the array
if (myLevel.worldGrid[row-3][col]>0) {
image(farWallFront,originX,originY);
}
}
//far left wall
if (row-2>=0){
if (myLevel.worldGrid[row-2][col-1]>0) {
image(farWallLeft,originX,originY);
}
}
//far right wall
if (row-2>=0){
if (myLevel.worldGrid[row-2][col+1]>0) {
image(farWallRight,originX,originY);
}
}
(etc…)

I’d love to take a look at it but I can’t collaborate or promise anything (…)

Well, it’s not like I’m fighting people off that project anyway :slight_smile: so what I’ll do is finish the processing project, if you can help, cool, if you can’t oh well, I’ll either have to try myself, or move on to something else, no arm done… Trying to stay under 30K and make a proper game, even in Processing is a fun intellectual challenge anyway.

C++ can’t necessarily be rushed

Yep, I get that after looking at some samples and tutorials. That’s why I thought it would be clever to get the prototype first with a language I know… at the very least, I’ll still have a game.

About the enemies. So tonight I had a bit of time. I built an abstract enemy class that includes some random movement for enemies. that class alone weighs 3K.
On top of that, I built a “stalker” enemy that override the parent movement, tracks the player and aggressively pursue them. This extended class weighs 4.27 freaking K!!! Now my whole code weighs 27.3K and I’m getting worried.

I’ll post a video in a short while. Going to have to move at a slower pace: this week is very intense for me and I’m going this week end to the Orlando Indie Galactic Game Jam, so no work this week end for me :slight_smile:

Anyway, will keep people posted - if any contributor wants to step in, please feel free

Oh, missed this:
String is the datatype for strings of characters. As in
String mySentence = “this is a sentence”;

new is to create an instance of an object, as in:
Level myLevel;
void Setup(){ //only once
myLevel = new Level();
}
void Draw(){ //loop that gets repeated
myLevel.worldDrawGrid();
}

this is the first pass for enemies (they don’t show in the “preview” area, but look for the moving X in the minimap) - oh, and disregard the music, it’s not in game, I didn’t realize it was also recording what I was listening to :slight_smile:

1 Like

The amount of memory taken will almost always be less than any actual image file you produce because pretty much every standard image file format in modern use has at least some metadata. Even quaint old .bmp.

The Arduboy images are stored as an array of bytes starting width the width and height of the image and following this pattern:

image

(This image was made by @emutyworks, it’s a very good visual reference for explaining the format.)

Ah.

I’d suggest you pick your row/column offset values based on your character’s orientation.

If your player is facing north, look at tiles in the -Y direction, if your player is facing east, look at tiles in the +X direction et cetera.

Sort of like:

enum class Direction : uint8_t { North, South, East, West };

class Player
{
//...
Direction direction;
//...
};

Player player;

void drawWalls(const Player & player)
{
  switch(player.direction)
  {
    case Direction::North: drawNorth(); break;
    case Direction::South: drawSouth(); break;
    case Direction::East: drawEast(); break;
    case Direction::West: drawWest(); break;
  }
}

And obviously drawNorth would do what you’re currently doing, and the other three would do the same for the other directions.
Something like that at least.
(I’ve erred more on the side of readability than saving memory).

I’ve always got time to make suggestions about how to tackle problems or to explain things about C++, it’s just actually sitting down and writing working/tested code that I wouldn’t have time for at the minute.

You’ll find that much easier once you’ve gotten to grips with C++.
The design of C++ is very much about putting the programmer in charge of how the code does things (e.g. how it handles memory, how big things are, how efficiently things are done).
However that’s a double edged sword: it then means the programmer is actually responsible for having to consider those things - you can’t ignore fine details.

To clarify, that’s mostly the weight of the actual ‘instructions’, which is usually a one-time only cost.
Each enemy will only ‘weight’ as much as the amount of data in it (e.g. x, y, width, height).

Rather than extending the base class (which can actually end up duplicating the code for all the functions of the base class), for something like that you’d be better off following what’s called the “strategy pattern”. Basically you designate one class to containing the movement behaviour and pass it to the enemy.

// Note: this code is a rough idea, I haven't checked it will compile
// I might have gotten some details wrong

// Enemy.h
class MovementBehaviour; // pre-declaration

class Enemy
{
private:
  MovementBehaviour * movement;
public:
  Enemy(MovementBehaviour * movement);
  void HandleMovement(void);
};

// MovementBehaviour.h
class MovementBehaviour
{
virtual ~MovementBehaviour(void) {} // required
virtual void move(Enemy & enemy);
};

// Enemy.cpp
Enemy::Enemy(MovementBehaviour * movement)
{
  this->movement = movement;
}

void Enemy::HandleMovement(void)
{
  if(movement != nullptr)
    this->movement.move(*this);
}

// StalkerMovementBehaviour.h
class StalkerMovementBehaviour : public MovementBehaviour
{
  void MovementBehaviour(Enemy & enemy) override
  {
    // do stuff with enemy
  }
};

Yes, but in C++/Arduino there’s a String class and then there’s a char * class.
char * is very lightweight, String is much heavier and does a thing called ‘dynamic allocation’ that should be avoided on embedded systems.

In C++, creating an object would just be something like:
Level myLevel = Level()
Adding the word new changes the behaviour to do dynamic allocation - which (again) is usually a bad thing.

I’ve written a simple explanation of dynamic allocation and why it should be avoided if you want to read it, but I won’t post it yet because even the ‘short’ version is long.

@Pharap
Your image explanation makes sense! However, does that mean that it’s either the pixel is lit (white) or not(black) in Arduboy? because that would preclude me from using the background (floor tiles and ceiling) as the lit pixels would show through the black pixels of my walls etc…

Your C++ example are very different from what I’m using, but I think I can wrap my head around your method for the “vision” part, definitely something I will explore!

I found a good soul to help me @filmote

Yes, in processing, there is also a char type. I went the easy way to store sentences, but I guess I could store them in an array, and parse them in a char variable? is that how you would do it to avoid using String?

Not sure what dynamic allocation is :slight_smile: I checked wikipedia, and it seems it’s part of memory allocation? In processing, we don’t deal with that, so new is the only way I’ve ever instantiated objects! If you have a link, I’d be curious to read it, just for my personal edification.

light is ‘lit’. dark is ‘off’.

The msb (left hand side) of the byte ends up at the bottom and the lsb (right hand side) of the byte ends up at the top.

image

Luckily pretty much nobody ever has to edit the image data manually because there are many image converters available, a non-exhaustive list of which can be found here.
(The fact I compiled the list isn’t coincidence - it’s good planning :P.)

For a non-animated image it should take roughly 2 + ((width * height) / 8) bytes. You have to round the height up to the next multiple of 8 though, e.g. a 6x10 image would become 6x16.

The first example is fairly easy, but the second example is quite an advanced technique that does rely on knowledge of some more complicated techniques. The idea itself is simple - making behaviour an object - but the implementation requires knowledge of pointers, inheritance and virtual functions. There is a slightly easier version you could try using a thing called ‘function pointers’, but even that’s still a bit advanced. I wouldn’t recommend trying either until you’re more comfortable with C++ and at the very least understand pointers.

Ah, that explains why he decided to call 1943 finished, he’s found a new game to work on :P.
Trust me, you’re in good hands there.

I don’t know much about processing (for all I know, processing’s String might be a char *), so if you’re working in processing I can’t help you much there.

For Arduboy code the Arduboy2 class has several print functions that print text, in which case you can use the F macro to do text inline, or you can store larger sentences in char arrays in progmem.

For example:

void someFunction()
{
  arduboy.println(F("A line of text"));
  arduboy.print(F("Line number: "));
  arduboy.println((int)2);
}

Or:

const char text[] = "Hello World";

// This tricks the arduboy into thinking a progmem string has been created with the `F` macro
constexpr inline const __FlashStringHelper * AsFlashString(const char * flashString)
{
	return reinterpret_cast<const __FlashStringHelper*>(flashString);
}

void someFunction()
{
  arduboy.println(AsFlashString(text));
}

Hrm, I’m guessing that must mean there’s no way to do dynamic allocation in processing and new is just how you normally allocate things. That is the case in some other languages so it’s understandable, but at least now you know to avoid new in C++.

I’ll PM you my simplified explanation to avoid derailing the thread any more than I already have. Sadly I’m not aware of any single simple article online.

Been pretty busy with classes this week, so not much update, but tonight the wife wanted to work and go to bed early, so I got a bit of time to brush up my D&D bestiary… here are the new enemies:

I’m planning on some more (granted that we have enough room!) such as Slime, Mimics and a Lich…

Most likely, my next task will be to prototype the turn based fight system.

6 Likes

just to show that @filmote is doing an awesome work!
screenshot1

5 Likes

While filmote is integrating the existing content, I’m seeing how we can create more variation with the environment: here’s a much lighter wall tileset (below the existing one):

dark&under3

4 Likes

That does say “King’s thot court” right?
I’m not imagining that?

Screens look amazing this is on the top of want list.

Nope, King’s Thot indeed, though not sure if it will stick, it’s just sample text right now, until I imagine a proper progression scenario, hence what those places really mean/represent!

Thanks! I’m super glad to see it come to life as well!

1 Like

by the way, since this isn’t finished, it may not belong to the games category, but just demo? any thoughts?

I’m about to start the combat system. My original mockup was a bit incomplete, so I thought about the minimum amount of steps I could have to make the combat fun while keeping the UI to a bare minimum. Here’s what I thought of so far.
I could use some feedback.

6 Likes

Just for those following the topic and wondering what’s happening: the game is well underway :slight_smile: All systems are mostly in place, and we are starting to bring level content in.

4 Likes

I’m excited to try this out. I’ve been wanting to play some RPGs on here. Arcade games are fun, but I think the arduboy is capable of more. This and arduventure are on my watch list.

4 Likes

Its coming along slowly … we have been developing this over the last few weeks and re-worked it again and again to save memory to allow for more images (enemies and items) and to increase game play. I now have all the respect in the world for what @JO3RI has achieved with Arduventure !

7 Likes

wow when will a demo be available?

1 Like

Realistically, a beta version (not a demo) could be available in a few weeks time. @gambler172 would you like to be a beta tester??

4 Likes

yes…but only if i get a hex file to upload in the arduboy Manager…it would be a pleasure for me.
you can contact me on
gmblr173@aol.com or here in the Forum.
greetings Walter