D doesn't have weak references. So how can I make a associative array of objects without preventing their destruction?
A "weak reference" (in the sense that I'm referring to) is a feature in some programming languages for a reference to an object that doesn't prevent the GC from destroying that object. My current understanding is that D doesn't have weak references, though I've found some posts in this forum from many years back that mention something called "weakref". So is weakref a real thing, or just a concept that never got implemented? The functionality that I'm going to describe would be easy with weak references, but I don't know how I would implement it without it. If there is a way to implement it without it, I would like to know how. I am going to describe my specific example, but it may apply to any class that's initialized using contents of a file without any of that data being modified after. In my particular case, the class I've created is a wrapper for the `Texture2D` struct in Raylib. This class holds an image that was loaded from a file. ``` Sprite[string] spritesByPath; Sprite getSprite(string path) { path = path.asAbsolutePath; if (path !in spritesByPath) { spritesByPath[path] = new Sprite(path); } return spritesByPath[path]; } class Sprite { Texture2D texture; alias this = texture; string path; this(string path) { texture = LoadTexture(path.toStringz); this.path = path; } ~this() { if (IsWindowReady) UnloadTexture(texture); if (path in spritesByPath) spritesByName.remove(path); } } ``` Alternatively, `spritesByPath` and `getSprite` may be static members of `Sprite`. If D had weak references, than `spritesByPath` would be made of weak references so that they don't prevent the destruction of `Sprite` objects, which should be destroyed whenever they don't have any references elsewhere. I've considered making `Sprite` reference-counted, but I couldn't manage to figure out how to do it properly. I tried doing `SafeRefCounted!Sprite` but the compiler said it doesn't work on `Object` types. I then tried making my own struct for reference counting that would be placed in place of a direct reference to the `Sprite` object, but there was some bug in which sometimes it didn't increment the reference count, so it didn't work. What's a good way I can achieve what I'm trying to do, using either reference counting or a garbage-collected object?
Re: How can I put the current value of a variable into a delegate?
On Wednesday, 8 May 2024 at 12:29:05 UTC, Rene Zwanenburg wrote: Interestingly enough C# used to have the same behaviour but MS decided to go for a breaking change in C# 5; now it behaves as most people expect. Wow! I wonder if D would be willing to allow such a breaking change with the release of Phobos 3. My choice would be to have it use the current value by default for value types, but allow them to be linked to the same memory address using `*&` when the variable is placed in a delegate. I think that the distinction between value types and reference types should be consistent. If such a breaking change isn't considered acceptable, I suppose a new operator can be introduced for dereferencing a variable when placed in a delegate. Maybe `#` or `$` if they don't conflict with any existing use of those symbols.
Re: How can I put the current value of a variable into a delegate?
On Monday, 6 May 2024 at 16:41:38 UTC, Steven Schveighoffer wrote: On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote: Delegates can be a pain, as they often have results different from what one would intuitively expect. This can easily result in bugs. Here's a line that caused a bug that took me awhile to find: ``` foreach(card; unitCards) card.submitted = delegate() => selectUnit(card.unit); ``` Each `UnitInfoCard` object (which `card` is a member of) contains a `Unit` object called `unit`. The intention of this line was that each object in `unitCards` would call `selectUnit` with it's own `unit` every time it calls `submitted`. Instead, every card calls `submitted` with the *last* value of `card`. Yes, this is because the foreach loop reuses the same memory slot for `card`. Even though this is allocated as a closure, it still only allocates the frame stack of the *enclosing function*, and does not allocate a new slot for each loop iteration. You can force this by using a lambda which allocates the closure: ```d foreach(card; unitCards) card.submitted = (c2) { return () => selectUnit(c2.unit); }(card); ``` This is a lambda which accepts `card` as a parameter, and returns an appropriate delegate. It is important to use a parameter, because if you just use card inside there, it's still using the single stack frame of the calling function! ... I would love to see a solution, but the workaround at least exists! -Steve Well that's something. It's not a very good solution for a language that aims for readability. It took me awhile looking at it to figure out what it is about, as I'm not familiar with this syntax. The solution that I did before seeing this was to add a function to `UnitInfoCard` to give it a delegate with a `Unit unit` parameter, and then that function would give that function with the `unit` parameter set to itself to it's own `submitted` member. I will probably keep it like this for readability. ``` void clickAction(void delegate(Unit) @safe clickAction) { submitted = () => clickAction(unit); } ```
How can I put the current value of a variable into a delegate?
Delegates can be a pain, as they often have results different from what one would intuitively expect. This can easily result in bugs. Here's a line that caused a bug that took me awhile to find: ``` foreach(card; unitCards) card.submitted = delegate() => selectUnit(card.unit); ``` Each `UnitInfoCard` object (which `card` is a member of) contains a `Unit` object called `unit`. The intention of this line was that each object in `unitCards` would call `selectUnit` with it's own `unit` every time it calls `submitted`. Instead, every card calls `submitted` with the *last* value of `card`. This is because the delegate assignment causes the local `card` variable to remain alive. The delegate that's assigned is linked to this variable itself, not the value at the time that the delegate is assigned. Is there a way I can dereference a variable when placing it in a delegate, so that it's current value is used, rather than the variable itself?
Re: Phobos function to remove all occurances from dynamic array?
On Wednesday, 1 May 2024 at 01:24:55 UTC, Lance Bachmeier wrote: Does filter do what you need? https://dlang.org/phobos/std_algorithm_iteration.html#.filter It seems to do it with the following line: ``` allObjects = allObjects.filter!(element => element !is this).array; ``` So I've found a way to do it. It's still rather strange that it's so difficult to find the solution to such a common problem in the documentation.
Re: Doing a `static foreach` or `foreach` through enum members in a template or CTFE function, while disabling deprecation warnings
On Friday, 19 April 2024 at 22:24:17 UTC, Liam McGillivray wrote: ``` template enumMixin(alias Enum) { static foreach(m; __traits(allMembers, Enum)) static if (!__traits(isDeprecated, __traits(getMember, Enum, m))) { mixin("alias "~m~" = __traits(getMember, Enum, m);"); } }; ``` Correction: The code shown above actually *does* work properly without any deprecation warnings. I made a mistake with the enum being set to the CTFE function I was previously using instead of this template. This template actually works. I posted here for visibility and searchability, in case anyone else wants to do something like this.
Re: Doing a `static foreach` or `foreach` through enum members in a template or CTFE function, while disabling deprecation warnings
Well, someone on the Discord server has been helping me attempt this, but while I managed to get a solution that compiles without errors, I still get the deprecation warning. Here is what I ended up with: ``` template enumMixin(alias Enum) { static foreach(m; __traits(allMembers, Enum)) static if (!__traits(isDeprecated, __traits(getMember, Enum, m))) { mixin("alias "~m~" = __traits(getMember, Enum, m);"); } }; ``` Unfortunately, the deprecation warnings still appear if the enum contains any deprecated members. I'm starting to suspect that the language doesn't currently have any features to stop this from happening. This is unfortunate, as it *should* be possible to process an enum with deprecated members *without* getting these warnings.
Doing a `static foreach` or `foreach` through enum members in a template or CTFE function, while disabling deprecation warnings
I know that DStep generates CTFE functions to automatically make aliases for enum members so that the can be used without the enum name, as is done in C. DStep does it with a CTFE function, though it should also be possible with a mixin template. Here is my attempt so far, using a mixin template: ``` template enumMixin(Enum) { private import std.traits; static foreach(member; EnumMembers!Enum) static if (__traits(isDeprecated, member)) { private alias m = __traits(identifier, member); alias m = member; } }; ``` It hasn't worked so far.
Re: Making one struct work in place of another for function calls.
On Wednesday, 17 April 2024 at 02:39:25 UTC, Paul Backus wrote: This is called [row polymorphism][1], and it does not exist in D. You could approximate it by making `someFunction` a template, and accepting any type `T` that has the necessary members instead of only accepting `typeB`. But this is only possible if you are free to modify the definition of `someFunction`. Is there a way I can replace "`TypeB`" in the function parameters with another symbol, and then define that symbol to accept `TypeB` as an argument, but also accept `TypeA` which would get converted to `TypeB` using a function? I'm willing to make a function template if it's rather simple.
Making one struct work in place of another for function calls.
I have two structs that serve roughly the same purpose, and I would like one to be accepted when the other is declared as a function parameter. To better understand what I mean, take the following example, where I have a function, and two structs. ``` struct typeA { // Some member variables here } struct typeB { // Some similar member variables here, but in a different format } float someFunction(typeB input) { // Does some stuff // Returns result } ``` If I want to be able to call `someFunction` (or any function with `TypeB` as a parameter) using `TypeA` in place of `TypeB`, and I'm willing to modify the definition of `TypeA`, I know that I can add an `opCast` and `alias this = opCast!TypeB` to `TypeA`. But what if `typeA` is in an external library? Is there any way I can get `someFunction` (and any function with a `typeB` parameter) to accept `typeA`, only modifying the definition of `TypeB` (and possibly adding a single global line in it's module)?
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Friday, 12 April 2024 at 15:24:38 UTC, Steven Schveighoffer wrote: ```d void InitWindow(int width, int height, ref string title) { InitWindow(width, height, cast(const(char)*)title); } ``` This is invalid, a string may not be zero-terminated. You can't just cast. Well, it did work when I tried it (using a string variable, not a literal of course). It displayed as it is supposed to. But from the information I can find on the web it looks like strings are sometimes but not `always` zero-terminated. Not a great look for the language. Are there any rules to determine when it is and when it isn't (for string variables)? So there are a few things to consider: 1. Is the string *transiently used*. That is, does the function just quickly use the string and never refers to it again? Given that this is raylib, the source is pretty readable, so you should be able to figure this out. I suppose. But if it turns out that the string is used continuously (as I assume to be the case with `InitWindow` and `SetWindowTitle`) and it doesn't make a copy of it, I imagine it would be difficult to design the function overload, as it would need to store a copy of the string somewhere. In that case, the only clean solution would be to have a global array of strings to store everything that's been passed to such functions, but that doesn't feel like a very satisfying solution. I may take a look inside some Raylib functions if I get back to this task. 2. If 1 is false, will it be saved in memory that is scannable by the GC? This is one of the most pernicious issues with using C libraries from D. In this case, you will need to either allocate the memory with C `malloc` or pin the GC memory. You mean that the GC can destroy objects that still have references from the C code? For transiently used strings, I would point you at the function [`tempCString`](https://github.com/dlang/phobos/blob/0663564600edb3cce6e0925599ebe8a6da8c20fd/std/internal/cstring.d#L77), which allocates a temporary C string using malloc or a stack buffer, and then frees it when done with it. Thank you. In a previous thread, someone told me that having to do many deallocations slows down the program, and the GC is more efficient because it deallocates many objects simultaneously. Is this something worth considering here, or is the overhead going to be tiny even when it's called a few times per frame? The obvious problem in all this is to avoid accepting string literals (which are magic and automatically convert to const char *). This is currently impossible with function overloading, and so you need a separate function name, or put them in a different module. Aren't there any compile-time conditions for this?
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Tuesday, 9 April 2024 at 12:45:55 UTC, Richard (Rikki) Andrew Cattermole wrote: On 09/04/2024 12:48 PM, Liam McGillivray wrote: I suppose this was a good new thing to learn, though I'm still quite far from being able to construct a function from another function using a template. I suppose that if I wanted it to make a function from another function, I may be able to do it in a template using some `static foreach` to make arrays of function parameters, and then combine them together without the use of strings, instead using placeholders (aliases or whatever they'd be called) and maybe the `tupleof` function. Am I headed in the right direction (if you can understand my weak attempt to describe the direction I'm thinking of going in)? ``tupleof`` isn't a function, its a property to get a "tuple" a sequence of fields for a struct/class. However most likely you'd have to resort to string mixins if you're messing about with parameters like I think? you are asking for. I'm not entirely sure what you're wanting there. Here's what I wanted to do. In the library I'm working on, there are various declarations for functions defined in an external C library following the line `extern (C) @nogc nothrow:`. Here are some examples of such declarations which have a `const(char)*` parameter: ``` void InitWindow(int width, int height, const(char)* title); void SetWindowTitle(const(char)* title); Shader LoadShader(const(char)* vsFileName, const(char)* fsFileName); ``` I wanted to generate definitions of overloads of these functions using strings as parameters instead of `const(char)*`. For the `InitWindow` function shown above, the overload should be defined like this: ``` void InitWindow(int width, int height, ref string title) { InitWindow(width, height, cast(const(char)*)title); } ``` or alternatively, like the following: ``` void InitWindow(int width, int height, string title) { InitWindow(width, height, title.toStringz); } ``` I'm not sure which of these is better, thought the latter one would need to be modified to not accept string literals. I found that the former one has the advantage that making the `title` parameter `ref string` means that string literals use the existing version of the function. I know that the former can be `@nogc`, unlike the latter, though I don't know if there is any advantage offered by `toStringz` over `cast(const(char)*)`. But anyway, my goal was to generate function overloads like either of the above. I have already posted a version of a CTFE function that does this, though I put them under `version (D_TypeInfo)` so that they aren't available in `betterC` builds, since the function I wrote doesn't build with `betterC`.
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Tuesday, 9 April 2024 at 23:50:36 UTC, Richard (Rikki) Andrew Cattermole wrote: The string mixin triggers CTFE, if ``EnumPrefixes`` wasn't templated, that would cause codegen and hence error. If you called it in a context that wasn't CTFE only, it would codegen even with template and would error. For quite a long time we emitted -betterC errors during semantic, we learned that this was all around a bad idea and moved (hopefully all but I doubt it) into the glue code. So only if it codegens will it error. Well then, perhaps this is a bug (though a useful bug in my case). If you want to investigate, you can download [this commit](https://github.com/LiamM32/raylib-d/blob/49a8f2a2e4285fc85b9db54ae9a49cafe8b1a5ed) of Raylib-D. The DUB package in the `rayguiexample` directory has `betterC` as a build option, yet doesn't have this error. This is despite the inclusion of a CTFE function with string appending. It's in [`source/raylib/package.d`](https://github.com/LiamM32/raylib-d/blob/49a8f2a2e4285fc85b9db54ae9a49cafe8b1a5ed/source/raylib/package.d) where `mixin(EnumPrefixes!Key("KeyboardKey", "KEY_"));` appears. The definition of `EnumPrefixes` is in [`source/templates.d`](https://github.com/LiamM32/raylib-d/blob/49a8f2a2e4285fc85b9db54ae9a49cafe8b1a5ed/source/templates.d).
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Sunday, 7 April 2024 at 08:59:55 UTC, Richard (Rikki) Andrew Cattermole wrote: Unfortunately runtime and CTFE are the same target in the compiler. So that function is being used for both, and hence uses GC (appending). Are you sure that string appending was really the problem that caused the "TypeInfo" build error? I forgot about this, but I had already had a working CTFE function with string appending before adding the new one that lead to this error. The symbols that it generates could be used in the program compiled with `betterC`. ``` string EnumPrefixes(T)(string oldName, string prefix) { string result = "enum " ~ oldName ~ " {\n"; static foreach(member; __traits(allMembers, T)) { result ~= "" ~ prefix ~ member ~ " = " ~ __traits(getMember, T, member).to!int.to!string ~ ",\n"; } return result ~ "}\n"; } ``` The purpose of this was that the enums used by the C library were too verbose. I had changed them from things like `KeyboardKey.KEY_C` to `Key.C`. I wanted to leave the new enums written directly in the module since these were recommended for use, but then generate the old ones with CTFE for backwards compatibility. The function above was used like `mixin(EnumPrefixes!Key("KeyboardKey", "KEY_"));`, and the compiler would allow it even when building with `betterC`.
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Tuesday, 9 April 2024 at 00:02:02 UTC, Richard (Rikki) Andrew Cattermole wrote: ```d enum Value = (a, b) { return a + b; }(1, 2); ``` This alone should be a CTFE only function. But if we want template parameters, we'd need to wrap it with the template. ```d template Value(int a, int b) { enum Value = () { return a + b; }(); } int value = Value!(1, 2); ``` Does that help? I had to reread this a few times to get a sense of what this is. I might have just got it. This is effectively a CTFE function for generating a constant based on the sum of two numbers, right? Doing `int value = Value!(1, 2);` would set `value` to 3, right? I suppose this was a good new thing to learn, though I'm still quite far from being able to construct a function from another function using a template. I suppose that if I wanted it to make a function from another function, I may be able to do it in a template using some `static foreach` to make arrays of function parameters, and then combine them together without the use of strings, instead using placeholders (aliases or whatever they'd be called) and maybe the `tupleof` function. Am I headed in the right direction (if you can understand my weak attempt to describe the direction I'm thinking of going in)?
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Monday, 8 April 2024 at 08:12:22 UTC, Richard (Rikki) Andrew Cattermole wrote: ```d template Foo(Args) { enum Foo = () { return Args.init; }(); } ``` Something like that should work instead. I'm sorry, but I can't comprehend any of your example. What would be fed into `Args`? I don't understand how this works, or how I would use it for what I want. You would replace it with whatever template parameters you want (including nothing). It's there as a place holder. Same for the return on the closure. But the main thing to understand is that the closure that gives the enum a value, that'll be CTFE only, no runtime target. Are you saying that this is a way to guarantee that the code is compile-time only? I still understand very little of this code. I'm not experienced in D metaprogramming; just the function I posted above was a major achievement for me. I don't understand how I would use the code you gave in place of the function I have written and posted above. When you say that "You would replace it with whatever template parameters you want", are you saying that instead of doing `mixin(MakeStringOverload!SetWindowTitle); mixin(MakeStringOverload!LoadShader);` as posted above, I would write `mixin(Foo!(SetWindowTitle, LoadShader));`? What does the `return Args.init;` line mean in your example? Am I supposed to replace this with a call to the CTFE function I had already written? If so, it didn't work. Making such a replacement resulted in the same "TypeInfo" error that I had already.
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Sunday, 7 April 2024 at 08:59:55 UTC, Richard (Rikki) Andrew Cattermole wrote: Unfortunately runtime and CTFE are the same target in the compiler. :-( Will this ever be changed? ```d template Foo(Args) { enum Foo = () { return Args.init; }(); } ``` Something like that should work instead. I'm sorry, but I can't comprehend any of your example. What would be fed into `Args`? I don't understand how this works, or how I would use it for what I want.
"Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
I'm making a modification to a D binding for a C library. I made a CTFE function which takes a function declaration with one or more `const(char)*` or `char*` parameters and makes an overload that accepts D strings. While this function is only used during compile time, unfortunately, I have found that it results in the library no longer supporting `-betterC`. The compiler gives the following error. ``` /usr/include/dlang/dmd/core/lifetime.d(2760,42): Error: `TypeInfo` cannot be used with -betterC /usr/include/dlang/dmd/std/utf.d(1556,24):instantiated from here: `_d_newclassT!(UTFException)` /usr/include/dlang/dmd/std/utf.d(1563,32):instantiated from here: `exception!(const(char)[])` /usr/include/dlang/dmd/std/utf.d(1186,54):instantiated from here: `decodeImpl!(true, Flag.no, const(char)[])` /usr/include/dlang/dmd/std/range/primitives.d(2551,18): instantiated from here: `decode!(Flag.no, const(char)[])` /usr/include/dlang/dmd/std/range/primitives.d(178,40): instantiated from here: `front!char` Error /usr/bin/dmd failed with exit code 1. ``` I don't know what part of the function uses `TypeInfo` (as I don't really understand what that is), but I know that it is this CTFE function causing the error, because commenting out the mixins that use it results in the `-betterC` program compiling properly. Here is the CTFE function I wrote: ``` string MakeStringOverload(alias func)() { string def = ReturnType!func.stringof ~" "~ __traits(identifier, func) ~ "("; auto paramNames = ParameterIdentifierTuple!func; import std.algorithm.searching; foreach(i, paramType; Parameters!func) { if (paramType.stringof.canFind("char")) def ~= "ref string"; // Made a reference so that D string literals know to use the base version of the function and not this one. else def ~= paramType.stringof; def ~= " "~paramNames[i] ~ ", "; } def.length -= 2; def ~= ") { "; if (ReturnType!func.stringof != "void") def ~= "return "; def ~= __traits(identifier, func) ~ "("; foreach(i, argument; paramNames) { if (Parameters!func[i].stringof.canFind("char")) def ~= "cast(char*)"; def ~= argument ~ ", "; } def.length -= 2; def ~= "); }"; return def; } ``` In the module where the base versions of functions are declared, I do the following to generate overloads: ``` mixin(MakeStringOverload!SetWindowTitle); mixin(MakeStringOverload!LoadShader); mixin(MakeStringOverload!LoadShaderFromMemory); mixin(MakeStringOverload!GetShaderLocation); ``` So what part of my function is using "TypeInfo"? Can I somehow label my function as compile-time only so that it stops complaining? If not what else can I do to get it to stop complaining and compile with `betterC`?
How best to implement items and weapons in my RPG. Nested classes? Delegates?
For my tactical role-playing game, I want to finally implement items and weapons. These are objects that a `Unit` object can make use of. Just as tools are often said to be an extension of their user, I want items to be an extension of the unit who uses them. I'm trying to figure out how to best implement them. I already have an `Item` and `Weapon` class in [my repository](https://github.com/LiamM32/Open_Emblem), with the latter being a derived class of the former. But they are not used much, as they are not well-developed yet. [`unit` module](https://github.com/LiamM32/Open_Emblem/blob/master/source/unit.d) [`item` module](https://github.com/LiamM32/Open_Emblem/blob/master/source/item.d) Different weapon types would have different formulas to determine whether or not they can reach a certain tile, and different formulas for damage. Therefore, they would need their own functions. For example, a bow would have a function that checks for obstructions over it's range, while a sword would simply check whether the target is in range. There are even more functions for non-weapon items. I want each item to be able to return a list of actions that can be performed in it, for when it is selected in the menu. For weapons, this would be "equip", but also a list of moves that can be performed. If possible, I may want them to be able to access protected members of the `Unit` object that uses them. In order to pass a list of options to a menu, I'm thinking of having a `ItemAction` struct which contains a string for it's name (as would appear on the menu), and a delegate for the function that would be called if selected. Each item can have an array of these. For implementation of their unique functions, I've thought of two ideas. One is that the `Weapon` class will have many derivative classes, such as `Bow`, `Sword`, `Spear` etc, each with their own functions. The other idea is that there is only one weapon class, but it holds an array of functions or delegates for various moves, which would be given the appropriate functions for it's weapon type during construction. An advantage of the latter is that the weapon type can be determined within the constructor. Another idea I'm not sure of is whether the `Item` class and it's derivatives should be a nested class within `Unit`. If I understand correctly, objects of nested classes are always associated with an object of the outer class, and have access to it's protected and private members. This may be an advantage if I decide to set any of the required unit attributes to `protected`. If I don't make them nested classes, the functions in the `Item` class and it's derivatives would need to have either a reference to it's unit in the parameters, or the relevant attributes of the unit.
Re: Unittests pass, and then an invalid memory operation happens after?
On Friday, 29 March 2024 at 01:18:22 UTC, H. S. Teoh wrote: Take a look at the docs for core.memory.GC. There *is* a method GC.free that you can use to manually deallocate GC-allocated memory if you so wish. Keep in mind, though, that manually managing memory in this way invites memory-related errors. That's not something I recommend unless you're adamant about doing everything the manual way. Was this function removed from the library? I don't see it in [the document](https://dlang.org/phobos/core_memory.html). How is `GC.free` different from `destroy`? I might take a look at it, but I'm not adamant about doing everything the manual way, so I probably won't use it very soon. I think you're conflating two separate concepts, and it would help to distinguish between them. There's the lifetime of a memory-allocated object, which is how long an object remains in the part of the heap that's allocated to it. It begins when you allocate the object with `new`, and ends with the GC finds that it's no longer referenced and collects it. No. I understand that when an object disappears from memory might happen after it disappears from the game. I'll explain later in this post why I wanted to remove the Unit object from memory when the unit dies. There's a different lifetime that you appear to be talking about: the logical lifetime of an in-game object (not to be confused with an "object" in the OO sense, though the two may overlap). The (game) object gets created (comes into existence in the simulated game world) at a certain point in game time, until something in the game simulation decides that it should no longer exist (it got destroyed, replaced with another object, whatever). At that point, it should be removed from the game simulation, and that's probably also what you have in mind when you mentioned your "die" function. Yes; exactly. This was your hint that I'm not confusing these two things. Whether or not the unit object gets deleted, I need a function to remove it from the game on death. The `die` function if I want the object to be destroyed on death: ``` void die() { if (this.map !is null) this.map.removeUnit(this); if (this.faction !is null) this.faction.removeUnit(this); if (this.currentTile !is null) this.currentTile.occupant = null; destroy(this); } ``` The `die` function without object destruction: ``` void die() { if (this.map !is null) this.map.removeUnit(this); if (this.faction !is null) this.faction.removeUnit(this); if (this.currentTile !is null) this.currentTile.occupant = null; } ``` They're the same, except that the latter doesn't call `destroy`. The other 3 lines are required to remove references to the object, effectively removing it from the game. With the latter version, I suppose that the garbage collector should eventually clean up the "dead" unit object now that there are no references to it. However, I can see this leading to bugs if there was another reference to the unit which I forgot to remove. One benefit I see in destroying the object when it's no longer needed is that an error will happen if any remaining reference to the object gets accessed, rather than it leading to unexpected behaviour. However I've thought about having it destroy the unit object at the end of the turn rather than immediately. Another option, if I don't want this benefit for debugging but still want fewer deallocations in the end result, would be to set that last line to `version (debug) destroy (this)`. Anyway, I made [a commit](https://github.com/LiamM32/Open_Emblem/commit/64109e556a09ecce73b1018a9e651744a5e8fcd9) a few days ago that solves the unittest error. I found that explicitly destroying every `Map` object at the end of each unittest that uses it resolved the error. Despite this resolving the error, I decided to also move those lines from the `Unit` destructor to the new `die` function. I currently have it call `destroy` on itself at the end of this new function for the reasons described, but I suppose this line can be removed if I want to. And here's the important point: the two *do not need to coincide*. Here's a concrete example of what I mean. Suppose in your game there's some in-game mechanic that's creating N objects per M turns, and another mechanic that's destroying some of these objects every L turns. If you map these creations/destructions with the object lifetime, you're looking at a *lot* of memory allocations and deallocations throughout the course of your game. Memory allocations and deallocations can be costly; this can become a problem if you're talking about a large number of objects, or if they're being created/destroyed very rapidly (e.g., they are fragments flying out from explosions). Since most of these objects are identical in type, one way of optimizing the code is to preallocate them: before starting your main loop, say you
Re: Unittests pass, and then an invalid memory operation happens after?
On Thursday, 28 March 2024 at 04:46:27 UTC, H. S. Teoh wrote: The whole point of a GC is that you leave everything up to it to clean up. If you want to manage your own memory, don't use the GC. D does not force you to use it; you can import core.stdc.stdlib and use malloc/free to your heart's content. Unpredictable order of collection is an inherent property of GCs. It's not going away. If you don't like it, use malloc/free instead. (Or write your own memory management scheme.) I disagree with this attitude on how the GC should work. Having to jump immediately from leaving everything behind for the GC to fully manual memory allocation whenever the GC becomes a problem is a problem, which gives legitimacy to the common complaint of D being "garbage-collected". It would be much better if the garbage collector could be there as a backup for when it's needed, while allowing the programmer to write code for object destruction when they want to optimize. Anyway, I suppose I'll have to experiment with either manually destroying every object at the end of every unittest, or just leaving more to the GC. Maybe I'll make a separate `die` function for the units, if you think it's a good idea. I think you're approaching this from a totally wrong angle. (Which I sympathize with, having come from a C/C++ background myself.) The whole point of having a GC is that you *don't* worry about when an object is collected. You just allocate whatever you need, and let the GC worry about cleaning up after you. The more you let the GC do its job, the better it will be. Now you're giving me conflicting advice. I was told that my current destructor functions aren't acceptable with the garbage collector, and you specifically tell me to leave things to the GC. But then I suggest that I "leave more to the GC" and move everything from the Unit destructor to a specialized `die` function that can be called instead of `destroy` whenever they must be removed from the game, which as far as I can see is the only way to achieve the desired game functionality while following your and Steve's advice and not having dangling references. But in response to that, you tell me "I think you're approaching this from the wrong angle". And then right after that, you *again* tell me to "just let the GC worry about cleaning up after you"? Even if I didn't call `destroy` at all during my program, as far as I can see, I would still need the `die` function mentioned to remove a unit on death. It would be nice if you can clarify your message here. Right now I'm confused. I see no way to take your advice without also doing the `die` function. As far as performance is concerned, a GC actually has higher throughput than manually freeing objects, because in a fragmented heap situation, freeing objects immediately when they go out of use incurs a lot of random access RAM roundtrip costs, whereas a GC that scans memory for references can amortize some of this cost to a single period of time. By "manually freeing objects", do you mean through `destroy`? If so that's actually quite disappointing, as D is often described as a "systems programming language", and I thought it would be fun to do these optimizations of object destruction, even if I have the garbage collector as a backup for anything missed. Or did you mean with `malloc` and `free`? Now somebody coming from C/C++ would immediately cringe at the thought that a major GC collection might strike at the least opportune time. For that, I'd say: (1) don't fret about it until it actually becomes a problem. I.e., your program is slow and/or has bad response times, and the profiler is pointing to GC collections as the cause. Then you optimize appropriately with the usual practices for GC optimization: preallocate before your main loop, avoid frequent allocations of small objects (prefer to use structs rather than classes), reuse previous allocations instead of allocating new memory when you know that an existing object is no longer used. Well, I suppose that's fine for when the GC problem is specifically over slowness. I'm quite new to D, so I don't really know what it means to "preallocate before your main loop". Is this a combination of using `static this` constructors and `malloc`? I haven't used `malloc` yet. I have tried making static constructors, but every time I've tried them, they caused an error to happen immediately after the program is launched. I've used C++, but I haven't gotten much done with it. It was PHP where I made the biggest leap in my programming skills. This game is the furthest I've gone at making a complex program from the `main` loop up. I suppose I can turn the `Tile` object into a struct, which I suppose will mean replacing all it's references (outside the map's `Tile[][] grid`) with pointers. I have thought about this before, since tiles are fundamentally associated with one particular map,
Re: Unittests pass, and then an invalid memory operation happens after?
On Wednesday, 27 March 2024 at 22:14:16 UTC, H. S. Teoh wrote: What's the definition of this.map, this.faction, and this.currentTile? As was said, and can be found on the linked repository, they are references to class objects. On Thursday, 28 March 2024 at 01:47:27 UTC, Steven Schveighoffer wrote: On Wednesday, 27 March 2024 at 21:43:48 UTC, Liam McGillivray wrote: `Unit` destructor: ``` ~this() { this.alive = false; if (this.map !is null) this.map.removeUnit(this); if (this.faction !is null) this.faction.removeUnit(this); if (this.currentTile !is null) this.currentTile.occupant = null; } ``` The GC does not guarantee destructor order. So this code is not valid -- e.g. you can't count on `map` to be a valid object at this point. Well, this was originally done so that when I explicitly call `destroy` on a Unit object (which happens in-game) it will delete all references to itself. Do you think it's better for me to move this code to a `die` function that I can call instead, which will then call for it's own destruction after running those function calls? The *only* thing you should be doing in a destructor is freeing non-GC resources. I read that the garbage collector *sometimes* but not *always* calls destructors on deletion, which sounds crazy to me. The GC is not guaranteed to delete memory or run destructors. In the current implementation, it will destroy everything at the end of the program that was allocated using the GC, but the language does not guarantee this. What's strange is that even if I explicitly call `destroy` for the only two objects at the end of the last unittest, it still happens. I assumed that each unittest was like it's own program, but I suppose not. It's deleting objects from an earlier unittest, right? I may be now starting to see why the use of a garbage collector is such a point of contention for D. Not being able to predict how the garbage collection process will happen seems like a major problem. As mentioned, GCs do not work this way -- you do not need to worry about cascading removal of anything. Wanting to avoid the GC pauses that I hear about, I was trying to optimize object deletion so that the GC doesn't have to look for every object individually. It sounds like what I'm hearing is that I should just leave everything to the GC. While I can do this without really hurting the performance of my program (for now), I don't like this. I hope that solving the unpredictable destruction pattern is a priority for the developers of the language. This problem in my program wouldn't be happening if either *all* of the objects had their destructors called or *none* of them did. Anyway, I suppose I'll have to experiment with either manually destroying every object at the end of every unittest, or just leaving more to the GC. Maybe I'll make a separate `die` function for the units, if you think it's a good idea. Also, check your Github notifications. I have something for you.
Unittests pass, and then an invalid memory operation happens after?
In my current [game project](https://github.com/LiamM32/Open_Emblem), [something strange](https://github.com/LiamM32/Open_Emblem/issues/20) has happened as of a recent commit. When running `dub test`, all the unittests appear to pass, but then after the last unittest has concluded an "Invalid memory operation" happens. Removing a few lines replaces this error with a segfault, but either way, these errors shouldn't be happening. Weirdly, the commit where these errors first appear did nothing but replace a single class-member function with a seemingly identical function through a mixin template. The errors seem to be related to object deletion. The traceback output for the first error, and where GDB points to for the second error, is the destructor for my `Unit` class. You see, every `Unit` object is associated with a particular `Map` object and `Faction` object, which it hold references to. Those objects in turn each have an array of `Unit` objects that they are associated with. In the `Unit` destructor, I have it call the `removeUnit` function in both the associated `Map` and `Faction` objects. The errors are happening in either the `Unit` destructor itself, or the `removeUnit` function that it calls. Until the commit that introduced these errors, the `removeUnit` function was written directly in the `Map` class in it's module, but this commit replaced it with the mixin template `UnitArrayManagement`, which `Faction` also uses. `Unit` destructor: ``` ~this() { this.alive = false; if (this.map !is null) this.map.removeUnit(this); if (this.faction !is null) this.faction.removeUnit(this); if (this.currentTile !is null) this.currentTile.occupant = null; } ``` ``` template UnitArrayManagement(alias Unit[] unitsArray) { bool removeUnit(Unit unit) { import std.algorithm.searching; writeln("Doing `Map.removeUnit`"); Unit[] shiftedUnits = unitsArray.find(unit); ushort unitKey = cast(ushort)(unitsArray.length - shiftedUnits.length); debug { writeln("unitsArray: "); foreach (listedUnit; unitsArray) writeln(listedUnit.name~", "); writeln("shiftedUnits: "); foreach (listedUnit; shiftedUnits) writeln(listedUnit.name~", "); } if (shiftedUnits.length > 0) { debug writeln("shiftedUnits.length > 0"); unitsArray[$-shiftedUnits.length] = null; for (ushort i=0; idebug writeln("In loop. unitKey = ", unitKey, ", i = ", i); unitsArray[unitKey+i] = unitsArray[unitKey+i+1]; } unitsArray.length--; return true; } else return false; } } ``` The first error happens because I inserted some uses of `writeln` for debugging purposes in the new version of `removeUnit` (because I haven't figured out how to do the same thing with GDB), in which I try to get it to print the names of all the units in the array before deleting any of them. I suppose that it might get a `Invalid memory operation` when trying to access a member of a `Unit` object that no longer exists, but this shouldn't be happening. When that other `Unit` object got destroyed, the destructor should have called this same `removeUnit` function to remove it's reference from the array. I read that the garbage collector *sometimes* but not *always* calls destructors on deletion, which sounds crazy to me. Is this a case of one unit being deleted without the destructor and then the next unit (of the same `Map` object) having the destructor called? Are destructors normally called after a program is concluded? The second error, which can be achieved by removing the instances of `writeln` in `removeUnit` (making it seemingly identical now to the version of this function previously defined in the `Map` class) is also strange. It seems to be a case of the `Unit` object calling a `Map` object that no longer exists. However, that's also strange, as the `Map` object is supposed to delete all it's associated units on destruction. I wrote these destructors so that objects wouldn't have references floating around on their deletion, yet now I'm getting errors from the destructors. So why are these things even happening *after* the unittests have been run? What else do I need to know about object destruction? What may be happening?
Re: How do I use libdparser, or any library for editing D code?
Unfortunately there's no "edit" option here, but the library I was referring to is actually "libdparse".
Re: Can a D library have some types determined by the client program?
On Thursday, 7 March 2024 at 22:18:40 UTC, Richard (Rikki) Andrew Cattermole wrote: There are two ways to do this. 1. Use templates. https://tour.dlang.org/tour/en/basics/templates Thank you for teaching me how to do this. This is where I first learned to use templates in D, and I have been using them since for functions, and as of yesterday, my first mixin template. That being said, I'm pleased to announce the return of the `Map` class. As of yesterday's commit, the class template `class MapTemp(TileType:Tile, UnitType:Unit)` and `interface Map` have now been replaced with a single `Map` class as they were before. At the time I had asked about this, I had not yet discovered that an array of objects can be filled with objects of a derived type by just using the regular cast syntax. Now that I know this, I've decided to just create the objects under the `VisibleTile` and `VisibleUnit` classes, place them in the `Map` object's arrays (cast to `Tile` and `Unit`), and then cast them back whenever I need to access anything specific to the derived classes. Now I no longer have to deal with the limitations of interfaces. Things should be easier now. The straw that broke the camels back was when I made my first mixin template, which adds functionality to a class for manipulating arrays of `Unit` objects. The compiler wasn't allowing it in the `Map` class because the array that I was trying to give it access to was of `UnitType`, not specifically the base `Unit` class. I'm happy to have it back.
Re: Reworking the control flow for my tactical role-playing game
On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote: * You should probably not do this, but it might give you some ideas for later. What I would do is make a separate thread for managing the UI state and push events to that thread through the mailbox. I have done this once (on my third version of a program) and it was by far the cleanest and something I was proud of. The benefit is you can publish those same events to a log and if something in your UI goes wrong, you can look at the log. I was thinking about how I can have one thread doing the rendering and another doing everything else, given that the "everything else" thread would be idle most of the time. I thought about giving the "everything else" thread a queue; an array of functions that it's tasked with going over. Every UI interaction would add one to the queue. It just occurred to me that this must be what you were suggesting here.
Re: Reworking the control flow for my tactical role-playing game
On Saturday, 23 March 2024 at 23:59:18 UTC, Liam McGillivray wrote: I replaced `destroy(unit)` with `map.deleteUnit(unit)`, and it solved the problem. Nevermind. It turns out this was because the call to the Unit destructor was missing in `Map.deleteUnit`. The segfault happens whenever a unit is destroyed. In this case, how should I handle safe destruction of units, given that there are multiple arrays that contain references to it? - Just call the unit destructor directly. The unit destructor will call functions in `Map` & `Faction` to delist the unit from it's arrays. - Call a function in `Map` which will delist the unit from `allUnits`, call a function in it's faction to delist it, and then call the unit's destructor. - Just call the units destructor, which will be rather plain. `Map` & `Faction` will have functions that frequently go over it's list of units, and delete any null references found.
Re: Reworking the control flow for my tactical role-playing game
On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote: This comment points to a symptom of the circular dependency: //Always set `destroy` to false when calling from the Unit destructor, to avoid an infinite loop. I was just doing some work on the AI system, and I had a segfault every time the enemy was in reach to attack a unit. It turns out this was because the destructor was called. I replaced `destroy(unit)` with `map.deleteUnit(unit)`, and it solved the problem.
Re: Reworking the control flow for my tactical role-playing game
On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote: You should engineer the system in a way that makes sense to you. The currency of finishing programs is motivation and that comes from success and believing you will succeed. If you're implementing XYZ pattern from someone else, if you don't get it then you will get unmotivated. I have seen some pretty horrible programs make it to all the way done and have almost never seen someone's first run at a problem be both pretty and get finished. Don't beat yourself up about keeping it clean. If you feel like it or it's getting out of control where you can't understand it, then you should go look for a solution. The motivation is in moving forward, though. This is probably the piece of advice I wish I had in the beginning! You can always refactor later when it's done. Alright. I suppose this is largely what I'm doing. Thank you very much for looking through my code and making the effort to understand it. So far you are the first person to comment on my code, beyond the little excerpts I've pasted directly onto this forum. Move to the tick system. You make a loop and update each object based on the time that has passed. If your tick is 1/60th of a second then you make a loop. In the loop, you update the map state knowing 1/60th of a second has passed. Then you update all the items and move them or deplete them or whatever however much would happen in 1/60th of a second. Then you update all of the units. Then you can update the factions or check win conditions. At the end of the loop, you draw everything. When you said "tick system", I thought you meant that it would be asynchronous to the framerate, but then you say "At the end of the loop, you draw everything". Right now the function that moves units across the screen moves them each frame a distance proportional to the duration of the previous frame. I was thinking that a tick system would go hand-in-hand with making animations happen in a separate thread, but it sounds like you're talking about the same thread. Are you suggesting a fixed framerate? Because this is a turn-based game, I don't need to update the factions and win conditions every frame, but at most every time a unit makes a move or when a new turn starts. Your verifyEverything method is awesome. I call that strategy fail-fast. It means you fail right away when you have a chance to identify what went wrong. That's nice. I thought it might be an amateurish solution to something that better programmers would do differently, similar to how I use `writeln` to print variables for debugging. It looks like I don't yet have any calls to this function, so perhaps I should add one under the debug configuration. Construct the unit and then call map.setOccupant(unit) after the unit is constructed. I would not do anything complicated in a constructor. It's also generally frowned upon to pass a reference to an object to anything before the constructor completes. Most of the changes I mention are things to think about, but this specifically is something you ought to change. I didn't immediately understand what you were saying, but then I looked at what line `unit.d:44` was at the time you wrote this. ``` map.getTile(xlocation, ylocation).setOccupant(this); ``` This is during the Unit's constructor, where it gives the `Tile` object a reference to itself. What exactly is wrong with this? Can memory addresses change when a constructor completes? I assumed that objects come into existence at the beginning of the constructor function. Anyway, I can change this by calling `Unit.setLocation` after creating a new `Unit` object. That's unless if there's a particular reason why you think I should make this a function of the `Map` object. I suppose the current system for setting up objects from a `JSONValue` is messy because much of the data applies to the base `Tile` & `Unit` objects, but then some of it needs to be in `VisibleTile` & `VisibleUnit` because it has sprite information. I would also remove the unit from the map and then delete the unit rather than removing the unit from within the map class. Sure. I'll change that. Even when I wrote the Unit destructor I was thinking that perhaps this was a bad way to implement this. I suppose I should just call the `Map.deleteUnit` whenever a unit should be deleted, right? I was also thinking of replacing `Map.deleteUnit` with a function that removes all null references from `this.allUnits` which can be called after destroying a unit, but unless if I need to hyper-optimize, that probably won't be any better than the function I have. Another reason I would switch that line is that it's best to avoid circular dependencies where you can. It will make it hard to reason about either in isolation. It relates to that line because your map has units in it and your unit takes Map in the constructor. That is a red flag that you are too
Re: Optimization when using a 2-dimensional array of objects
On Friday, 22 March 2024 at 07:34:33 UTC, monkyyy wrote: Is one option more efficient than the other? You should probaly do the lazyest thing, factor out your "ispassable" logic, like what your walking n of 3, n of 8, n of 15? so long as you dont do something insane it will be fast on a modern computer; allocating several dynamic array that are the size of your game world every frame could easily be not very sane. Well, none of the stuff you wrote closely resembles the code that I have. There are 3 reasons why I put this kind of effort into optimization: - I'm obsessive. - For the learning experience. - Because things may get more demanding when I get further with the enemy AI system. One possibility is to have it make multiple copies of all the game objects which it will use to look ahead to the next 1-2 turns. and if you really really wanted to care, you could precompute the "connected compoints" by flood filling across passable tiles with a "color" of 0, then finding an empty cell, flood filling with 1, etc.; and when you draw the overlay for where you can move you can do a heuristic check for a) they are in the same component, and b) the manhattan distances before c) doing a greedy check I barely understand any of this, though I know what a Manhattan distance is. Is this about measuring distances? Manhattan distances appear to be how distances are determined in Fire Emblem, though I'm using a slightly more intensive `abs(x) + abs(y) + max(abs(x) + abs(y))` whenever I need a quick estimate of distance that doesn't account for obstructions. Is there a memory allocation technique that would make each tile's location in grid inferrable based on it's memory address? Yes its called an array theres some details you need to know and you need to cast pointers; just try some trial and error with code like: But objects are reference by default. This means that they don't really 'live' in the array I put them in, doesn't it? Wouldn't the the array entries just be references on the same level as any other? ```d int[10] foo; [1].print; ([7]-[0]).print; ``` This appears to be a different programming language. It isn't D.
Optimization when using a 2-dimensional array of objects
In the [game I am currently making](https://github.com/LiamM32/Open_Emblem/blob/master/oe-raylib/source/app.d), I have a `Map` class (actually a combination of an interface & class template, but I'll call it a "class" for simplicity), in which there will probably be only one instance running at a time. In that map class is a 2-dimensional dynamic array of `Tile` objects called `grid`. What these `Tile` objects represent are like squares on a chessboard. Their placement in `grid` represents their location on the map. Whenever a function in the game has to pass a location on the map, I have a dilemma between passing a reference to the tile object, and passing it's grid coordinates through `struct Vector2i {int x; int y;}`. The functions that receive this information sometimes must access the Tile's variables to know it's properties, but may also need to know it's location so that it can find neighbouring tiles. The `Unit` class also has a 2-dimensional dynamic array of entities holding information on the unit's distance from that tile, and whether it can reach it during this turn. Is one option more efficient than the other? I already have the location of each tile cached as a pair of variables within each tile. To get a location from a Tile object, a call would be made to the member function `Vector2i location()`. To get a tile object from it's coordinates, a member function of `Map` `Tile getTile(Vector2i location)` would be called. Should I stick to one over the other? Is there a memory allocation technique that would make each tile's location in `grid` inferrable based on it's memory address? It would be nice if the two were interchangeable, so that I wouldn't have this dilemma. Not knowing which option is best has lead to a little bit of messy syntax. Right now I have multiple versions of the functions `getReachable` & `getAttackable` in the [`Unit`](https://github.com/LiamM32/Open_Emblem/blob/master/source/unit.d) class which return a different type, because I'm not sure which is better.
Re: Reworking the control flow for my tactical role-playing game
On Thursday, 21 March 2024 at 16:48:39 UTC, Steven Schveighoffer wrote: On Sunday, 17 March 2024 at 00:14:55 UTC, Liam McGillivray wrote: As many of you know, I have been trying to write a tactical role-playing game (a mix of turn-based stategy & RPG) in D. This is the furthest I have ever gotten in making an interactive program from the main function up. Right now, it is not yet playable as a game, but you can interact with it and get a rough idea of what I'm going for. Feel free to download and run it to see what I have so far. https://github.com/LiamM32/Open_Emblem I got it to run on my mac, I had to do a few updates to the dub.sdl file, but it did work, though I couldn't figure out how to make attacks work. Great. You may be the first person to download and run it. I would appreciate if you committed and pushed the changes to the `dub.sdl` file. So far I've only tested it on Linux. Attacks don't fully work yet. When selecting "Attack" in the menu, you should see the tiles in range marked in red, but clicking one will as far as you can tell, do nothing but bring you back to the previous menu. Right now it's programmed to lower the enemy HP on attack, but there's no way for the player to see that it worked. Nothing currently happens when HP goes to zero or lower. ## The Current Structure: The code for Open Emblem (name subject to change) is split between a source library, which handles the internal game logic, and a graphical front-end program which uses that library, but makes it usable. This is kind of cool, I like the idea! Good to hear. It makes some things difficult when I don't allow myself to put anything specific to any graphics or UI library in the library, but it also may make it easier if I rework the graphics and UI. Everything here is single-threaded. Despite that, I still get thousands of frames-per-second when disabling the cap on framerate. Note that disabling the cap on framerate just avoids the sleep-per-frame that raylib does. I always recommend setting a cap of something like 60 unless you are going to use vsync. The "framerate-test" configuration only exists as a benchmark to give me an idea of how far I am from the CPU's limit. It's not for playing. In the default configuration and the others, it currently uses the `getRefreshRate` function to set the target framerate to the monitor's refresh rate on Linux. It's supposed to do that too on Windows, but I haven't tested it. On Mac it just sets it to 60 FPS. So for instance, an animation that needs to move an object from A to B, should be captured into a temporary item (class object, struct, member of the sprite, etc), where you tell it every time you are drawing a frame (or even better yet, each game tick), and let it make the changes necessary for one tick of time. For instance, build an object that takes start position, end position, time to animate, and maybe a path function (like linear, ease-in/ease-out, etc), and then each frame calculates where the position should be based on the current time vs. the start time. Encapsulating all this into an object makes things easy to deal with. Then you just need to call it every frame/tick. Interesting. This is a different approach from how I imagined it. I never thought I would add a whole new object just to move another object around. Instead I was thinking of having a function in `VisibleUnit` that moves itself to the next location on a path (represented as an array of either directions or locations). Either this would be called for every unit every frame (but it would do nothing if they don't have a path), or there would be an array of moving units in which this function would be called in the rendering loop. Perhaps if I had just used the plain `Unit` class from the library instead of making the derived `VisibleUnit` class, I would consider this approach. I'm not sure if you want to do event driven here. It's a possibility. But I find a game-tick system, where each tick, you update each object according to its wishes to be pretty easy to develop with. I will add the caveat that I am also a pretty novice game developer, and have never actually built a complete game. If I were to recommend a system here, I'd create a linked list of items to "tick" every frame, with something like: ```d interface GameObj { // returns false if this object is done bool tick(); } ``` Then basically, you go through your list every frame, and call the tick function, which will make needed changes, and if it returns false, then you remove from the list while iterating. This means you can do N things at once, and you don't need multiple threads to do it. Well this sounds not so different from signals and slots. My current understanding is that every time the signal is called, that same thread goes through a list of functions connected to that signal. Back when I wrote this post, I had a worse
Reworking the control flow for my tactical role-playing game
As many of you know, I have been trying to write a tactical role-playing game (a mix of turn-based stategy & RPG) in D. This is the furthest I have ever gotten in making an interactive program from the main function up. Right now, it is not yet playable as a game, but you can interact with it and get a rough idea of what I'm going for. Feel free to download and run it to see what I have so far. https://github.com/LiamM32/Open_Emblem I'm now at a point where I have trouble figuring out the next step to making the game playable. The complexity may have just reached a point where I find it harder to keep track of everything that I have written. There is probably a fair amount of unused code that I abandoned after deciding on a different solution, but forgot to delete. There are probably also some amateur decisions I've made in structuring the program, given that I largely figured it out myself. For some time now I've thought that I may later want to overhaul how the whole rendering and UI system work. Perhaps now is a good time since my productivity under the current system is slowing down. ## The Current Structure: The code for Open Emblem (name subject to change) is split between a source library, which handles the internal game logic, and a graphical front-end program which uses that library, but makes it usable. When starting, I decided to structure it this way so that I can experiment with different graphics and UI libraries. This may have been a good move, even if it complicates some aspects, as the first library I tried wasn't the one I've stuck with. I also thought that this library may also be usable as a platform for others to make their own tactical RPG games, though that's unlikely with the current direction of the project. ### The Library: The most important modules here are `map`, `tile`, & `unit`, which contain the classes `Map`, `Tile`, & `Unit`. There is nothing here specific to any particular graphics or game library. Well, `Map` is now longer actually a class, as it's been replaced by the `Map` interface and `MapTemp` template which implements it, but for simplicity, I'll refer to `Map` as a class. This class is meant to serve as the master that controls the flow of a single game mission. Only one instance is meant to exist at a time. It holds a 2-dimensional array of `Tile` objects which represents the grid that the game is on (like a chessboard) and an array of all `Unit` objects. `Unit` represents a character in the game that can be moved on the map (like a chess piece). It has some stats stored as variables, and some functions to do various things a player (or AI) may ask the unit to do during their turn. Each unit occupies a tile object. `Tile` is a square on the map, which has it's own *x* & *y* coordinate. The `Faction` class currently only serves to store a set of units belonging to a certain player or AI, but is planned to play a bigger role later. ### The Raylib Front-end: After looking at many libraries and taking a shot at [ae](https://github.com/CyberShadow/ae) & [godot-D](https://github.com/godot-d/godot-d) but not really figuring it out, I was recommended [raylib-d](https://github.com/schveiguy/raylib-d), a binding for [raylib](https://www.raylib.com/) by @Steven Schveighoffer. Raylib is a rather simple graphical library written in C. I ended up sticking with it because the website has so many easy-to-follow examples that make it easy as my first graphical library. They're written in, but I adapted them to D rather easily. Of course, being written in C has limitations as it isn't object-oriented. This is front-end is in the [`oe-raylib/`](https://github.com/LiamM32/Open_Emblem/tree/master/oe-raylib) directory. For this front-end, I've made the classes `VisibleTile` and `VisibleUnit`, which inherit `Tile` & `Unit`, but add sprite data and other graphics-related functionality. I then have the `Mission` class which inherits the `MapTemp` class. This class dominates the program flow in it's current state. It handles loading data from JSON files, switching between different game phases and does most of the function calls related to rendering and input. The way I have it currently, there's a `startPreparation` function and `playerTurn` function, each of which run a once-per-frame loop that renders all the necessary objects and takes user input. They each have a rather messy set of if-statements for the UI system. Any UI elements that may pop-up are declared before the loop begins, with if-statements to determine whether they should be visible this frame. For UI elements, I currently have `version` flags for either `customgui` (which I started writing before discovering raygui) and `customgui`, which you can select between using `dub --config=`. Having both makes the code messier, but I haven't yet decided on which I prefer. They are both currently achieve equivalent functionality.
Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow
On Friday, 15 March 2024 at 17:25:09 UTC, Daniel N wrote: On Tuesday, 12 March 2024 at 05:38:03 UTC, Liam McGillivray wrote: I am in need of a data type for holding direction information; one of 8 directions on a single axis. They are named in terms of compass directions. If D had a 4-bit datatype, I would just use this and do `+=2` whenever I want to change the datatype, but it doesn't. Perhaps this would be a good programming challenge for someone more experienced than me. Make a data type (probably a struct) for holding one of 8 directional values using 3 bits. It should accept the use of increment operators to change the angle. Ideally (but optionally), it should work as an enum of the same name; "Direction". Here's a unittest that it should ideally pass: D actually supports both 3 and 4 bit integers. People will likely warn you of minor portability risks... but if you target a limited amount of platforms and prefer concise readable code, then it's a text book example for bitfields. The risk can easily be mitigated by having an unittest to catch the error directly(if you try to port to some exotic platform). dmd -preview=bitfields (Some lines stolen from Rikki) ```d struct Direction { private uint value : 3; alias this = value; enum Direction N = Direction(0); enum Direction NE = Direction(1); enum Direction E = Direction(2); enum Direction SE = Direction(3); enum Direction S = Direction(4); enum Direction SW = Direction(5); enum Direction W = Direction(6); enum Direction NW = Direction(7); } ``` Oh wow! That looks so clean and elegant, aside from the `: 3` part being easy to miss, and not very readable for those not aware of this feature. This would be so simple. If I used this, I wouldn't even need to make a struct and write the operator overload functions; just make an enum for a 3-bit uint. Based on the words in the command and a quick search, I'm guessing that this is an experimental feature that has not yet been accepted as part of the language. Perhaps I shouldn't use this then, just in case it gets pulled and someone who discovers my project in the future will have a build error that they don't know how to solve. This seems like a bigger problem than the extra memory the current ubyte version takes up, which is probably quite small for a computer of today anyway. I suppose this would be a nice feature for the language to have if the syntax were reworked. Perhaps something like `uint!3 value;` would be better.
Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow
On Friday, 15 March 2024 at 00:21:42 UTC, H. S. Teoh wrote: On Thu, Mar 14, 2024 at 11:39:33PM +, Liam McGillivray via Digitalmars-d-learn wrote: [...] I tried to rework the functions to use bitwise operations, but it was difficult to figure out the correct logic. I decided that it's not worth the hassle, so I just changed the value storage from `bool[3]` to `ubyte`. [...] Just wanted to note that while in theory bool[3] could be optimized by the compiler for compact storage, what you're most likely to get is 3 bytes, one for each bool, or perhaps even 3 ints (24 bytes). When dealing with units of data smaller than a byte, you generally need to do it manually, because memory is not addressable by individual bits, making it difficult to implement things like slicing an array of bool. So the compiler is most likely to simplify things by making it an array of bytes rather than emit complex bit manipulation code to make up for the lack of bit-addressability in the underlying hardware. Using bit operators like others have pointed out in this thread is probably the best way to implement what you want. T I'm curious as to what "manual implementation" would mean, since clearly making my own struct with `bool[3]` doesn't count. Does D have features for precise memory manipulation? Anyway, I'm surprised that D has a special operator `&=` for doing bit manipulation on integers, especially given that the steps to convert an int into a bool array is more complicated. I would imagine the former would be a rather niche thing.
Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow
On Thursday, 14 March 2024 at 01:58:46 UTC, Richard (Rikki) Andrew Cattermole wrote: The cost of an add + increment then a bitwise and is only 2-4 cycles on a Haswell cpu. Depending upon if its working solely in registers (via inlining) or its operating on ram. Whereas if you need to do branching (if statement, loops), this is an unpredictable cost and loops where a simple bitwise operation can be done is out right non-optimized. As for exceptions, totally not required. You can solve this by simply making your state private so nobody else can mutate it. Bounds checking will ensure if the state is corrupted it'll error out if you use the lookup method I suggested above. I tried to rework the functions to use bitwise operations, but it was difficult to figure out the correct logic. I decided that it's not worth the hassle, so I just changed the value storage from `bool[3]` to `ubyte`. Now it works much more like your version. https://github.com/LiamM32/Open_Emblem/blob/c2014ab3f77e89c0cedcd6dbf7f8362ebfac33a9/source/common.d I did a little reading, so now I understand what it means when you have `&= 7`. But I want to ask, is this faster than `%= 8`? If not, I would like to change it to the latter for readability.
Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow
On Tuesday, 12 March 2024 at 06:38:28 UTC, Richard (Rikki) Andrew Cattermole wrote: By taking advantage of integer wrapping and a bitwise and, its quite a simple problem to solve! Challenge for the reader: add support for binary operations and toString support. Last night I pushed the latest commit to the GitHub repository for my game. It contains the `Direction` struct in [`source/common.d`](https://github.com/LiamM32/Open_Emblem/blob/master/source/common.d). Here it is: ``` struct Direction //One of 8 directions stored in 3 bits { import std.conv; import std.traits: isNumeric; bool[3] b; static Direction N = Direction(b:[false,false,false]); static Direction NE = Direction(b:[true,false,false]); static Direction E = Direction(b:[false,true,false]); static Direction SE = Direction(b:[true,true,false]); static Direction S = Direction(b:[false,false,true]); static Direction SW = Direction(b:[true,false,true]); static Direction W = Direction(b:[false,true,true]); static Direction NW = Direction(b:[true,true,true]); ref Direction opUnary(string op)() if (op == "++" || op == "--") { static if (op == "++") const bool up = true; else const bool up = false; if (b[0]) { if (b[1]) b[2] = !b[2]; b[1] = !b[1]; } b[0] = !b[0]; return this; } void opOpAssign(string op)(int amount) if (op == "+" || op == "-") { amount = amount%8; if (amount > 0) for (uint i = 0; i < amount; i++) { static if (op=="+") this++; else this--; } else for (uint i=0; i > amount; i--) { static if (op=="+") this--; else this++; } } T to(T)() const if(isNumeric!T) { return cast(T)(b[0] + 2*b[1] + 4*b[2]); } T opCast(T)() if (isNumeric!T) { return cast(T)(b[0] + 2*b[1] + 4*b[2]); } T to(T)() const if(is(T==string)) { if (this==Direction.N) return "north"; else if (this==Direction.NE) return "northeast"; else if (this==Direction.E) return "east"; else if (this==Direction.SE) return "southeast"; else if (this==Direction.S) return "south"; else if (this==Direction.SW) return "southwest"; else if (this==Direction.W) return "west"; else if (this==Direction.NW) return "northwest"; else throw new Exception("Direction.to!: direction has a value that should be impossible."); //else return ""; //This should never happen. } bool[3] opCast() const { return this.b; } Direction opposite() const { return Direction([b[0], b[1], !b[2]]); } bool diagonal() { return b[0]; } int getAngle() { if (this==Direction.N) return 0; else if (this==Direction.NE) return 45; else if (this==Direction.E) return 90; else if (this==Direction.SE) return 135; else if (this==Direction.S) return 180; else if (this==Direction.SW) return 225; else if (this==Direction.W) return 270; else if (this==Direction.NW) return 315; else throw new Exception("Direction.getAngle: direction has a value that should be impossible."); } } ``` The one thing that cant be done on this is doing `direction+8`. Perhaps it would have been easier if I had chosen to store the value as a ubyte rather than an array of bools. While this is probably over-optimized given the large amount of memory in today's computers, I like it that it can never be an illegitimate value. There's probably some trick I can use to make it easier to figure out the functions to do numerical operations on bits, but I don't know how best to cleanly represent this kind of thing in code. Maybe I need to look for examples of how it's already done. I noticed among the options for overloading unary operations are the symbols "+" & "-". What operation is being overloaded with the function `ref Direction opUnary(string op:"+")(int amount)`?
Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow
On Tuesday, 12 March 2024 at 06:38:28 UTC, Richard (Rikki) Andrew Cattermole wrote: By taking advantage of integer wrapping and a bitwise and, its quite a simple problem to solve! Challenge for the reader: add support for binary operations and toString support. https://dlang.org/spec/operatoroverloading.html ```d struct Direction { private int value; Direction opUnary(string op:"++")() { value++; value &= 7; return this; } Direction opUnary(string op:"--")() { value--; value &= 7; return this; } void opOpAssign(string op:"+")(int amount) { value += amount; value &= 7; } void opOpAssign(string op:"-")(int amount) { value -= amount; value &= 7; } enum Direction N = Direction(0); enum Direction NE = Direction(1); enum Direction E = Direction(2); enum Direction SE = Direction(3); enum Direction S = Direction(4); enum Direction SW = Direction(5); enum Direction W = Direction(6); enum Direction NW = Direction(7); } unittest { Direction direction = Direction.N; direction++; assert(direction == Direction.NE); direction+=3; assert(direction == Direction.S); direction--; assert(direction == Direction.SE); direction-=4; assert(direction == Direction.NW); } ``` Interesting. I didn't know that an enum can be defined inside a struct like that. I had used functions to get around it. Here is what I had already mostly written, using help from ChatGPT (but only for the opUnary syntax, not the algorithm): ``` struct Direction //One of 8 directions stored in 3 bits { bool[3] d; static Direction N() { return Direction(d:[false,false,false]); } static Direction NE() { return Direction(d:[false,false,true]); } static Direction E() { return Direction(d:[false,true,false]); } static Direction SE() { return Direction(d:[false,true,true]); } static Direction S() { return Direction(d:[true,false,false]); } static Direction SW() { return Direction(d:[true,false,true]); } static Direction W() { return Direction(d:[true,true,false]); } static Direction NW() { return Direction(d:[true,true,true]); } ref Direction opUnary(string op)() if (op == "++" || op == "--") { if (op == "++") const bool up = true; else const bool up = false; if (d[0]) { if (d[1]) d[2] = !d[2]; d[1] = !d[1]; } d[0] = !d[0]; return this; } auto to(T)() const { return cast(T)(d[0] + 2*d[1] + 4*d[2]); } } ``` I am not entirely sure how well it works. I will come back later with an updated version with more functions. I'm not familiar with the syntax of the line `value &= 7;`. Is it equivalent to writing `value = value % 7;`? Anyway, you used an int, but I used an array of 3 bools. I'm guessing that mine uses less memory, but I'm not sure how memory it adds when it's a struct with functions.
Challenge: Make a data type for holding one of 8 directions allowing increment and overflow
I am in need of a data type for holding direction information; one of 8 directions on a single axis. They are named in terms of compass directions. If D had a 4-bit datatype, I would just use this and do `+=2` whenever I want to change the datatype, but it doesn't. Perhaps this would be a good programming challenge for someone more experienced than me. Make a data type (probably a struct) for holding one of 8 directional values using 3 bits. It should accept the use of increment operators to change the angle. Ideally (but optionally), it should work as an enum of the same name; "Direction". Here's a unittest that it should ideally pass: ``` unittest { Direction direction = Direction.N; direction++; assert(direction == Direction.NE); direction+=3; assert(direction == Direction.S); direction--; assert(direction == Direction.SE); direction-=4; assert(direction == Direction.NW); } ```
Re: Can a D library have some types determined by the client program?
On Sunday, 10 March 2024 at 04:39:33 UTC, Liam McGillivray wrote: https://github.com/LiamM32/Open_Emblem/tree/templates-interfaces I will probably merge it into master soon. I have put up a merge request for these changes I have made to the library and the Raylib front-end. I would be interested in having my code looked at by someone more experienced than me (which would be everyone who has replied here and most of those reading). https://github.com/LiamM32/Open_Emblem/pull/2 You can take a look in `source/map.d` where the former `Map` class has been replaced with the `Map` interface and the `MapTemp` template. You may also look in `oe-raylib/source/mission.d`, and compare how sprites were handled before vs after. Of course, you can also compile and run it yourself (assuming I didn't accidentally leave out a file). Other commentary on my code would also be appreciated. I don't know if there's a forum section appropriate for sharing personal projects, but I may post there too.
Re: Can a D library have some types determined by the client program?
I have made a new branch of my project called "templates-interfaces" which reworks some things, and turns the Map class into an interface and template. It is now functioning like the master branch, but I think the code should now be (arguably) easier to follow. At least that's true for the Raylib front-end, though maybe a little less so for the library. Here it is: https://github.com/LiamM32/Open_Emblem/tree/templates-interfaces I will probably merge it into master soon.
Re: Can a D library have some types determined by the client program?
Update on two things: One is that I now better understand what it means that D objects are "reference by default". This means that references *can* be null if they are declared with a class. In my commits last night, I have changed many pointers into references. I think my time will be smoother from now on, spending far less time trying to debug segfaults. Secondly, I found out that interfaces can't have variables. What!? That's crazy! Why wouldn't they? They totally should. Doesn't this mean that I will need to use getter and setter functions instead of direct access when using interfaces? I don't like this.
Re: Why am I getting segfaults when doing `foreach` with arrays of references?
On Saturday, 9 March 2024 at 07:49:52 UTC, Liam McGillivray wrote: But that begs the question; why? Don't dynamic arrays always start with a length of 0? If the array was only extended when valid objects were appended using the append operator `~=`, and none of those objects were deleted (as I the destructor was never called), why would some of the array elements be null? I'll answer my own question; because the thing assigned to the array was already null. Anyway, I managed to fix the segfaults. In the latest two commits, I have turned some pointers into references. Now that I understand this, I should have fewer segmentation faults.
Re: Why am I getting segfaults when doing `foreach` with arrays of references?
On Saturday, 9 March 2024 at 06:37:02 UTC, Richard (Rikki) Andrew Cattermole wrote: Something that I have noticed that you are still doing that was pointed out previously is having a pointer to a class reference. Stuff like ``Tile* currentTile;`` when it should be ``Tile currentTile;`` A class reference is inherently a pointer. So when you checked for nullability in the foreach loop of mission: ```d if (startTile.occupant !is null && (*startTile.occupant) !is null) { ``` I think I'm starting to understand better. I was thrown off somewhere when I read that "references in D cannot be null". I tried doing some if-statements to determine if array objects are null, and some of them were. But that begs the question; why? Don't dynamic arrays always start with a length of 0? If the array was only extended when valid objects were appended using the append operator `~=`, and none of those objects were deleted (as I the destructor was never called), why would some of the array elements be null?
Why am I getting segfaults when doing `foreach` with arrays of references?
With [my game project](https://github.com/LiamM32/Open_Emblem), I have been getting segmentation faults that are unexplainable at my knowledge level. They seem to happen when doing a "foreach" loop through an array of references. Skip to the bolded text if you don't want to read too much, as I found a way around the first example. Prior to the latest commit, I had this "foreach" loop lines starting at `oe-raylib/source/mission.d:214` ([see file](https://github.com/LiamM32/Open_Emblem/blob/09505794970168c68ed5cffd9aa2ed69490ee80e/oe-raylib/source/mission.d)). It would segfault on the second line shown here: ``` foreach (startTile; this.startingPoints) { startTile.occupant.map = this; writeln("Just assigned Unit.map to the Mission object."); this.factionUnits["player"] ~= *startTile.occupant; } ``` This was in the `Mission` class (a derivative of `Map`), which `this` would be a reference to. `startTile` is an instance of the `GridTile` struct, which contains a reference to a `Tile` object called `tile`. The `Tile` object had a pointer to a `Unit` object called `occupant`. `GridTile.occupant` is a convenience function that's equivalent to `GridTile.tile.occupant`. Finally, the `Unit` class contains a reference to a `Map` object called `map`. Because `Mission` is a derived class, a `Mission` object can also fit. All of the things being accessed were public. I thought the problem was that it was looking in `Tile` objects with `occupant` being null, but changing line 214 to the following didn't solve it. ``` foreach (startTile; this.startingPoints) if (startTile.occupant !is null) { ``` **Current example** I ended up getting rid of that line causing the segmentation fault and achieving the desired functionality a different way, but now I get a similar one later in the program. The `turnReset` function in my [`Map` class](https://github.com/LiamM32/Open_Emblem/blob/master/source/map.d) does a 'foreach' loop through an array of `Unit` objects: ``` void turnReset() { foreach(unit; this.allUnits) { unit.turnReset; } } ``` My program successfully completed one cycle of the loop, but segfaulted with the second one. I found in GDB that for the second object it didn't even reach the first line in `Unit.turnReset()`. This may imply that the array length of `Map.allUnits` is more than one, but no object has been assigned to `allUnits[1]`. However, there are no lines anywhere in my code that changes the length of this array without appending. I tried doing the `grep -r allUnits` command to look for every mention of this array in my code, and here is what I have: ``` source/map.d:public Unit[] allUnits; source/map.d:foreach (unit; this.allUnits) { source/map.d:foreach(unit; this.allUnits) { source/map.d:assert (canFind(map.allUnits, unit)); source/unit.d:if (this in map.allUnits) { oe-raylib/source/mission.d:this.allUnits ~= *startTile.occupant; oe-raylib/source/mission.d:foreach (unit; this.allUnits) { oe-raylib/source/mission.d:if (addToMap) allUnits ~= newUnit; oe-raylib/source/mission.d:foreach (unit; mission.allUnits) { oe-raylib/source/mission.d.bak2:foreach (unit; this.allUnits) { ``` As far as I see, there's no way that the `allUnits` array would be longer than the number of objects that have been added to it, so why would calling a public function of one of it's members cause a segfault?
Re: Can a D library have some types determined by the client program?
On Friday, 8 March 2024 at 16:54:48 UTC, cc wrote: If you don't want Unit to be a template, you can just have Map derive from a basic interface or abstract class. You can also have every relevant class share similar templates, you just need to remember to supply the template arguments everywhere. Right. Interfaces. I haven't used this feature yet, but I had read about them, thinking I would likely use them. I forgot about them at the time of making this thread. I will try making Map & Tile an interface, and maybe Unit as well. Can an interface and a template have the same name, similar to function overloading? In that case, `Map!Tile` would refer to the template, while `Map` would be the interface. Maybe I'll have figured this out myself by the time someone replies. You'll need to think about how much interoperation you want between these classes. Does Unit really need to know what TileType map is using, or can it just trust that when it asks Map to move, Map will handle everything related to tile types? Generally it's best practice to have as much of the inner workings isolated as possible and just provide methods to access functionality. I don't think `Tile` and `Unit` will need to know the details of what kind of Tile & Unit derivative the map is using. As an aside on this topic, I wonder if my `Map` class and it's derivative `Mission` are doing too many things. I don't know if there is enough of a problem with one "master" class dominating the program that it's worth splitting it up despite the more complex programming. After changing `class Unit` to `class Unit (TileType)`, it complains about the line `Unit* occupant;` in Tile. Are you sure you need a pointer here? Class objects in D are already reference-type by default. I'm pretty sure I do, as references can't be null. As an approximation of what I'm doing, think of `Map` as a chess board, `Tile` as a square on the board, and `Unit` as a chess piece. Not every tile on the chess board is occupied by a piece. If you want, you can see the program I have so far on [my GitHub repository](https://github.com/LiamM32/Open_Emblem). Right now the `master` branch is the most up-to-date, but I might soon make a new branch to try out templates and interfaces.
Re: Can a D library have some types determined by the client program?
On Friday, 8 March 2024 at 03:19:59 UTC, Richard (Rikki) Andrew Cattermole wrote: On 08/03/2024 4:09 PM, Liam McGillivray wrote: Thank you. Is this first example you gave the template? Is the syntax `(ATile : Tile)` saying that ATile must be a derived class of Tile? If this isn't worse in any way than your second example, then I don't know why I wouldn't choose this one. Typically in D we use templates quite heavily, but what you are wanting is probably more familiar to you via the OOP method with a factory of some kind. Nope, but thank you. I am not a very experienced programmer. The most complex thing I've ever done previous to this was my work on [Condorcet](https://github.com/julien-boudry/Condorcet) which is in PHP. I might have encountered something about factory methods, but I don't remember. I have some C++ experience, but I haven't been very successful with it. What I have so far in the game I'm making is the most complex program I have ever written. I suppose that if I do this, then the derived class `Mission` would be declared like `class Mission : Map(GridTile)`, right? ``class Mission : Map!GridTile`` but right idea. When I tried adding that parameter to the Map class, on attempting to build it it complained that references to Map in other classes were incomplete, as they didn't include a parameter. I suppose I must make my other classes templates too. I have an update on this, after taking another go at it. A problem I have is that the 3 classes Map, Tile, and Unit reference each-other. If I turn Map into a template, than it complains about the member variable of Unit declared as `Map map;` without arguments. I change this line to `Map!TileType map;` but this requires that Unit is also turned into a template. After changing `class Unit` to `class Unit (TileType), it complains about the line `Unit* occupant;` in Tile. I try turning Tile into a template with the `TileType` parameter, which means that the class inheriting Tile will need to use itself as a parameter. Surprisingly, I have done this and it hasn't taken issue (so far). But now that I have turned Tile into a template, it complains about the declaration of Map being `class Map (TileType : Tile)`, as `Tile` is no longer a class but a template. Here are some of the build errors: ``` Starting Performing "debug" build using /usr/bin/dmd for x86_64. Up-to-date bindbc-freetype 1.1.1: target for configuration [staticBC] is up to date. Up-to-date fluid 0.6.3: target for configuration [default] is up to date. Building open_emblem_raylib ~master: building configuration [application] ../source/map.d(185,13): Error: template class `unit.Unit(TileType)` is used as a type without instantiation; to instantiate it use `Unit!(arguments)` ../source/map.d(21,19): Error: template class `unit.Unit(TileType)` is used as a type without instantiation; to instantiate it use `Unit!(arguments)` ../source/map.d(22,27): Error: template class `unit.Unit(TileType)` is used as a type without instantiation; to instantiate it use `Unit!(arguments)` ../source/map.d(125,11): Error: template class `tile.Tile(TileType)` is used as a type without instantiation; to instantiate it use `Tile!(arguments)` ../source/map.d(129,14): Error: template class `tile.Tile(TileType)` is used as a type without instantiation; to instantiate it use `Tile!(arguments)` ../source/map.d(133,11): Error: template class `unit.Unit(TileType)` is used as a type without instantiation; to instantiate it use `Unit!(arguments)` ../source/unit.d(12,12): Error: template instance `map.Map!(VisibleTile)` error instantiating ../source/tile.d(19,9):instantiated from here: `Unit!(VisibleTile)` source/vtile.d(4,21):instantiated from here: `Tile!(VisibleTile)` ``` Will I somehow manage to solve this problem? Given that it's possible to declare an object inside a class, and then fill it with an object of a derived class, I would have thought it would be possible to use a template as a type, and then fill it with an object of a class derived from that template.
Re: Can a D library have some types determined by the client program?
On Thursday, 7 March 2024 at 22:18:40 UTC, Richard (Rikki) Andrew Cattermole wrote: There are two ways to do this. 1. Use templates. https://tour.dlang.org/tour/en/basics/templates 2. Use a factory function. https://tour.dlang.org/tour/en/basics/delegates ```d class Map(ATile : Tile) { ATile[] tiles; } ``` Thank you. Is this first example you gave the template? Is the syntax `(ATile : Tile)` saying that ATile must be a derived class of Tile? If this isn't worse in any way than your second example, then I don't know why I wouldn't choose this one. I suppose that if I do this, then the derived class `Mission` would be declared like `class Mission : Map(GridTile)`, right? When I tried adding that parameter to the Map class, on attempting to build it it complained that references to Map in other classes were incomplete, as they didn't include a parameter. I suppose I must make my other classes templates too. Something strange that I just realized is that (without doing any of the changes you suggested to me), I have a reference to a Map object as one of the class variables in Unit, yet it has allowed me to place a Mission object in it's place. It no longer allows me if I change it to a pointer. Why is it sometimes possible to put a derived class in a place meant for the class it inherits from?
Can a D library have some types determined by the client program?
In a source library written in D, is it possible to have some objects, variables, pointers etc which are determined by the program using the library? An example of where this would be useful is in the library I am currently writing. I have a class called `Map`, which holds an array of objects of the `Tile` class. A program using my library can inherit the Map class if they want to add more functions and variables, but what if they want to add more to the Tile class? Even if they make a derived class of `Tile`, they can't override the use of the base Tile class in the Map class. In cases like this, it would be useful to allow the client program to determine the type for some objects. For it to work with types defined in the client software code, the client software will also need a way to give it access to a module of the client software. I know that D has something called compile-time function evaluation, but I don't know the full capabilities.
Re: Error when using `import`.
There's something that I'm trying to do that D may or may not be capable of. In the Map class, there is a 2-dimensional array called `grid`, where the Tile objects are stored. The Mission class inherits the Map class. In the Mission class, I want the `grid` array to instead be composed of a derivative of the Tile class. I tried making a derived class called `GridTile` which contains the additional property specific to the Raylib front-end. I tried doing this, but it won't let me override `grid`, even if I change it from `private` to `protected` in the Map class. Is there a way I can do this, without this additional functionality being put in the base Tile class?
Re: Error when using `import`.
I have made some progress on this. For the raylib front-end, I tried making a class called `Mission` which inherits `Map`. This class handles the graphics, input, and other game events. The program now compiles without errors, and there are some graphics. I have pushed these updates to the GitHub repository. https://github.com/LiamM32/Open_Emblem Currently, it just displays a map of grass tiles with one unit. Clicking on the unit causes a segmentation fault. There is something that's supposed to happen when clicked, but I don't know why it segfaults. The line where it segfaults appears to be roughly `oe-raylib/source/mission.d:125`. I am continuing to work on this, but have been getting more strange runtime errors since the latest push.
Re: Error when using `import`.
I now have the Raylib functions working by using `toStrinz`. I pushed some updates to the repository. I made the main project a source library so that I can experiment with different graphics library front-ends. I put have the front-end using Raylib in the `raylib_frontend` directory. It doesn't yet have any interactivity, but it should build and run successfully IIRC. I don't know how best to organize the code. So far I have been putting the loop that runs during gameplay in the `Mission` function in `mission.d`. This function contains the arrays where sprites are stored. The code for unloading data from files is split between this function and `maps.d`. I was going to have a file in the main `source/` (not `raylib_frontend/source`) called `loadData.d` which would handle unloading from files, but then I realized that those functions would need write access to multiple variables, making it a not very tidy approach. One possibility is to turn `Mission` into a class. The Mission object would control the Map object and other things during gameplay. The other possibility is to make a derived class of Map with more graphics-related functionality and more.
Re: Error when using `import`.
There's something very strange going on when using Raylib-D. I tried using the raylib function `LoadTexture` like this: ``` tileSprites[i] = LoadTexture("../sprites/" ~ spriteName); ``` I got the following error: ``` Error: function `raylib.LoadTexture(const(char)* fileName)` is not callable using argument types `(string)` ``` So it's not allowing me to use a D string, but wants me to use (what I believe to be) the archaic C-style string. Here is how this function, as well as `DrawText` is declared in the Raylib-D bindings: ``` void DrawText(const(char)* text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) Texture2D LoadTexture(const(char)* fileName); // Load texture from file into GPU memory (VRAM) ``` The weird thing is that both of these functions are declared only once and with these C-style strings as arguments, yet I have already successfully called `DrawText` using a D string, yet `Texture2D` results in an error. ``` DrawText("Open Emblem", 180, 300, 64, Colors.RAYWHITE); ``` So why is it that one of these functions, but not the other is allowing D strings in place of C-style strings?
Array types and index types
In D, it appears that dynamic arrays (at least by default) use a ulong as their key type. They are declared like this: ``` string[] dynamicArray; ``` I imagine that using a 64-bit value as the key would be slower than using 32 bits or 16 bits, and 64 bits is way overkill for nearly everything. However, if I declare the array as `string[uint] myArray;` or `string[ushort] myArray`, it's treated as an associative array. This means that I don't get to do the things I want to do with a dynamic array, such as appending. So I have some questions: Is there a way to declare a dynamic array with a uint, ushort, or ubyte key? If there was, would it really be faster? Is an associative array with a ushort key faster than a dynamic array with a ulong key?
Re: Error when using `import`.
On Tuesday, 27 February 2024 at 03:43:56 UTC, Liam McGillivray wrote: Raylib looks promising. I installed it along with your Raylib-d. I managed to build the example you provided with dub, but trying to use it in it's own dub project in a separate directory isn't working. Just copying and pasting `app.d` from the very example you provided results in a huge wall of errors, mostly "undefined reference to [some function]". Nevermind this. I just needed to add `libs "raylib"` to dub.sdl. I didn't think I would need to specify the libraries in the project when they are accessed through an external library. Now I know. Looking at the code examples on the Raylib and SFML website, they look similar in complexity of getting started, but I like it that the Raylib website has lots of simple demonstration programs on the website with the code provided. This is a great way to help with learning. https://www.raylib.com/examples.html So far it's been working when I try to do their C++ examples in D.
Re: Error when using `import`.
On Tuesday, 27 February 2024 at 03:06:19 UTC, Steven Schveighoffer wrote: If you are going for game development, I would recommend raylib-d (https://code.dlang.org/packages/raylib-d), which is my wrapper around the very good raylib library. For doing GUI, raygui is supported, but I also can say I've seen some good things from fluid: https://code.dlang.org/packages/fluid -Steve Raylib looks promising. I installed it along with your Raylib-d. I managed to build the example you provided with dub, but trying to use it in it's own dub project in a separate directory isn't working. Just copying and pasting `app.d` from the very example you provided results in a huge wall of errors, mostly "undefined reference to [some function]".
Re: Error when using `import`.
I don't know whether I should continue this topic or start a new one now that the problem mentioned in the title is fixed. I have now uploaded some of the code to [a GitHub repository](https://github.com/LiamM32/Open_Emblem). To make this game usable, I will need a library for graphics and input. I don't have any experience with making GUI programs aside from a little bit with Qt and C++. I have considered the following libraries: - ~~SDL~~: Seems too low-level for me. - Allegro via [DAllegro5](https://github.com/SiegeLord/DAllegro5): I found some C & C++ tutorials for this one, but I don't know how I would do it with D. This one looks difficult. - ~~Imgui via [Dimgui](https://github.com/d-gamedev-team/dimgui)~~: While [Imgui](https://github.com/ocornut/imgui?tab=readme-ov-file) looks well-developed, the Dimgui readme links to [this repository](https://github.com/AdrienHerubel/imgui), which looks like a very old version of Imgui. - Godot via [Godot-Dlang](https://github.com/godot-dlang/godot-dlang?tab=readme-ov-file#manually-creating-project): A well-developed game engine with an editor that may allow me to get fancier graphics without a huge amount of effort. However, the project page for Godot-Dlang gives a warning that it's unfinished. This may or may not be a problem given that this is just a hobby project. I would be happy to share any problems with the developers. - SFML via [BindBC-SFML](https://github.com/BindBC/bindbc-sfml): SFML appears to be an easier way to get 2D graphics working compared to SDL & Allegro when using C++. However, it may take more effort to use it with D. - [AE](https://github.com/CyberShadow/ae): This is a D library that provides graphics and other utilities using various C libraries. I am beginning to understand this one, as I've been looking at the provided demos. However, this one seems to SDL functions directly whenever an image is placed on-screen, which I don't understand the theory behind. I have writing the code for the internal game logic as a library that can be used by various front-ends for graphics. This would let me experiment with different software for graphics, but it would make the code more complicated. So far I have been attempting to get it working with AE for graphics, not using the library approach described above. I haven't committed it with git, as I have copied and pasted substantial code from the AE examples and I will need to look at the license before I share it. I have managed to get it to read a PNG using libpng, but not display it. I have had trouble with this. One of the demos uses a function `s.draw` for displaying an image, which isn't defined anywhere in AE, so it might be an SDL function. I don't know how it has access to it. I chose to use D for this project because I have long wanted to learn the language, but I wonder if it's overkill for this project, given the low performance requirement. Maybe I would be better-off using a dynamic interpreted language. The benefit of D is largely for the learning experience.
Re: Error when using `import`.
On Sunday, 25 February 2024 at 03:23:03 UTC, Paul Backus wrote: You can't give a class the same name as the file it's in. If you do, then when you try to use it from another file, the compiler will get confused and think you're referring to the file instead of the class (that's what "import is used as a type" means). Thank you. In PHP, I was told to put every class definition in a file of the same name (whether I like it or not). However, I actually now have it working *without* having done that. Both the file name and the class name are capitalized, and it's working. However, maybe that's because they each start with a `module` line that makes the module name lowercase. I will keep this in mind, and maybe rename the files.
Re: Error when using `import`.
On Saturday, 24 February 2024 at 10:34:25 UTC, Richard (Rikki) Andrew Cattermole wrote: A few things. Module names should be lower case. I capitalised the first letter in the class names so that I can make instances of them in lowercase. Should I rename the classes, modules, and filenames to all be lowercase? It appears to be solved now after adding module declarations to the beginning of each file in all-lowercase. This is despite the classes and the class names still being capitalized. I'm still getting errors, but they appear to be unrelated. Thank you.
Error when using `import`.
I am trying to make a tactical role-playing game which I am likely to open-source. Right now the code is very simple, with only 3 files each containing a class with the same name. The files are `Map.d`, `Tile.d`, and `Unit.d`. Each of these files contains an `import` line to access one of the others. I got the following errors when trying to compile all 3 files with DMD, and the same errors after switching to DUB. ``` source/Unit.d(6,17): Error: import `Unit.Map` is used as a type source/Unit.d(16,5): Error: import `Unit.Map` is used as a type source/Tile.d(9,15): Error: import `Tile.Unit` is used as a type source/Map.d(6,22): Error: import `Map.Tile` is used as a type source/Map.d(19,11): Error: import `Map.Tile` is used as a type ``` I thought that the circular chain of imports may be the problem, but removing all references to `Unit` in `Tile.d` did not fix the problem. Here are the contents of Tile.d: ``` import Unit; class Tile { private bool allowStand = true; private bool allowFly = true; public int stickyness = 0; public Unit* occupant; bool allowUnit(bool isFlyer) { if (isFlyer) return this.allowFly; else return this.allowStand; } } ``` `Unit.d` & `Map.d` are longer files. `Map.d` begins with `import Tile;`, and `Unit.d` begins with `import Map;`. Why are the errors happening? What's the problem? Why is it `currentclass.importedclass` instead of simply the imported class?