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
the holy poopacy
May 16, 2009

hey! check this out
Fun Shoe
Pirates! is the most iconic example and it does have a certain amount of fruitless circling, but it did have some countermeasures:

-Winds randomly changed direction and strength, which could make continued circling difficult or impossible
-Enemy ships usually had different capabilities and objectives, so true mirror matches were rare and usually one ship would not be able to keep up with the other
-Broadsides were pretty devastating, and there was a lot of incentive to finish with boarding actions, so cannon duels were more of a brief softening up phase

Adbot
ADBOT LOVES YOU

Maxwell Lord
Dec 12, 2008

I am drowning.
There is no sign of land.
You are coming down with me, hand in unlovable hand.

And I hope you die.

I hope we both die.


:smith:

Grimey Drawer
Yeah that’s an interesting design challenge and while it’s nothing to do with my current game it is an idea I’ve had for fooling around with a Star Trek like thing. (Star Trek Online has a number of gameplay issues and I wonder if I could render something like its ship combat but in 2d and flowing better.)

In the meantime I’m working on computers- specifically as a thing in an espionage roguelike. Mechanically they can do two things- give XP rewards for accessing secret files, and let the player do things in the level. Reveal parts of the map, reveal traps, set off traps where enemies are, etc. (This may be tricky since normally the enemies don’t exist until the player sees them because I don’t want to have to resolve turns for 20+ units all the time in every level.)

Of course beyond all this I’m working on UI and trying to work out basic things like incrementing text that I know I’ve done before but not here.

Maxwell Lord
Dec 12, 2008

I am drowning.
There is no sign of land.
You are coming down with me, hand in unlovable hand.

And I hope you die.

I hope we both die.


:smith:

Grimey Drawer
Also at some point I’m going to need to be able to have one of those scrolling message feeds like most RPGs and MMOs do.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe

xgalaxy posted:

Are there any good examples of 2D games with naval combat in the golden age of piracy?
Any thing that cleverly avoids the "let’s circle each other endlessly" problem?

Starsector is a really good space based game that has clear analogue to this kind of combat but it also has the "let’s circle each other endlessly" problem. It somewhat gets away with it because of flashy visuals that a game set in the 1700s wouldn’t be able to lean on IMO.

The only thing I can think of would be to do something FTL-like and just eliminate movement entirely from the equation.

Puzzle Pirates does turn-based ship-to-ship combat. You lock in 4 actions, as well as when you fire your cannons, so e.g. a turn might be "go forwards; turn to the left and fire a broadside on the left side of the ship; don't move and fire another broadside on the left side; turn to the right". It's all about anticipating what your opponent is likely to do, and steering your ship such that you can hit that point and hopefully not get hit yourself. The board has winds that act like conveyor belts, and whirlpools that both move and turn any ship that ends on them; there's also rocks that act as walls. Also, your "turn left/right" actions are actually "move forward, turn 90 degrees, and move forward again" (i.e. they move diagonally forward and turn), so precise movement can be difficult sometimes. Which constrains your options and makes you easier to predict!

The other option of course is to throw theming away and add a bunch of wacky poo poo to your game. Let ships jump and strafe, give them weapons that freeze the ocean, create big explosions, that kind of thing. Basically what Waves of Steel did but set 200-300 years earlier :v:

JerikTelorian
Jan 19, 2007



I'm toying around with Godot and GScript and I'm having a bit of trouble finding what the preferred procedure is for storing and importing basic game data. Something like how a game might have a bunch of different swords (bronze, iron, steel, mithril, crystal, etc) that have different attack values and prices. I know that many games store this data in human readable files that can be readily edited to make mods or just tweak values.

In Godot, what would be the best way to do this? I know some games use scripting languages like Lua, and that C# has support for all kinds of stuff including XML. I'd like to stick with GScript since it seems like it's worth learning for ease of use with Godot. I saw that there is a "settings file" import but I'm not sure if that's suited to this purpose.

Dieting Hippo
Jan 5, 2006

THIS IS NOT A PROPER DIET FOR A HIPPO

JerikTelorian posted:

I'm toying around with Godot and GScript and I'm having a bit of trouble finding what the preferred procedure is for storing and importing basic game data. Something like how a game might have a bunch of different swords (bronze, iron, steel, mithril, crystal, etc) that have different attack values and prices. I know that many games store this data in human readable files that can be readily edited to make mods or just tweak values.

In Godot, what would be the best way to do this? I know some games use scripting languages like Lua, and that C# has support for all kinds of stuff including XML. I'd like to stick with GScript since it seems like it's worth learning for ease of use with Godot. I saw that there is a "settings file" import but I'm not sure if that's suited to this purpose.

There's no built-in data table view like Unreal Editor would have, but there is a Godot plugin that adds that functionality. I've been meaning to grab it since I'm going to be needing to use something like this real soon.

Tupperwarez
Apr 4, 2004

"phphphphphphpht"? this is what you're going with?

you sure?

JerikTelorian posted:

In Godot, what would be the best way to do this? I know some games use scripting languages like Lua, and that C# has support for all kinds of stuff including XML. I'd like to stick with GScript since it seems like it's worth learning for ease of use with Godot. I saw that there is a "settings file" import but I'm not sure if that's suited to this purpose.

From my understanding, the usual way to do this in Godot is to have your data structure as a class that extends the Resource class. Then, you use an instance of that class as normal in your game, change the data within, etc. and then save/load the data to file with the ResourceSaver and ResourceLoader singletons.

As for actually editing the resource files with a human-readable editor? You'll need to use a plugin like the one linked in a previous post, if you want to edit the resource in the Godot editor.

Alternatively, you can use file formats like CSV or JSON, as the File class has methods for parsing lines from CSV or parsing JSON files into Dictionary variables. I think there are some export shenanigans that you have to be mindful of when using CSV and JSON files, so be sure to read the docs.

anatomi
Jan 31, 2015

Dieting Hippo posted:

There's no built-in data table view like Unreal Editor would have, but there is a Godot plugin that adds that functionality. I've been meaning to grab it since I'm going to be needing to use something like this real soon.
Didn't know about that plugin. Very useful.

anatomi
Jan 31, 2015

anatomi posted:

Didn't know about that plugin. Very useful. Thanks.

Dieting Hippo
Jan 5, 2006

THIS IS NOT A PROPER DIET FOR A HIPPO
Speaking of Godot, I'm toying around with a roguelike in one. Got in some numpad-based movement and spent a bit of time on terrain generation. I finally got it to the point where it looks like terrain! I'll have to swap out the Kenney tileset for my own down the road, but for just getting things working now it's a godsend.

https://i.imgur.com/otu5oil.mp4
The current room ID number is displayed below the player, -2 means it's a "tunnel" between two rooms. Also, the box is the "in" stairs and the bars are the "out" stairs.

My current steps for generating terrain:

- Generate individual rooms based on a randomized Perlin noise. This makes a bunch of organic-looking holes of walkable terrain in the map, but none of them are connected.
- Find each individual room and the cells in them, grouping the cells by room.
- Get the shortest distance from every cell in each room, to the closest cell in each other room. This list gets sorted by distance between room cells from the smallest distance to the largest.
- Tunnel out paths between rooms in the Wall layer starting with the shortest distance, going to longest distance between their closest cells. Right before each tunneling a pathfinder check is performed, and if the two cells already have a connection through walkable terrain I skip the wall tunneling.

This gives nice winding paths where each spot of the level can be explored by walking, but never usually a straight shot since the paths will be winding. If I want I can then go back to my list of room connections I skipped and insert a few more tunnels for extra path variety.

Hammer Bro.
Jul 7, 2007

THUNDERDOME LOSER

I normally serialize to/from JSON in Godot.

There aren't automatic methods for determining what gets serialized because there's no one-size-fits-all assumption about what needs to be serialized, but it's not too hard to write your own classes around this that tailor it to your game logic.

For instance I like to write a Singleton class which can be requested to serialize some given object. It stores the path to the scene followed by one of either two things: 1) If the object has a _serialize_by_keys() method, act upon that. 2) If not, pluck out all script-defined variables and use them.

_serialize_by_keys() just returns the names of all variables I explicitly want serialized. So in practice I wrote the one clever class and then I can just tag the variable names I care about on any given class.

It gets a little more complicate as you drill down but it's not an unsurmountable task (and I enjoy that type of computer science).

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
I've been working on adding a "resumable" ship spawner to Waves of Steel. Ships in the game are complicated objects, with a lot of sub-components, and they create a lot of lag when they're created. The main game handles this by pre-loading everything that each individual mission needs, and just activating the ships when they need to be spawned in, but I want to work on a "survivors"-type game mode, where new ships are continually spawning in, and I want to avoid lag. So basically I just took the core ship assembly process (where the ship parts are instantiated, which is by far the laggiest part) and moved it from a synchronous function to a generator, sprinkling in a "yield return null" after each major step. Then the existing synchronous caller goes from code like

var ship = SpawnShip(...)

to

GameObject ship;
foreach (var step in ResumableSpawnShip(...)) {
ship = step;
}

where ResumableSpawnShip's return type is IEnumerable<GameObject>

This seems to work fine, with one single solitary exception. Every ship has two copies of its hull made for graphical purposes. One helps tell the ocean where the hull is, so that the ocean shader doesn't protrude above the deck's Y position. The other creates a "shadow" in the water underneath the ship, to help sell that the ocean is semitransparent instead of opaque. They both work by being exactly the same shape as the ship's hull, and in exactly the same place. ...except that as of this most recent change, they aren't in the same place. They're slightly offset, instead, both positionally and rotationally. This causes visual oddities in-game.

What's especially weird about this is that nothing in the codebase explicitly cares about these objects. The magic happens via putting one on a special layer, and using a special material for the other. Nothing should be adjusting their transforms, they have no colliders or rigidbodies, no references to them are stored and I'm sure not using GameObject.Find to dig them up. The only components on them are the transform, a mesh renderer, and a mesh filter.

I went so far as to sprinkle logging throughout every single Start and Awake call in my code, tracking the position of one of the stencil objects. From this I have learned that the object's transform spontaneously changes somewhere between the end of ShipDeathEffect.Start() and the beginning of CrowdControlShim.Start(). That isn't terribly useful though. ShipDeathEffect.Start() is part of the ship in question, so basically by the time the ship is done spawning, it thinks the stencil is in the right location. CrowdControlShim is directly part of the scene, so its Start runs sometime during scene initialization as a matter of course.

Naturally, there's no way to set a trap on the transform of an object, to figure out what could be changing it.

For the record, this is the code that sets up the stencil objects:
code:
    // Creates a copy of the hull with a special material. We have two
    // modes: one creates a stencil on a special layer that keeps the
    // ocean from appearing on top of the ship. The other creates a
    // copy of the ship that draws "underneath" the ocean, like
    // submarines do.
    private void AttachWaterStencil(GameObject ship, ShipAsset asset, bool isOceanCutout) {
        var stencil = asset.CopyShip();
        stencil.name = isOceanCutout ? "ocean cutout stencil" : "water shadow stencil";
        // Can't have the water cam seeing the low-detail version of the ship.
        ShipDesignerController.SetBestDetail(stencil);
        if (isOceanCutout) {
            // Stencil should be deactivated when in binoculars, otherwise
            // we can see the playership's effect on the ocean and it looks weird.
            ToggleOnBinocularsEvent.Attach(stencil, false);
            DieWithShip.Attach(stencil, ship);
        }
        // Apply materials
        foreach (var rend in stencil.GetComponentsInChildren<Renderer>()) {
            var mats = new Material[rend.materials.Length];
            for (int i = 0; i < rend.materials.Length; ++i) {
                mats[i] = isOceanCutout ? shipStencilMaterial : shipShadowMaterial;
            }
            rend.materials = mats;
        }
        // It has no physics.
        Destroy(stencil.GetComponentInChildren<Rigidbody>());
        foreach (var collider in stencil.GetComponentsInChildren<Collider>()) {
            Destroy(collider);
        }
        if (isOceanCutout) {
            LayerUtil.RecursiveSetLayer(stencil.transform, LayerUtil.waterEffectsLayer, null);
        }
        else {
            LayerUtil.RecursiveSetLayer(stencil.transform, ship.layer, null);
        }
        if (!isOceanCutout) {
            // Some cinematics want to be able to turn these off
            DisableOnCinematic.Attach(stencil, DisableOnCinematic.Type.WATER_SHADOW);
        }
        stencil.transform.SetParent(ship.transform);
        stencil.transform.localPosition = Vector3.zero;
        stencil.transform.localRotation = Quaternion.Euler(0, 180, 0); // HACK: why backwards?
        if (isOceanCutout) {
            // Narrower than the ship, slightly smaller in other dimensions.
            // The narrowness reduces visible "chunkiness" in the water along the edge of the ship's hull.
            stencil.transform.localScale = new Vector3(.6f, .99f, .99f);
            ShipStencilTracker.Attach(stencil, ship);
        }
        else {
            stencil.transform.localScale = Vector3.one;
        }
    }

anatomi
Jan 31, 2015

Do they have a parent GameObject that somehow changed its transform?

Red Mike
Jul 11, 2011

So your ship generation is now instead of happening in a single frame, happening across multiple frames. You're doing "ship = step;" in each step, and presumably the call to ResumableSpawnShip is passing in "ship" (which changes in each frame). Then when you then call AttachWaterStencil, you pass in "GameObject ship". I'm assuming that ResumableSpawnShip is generating a new GameObject in the first place from each call, otherwise I'm not clear why you're assigning "ship" over and over.

Is the "ship" you pass into AttachWaterStencil the initial GameObject, an intermediate one, or the final one? Because between every "frame" the game object will have moved.
Is there another yield return null after the final one? So that the "ship" you've saved is actually one frame behind?

Basically, it sounds almost like during AttachWaterStencil "ship.transform" is one frame behind or in front of where you expect. Hard to say more without knowing more about what all these bits are doing (like asset.CopyShip(), and ResumableSpawnShip()).

e: Are you meant to have AttachWaterStencil be in LateUpdate after the entire creation is done; in case the order of processing is different sometimes and it's only obvious now that the creation happens across multiple frames.

Red Mike fucked around with this message at 11:10 on Apr 18, 2024

TW0
Oct 31, 2022

The figure that still lies asleep in the Fantasy

I can't see anything wrong in your script, although there may be something affecting the transform of one of them in either DieWithShip or ShipStencilTracker.

Definitely keep looking through your ship assembly coroutine to make sure it matches the behaviour of the original function. Since the work is now being split across multiple frames, the order some functions are called in might now affect the result. Maybe try setting the parent transform in the Instantiate() function rather than afterwards with SetParent().


I assume your hierarchy looks something like this:
pre:
ship
  -> ocean cutout stencil
  -> water shadow stencil
You could also try making them both children of a GameObject called hull.
pre:
ship
  -> hull
    -> ocean cutout stencil
    -> water shadow stencil
If you only change the transform of hull, that should reduce the chance of them becoming misaligned.


Also, check if your version of Unity supports the InstantiateAsync() function. It's very useful for spawning objects at runtime without blocking the main thread and causing stutters, although it has to be done in a Coroutine or UniTask.

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

TW0 posted:

I can't see anything wrong in your script, although there may be something affecting the transform of one of them in either DieWithShip or ShipStencilTracker.

Definitely keep looking through your ship assembly coroutine to make sure it matches the behaviour of the original function. Since the work is now being split across multiple frames, the order some functions are called in might now affect the result. Maybe try setting the parent transform in the Instantiate() function rather than afterwards with SetParent().


I assume your hierarchy looks something like this:
pre:
ship
  -> ocean cutout stencil
  -> water shadow stencil
You could also try making them both children of a GameObject called hull.
pre:
ship
  -> hull
    -> ocean cutout stencil
    -> water shadow stencil
If you only change the transform of hull, that should reduce the chance of them becoming misaligned.


Also, check if your version of Unity supports the InstantiateAsync() function. It's very useful for spawning objects at runtime without blocking the main thread and causing stutters, although it has to be done in a Coroutine or UniTask.

you could always throw it in a Task, but it likely needs to be on the UnitySynchronizationContext anyway

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
EDIT: fixed it. Merely destroying a rigidbody isn't enough! You have to set it to kinematic, otherwise it'll be active for the rest of the frame for some goddamn reason :psyduck: Maybe this is fixed in later Unity versions (I'm on 2019.4), but jesus christ.

anatomi posted:

Do they have a parent GameObject that somehow changed its transform?

I've verified that its transform is properly "zeroed out" throughout the spawn process, but at some point later on (in the same frame, but later, and not in any Start/Awake code that I can detect), it changes, and I can't figure out why. The nature of the change (a slight displacement and rotation) would be consistent with the ship itself responding to being floated by the ocean, and that response somehow not propagating to the stencil objects. I just can't figure out why that would be. None of the rest of the game cares about these objects or knows that they exist.

EDIT: OK, that "would be consistent with" line I wrote got me thinking, and I dug up the code that the ship physics system uses to track the orcean, which has now been modified:

code:
    // Apply force at the back of the ship to get us to point towards our desired heading.
    private void SteerTowardsHeading(float delta) {
        // Scaling factor changes how responsively the ship chases the heading.
        // Scaling factor of 1 makes very smooth, slow-responding ships.
        // 10 is basically instant start/stop when turning.
        Vector3 force = new Vector3(delta * 2, 0, 0);
        // Convert force to local coordinates.
        force = transform.TransformVector(force);
        // Discard vertical component of force, which only appears if the ship is pitched
        // and which causes instability when steering (e.g. getting stuck on end or
        // spinning about the ship's long axis).
        force = force.WithY(0);
        var __foo = GameObject.Find("water shadow stencil"); if (__foo != null) Debug.Log($"CHECK: {__foo.transform.GetChild(0).localPosition}");
        Vector3 applyPos = transform.position - (forwardCache * shipLength / 2);
        rbod.AddForceAtPosition(force, applyPos, ForceMode.VelocityChange);
        // HACK: apply a countering force to the center of the ship, to keep it from drifting.
        rbod.AddForce(-force, ForceMode.VelocityChange);
        if (__foo != null) Debug.Log($"CHECK: {__foo.transform.GetChild(0).localPosition}");
        Physics.autoSimulation = false;
        Physics.Simulate(Time.fixedDeltaTime);
        if (__foo != null) Debug.Log($"CHECK: {__foo.transform.GetChild(0).localPosition}");

        if (!amKickflipping) {
            rbod.angularVelocity = Vector3.zero;
        }
    }
Immediately after that Physics.Simulate call, the stencil's transform is incorrect, i.e. it is that single physics tick that is causing the stencil to drift relative to the parent ship. Why this might be the case, I have no idea. As I mentioned, the stencil objects have no physics, they're just meshes childed to the ship.

This code runs on the root object of the ship, which the stencil is childed to. So the force is being applied to the ship, but not to the stencil object, causing said object to drift relative to the parent.

...is this a case of Destroy not taking effect immediately, maybe? There's code in the water stencil spawn function to remove rigidbodies and colliders, but of course, but of course that's not an immediate action...

Red Mike posted:

So your ship generation is now instead of happening in a single frame, happening across multiple frames.
Sorry, I wasn't clear in my previous post. No, it is not happening across multiple frames. I am working on enabling that to happen for some ships, but all existing ship spawns are still synchronous, because they consume all of the steps of the iterator in a single frame. I didn't want to re-architect the entire mission loading process, precisely because I was trying to avoid the kind of weird, hosed-up bugs I'm running into anyway :negative:

As for why I'm doing "ship = step" each step, that's the simplest way I could figure out to have a generator function actually return something. It only ever creates a single objects, which is the last object it `yield return`s. You aren't allowed to use out vars in generators, otherwise I'd do that.

TooMuchAbstraction fucked around with this message at 15:46 on Apr 18, 2024

Red Mike
Jul 11, 2011

TooMuchAbstraction posted:

As for why I'm doing "ship = step" each step, that's the simplest way I could figure out to have a generator function actually return something. It only ever creates a single objects, which is the last object it `yield return`s. You aren't allowed to use out vars in generators, otherwise I'd do that.

Ah I think I get what you're saying, you basically are creating the object at the 'first step' and then the subsequent steps aren't changing it (but need a reference to it)? If so, what I tend to do is create the game object itself (a wrapper or whatever) outside that method, and basically have the 'step' functions just accept that already-existing object. That way they never have to return anything, only modify what was passed in (which is initially blank). This also then lets you run the step functions on a pre-populated object in a different scenario. It also means you can't accidentally do `ship = X' within a step and have it somehow overwrite everything the previous steps did.


TooMuchAbstraction posted:

EDIT: fixed it. Merely destroying a rigidbody isn't enough! You have to set it to kinematic, otherwise it'll be active for the rest of the frame for some goddamn reason :psyduck: Maybe this is fixed in later Unity versions (I'm on 2019.4), but jesus christ.

Ahh, welcome to Unity's crazy Destroy internal logic.

Destroying the actual objects never takes effect before the end of the Update loop (but does take effect before LateUpdate, I believe), but removal of components from an object (when you destroy a component) sometimes takes effect and sometimes doesn't. DestroyImmediate doesn't suffer from this (but obviously has its own set of weirdness).

Also setting it to kinematic won't for example stop it triggering kinematic collision events or whatever.

If I'm understanding right, what's happening is basically: within an Update loop you're making a copy of the ship and all its components, then removing the rigidbodies/etc from the copy, but somehow the Update for another object is picking up the new object before the rigidbody removal?
If so, you can avoid that by setting the ship object inactive, making the copy, then making the ship active again; assuming you're not relying on OnEnable/etc too much. The copy starts off inactive, which should stop it being picked up by Update for the other components.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe

Red Mike posted:

If I'm understanding right, what's happening is basically: within an Update loop you're making a copy of the ship and all its components, then removing the rigidbodies/etc from the copy, but somehow the Update for another object is picking up the new object before the rigidbody removal?
I believe what's happening is:
1. Create ship with all its components
2. Clone specifically the ship's hull, which is just a mesh/collider/rigidbody combination
3. Child the clone to the ship (which means we now have a rigidbody that's a child of another rigidbody)
4. Destroy the rigidbody and colliders
5. Physics applies forces to the ship, but not to the clone because it apparently still has its own rigidbody
6. Rigidbody and colliders are actually removed

I dunno why the restructuring of my code caused this to happen, since both before and after the change, the entire ship is getting created and the Destroy calls are happening before physics gets involved. :shrug:

Red Mike
Jul 11, 2011
It's entirely possible that it was always broken, but the Update() calls happened to run in the right order such that it didn't matter.

TooMuchAbstraction posted:

1. Create ship with all its components
2. Clone specifically the ship's hull, which is just a mesh/collider/rigidbody combination
3. Child the clone to the ship (which means we now have a rigidbody that's a child of another rigidbody)
4. Destroy the rigidbody and colliders
5. Physics applies forces to the ship, but not to the clone because it apparently still has its own rigidbody
6. Rigidbody and colliders are actually removed

Before your changes, #5 might have been running before #1-4 just because its Update() call happened to run first. The order is deterministic within a build but effectively random and things can influence it unexpectedly. Once #5 started running after #1-4, the fact that the rigidbody/colliders never got removed suddenly mattered. This usually tends to happen with transforms particularly because of how the transforms basically update as-the-updates-happen, so you end up with weirdness like cameras pointing at old/new locations unexpectedly.

This is why a lot of smaller projects don't tend to rely on the built-in Update() method and instead have their own manager singleton object that will within its own Update order and call the real Update from every object in the scene. Which is overkill and hard to do in a performant way, but avoids these weird issues.

Your Computer
Oct 3, 2008




Grimey Drawer
sometimes u just gotta return


https://i.imgur.com/JrxDzkF.mp4

Deki
May 12, 2008

It's Hammer Time!
A friggin year after I started working on the current iteration of my game in earnest, I finally have the animation window showing the game looking like a weapon shop.

Hammer Bro.
Jul 7, 2007

THUNDERDOME LOSER

Speaking of revisiting old things, I'm circling back to my best jam game (for the third(?) time now) but trying to do it in actual-3D:

https://twitter.com/StrangeHill2DO/status/1781913670253175176

Can anyone explain how to translate a Node3D (3D Object)'s rotation into 2D (for the sprite)?

global_rotation.z is clearly not quite right.

megane
Jun 20, 2008



I think you'd do something like
pre:
var fw : Vector3 = -global_basis.z
var fw2d : Vector2 = Vector2(fw.x, fw.z).normalized()
# if you want the rotation:
var rot : float = fw2d.angle()

Moskau
Feb 17, 2011

HEY GUYS DON'T YOU LOVE ANIME?! I LOVE ANIME SO MUCH ESPECIALLY ALL THE PANTY SHOTS AND FAN SERVICE AND MOE MOE MOE! I JUST CAN'T GET ENOUGH!

digging the Spectrum vibes :allears:

Shoehead
Sep 28, 2005

Wassup, Choom?
Ya need sumthin'?
Been working on my games a little again this month. I keep seeing small updates I made to both of these in 2022 and like very little after, it's been such a weird like 18 months!

New guy for the Zelder game
https://x.com/Shoehead_art/status/1774450445995438404

And then a nasty surprise for the shooter
https://x.com/Shoehead_art/status/1782041295877263622

I also fixed a heap of my lovely dumb bugs. I've a huge area for the shooter in greyboxed planning done, and heaps of little things for the zelda game. I really should stop splitting my attention like this but whatever

Shoehead fucked around with this message at 14:57 on Apr 21, 2024

KRILLIN IN THE NAME
Mar 25, 2006

:ssj:goku i won't do what u tell me:ssj:


paging TWD to the thread

https://twitter.com/maxbittker/status/1782645521888247956

Aryoc
Nov 27, 2006

:black101: Goblin King :black101:
Grimey Drawer
Did some renovating on Goblin Camp's buildings menu. Now if you click a notification that references a building it'll autofill the search bar, I made the search fuzzy so it'll match even if you typo a bit _and_ buildings that don't match the filter are visible but grayed out. Feels like it makes it way easier to find the building you want to build now, and should keep working even as the number of buildings keeps growing.

https://i.imgur.com/WIV4ScR.mp4

[edit: fixed the imgur link]

Aryoc fucked around with this message at 12:25 on Apr 23, 2024

Hammer Bro.
Jul 7, 2007

THUNDERDOME LOSER

Those were never my style games but man is that doing a good job of capturing those style games. Givin' me a pang of nostalgia for something I didn't really play.


They brute forced their way into a million dollars and I am here for it.

xzzy
Mar 5, 2009

step one: make game
step two: never optimize
step three: seriously, never optimize
PROFIT!!

Polio Vax Scene
Apr 5, 2009



unironically true. i cant argue with the results

Phigs
Jan 23, 2019

To optimize Balatro would have been premature.

FUCK SNEEP
Apr 21, 2007




you don't need to optimize until you have to ;)

Bongo Bill
Jan 17, 2012

If it gets you over the finish line, it's good enough. But it's prudent to prepare for the likelihood that it's going to be more complicated than you thought.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
At some level, this complexity needs to be encoded somewhere. And sure, maybe you could have a big data table that encodes it instead, and load a CSV or JSON file or something...but depending on how many different kinds of behaviors you need to represent, that may not actually save you much.

Dewgy
Nov 10, 2005

~🚚special delivery~📦
Also it’s Lua, which has been deceptively efficient for decades. Just hand it whatever poorly thought out half assed (but functional) bullshit you want to do and it’ll fly with it.

Semi-famous example: Based the remastered version’s commentary, Grim Fandango had a bug where the live, dynamic, off-screen cat races they set up for one part of the game accidentally never switched off.

They never noticed because it never caused any problems or performance issues. Just kept racing, frame after frame, eternally, until you hit the end of the credits and started a new game. And this was back in 1998, in a game that was kind of considered to be pushing the envelope for its time.

xzzy
Mar 5, 2009

If I had to choose between a thousand row spreadsheet and a thousand if statements, I'd probably choose the if statements.

For a game like Balatro where you got a lot of entities with a lot of custom behaviors, trying to encode that on a spreadsheet sounds like more work than making the game. At least an if statement lets you customize on a per case basis. Added bonus it runs your game!

Tunicate
May 15, 2012

IIRC Lua doesnt' have a match statement or switch statement built in, right?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
A common way to do that would be to use polymorphism or some other dynamic dispatch - just have a separate Behaviour object for each joker and put whatever code you want in an onScore function.

But it feels like a ton of boilerplate to write it that way when you're starting out with only a half-dozen cases, it's often easier to just start with something that works well at that small scale and then keep growing it.

Adbot
ADBOT LOVES YOU

hailthefish
Oct 24, 2010

Tunicate posted:

IIRC Lua doesnt' have a match statement or switch statement built in, right?

afaik

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