Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Telarra
Oct 9, 2012

Ihmemies posted:

Well thanks. I have never ever seen colors being defined as floats between 0.0...1.0 anywhere before :D But I guess it makes sense in some way. Seems I have to use Color8(200, 150, 45) if I want to use human-readable formats without breaking out the pocket calculator or doing stupid poo poo like 1/255*200 when defining colors.

Edit: also learning C# would help to get rid of this annoying editor in Godot which is extremely barebones. With C# I could just use VSC or something modern instead. This doesn't even have splitscreen?!

If you're wanting to use VS Code, just grab the godot-tools extension for gdscript support, and set it up as an external editor in godot: https://docs.godotengine.org/en/stable/tutorials/editor/external_editor.html

Adbot
ADBOT LOVES YOU

Ihmemies
Oct 6, 2012

Telarra posted:

If you're wanting to use VS Code, just grab the godot-tools extension for gdscript support, and set it up as an external editor in godot: https://docs.godotengine.org/en/stable/tutorials/editor/external_editor.html

But it was updated quite long time ago. I started this project on 5th of Feb with godot4 beta17, and recently upgraded to rc1. I did not see point in learning to use the old version, since so much stuff has changed in 4, and it's release is imminent. Does the extension support godot 4, hmm? Maybe I could try it out.

Next I'm wondering how to clamp camera2d's position. I currently use this to move the camera with mouse:

Python code:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:		
	if !is_panning_camera and event.pressed:
		is_panning_camera = true
	if is_panning_camera and !event.pressed:
		is_panning_camera = false

if event is InputEventMouseMotion and is_panning_camera:
	self.position -= event.relative * Globals.CAMERA_PAN_MULTI
I can limit the camera viewport with this:

Python code:
func _on_main_worldgen_ready() -> void:
	# set camera bounds to map size, with chunk_in_px room to go over
	var chunk_in_px:Vector2i = Vector2i(Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X, Globals.CHUNK_SIZE.y*Globals.TILE_SIZE_Y)
	
	self.set_limit(SIDE_LEFT, -chunk_in_px.x)
	self.set_limit(SIDE_RIGHT, Globals.map_size*Globals.TILE_SIZE_X + chunk_in_px.x)
	self.set_limit(SIDE_TOP, -chunk_in_px.y)
	self.set_limit(SIDE_BOTTOM, Globals.map_size*Globals.TILE_SIZE_Y + chunk_in_px.y)	
But the actual self.position is allowed to go as far beyond the limits as the user wants to :sigh:

I thought about clamping the self.position somehow in Camera2d but maybe my way of moving the camera isn't the supposed to way to move the camera...

Edit: apparently at least by clamping the position after setting it.. not great, but as far as other spaghetti in my code is considered, not terrible..

Python code:
self.position.x = clamp(
	self.position.x,
	chunk_in_px.x, 
	Globals.map_size*Globals.TILE_SIZE_X - chunk_in_px.x
	);
self.position.y = clamp(
	self.position.y,
	0,
	Globals.map_size*Globals.TILE_SIZE_Y
	);

Ihmemies fucked around with this message at 19:19 on Feb 14, 2023

Raenir Salazar
Nov 5, 2010

College Slice
Okay time to fix the issue that my default Blender install is still 2.79.

Raenir Salazar
Nov 5, 2010

College Slice
Double post but, this is weird.

code:
    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        FVector vertex, normal;
        // process vertex positions, normals and UVs
        vertex.X = mesh->mVertices*.x;
        vertex.Y = mesh->mVertices*.y;
        vertex.Z = mesh->mVertices*.z;

        normal.X = mesh->mNormals*.x;
        normal.Y = mesh->mNormals*.y;
        normal.Z = mesh->mNormals*.z;

        // if the mesh contains tex coords
        if (mesh->mTextureCoords[0]) {
            FVector2D uvs;
            uvs.X = mesh->mTextureCoords[0]*.x;
            uvs.Y = mesh->mTextureCoords[0]*.y;
            _uvs[_meshCurrentlyProcessed].Add(uvs);
        }
        else {
            _uvs[_meshCurrentlyProcessed].Add(FVector2D(0.f, 0.f));
        }
        _vertices[_meshCurrentlyProcessed].Add(vertex);
        _normals[_meshCurrentlyProcessed].Add(normal);
    }
I don't recall C++ having semantics like this and Visual Studio 2019 for sure throws a fit. Was this an actual thing at some point? Look at the stars.

jizzy sillage
Aug 13, 2006

Looks fuckin' whack to me. Are they trying to dereference mVertices?

Raenir Salazar
Nov 5, 2010

College Slice

jizzy sillage posted:

Looks fuckin' whack to me. Are they trying to dereference mVertices?

Yeah its weird I have no idea why the original poster did it like that.

mVertices is defined in ASSIMP as:

code:
C_STRUCT aiVector3D *mVertices;
So clearly mVertices is an array of aiVector3D's.

And in the context of the for-loop is clear we're iterating through mVertices.

Lowen
Mar 16, 2007

Adorable.

Raenir Salazar posted:

Double post but, this is weird.

code:
    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        FVector vertex, normal;
        // process vertex positions, normals and UVs
        vertex.X = mesh->mVertices*.x;
        vertex.Y = mesh->mVertices*.y;
        vertex.Z = mesh->mVertices*.z;

        normal.X = mesh->mNormals*.x;
        normal.Y = mesh->mNormals*.y;
        normal.Z = mesh->mNormals*.z;

        // if the mesh contains tex coords
        if (mesh->mTextureCoords[0]) {
            FVector2D uvs;
            uvs.X = mesh->mTextureCoords[0]*.x;
            uvs.Y = mesh->mTextureCoords[0]*.y;
            _uvs[_meshCurrentlyProcessed].Add(uvs);
        }
        else {
            _uvs[_meshCurrentlyProcessed].Add(FVector2D(0.f, 0.f));
        }
        _vertices[_meshCurrentlyProcessed].Add(vertex);
        _normals[_meshCurrentlyProcessed].Add(normal);
    }
I don't recall C++ having semantics like this and Visual Studio 2019 for sure throws a fit. Was this an actual thing at some point? Look at the stars.

I wonder if it's supposed to be .* rather than *.?
edit: also why are the first lines like
vertex.X = mesh->mVertices*.x;
and not something like
vertex.X = mesh->mVertices[i]*.x;
Seems like the index should get used there, I don't see any way this would advance past the first element otherwise.

Lowen fucked around with this message at 04:09 on Feb 15, 2023

Ranzear
Jul 25, 2013

Maybe it's some jank/kludge to get swizzling to work? Or would that work by default?

Lowen
Mar 16, 2007

Adorable.

Raenir Salazar posted:

Double post but, this is weird.

code:
    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        FVector vertex, normal;
        // process vertex positions, normals and UVs
        vertex.X = mesh->mVertices*.x;
        vertex.Y = mesh->mVertices*.y;
        vertex.Z = mesh->mVertices*.z;

        normal.X = mesh->mNormals*.x;
        normal.Y = mesh->mNormals*.y;
        normal.Z = mesh->mNormals*.z;

        // if the mesh contains tex coords
        if (mesh->mTextureCoords[0]) {
            FVector2D uvs;
            uvs.X = mesh->mTextureCoords[0]*.x;
            uvs.Y = mesh->mTextureCoords[0]*.y;
            _uvs[_meshCurrentlyProcessed].Add(uvs);
        }
        else {
            _uvs[_meshCurrentlyProcessed].Add(FVector2D(0.f, 0.f));
        }
        _vertices[_meshCurrentlyProcessed].Add(vertex);
        _normals[_meshCurrentlyProcessed].Add(normal);
    }
I don't recall C++ having semantics like this and Visual Studio 2019 for sure throws a fit. Was this an actual thing at some point? Look at the stars.

You successfully nerd sniped me, I have an old openGL engine project that used assimp, which I can confirm works to this day.
I was just looking through it and I actually have a really similar for loop. No weird *.'s or .*'s though!
I don't know if mine is being used for the same purpose as yours, but it might be useful to untangle the pointer access semantics:

code:
...
    const aiMesh* mesh = m_scene->mMeshes[meshNum];
...
    // go through all vertexes
    for (unsigned i = 0; i < mesh->mNumVertices; ++i)
    {
            vertexBuffer.loadFloats (&mesh->mVertices[i].x, 3);
            vertexBuffer.loadFloats (&mesh->mNormals[i].x, 3);
            if (mesh->HasTextureCoords (0))
            {
                vertexBuffer.loadFloats (&mesh->mTextureCoords[0][i].x, 2);
            }
            else
            {
                float data[2] {0.f, 0.f};
                vertexBuffer.loadFloats (data, 2);
            }
    }
...
VertexBuffer::loadFloats (const float* data, int numFloats)
...

Raenir Salazar
Nov 5, 2010

College Slice

Lowen posted:

You successfully nerd sniped me,

Hahaha. :getin:

quote:

I have an old openGL engine project that used assimp, which I can confirm works to this day.
I was just looking through it and I actually have a really similar for loop. No weird *.'s or .*'s though!
I don't know if mine is being used for the same purpose as yours, but it might be useful to untangle the pointer access semantics:

code:
...
    const aiMesh* mesh = m_scene->mMeshes[meshNum];
...
    // go through all vertexes
    for (unsigned i = 0; i < mesh->mNumVertices; ++i)
    {
            vertexBuffer.loadFloats (&mesh->mVertices[i].x, 3);
            vertexBuffer.loadFloats (&mesh->mNormals[i].x, 3);
            if (mesh->HasTextureCoords (0))
            {
                vertexBuffer.loadFloats (&mesh->mTextureCoords[0][i].x, 2);
            }
            else
            {
                float data[2] {0.f, 0.f};
                vertexBuffer.loadFloats (data, 2);
            }
    }
...
VertexBuffer::loadFloats (const float* data, int numFloats)
...

Yup thanks for checking! As far as I can tell everything works fine on my end doing the same thing basically you did, I substituted '[ i]' where the weird "*"'s were and everything more or less worked fine.

Except for my Procedural Mesh disappearing after I adjusted the Scale, which was weird, I recalculated normals in Blender and re-exported the FBX, also boosted the base-scaling when exporting to 100 to match Unreal units and now it seems to be working fine. I am also not sure if being in Construction Script instead of Begin Play made any difference either.

One thing I'm not sure about though regarding Assimp is that it generally seems to be referencing Faces which seems like it could either be Quads/NGONs or Triangles depending on how I export the model? Is this correct?

Lowen
Mar 16, 2007

Adorable.

Raenir Salazar posted:

Hahaha. :getin:

Yup thanks for checking! As far as I can tell everything works fine on my end doing the same thing basically you did, I substituted '[ i]' where the weird "*"'s were and everything more or less worked fine.

Except for my Procedural Mesh disappearing after I adjusted the Scale, which was weird, I recalculated normals in Blender and re-exported the FBX, also boosted the base-scaling when exporting to 100 to match Unreal units and now it seems to be working fine. I am also not sure if being in Construction Script instead of Begin Play made any difference either.

One thing I'm not sure about though regarding Assimp is that it generally seems to be referencing Faces which seems like it could either be Quads/NGONs or Triangles depending on how I export the model? Is this correct?

Yeah - I don't know if you have a comparable line in your code, but I'm using assimp to load entire model files starting via this line:
code:
m_scene = m_importer.ReadFile (fileName, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices);
So, the aiProcess_Triangulate option takes care of that and I can just assume every face is a triangle after that point.
(m_importer is type Assimp::Importer via #include <assimp/Importer.hpp> )

more falafel please
Feb 26, 2005

forums poster

IIRC from when I cared a lot more about the pedantic details of the standard, *foo and foo* are the same thing assuming it won't be parsed as the type pointer-to-foo.

That said, that's dumb as hell. Is that in UE4/5 source? whoops, saw FVector and assumed things

more falafel please fucked around with this message at 06:46 on Feb 15, 2023

Dr Jankenstein
Aug 6, 2009

Hold the newsreader's nose squarely, waiter, or friendly milk will countermand my trousers.
Ok, so I stepped back to do an easier project, and I'm doing a little breakout clone also to play with shadergraph cause ooooh pretty. But mostly to force myself to get comfortable offloading everything to separate objects, and well, I've hit a weird snag. I have a script to spawn a power up, and basically it uses a coroutine to change the material, and then after 5 seconds change it back. Only whenever I reload after, say, a game over, it spawns multiple objects with the power up material applied. The only thing I can think of is I missed something with how unity handles coroutines and how they work with scene loads. but at this point, I have tried just a plain reload, a reload where I'm nuking the layout and rebuilding it, I've tried putting something in the script for the bricks themselves that sets the material in Start(), and I keep getting a nice fibonnaci sequence of bricks with the wrong material, so i know it's something about how I'm dealing with this coroutine that is causing it.

Like I know I did something to make it persist through a load, even though its script isnt marked Dontdestroyonload, and the game object the script is attached to does destroy and reinstantiate every time i load.

so how tf do you get a debugger to work in Unity when you don't use VS? I fell in love with sublime text when i was running a 1st gen i5, since like, it would actually *run* and every tutorial i can find about how to get debugging to work involves using VS. I know enough to know a debugger would be helpful, as i could see what is acting on what to make it do that, but I cant figure out how to make one work because everything assumes you're using VS.

Dr Jankenstein fucked around with this message at 10:17 on Feb 15, 2023

Ihmemies
Oct 6, 2012

Any pro tips on how to move 2d camera x,y coords to "correct" direction despite camera rotation?

If camera rotation is 0, self.position -= event.relative * Globals.CAMERA_PAN_MULTI works.

If camera is rotated, it stops working. If camera is rotated 180 degrees, camera will now move to the opposite direction. Chatgpt suggested vectors and trigonometry, but don't really understand vectors and trigonometry.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Take your mouse event vector, and rotate it by the camera rotation?

Ihmemies
Oct 6, 2012

Jabor posted:

Take your mouse event vector, and rotate it by the camera rotation?

I can just rotate vectors?:aaaaa: Uh Hmm that is worth trying, thanks!

Edit: this worked :cool:

Python code:
self.position -= event.relative.rotated(self.rotation) * Globals.CAMERA_PAN_MULTI
Edit: next step is to wonder how to divide a 2D array cells to roughly rectangular shapes. Then I need to add the corner coords to a packedvector2array, and use draw_polylines to draw the shapes on screen. I have never done anything like this and hnngh.

Aim is to divide the map to umm, cadastres? parcels? https://en.wikipedia.org/wiki/Cadastre#Parcel and show the divisions on screen.

Hopefully it won't matter too much that basically all the lines will overlap with each others... From the x,y coordinate data, maybe it could be possible to calculate only a list of lines required to draw the grid.

Ihmemies fucked around with this message at 19:28 on Feb 15, 2023

Raenir Salazar
Nov 5, 2010

College Slice
Going through our code at work and my feathers are ruffled.

It seems like we have several modules who in what I'll observe as "singletonly" acquiring dependencies at runtime at initialization. Except oh nyo, some of these dependencies don't exist as they don't take the load order into account!

To disentangle this problem it seems like I could set the modules that need to go before as predefault, or maybe create a new class whose job it is to point at two modules and yell at them to shake hands, and have it invoked by the Game Instance as it seems like it's guaranteed to exist after all the modules are finished being loaded by the engine?

e to add, by "Singletonly" here's an example.

code:
if (UGoonManager* GoonManager = UGoonManager::Get(GetWorld()) {
    // Do something with goons
}
We have a unique instance of the manager object which gets added into the modules reference map which manages the lifetime of the object there. I assume this is basically what the Singleton pattern describes and it is 90% of how our project works, every object that needs something from the current or another module just yoinks it like above. Life is pain.

Raenir Salazar fucked around with this message at 23:54 on Feb 17, 2023

BabelFish
Jul 20, 2013

Fallen Rib

Raenir Salazar posted:

Going through our code at work and my feathers are ruffled.

It seems like we have several modules who in what I'll observe as "singletonly" acquiring dependencies at runtime at initialization. Except oh nyo, some of these dependencies don't exist as they don't take the load order into account!

To disentangle this problem it seems like I could set the modules that need to go before as predefault, or maybe create a new class whose job it is to point at two modules and yell at them to shake hands, and have it invoked by the Game Instance as it seems like it's guaranteed to exist after all the modules are finished being loaded by the engine?

e to add, by "Singletonly" here's an example.

code:
if (UGoonManager* GoonManager = UGoonManager::Get(GetWorld()) {
    // Do something with goons
}
We have a unique instance of the manager object which gets added into the modules reference map which manages the lifetime of the object there. I assume this is basically what the Singleton pattern describes and it is 90% of how our project works, every object that needs something from the current or another module just yoinks it like above. Life is pain.

All these terms make me think you're in Unreal. Modules are really intended to have pre-defined dependencies in their build.cs file.

I think what you're actually looking for is subsystems?
https://docs.unrealengine.com/5.1/en-US/programming-subsystems-in-unreal-engine/
https://benui.ca/unreal/subsystem-singleton/

Raenir Salazar
Nov 5, 2010

College Slice
Yes and no, it's complicated. Yes we're in Unreal, and maybe subsystems are a thing, but it doesn't look like something we use. We seem to use something similar in principle to it, but doesn't use the actual Subsystem-system.

So yes Modules have their Build.cs and other Modules they need are included in the Build.cs because otherwise it would not even compile. I am using the term "Module" interchangeably with that what modules are used for is to collect together shared behaviours of the system. I.e a "Inventory" module has difference classes, behaviours, and systems from a "Travel" system. So In your project source folder there would be a "Travel" module folder and a "Inventory" module folder which have their Build.cs files and then a Travel.h file and a Inventory.h file which define the modules like FTravel and FInventory and they get loaded in their StartupModule() functions and do stuff extra stuff in their OnPostWorldInitialization methods and clean up.

So when I'm talking about being in the Goon module and needing something from the InternetSpaceships module I'm more specifically referring to working with some sort of class that inside a Folder Called Goon (that is also a Module) and it needs to access/reference a class that exists in a different folder called InternetSpaceships. Doing so then requires the steps of needing an include in the cpp file to that Manager class, and then the above boilerplate code to acquire a reference to the Manager class via singleton that basically I suppose acts as a glorified Mediator to the behaviour, service, data or whatever we want from that other module.

This is what I mean by a dependency, not that "the module" has a specific dependency, but that this class has a need for something that is a different class and the main way we currently go about acquiring that object is to zoink it.

Suppose we have an Inventory system/module and a separate Vehicle system/module. So what happens is sometimes you get a situation where maybe a Vehicle gets to have an inventory and now it needs to reference the InventoryManager. And so what we basically do with this hypothetical situation is we'd just zoink a reference to the InventoryManager via Singleton as indicated in my previous post. Which I strongly suspect is not best best practice. Because as I'm finding it, it's a pain to refactor it. Because how or even when a particular object gets initialized isn't clear at a glance.

So to recap, suppose a class like:

code:
UInventoryManager:
// Is a Singleton with a Get method
// Is in its own "Inventory" or Item module.
...


USpaceshipManager:
// is also a singleton class with a get, but both when they're loaded by their modules, need to Initialize...
    Function Init():
        // now we need something from Spaceship...
        UInventoryManager* MyInventoryManager = UInventoryManager::Get(GetWorld())
        // Ooops now I have no idea from the API of USpaceshipManager that it's doing this and also
        // no gaurantee that MyInventoryManager is a valid pointer if USpaceshipManager before UInventoryManager!
I'm mainly trying to look at this from a "What does software engineer principles tell me is bad and how should I fix it?" perspective, as there's probably some aspects of Unreal that probably aren't super relevant because its like a 5 year old project with a lot of technical debt.

Raenir Salazar fucked around with this message at 04:36 on Feb 18, 2023

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
If the Goon module needs to access a class from the InternetSpaceships module, then that's literally what is meant by "having a dependency on", and that dependency should be in the Build.cs file.

That way, the module dependency system will ensure that the InternetSpaceships module has been loaded and is ready to go before the Goon module loads and attempts to access classes from it.

Raenir Salazar
Nov 5, 2010

College Slice

Jabor posted:

If the Goon module needs to access a class from the InternetSpaceships module, then that's literally what is meant by "having a dependency on", and that dependency should be in the Build.cs file.

That way, the module dependency system will ensure that the InternetSpaceships module has been loaded and is ready to go before the Goon module loads and attempts to access classes from it.

So based on my experience and rereading the article and checking my own project I don't think that's what the Build.cs file does.

From the link:

quote:

You should use the PublicDependencyModuleNames list if you use the classes from a module publicly, such as in a public .h file. This will make it possible for other modules that depend on your module to include your header files without issues.

You should put a module's name in the PrivateDependencyModuleNames list if they are only used privately, such as in .cpp files. Private dependencies are preferred wherever possible, as they can reduce your project's compile times.

I am pretty sure all this is saying that if you don't want a compiler error when using classes from other modules in the current module either in the cpp file or the header; then you need to either add them to the public or private list of dependencies, it doesn't say anything about this affecting load order.

And I did mention earlier that the other modules were included, and I went and confirmed this, so unless I am missing something it would be unlikely for Build.cs to be the issue/solution here.

Lower down in the Controlling How Modules Load section the only thing it mentions is the LoadingPhase:

quote:

While the Default loading phase is suitable for most gameplay modules in your project, plugins sometimes need to load earlier. If you frequently see errors from Unreal Editor trying to find C++ classes in a plugin, try setting them to PreDefault.

Which I had discovered earlier but I think would be insufficient to fully fix the problem which is more due to bad design practices than a configuration issue.

jizzy sillage
Aug 13, 2006

Yeah that project sounds horrifying to work in. Introduce the team to the concept of delegates and event-based code and pray they don't make it worse while you disentangle the patch they've assigned you.

Raenir Salazar
Nov 5, 2010

College Slice
We do use events, just... Not as much as we should, is what I'll say.

In other news, my next assignment for my VR Game Dev class involves me finally using the Occulus Quest 2! Which the school provided me on a temporary basis.

Despite several immediate frustrations with the tech as a glasses wearer, I now once again really badly want my own VR Headset, I just find myself even in the dumb waiting room the console puts me in while its setting up and installing updates I'm really immersed. :smith:

I had once worked as a QA Tester on the Rift for some silly dumb fun frisby space robot game and I had a blast. I rammed my face head first multiple times into my own desk trying to catch the not even real frisby and I'd do it again! :black101:

Ihmemies
Oct 6, 2012

Umm yes. About patterns and communication. I had signals flying all around even altough I didn't really have features. It was a problem to tell to someone else that you must do something. I had _unhandled_input(event) listeners in a bunch of classes (moved them all to a single _unhandled_input in eventbus.

So uhh I refactored my game to something like this:



If player cliks a minimap, it sends a signal to eventbus. eventbus then does something like

Python code:
func _on_set_camera_position(pos:Vector2):
	node_camera.set_camera_position(pos)
I understood it might be called a https://en.wikipedia.org/wiki/Mediator_pattern. Is that OK or should I do something else?

I also managed to implement some parcels, the layer is toggled on/off from a button. I can now add easily a ton of other layers too.



The parcel division algorithm is extremely basic because I don't have the skills to do what I want to. Worldgen initially gives out some parcels to the city, and you can buy more later. Why operate in a 5x5 parcel grid like in Cities:skylines, when you can have so many more with current tech! :v:

Ihmemies fucked around with this message at 16:15 on Feb 18, 2023

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Ihmemies posted:

If player cliks a minimap, it sends a signal to eventbus. eventbus then does something like
I was so surprised that "broadcast signals" isn't an in-built thing that I looked it up, and yeah, it seems you have to do this yourself if you want that kind of behavior.

Though if it was me I would try to generalize it, so instead of eventbus having camera-specific operations in it (which is probably gonna be a lot of manual middleman functions), you'd do something like eventbus just has a map of string identifiers to functions, and on camera initialization you'd do eventbus.subscribe("set_camera_pos", self.set_camera_pos), and when you click on the map you'd do eventbus.notify("set_camera_pos", x, y), which causes eventbus to call each of the subscribed functions with the given params.

Ihmemies
Oct 6, 2012

roomforthetuna posted:

I was so surprised that "broadcast signals" isn't an in-built thing that I looked it up, and yeah, it seems you have to do this yourself if you want that kind of behavior.

Apparently no. So not "everyone" knows if a signal was sent. The signal must be directed specifically to some node/class it seems.

quote:

Though if it was me I would try to generalize it, so instead of eventbus having camera-specific operations in it (which is probably gonna be a lot of manual middleman functions), you'd do something like eventbus just has a map of string identifiers to functions, and on camera initialization you'd do eventbus.subscribe("set_camera_pos", self.set_camera_pos), and when you click on the map you'd do eventbus.notify("set_camera_pos", x, y), which causes eventbus to call each of the subscribed functions with the given params.

Thanks. I'll try to understand that and try it.

What if Camera zoom changes, and Minimap's CameraMarker needs to adjust its size? Previously I had the camera send a signal straight to the cameramarker. If I use some kind of middleman, the camera sends the info to the eventbus. But does the bus tell about it to UILayer? MiniMap? Straight to the CameraMarker?!? so direct child, child of child, child of child of child... ? :v:

Maybe I'll just scrap the whole idea and send direct signals from camera to cameramarker?!?? The bad thing about it is that if other stuff than just the camera marker has to be rotated too, like if I'm placing a building and the player wants to rotate the camera - the placement indicator must rotate too, I guess.. maybe I could just send a bunch of separate signals to a bunch of classes straight from the camera and uhh yes

Please send help. :shepicide:

Ihmemies fucked around with this message at 16:48 on Feb 18, 2023

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Ihmemies posted:

What if Camera zoom changes, and Minimap's CameraMarker needs to adjust its size? Previously I had the camera send a signal straight to the cameramarker. If I use some kind of middleman, the camera sends the info to the eventbus. But does the bus tell about it to UILayer? MiniMap? Straight to the CameraMarker?!? so direct child, child of child, child of child of child... ? :v:
The bus would tell about it to any class that had called eventbus.subscribe(that function). That's what's nice about doing it with a generic thing, the eventbus no longer needs to know anything about anything - the client classes call subscribe if they want to hear about an event, and broadcast/trigger/whatever if they want to trigger an event. You'd need to include unsubscribe as well probably, so when you destroy a thing you don't leave dangling callbacks.

I'm not sure if gdscript supports capturing lambdas with unknown numbers of parameters like python kwargs - if not then you might have to wrap params in a class.

Catgirl Al Capone
Dec 15, 2007

Ihmemies posted:

Umm yes. About patterns and communication. I had signals flying all around even altough I didn't really have features. It was a problem to tell to someone else that you must do something. I had _unhandled_input(event) listeners in a bunch of classes (moved them all to a single _unhandled_input in eventbus.

So uhh I refactored my game to something like this:



If player cliks a minimap, it sends a signal to eventbus. eventbus then does something like

Python code:
func _on_set_camera_position(pos:Vector2):
	node_camera.set_camera_position(pos)
I understood it might be called a https://en.wikipedia.org/wiki/Mediator_pattern. Is that OK or should I do something else?

I also managed to implement some parcels, the layer is toggled on/off from a button. I can now add easily a ton of other layers too.



The parcel division algorithm is extremely basic because I don't have the skills to do what I want to. Worldgen initially gives out some parcels to the city, and you can buy more later. Why operate in a 5x5 parcel grid like in Cities:skylines, when you can have so many more with current tech! :v:

if your signals are connected to a lot of listeners you might be better off doing a group call instead. if you send out a group call neither party has to know the other exists

Ihmemies
Oct 6, 2012

Thanks! I need to research about what you said, and try to understand the concept of what you said better. Currently I have no idea, but hopefully with time also understanding comes.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Catgirl Al Capone posted:

if your signals are connected to a lot of listeners you might be better off doing a group call instead. if you send out a group call neither party has to know the other exists
I looked at that for being more like the broadcast concept, but then it looked like something that might be more expensive than the subscribe/broadcast helper model. But now I say it in that context, maybe the group thing literally *is* the subscribe model, where when an entity with a group property is created it registers itself in the appropriate list.

In which case yeah that seems like the thing, done right, for no effort. (https://godotengine.org/qa/64965/call-a-function-with-a-variable-for-every-member-of-a-group has simple examples of the code, and setting it up is as simple as Node.add_to_group() and Node.remove_from_group() *or* adding the group on the Node dock in the editor.)

If you want to do it on an "interested in particular things" basis (which I would recommend), you'd just have groups with names like "camera_zoom_listeners" instead of "guards".

(I'm concerned for performance because call_group is a member of tree, which makes me think it might be walking the entire node tree beneath that point checking for members of the group, rather than having a map of subscribers. Also note, call_group will only hit at the next frame, so if you want instant calls like my version would have done, you want call_group_flags with GROUP_CALL_REALTIME).

roomforthetuna fucked around with this message at 18:24 on Feb 18, 2023

Ihmemies
Oct 6, 2012

Thanks. Perhaps now I understand. I can add members to a group, and with one call_group I can call the group members methods in one go. Seems nice!

So I should not send a signal at all, just call the group directly from camera node, without middlemen?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Ihmemies posted:

Thanks. Perhaps now I understand. I can add members to a group, and with one call_group I can call the group members methods in one go. Seems nice!

So I should not send a signal at all, just call the group directly from camera node, without middlemen?
Right, call_group is unrelated to signals, you don't need to even create a signal if you're doing it this way, it's just going to call by function name.

Ihmemies
Oct 6, 2012

🫡 maybe that is a decent way to do stuff. It is hard to figure these out, so many options and I don't even know about them 😁

Now I'm really out of excuses, I need to implement road placement now. Well three guys coded the whole game in 1993 (simcity 2000) and even it had diagonal roads..

And click and point roads. Click 1 point, game shows you an overlay between mouse cursor and the point you clicked, and autobuilds road there.

And they had isometric gfx, full terrain modification and all that, 30 years ago. Welll.

Ihmemies fucked around with this message at 20:09 on Feb 18, 2023

Bronze Fonz
Feb 14, 2019




Just participated in my first ever game jam. I might've just lost a few years of life expectancy from the final night of frantic coding but what a trip this was... cannot wait for the next one just maybe not this next weekend!

The 48th GameMaker Community game jam's theme was "glitches & bugs". :stare:

I've been working on a game for a couple of months now that involves a lot, and I mean a lot of GUI stuff in "pseudoretro" style and when I saw the theme... well, once I got over the excitement of being able to use all that GUI (very recent) experience remained the question of what the hell do you do with "glitches and bugs"... so I went with this:


quote:

After all this time suffering through crashOS 95 on your workstation, the sysadmin is finally about to upgrade you to crashOS XT!
Until that happens, exactly 2 minutes from now, can you accumulate enough glitches and bugs to reach a blue screen of death?


Break each program/feature to render the system unstable enough to reach your goal!
DOWNLOAD
24.7 mb (Windows only)
System requirements: should run on a 1955 tube radio provided it can handle very basic shaders

Interface is mouse-driven except when presented with a command-line interface so don't waste your time trying out weird keyboard stuff or ALT-F4, I'm not playing with you like that.
Just try to break the app/feature/thingy with what it shouldn't handle? Each app gives you a hint on how it can be broken...

Solutions for each app:

Calc: divide by zero
Note: text selection with mouse
Console: help, flopoff, root
Config: there are 2 (randomly chosen) settings that must be activated at the same time
NetOS: refresh 5 times
Skydie: avoid all the coins to die
Color/theme: drag to trash bin


Code and assets by me except for the config icon (Tango icons), cloud gif in title BG (Wikicommons) and the shader script used for the glitches (Odditica's bktglitch GML shader FX)
CC0/public domain sound effects via Freesound.org, music sourced via FreeMusicArchive
Voice of Floppy made with the amazing Murf.ai, voice of "Ken" with conversational and angry settings


The 2 minute timer (displayed as the clock in your taskbar) is active while in the OS itself and while playing Skydie, inactive during reboots.

Bronze Fonz fucked around with this message at 23:26 on Feb 21, 2023

Raenir Salazar
Nov 5, 2010

College Slice
Nice job! Reminds me of when my job used to be making CTFs for Hackathons...

Anyone else try using chatgpt for thinking about problems that are hard to google? I've been doing things like describing my use case/scenario and get back an answer that gives me an idea of what to focus my time on further researching.

"oh mirror mirror on the wall, which design pattern deals best with having a lot of setters for providing dependent objects to a class of them all?"

And the chat ai will be like, "I dunno why you're talking like that but I think you want the builder pattern."

Mr Shiny Pants
Nov 12, 2012

roomforthetuna posted:

The bus would tell about it to any class that had called eventbus.subscribe(that function). That's what's nice about doing it with a generic thing, the eventbus no longer needs to know anything about anything - the client classes call subscribe if they want to hear about an event, and broadcast/trigger/whatever if they want to trigger an event. You'd need to include unsubscribe as well probably, so when you destroy a thing you don't leave dangling callbacks.

I'm not sure if gdscript supports capturing lambdas with unknown numbers of parameters like python kwargs - if not then you might have to wrap params in a class.

Now you have just recreated the original situation: if someone does not subscribe to the bus it doesn't get executed. Now with an extra layer of complexity (the bus).

I agree in theory, but what does it solve pragmatically? Yes you don't have dangling callbacks, but are those such a big problem you need another layer of abstraction?

I am genuinely curious.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The big upside is that the things listening for events do not need to have a direct link to the things creating events. This is especially useful when the things that create events might have their own lifecycle that is independent from the things that listen for events.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Mr Shiny Pants posted:

Now you have just recreated the original situation: if someone does not subscribe to the bus it doesn't get executed. Now with an extra layer of complexity (the bus).

I agree in theory, but what does it solve pragmatically? Yes you don't have dangling callbacks, but are those such a big problem you need another layer of abstraction?

I am genuinely curious.

Callers don't need to know about callees. Callees don't need to know about callers.

The separation is most useful on large projects where separate teams might be responsible for the different halves.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

leper khan posted:

Callers don't need to know about callees. Callees don't need to know about callers.

The separation is most useful on large projects where separate teams might be responsible for the different halves.
I think the separation is useful a lot more than that. If you have, e.g. ball objects that make a noise, and guard objects that react to a noise, if you do direct subscriber things then whenever you create another guard or a ball you have to search the whole object tree for instances of the other type to subscribe to/from, and it gets even worse if there are more types of things that make noises and more types of things that respond to noises.

The fact that nothing happens if nobody subscribes isn't a *flaw* in the event-bus model, it's a feature - if there are no guards then making a noise shouldn't do anything.

Adbot
ADBOT LOVES YOU

MightyBigMinus
Jan 26, 2020

hi thread, i'm looking into using a game engine for 3d data visualizations in a vr headset. i can find infinity info on the graphical aspects of that, but what i'm having more trouble researching is the interaction with apis to pull that data into multi-player environments. like, say you and I are both wearing headsets and in the same level/map/room, and I want to show you some object/graph/whatever, I open up my menu and select something from it, a.) how do you wire that thing to then go fetch from some rest api on the internet and b.) when the data that api providers changes, how would you subscribe to that event and update the in-game object in such a way that both players see it?

in a way its kinda like a bot i think. how do you wire a two-way interactive bot that effectively proxies some api data into your multi-player/live game environment (say http/rest api one way and like eventbridge or kafka as the other way). is one particular engine & tools-ecosystem better at this kind of thing?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply