Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Simon

Pages: [1] 2 3 ... 207
Lix Main / Re: Undo in the editor
« on: July 10, 2020, 11:50:17 pm »
Thanks, several good ideas.

You drag some tiles, and mid-motion, hit the hotkey to rotate them. Should this generate 1 undoable, or 3 undoables (move, rotate, move)? I'm leaning towards 3.
I would not have expected this situation to be possible in the first place

I think I do it because I know how it's implemented. The mouse dragging moves the tiles 60 times per second; these moves (in 0.9.31 = current no-undo Lix) are committed instantly to level every time, thus the intermixed rotation is meaningful and uninterruptive.

The downside of this frequent committing is that it's more work now to merge the entire dragging into a single undoable.

This frequent committing isn't standard in GUI. Other programs will let user drag a shadow or an outline of the dragee. I'm really 50:50 on this. The rotation on the fly is cool and matches how we move real-life household objects.

clickable buttons to rotate / etc, while using the keyboard to move pieces.
follow up with some keyboard movement afterwards to get it to the exact desired spot.

Right, this tile nudging via keyboard is also extremely common. The keyboard is more precise than the mouse when grid alignment won't suffice.

When the mouse isn't dragging, and the key is merely tapped, not held, then I'll make the tap generate a single standalone undoable for its effect: moving all selected pieces, rotating selected pieces, deleting selected pieces, ... When we tap 5 times in quick succession to nudge selection rightwards by single pixel each, this generates 5 undoables that I won't merge. Sounds OK.

When a directional key is held, not merely tapped, the selection moves once, then waits (threshold), then moves 60 times per second. I would like the entire keyholding to generate only a single undoable.

There is more to reply. Until soon!

-- Simon

Lix Main / Re: 2020 Roadmap
« on: July 10, 2020, 07:23:22 am »
These two, I assume?

The lobby needs a place for the colorful bars after the game. Unclear where to sacrifice screen space. This is the main design problem. Otherwise, these two are very much doable.

-- Simon

Lix Main / Re: Undo in the editor
« on: July 09, 2020, 09:57:31 pm »
Right -- skills, name, number of lix etc. don't have to be undoable. I was unsure with this too. I suspected that it should be undoable for consistency with everything else, but good usability here will be delicate and costly, right.

Map dimensions and wrapping: When this changes, tiles may move/wrap. This seems much harder to keep orthogonal to what happens in the undo stack. Likely, I'll have to make this undoable.

-- Simon

Lix Main / 2020 Roadmap
« on: July 09, 2020, 09:39:08 pm »
For the second half of 2020, I'm planning:
  • Undo in the editor. I've poured serious effort into undo, but it's not finished. Undo must become a non-buggy releaseable feature. At first, only tile additions/deletions will be undoable. More actions will follow to become undoable. Probably some minor actions won't yet be undoable by end of 2019. We'll see.
  • Introduce an end-of-level screen that previews the next level. Maybe offer two levels: The next level, and the next unsolved level.
  • Replay tweaker: Add insert mode
  • Probably no physics change, no introduction of neutral lixes yet, ... But I should propose a battle plan for such breaking changes. Physics have subtle bugs, and I still haven't merged fixes that have been cooking since summer 2017.
-- Simon

Lix Main / Re: Undo in the editor
« on: July 09, 2020, 09:28:25 pm »
After heavy refactoring, this is the status quo of unreleased development lix-unstable, branch editor-undo:
  • Editor has undo/redo buttons.
  • Inserting a tile from the tile browser is undoable. This is good as-is, although rarely useful.
  • Deleting an arbitrary selection is undoable as a unit. Undo re-adds the tiles. They aren't selected after getting added. Should they be selected? This will be a doable but nontrivial task; ideally, we'll decide later.
  • Copying an arbitrary selection is buggy at the moment, this must be fixed, and this should also be undoable as a unit.
  • Moving an arbitrary selection is undoable, but in a terrible way: While the mouse isn't still, each individual moving tile generates 60 undoable commands per second only for this single tile. These must certainly be grouped. But how? Complex scenario: You drag 3 tiles, and mid-motion, hit the hotkey to rotate them. Should this generate 1 undoable, or 3 undoables (move, rotate, move)? I'm leaning towards 3. :lix-cool:
  • Rotation/mirroring/dark isn't undoable yet.
  • Changing level properties via dialogs isn't yet undoable. This is the most boring and I have 100 % compassion for NL to have had a bug there. :lix-blush:
  • When stuff happens that isn't yet undoable, but we undo the most recent undoable, consistency checks fire and crash the app with an error.
  • When the undo stack is empty, the undo/redo buttons are shown anyway. This is a general problem in the editor, it has clickable buttons that do nothing, e.g., rotate button when you have nothing selected.
Current no-undo Lix version is 0.9.31. Maybe I'll have enough undo in shape for 0.9.32, maybe not. Anyway, the first version with undo will probably get this:
  • Fix copying tiles. Then all adding/removing will be undoable. This will be useful already: Undoing deletions is the important use case.
  • Make the tile moving non-undoable, i.e., cut this half-baked feature. Undoable moving can happen in a future version. I haven't released in months, it's time to release something.
  • Empty the undo stack whenever we do something yet non-undoable in the editor. This will keep the undoing always consistent. No more crashes from detected inconsistency.
  • Show/hide the undo buttons when the stack is empty.
In the yet-distant future, everything should be undoable. The undo stack should never be emptied during normal work.

-- Simon

Interesting that there is this cultural discrepancy between tilesets and music. A pack can access the NL-installation-globally installed tilesets (in pack-independent folder) or come with its own tilesets (in its pack folder). I would have expected the music to follow the same culture, or the tilesets to follow the music culture.

But my world view of NL tilesets may be outdated; I'll have a chat with Icho today.

Edit: Discussed this with Icho. Tilesets must also be installed NL-installation-globally.

-- Simon

Yes, a blatant text on pause-on-time-exceeded is good. It's better than a dialog, and better than the uninformative pause.

-- Simon

I sympathize with the argument that a level should always be solvable, and pause as it becomes unsolvable. Main reason is simpler presentation, no need to interpret what pink means.

Exploration of the unsolvable state is also very nice. This avoids weird pauses; the meaning of the pauses isn't 100 % obvious at first.

If you can explore past the time limit, should you also be able to assign arbitrarily many skills, making the skill count negative? I remember Icho felt strongly against exploring with negative skills. Is the feeling against negative skills stronger than any feeling against exploring past the time limit?

On losing all lemmings, should the game act differently than on reaching the time limit?

-- Simon

General Discussion / Re: Simon blogs
« on: June 28, 2020, 08:46:10 pm »
Thanks for the suggestions to post in both places!

The problem is elaborate to describe from scratch, it relies on several details. For a start: Tiles and Occurrences, I'll probably move that and any replies to new topic.

Quote from: ccexplore
But I also think you are actually already the person on the forum who's most well-versed in the theory and practice of software design and architecture.

This is flattering. :lix-blush: I would have easily thought that you were the most well-versed, or else one of the professional software engineers who post less often, but supposedly have formal education and more years in the business. Thanks!

Still so much to learn, especially with my near-zero experience in multithreading and inter-process communication (apart from networking, or temp files).

Quote from: Dullstar
there's certainly not any harm in posting it here. I'd certainly be interested in seeing whatever you come up with; I find your posts on these topics quite interesting and informative.

This is very inspiring, thanks! This was the reason that I've begun here today with the explanation.

Re colors in Lix: Hmm, reasonable recommendations. I'll have to consider everything here in case of a physics or format change. Light grey would be a good neutral color.

-- Simon

Tech & Research / Re: Object-oriented design with Simon
« on: June 28, 2020, 07:37:32 pm »

I'll explain the Lix level data structure: what the level contains after the level's text file has been parsed, but before we play the level. This is my first step to describe my triple dispatch problem.

Consider the Lix level Building Block Maze.

There are more than 40 yellow building blocks in this level. You'll find their graphics in ./images/geoo/sandstone/. When Lix wants to render this level, it too must load these graphics files.

Even though the level contains over 40 blocks, Lix only loads these 11 images.

Tiles and Occurrences. Look at the exit tile (archway with staircase). This is a single Tile. Building Block Maze contains two Occurrences of this single Tile, one in the top left and one in the top right.

A Tile is the result of a tile image loaded from disk. A Tile has a certain size, a mask, and knows whether it's terrain, steel, hatch, exit, ...

class Tile:
    Bitmap bitmap
    constructor(String filename):
        bitmap = expensive_load_from_disk(filename)

An Occurrrence, for the lack of a better word, is a usage of a Tile in a level. An Occurrence has a position, rotation, and knows whether it must be drawn normally or rather erase other terrain.

class Occurrence:
    const(Tile)* tile
    Point position
    int rotation
    bool erase

Reason. Loading a file from disk is expensive, and so is video memory. While it wouldn't be a problem loading 40 tiles instead of 11, it will be nasty when large levels contain 1,000 or 10,000 Occurrences, and we would have a disk load for each.

We want to load the same file only once, and have it in video memory only once. Since a Tile is immutable, i.e., it won't change anymore after it has been created successfully, many Occurrences can refer to the same Tile without risking bugs from sharing memory.

Problem with my naming. Tile and Occurrence are classes in Lix. I absolutely wanted to avoid naming either class Object, Instance or Class -- these names are already common OO parlance. Nonetheless, I'm unhappy. Colloquially, I often refer to an Occurrence as a Tile. This is a hint that the class names aren't optimal. Alternatives:
  • NeoLemmix calls my Tile a MetaTile and my Occurrence a Tile.
  • The traditional language of the Flyweight pattern calls my Tile the intrinsic state and my Occurrence the extrinsic state. Not short, not catchy, but standard.

Tile database. How to ensure that we really load every Tile at most once from disk? When a level parses its text file that calls for two exit Occurrences, the level shouldn't construct a Tile for that exit all by itself. Instead, we defer the responsibility of construction to a dedicated tile database, and, throughout the program, fetch the Tiles from that database. After all, tricky construction and bookeeping is at the heart of the problem, it makes sense to relieve everybody else from that worry.

The tile database treats the tile filenames as keys. When the Tile is wanted for the first time, the tile database loads the Tile from disk, caches it, and returns a reference to it. Every future time the same Tile is wanted, a reference to the already-cached Tile is returned.

The tile database, ideally, is its own class: Occasionally, it makes sense to delete and recreate the database, e.g., to unload all Tiles because their hardware bitmaps are are tied to a screen, and you want to change screen modes. It's also better for testing to avoid many global variables or singleton classes.

Still, even though you should design the tile database so that it's not a singleton, it still behaves much like global state, with the usual problems: You must either pass it around everywhere, or put it in your context object, or just make a single global database object because that's the least nasty solution.

Summary. Flyweight decomposes an object into two parts, the intrinsic immutable platonic ideal (Lix's Tile) and the extrinsic part that may vary every time we need the object (Lix's Occurrence). This is useful when the intrinsic part is expensive (Lix must load an image from disk), yet we want hundreds of instances. A key-value storage creates and remembers the intrinsics. The remainder of the program gets its intrinsics from there via keys (Lix's tile filenames).

Game programmers may invent all of this themselves. Then, years later, we read on the internet that this is a classic object-oriented pattern with a dedicated name, Flyweight. :lix-grin:

-- Simon

Lix Main / Re: Replay Tweaker: Add insert mode, what else?
« on: June 22, 2020, 07:18:39 pm »

Right, that's my hunch, too: Insertion is most important to add. Together with deletion that doesn't cut, it allows many results reasonably quickly already.

We'll see what ideas appear in the future. The tweaker is still young and you haven't gotten substantial change requests yet, either.

-- Simon

Lix Main / Replay Tweaker: Add insert mode, what else?
« on: June 21, 2020, 10:46:09 pm »

Proxima has submitted to Level Design Contest #20: Thirteen Little Skills. This is a disjoint union (= the level is separated into several independent areas) and thus would profit from better tooling in Lix. We want to focus on one area without worrying about lix dying in other areas.

Lix has the replay tweaker (film-strip button in the panel during play) to move or delete assignments without cutting the replay.

The main missing functionality is insert: When you click to assign, instead of first cutting all future assignments, the new assignment will be inserted without cutting anything from the replay. I would like to offer this in the replay tweaker as a mode: The default is cut-then-append (= normal behavior of most Lemmings-like games with interruptable action replay), and the second mode is insert-without-cutting (= what NeoLemmix shows with blue letter R in the panel).

What else should the replay tweaker offer?

I'm still busy with undo in the editor, undo is a mammoth feature to make nice. Afterwards, I'm considering either buffing the replay tweaker, or make a dedicated end-of-level screen that offers next levels.

-- Simon

Engine Bugs / Suggestions / Re: [DISC][PLAYER] Remove timer on nuke
« on: June 20, 2020, 11:31:34 pm »
Countdown bypass nuke: When you activate this, it must remove (without explosion) all lemmings that are younger than 5 seconds. This is lovely for whoever knows the entire history of this feature, but will look odd to everybody else.

-- Simon

Engine Bugs / Suggestions / Re: [DISC][PLAYER] Remove timer on nuke
« on: June 19, 2020, 08:02:57 pm »
It seems like most existing nuke solutions should still work with this change by simply initiating the nuke 5 seconds later.
[...] And possibly a few other details
[...] these sorts of details are not typically used or required in nuke solutions.

Hard to assess whether "most" is correct; I'm not this deeply in custom content to judge.

At least one more level where undelayed nuke certainly affects solvability:
Spoiler (click to show/hide)

Hard decision.

There is the discrepancy between manually assigned exploders and nuke-exploders.

The nuke is highly special anyway; the nuke has a fool's license to work however it likes, softening the discrepancy. Aesthetically, both the timed and the undelayed nuke sound fine.

It would break a few select levels.

-- Simon

NeoLemmix Levels / Re: Was: TeleLems
« on: June 19, 2020, 05:04:46 pm »
mantha16 has unpublished TeleLems. We've deleted the original topic.

-- Simon

Pages: [1] 2 3 ... 207